Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
bool IrAtmosphere::calculateAtmosphereContribution(IrQueryMsg* const msg, double* totalSignal, double* totalBackground)
{
    const double* centerWavelengths = getWaveBandCenters();
    const double* widths = getWaveBandWidths();
    double totalWavelengthRange = ((centerWavelengths[getNumWaveBands() - 1] + (widths[getNumWaveBands() - 1] / 2.0f))-(centerWavelengths[0] - (widths[0] / 2.0f)));
    const double* sigArray = msg->getSignatureByWaveband();
    double range2D = msg->getRange();
    *totalSignal = 0.0;
    *totalBackground = 0.0;
    double backgroundRadiance(0.0);

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

        // viewAngleToTarget is angle to target, not angle my sensor is actually pointing.
        // we want the fov i'm actually pointing at, not a FOV centered 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
        // double range2D = msg->getRange();
        // double tanPhi = (double)( (msg->getTarget()->getAltitudeM() - msg->getOwnship()->getAltitudeM())/ range2D );
        // double 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
        {
            const base::Matrixd mm = msg->getGimbal()->getRotMat() * msg->getOwnship()->getRotMat();
            // compute Geodetic orientation angles
            base::Vec3d angles;
            base::nav::computeEulerAngles(mm, &angles);
            currentViewAngle = angles[Player::IPITCH];
        }

        // FAB determine angle to horizon, positive angles are down
        {
            double hDist = 1000000.0 * base::distance::NM2M;  // Distance to horizon (m) (default: really far away)
            double hTanAng = 0;

            // earth radius in meters
            const double er = base::nav::ERAD60 * base::distance::NM2M;

            // distance from the center of the earth
            const double distEC = msg->getOwnship()->getAltitudeM() + er;
            const double distEC2 = distEC * distEC;  // squared

            // earth radius squared
            const double er2 = er * er;

            // distance to horizon squared
            const double dh2 = distEC2 - er2;

            // the distance and the tangent of the angle to the horizon
            hDist = std::sqrt(dh2);
            hTanAng = ( hDist / er ); // positive angles are below level (down)
            viewAngleToHorizon = std::atan(hTanAng);
        }

        // determine ratio of earth and sky in the FOV
        const double angleToHorizon = currentViewAngle + viewAngleToHorizon;
        const double 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
            double 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++) {
        const double lowerBandBound = centerWavelengths[i] - (widths[i] / 2.0);
        const double upperBandBound = lowerBandBound + widths[i];

        // determine ratio of this band's coverage to entire atmosphere waveband
        const double fractionOfBandToTotal = (upperBandBound - lowerBandBound) / totalWavelengthRange;

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

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

        if (upperOverlap < lowerOverlap) upperOverlap = lowerOverlap;

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

        // this depends on whether target is a sky or earth based target
        const double backgroundRadianceInBand = backgroundRadiance * fractionOfBandToTotal * overlapRatio;

        double radiantIntensityInBin(0.0);
        if (sigArray == nullptr) {
            // 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];
        }
        //double 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;
}
//------------------------------------------------------------------------------
// getHeatSignature() - Get the heat signature
//------------------------------------------------------------------------------
double* AircraftIrSignature::getHeatSignature(IrQueryMsg* msg)
{
    Player* target = msg->getTarget();
    if (target != nullptr) {
        IrAtmosphere* atmos = nullptr;
        WorldModel* sim = target->getWorldModel();
        if (sim != nullptr) {
            atmos = dynamic_cast<IrAtmosphere*>( sim->getAtmosphere() );
        }

        unsigned int numBins = getNumWaveBands();
        if (airframeSig == nullptr)  airframeSig = new double [numBins * 3];
        if (plumeSigs == nullptr)    plumeSigs = new double [numBins * 3];
        if (hotPartsSigs == nullptr) hotPartsSigs = new double [numBins * 3];

        //double reflectivity = 1.0f - getEmissivity();
        double lowerBound = msg->getLowerWavelength();
        double upperBound = msg->getUpperWavelength();

        if (atmos != nullptr) {
            if (atmos->getNumWaveBands() != getNumWaveBands()) {
                // warning message
            }
        }

        // apparently no emissivity factor in these airframe signatures
        getAirframeSignatures(msg, lowerBound, upperBound);
        getPlumeSignatures(msg, lowerBound, upperBound);
        getHotPartsSignatures(msg, lowerBound, upperBound);

        const double* centerWavelengths = getWaveBandCenters();
        const double* widths = getWaveBandWidths();
        //double totalWavelengthRange = ((centerWavelengths[getNumWaveBands() - 1] + (widths[getNumWaveBands() - 1] / 2.0f))-(centerWavelengths[0] - (widths[0] / 2.0f)));

        for (unsigned int i=0; i<getNumWaveBands(); i++) {
            // determine if our sensor band overlap this signature band
            double lowerBandBound = centerWavelengths[i] - (widths[i] / 2.0f);
            double upperBandBound = lowerBandBound + widths[i];
            if (upperBound > lowerBandBound && lowerBound < upperBandBound) {

                // calculate how much of this wave band overlaps the sensor limits
                double lowerOverlap = getLowerEndOfWavelengthOverlap(lowerBandBound, lowerBound);
                double upperOverlap = getUpperEndOfWavelengthOverlap(upperBandBound, upperBound);
                if (upperOverlap < lowerOverlap) upperOverlap = lowerOverlap;
                double overlapRatio = (upperOverlap - lowerOverlap) / (upperBandBound - lowerBandBound);

                // get our main signature piece - airframe
                double baseHeatSignatureInBand = airframeSig[i*3 + 2];

                //if (isMessageEnabled(MSG_INFO)) {
                //std::cout << "For wavelength " << currentWavelength << " Airframe Heat Signature: " << baseHeatSignatureInBand << std::endl;
                //std::cout << "For wavelength " << currentWavelength << " Plume Signature: " << plumeSigs[i *3 +2] << std::endl;
                //std::cout << "For wavelength " << currentWavelength << " Hot Parts: " << hotPartsSigs[i * 3 + 2] << std::endl;
                //}

                // assume plume bins & hot parts bins are same as airframe bins, so we
                // can re-use the same overlap ratios and fractions. If not,
                // they will have to be separately calculated.
                baseHeatSignatureInBand += plumeSigs[i*3 + 2];
                baseHeatSignatureInBand += hotPartsSigs[i*3 + 2];

                // if we have an atmosphere model, get the reflected solar radiation contribution
                // Solar signature is solar value * reflectivity i.e. (1 - emissivity)
                // use of reflectivity here suggests that this is solar radiation reflected from the target
                // this now done in the atmosphere model, during query return processing
                //if (atmos != nullptr)
                //   baseHeatSignatureInBand += (reflectivity * atmos->getSolarRadiation(centerWavelengths[i], (double) target->getAltitudeM()));

                airframeSig[i*3 + 2] = baseHeatSignatureInBand * overlapRatio;
            }
        } // for loop over waveBand
    } // if (target != nullptr)
    return airframeSig;
}