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; }
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; }