bool IrAtmosphere1::calculateAtmosphereContribution(IrQueryMsg* const msg, LCreal* totalSignal, LCreal* totalBackground)
{
   // Sum the total signal that reaches the seeker of the target represented by the message
   // and the background noise observed by the seeker

   const LCreal* centerWavelengths = getWaveBandCenters();
   const LCreal* widths = getWaveBandWidths();
   const LCreal* sigArray = msg->getSignatureByWaveband();
   const Player* ownship = msg->getOwnship();
   const Player* target = msg->getTarget();

   // FAB - this should be angle of gimbal, not angle to target. (see base class)
   // Determine the angle above the horizon to be used for background radiation lookup
   const LCreal range2D = msg->getRange();
   const LCreal tanPhi = static_cast<LCreal>( (target->getAltitudeM() - ownship->getAltitudeM())/ range2D );
   const LCreal tanPhiPrime = tanPhi - ( range2D / 12756776.0f ); // Twice earth radius

   // appears that negative angles are down in this calculation
   LCreal viewingAngle = lcAtan(tanPhiPrime);

   // table limits are 0 to pi; this correction assumes that 0 in the table is straight down, PI is straight up
   viewingAngle += PI/2.0;

   *totalSignal = 0.0;
   *totalBackground = 0.0;

   for (unsigned int i=0; i<getNumWaveBands(); i++) {
      const LCreal lowerBandBound = centerWavelengths[i] - (widths[i] / 2.0f);
      const LCreal upperBandBound = lowerBandBound + widths[i];

      // determine ratio of this band's coverage to entire atmosphere waveband
      const LCreal fractionOfBandToTotal = (upperBandBound - lowerBandBound) / ((centerWavelengths[getNumWaveBands() - 1] + (widths[getNumWaveBands() - 1] / 2.0f))-(centerWavelengths[0] - (widths[0] / 2.0f)));

      // Find the limits of the sensor
      const LCreal lowerSensorBound = msg->getLowerWavelength();
      const LCreal upperSensorBound = msg->getUpperWavelength();

      // Determine how much of this wave band overlaps the sensor limits
      const LCreal lowerOverlap = getLowerEndOfWavelengthOverlap(lowerBandBound, lowerSensorBound);
      LCreal upperOverlap = getUpperEndOfWavelengthOverlap(upperBandBound, upperSensorBound);

      if (upperOverlap < lowerOverlap) upperOverlap = lowerOverlap;

      const LCreal overlapRatio = (upperOverlap - lowerOverlap) / (upperBandBound - lowerBandBound);

      // Get the background radiation given the sensor altitude and the viewing angle
      LCreal backgroundRadianceInBand = overlapRatio * getBackgroundRadiation(
                                                lowerBandBound,
                                                upperBandBound,
                                                static_cast<LCreal>(ownship->getAltitudeM()),
                                                viewingAngle);
      LCreal radiantIntensityInBin(0.0);
      if (sigArray == 0) {
         // signature is a simple number
         // distribute simple signature evenly across atmosphere bins
         // need to apply overlapRatio to simple signature - already applied for complex signature in IrSignature...
         radiantIntensityInBin = msg->getSignatureAtRange() * fractionOfBandToTotal * overlapRatio;
      }
      else {
         // Find the limits of the bin
         //lowerBandBound = sigArray [i*3];
         //upperBandBound = sigArray [i*3 + 1] ;
         // assuming that signature bands match atmosphere bands
         radiantIntensityInBin = sigArray[i*3 + 2];
      }

      // add in reflected solar radiation
      const LCreal solarRadiationInBin = ((1.0f - msg->getEmissivity()) * getSolarRadiation(centerWavelengths[i],
                                    static_cast<LCreal>(target->getAltitudeM())));
      radiantIntensityInBin += (solarRadiationInBin * overlapRatio);

      // Lookup the transmissivity in the wave band given the altitudes of sensor
      // and target and the ground range between the two
      const LCreal transmissivity = getTransmissivity(
                                                lowerBandBound,
                                                upperBandBound,
                                                static_cast<LCreal>(ownship->getAltitudeM()),
                                                static_cast<LCreal>(target->getAltitudeM()),
                                                range2D);

      *totalSignal += radiantIntensityInBin * transmissivity;

      // Add the background radiance from the this waveband within the sensor limits
      // to the total background radiance received by the sensor, watts/sr-m^2
      *totalBackground += backgroundRadianceInBand * transmissivity;
   }

   return true;
}
Beispiel #2
0
bool IrAtmosphere::calculateAtmosphereContribution(IrQueryMsg* const msg, LCreal* totalSignal, LCreal* totalBackground)
{
   const LCreal* centerWavelengths = getWaveBandCenters();
   const LCreal* widths = getWaveBandWidths();
   LCreal totalWavelengthRange = ((centerWavelengths[getNumWaveBands() - 1] + (widths[getNumWaveBands() - 1] / 2.0f))-(centerWavelengths[0] - (widths[0] / 2.0f)));
   const LCreal* sigArray = msg->getSignatureByWaveband();
   LCreal range2D = msg->getRange();
   *totalSignal = 0.0;
   *totalBackground = 0.0;
   LCreal backgroundRadiance = 0.0;

   // determine relation of FOV to horizon, to decide how much earth and how much sky in background
   {
      LCreal currentViewAngle;
      LCreal viewAngleToHorizon;

      // viewAngleToTarget is angle to target, not angle my sensor is actually pointing.
      // we want the fov i'm actually pointing at, not a FOV centred on each target

      // determine elevation angle to target, negative angles are down
   //{
   // //Player* ownship = msg->getOwnship();
   // // Determine the angle above the horizon to be used for background radiation lookup
   // LCreal range2D = msg->getRange();
   // LCreal tanPhi = (LCreal)( (msg->getTarget()->getAltitudeM() - msg->getOwnship()->getAltitudeM())/ range2D );
   // LCreal tanPhiPrime = tanPhi - ( range2D / 12756776.0f ); // Twice earth radius
   // // appears that negative angles are down in this calculation
   // currentViewAngle = lcAtan(tanPhiPrime);
   // // table limits are 0 to pi; this correction assumes that 0 in the table is straight down, PI is straight up
   // //viewAngleToTarget += PI/2.0;
   //}

      // determine elevation angle of gimbal/ownship, negative angles are down
      {
         osg::Vec3d angles;
         osg::Matrixd mm = msg->getGimbal()->getRotMat() * msg->getOwnship()->getRotMat();
         // compute Geodetic orientation angles
         Basic::Nav::computeEulerAngles(mm, &angles);
         currentViewAngle = angles[Player::IPITCH];
      }

      // FAB determine angle to horizon, positive angles are down
      {
         double hDist = 1000000.0 * Basic::Distance::NM2M;  // Distance to horizon (m) (default: really far away)
         double hTanAng = 0;
         
         // earth radius in meters
         double er = Basic::Nav::ERAD60 * Basic::Distance::NM2M;
         
         // distance from the center of the earth
         double distEC = msg->getOwnship()->getAltitudeM() + er;
         double distEC2 = distEC * distEC;  // squared
         
         // earth radius squared
         double er2 = er * er;
         
         // distance to horizon squared
         double dh2 = distEC2 - er2;
         
         // the distance and the tangent of the angle to the horizon
         hDist = sqrt(dh2);
         hTanAng = ( hDist / er ); // positive angles are below level (down)
         viewAngleToHorizon = lcAtan(hTanAng); 
      }
   
      // determine ratio of earth and sky in the FOV
      LCreal angleToHorizon = currentViewAngle + viewAngleToHorizon;
      LCreal fovtheta = msg->getSendingSensor()->getIFOVTheta();
      
      if (angleToHorizon - fovtheta >= 0) {
         // no ground, all sky?
         backgroundRadiance = getSkyRadiance();
      }
      else if (fovtheta - angleToHorizon >= 2*fovtheta) {
         // all ground, no sky?
         backgroundRadiance = getEarthRadiance();
      }
      else  {
         // looking at ground & sky
         LCreal ratio = 0.5 + 0.5*angleToHorizon/fovtheta;   // convert range of -1 to 1 noninclusive to range of 0 to 1 noninclusive
         backgroundRadiance = ratio*getSkyRadiance() + (1.0-ratio)*getEarthRadiance();
      }
   }
   
   for (unsigned int i=0; i<getNumWaveBands(); i++) {
      LCreal radiantIntensityInBin;
      LCreal lowerBandBound = centerWavelengths[i] - (widths[i] / 2.0f);
      LCreal upperBandBound = lowerBandBound + widths[i];
      
      // determine ratio of this band's coverage to entire atmosphere waveband
      LCreal fractionOfBandToTotal = (upperBandBound - lowerBandBound) / totalWavelengthRange; 
      
      // Find the limits of the sensor
      LCreal lowerSensorBound = msg->getLowerWavelength();
      LCreal upperSensorBound = msg->getUpperWavelength();
      
      // Determine how much of this wave band overlaps the sensor limits
      LCreal lowerOverlap = getLowerEndOfWavelengthOverlap(
                                                   lowerBandBound,
                                                   lowerSensorBound);
      LCreal upperOverlap = getUpperEndOfWavelengthOverlap(
                                                   upperBandBound,
                                                   upperSensorBound);
      
      if (upperOverlap < lowerOverlap) upperOverlap = lowerOverlap;
      
      LCreal overlapRatio = (upperOverlap - lowerOverlap) / (upperBandBound - lowerBandBound);
      
      // this depends on whether target is a sky or earth based target
      LCreal backgroundRadianceInBand = backgroundRadiance * fractionOfBandToTotal * overlapRatio;
      
      if (sigArray == 0) {
         // signature is a simple number
         // distribute simple signature evenly across atmosphere bins
         // need to apply overlapRatio to simple signature - already applied for complex signature in IrSignature...
         radiantIntensityInBin = msg->getSignatureAtRange() * fractionOfBandToTotal * overlapRatio;
      }
      else {
         // if the IrQueryMsg has a sigArray, then the signature is a multi-band signature
         // Find the limits of the bin
         //lowerBandBound = sigArray [i*3];
         //upperBandBound = sigArray [i*3 + 1] ;
         // assuming that signature bands match atmosphere bands
         radiantIntensityInBin = sigArray[i*3 + 2];
      }
      LCreal test = getTransmissivity(i, range2D);
      *totalSignal += radiantIntensityInBin * getTransmissivity(i, range2D);     //* getTransmissivity();
      
      // Add the background radiance from the this waveband within the sensor limits
      // to the total background radiance received by the sensor, watts/sr-m^2
      *totalBackground += backgroundRadianceInBand * getTransmissivity(i, range2D);   //* getTransmissivity();
   }
   
   return true;
}