Example #1
0
// this is called by the IrSeeker in the transmit frame, once for each target that returns a query
bool IrSensor::calculateIrQueryReturn(IrQueryMsg* const msg)
{
   Player* ownship = getOwnship();
   IrAtmosphere* atmos = nullptr;
   double totalSignal = 0.0;
   double totalBackground = 0.0;

   if (msg->getSendingSensor() != this) {
      // this should not happen
   }

   if (ownship != nullptr) {
      WorldModel* sim = ownship->getWorldModel();
      if (sim)
         atmos = dynamic_cast<IrAtmosphere*>(sim->getAtmosphere());
   }

   if (atmos == nullptr) {
      // assume simple signature
      totalSignal = msg->getSignatureAtRange();
   }
   else {
      atmos->calculateAtmosphereContribution(msg, &totalSignal, &totalBackground);
   }

   if (totalSignal > 0.0) {

      const double targetRange = msg->getRange();
      const double rangeSquared =  targetRange * targetRange;
      const double reflectorArea = msg->getProjectedArea();
      const double ifov = msg->getInstantaneousFieldOfView();

      // The relevant amount of background area is the field of view multiplied by the range squared

      const double backgroundArea =  ifov * rangeSquared;

      // The seeker detects by comparing the amount of signal present
      // with the target to the amount of signal there would be without the target.
      // The amount of signal with the target represents the signal power plus
      // that part of the background radiation that is not blocked by the target.
      // If the target is larger than the field of view than it is all of background
      // power in the field of view. Use this as the default value.

     // noiseBlockedByTarget is irradiance, in units of watts/m^2

      double noiseBlockedByTarget = totalBackground * ifov;

      // If the target is smaller than the field of view, it is the background power
      // in the effective field of view represented by the target, i.e. the
      // target area divided by the range squared.
      if (reflectorArea < backgroundArea) {
         // these two are equivalent
         // noiseBlockedByTarget *=  (reflectorArea/backgroundArea)
          noiseBlockedByTarget = (totalBackground * reflectorArea) / rangeSquared;
      }

      // attenuatedPower is irradiance, in watts/m^2
      const double attenuatedPower = totalSignal / rangeSquared;

      // signalAboveNoise is the signal that the detector sees minus what it would see with
      // only the background radiation, and is just the amount of power subtracted by how much
      // background power is being blocked.
      // = (attenuatedPower + totalBackground*ifov - noiseBlockedByTarget) - totalBackground*ifov
      // signalAboveNoise is irradiance, in watts/m^2

      double signalAboveNoise = attenuatedPower - noiseBlockedByTarget;

      // only Contrast seekers take absolute value in this equation.
      // Hotspot does not.

      if (signalAboveNoise < 0.0 &&
               (msg->getSendingSensor()->getSensorType() == IrSensor::CONTRAST)) {
         signalAboveNoise = -signalAboveNoise;
      }

      const double nei = msg->getNEI();

      // Determine the ratio between the signal above the noise as compared to the level of
      // radiation that would create a response at the same level as the sensor's internal noise.
      // if NEI is in watts/m^2, then SNR will be dimensionless.
      // if NEI is in watts/cm^2, then need to correct by 10^4.

      const double signalToNoiseRatio = signalAboveNoise / nei;
      const double backgroundNoiseRatio = noiseBlockedByTarget / nei;
      //double signalToNoiseThreshold = msg->getSendingSensor()->getThreshold();

      // allow all signals to be returned; threshold test will be applied in process()
      {
         const auto outMsg = new IrQueryMsg();
         outMsg->setTarget(msg->getTarget());
         outMsg->setGimbalAzimuth( static_cast<double>(msg->getGimbal()->getAzimuth()) );
         outMsg->setGimbalElevation( static_cast<double>(msg->getGimbal()->getElevation()) );
         outMsg->setAzimuthAoi(msg->getAzimuthAoi());
         outMsg->setElevationAoi(msg->getElevationAoi());

         base::Vec3d los = msg->getLosVec();

         {
            // This is for non-ownHdgOnly-stabilized gimbal angles
            base::Vec4d los0( los.x(), los.y(), los.z(), 0.0 );
            base::Vec4d los_vec = ownship->getRotMat() * los0;
            double ra = std::sqrt(los_vec.x() * los_vec.x() + los_vec.y()*los_vec.y());
            double az = std::atan2(los_vec.y(), los_vec.x());
            double el = std::atan2(-los_vec.z(), ra);
            outMsg->setRelativeAzimuth(az);
            outMsg->setRelativeElevation(el);
         }

         outMsg->setLosVec(msg->getLosVec());
         outMsg->setTgtLosVec( -msg->getLosVec() );
         outMsg->setPosVec(msg->getTarget()->getPosition());
         outMsg->setVelocityVec(msg->getTarget()->getVelocity());
         outMsg->setAccelVec(msg->getTarget()->getAcceleration());

         double angleAspect1 = outMsg->getPosVec().y() *
                                 outMsg->getVelocityVec().x() -
                                 outMsg->getPosVec().x() *
                                 outMsg->getVelocityVec().y();

         double angleAspect2 = outMsg->getPosVec().x() *
                                 outMsg->getVelocityVec().x() +
                                 outMsg->getPosVec().y() *
                                 outMsg->getVelocityVec().y();

         outMsg->setAngleAspect(std::atan2(-angleAspect1,angleAspect2));

         outMsg->setSignalToNoiseRatio(signalToNoiseRatio);
         outMsg->setBackgroundNoiseRatio(backgroundNoiseRatio);
         outMsg->setSendingSensor(msg->getSendingSensor());

         // probably unnecessary - should be default val
         outMsg->setQueryMergeStatus(IrQueryMsg::NOT_MERGED);   // FAB

         msg->getSendingSensor()->addStoredMessage(outMsg);
      }
      //else   // FAB - debug
      //{
      // int x = 0;
      // x = x +1;
      // }
   } //totalSignal > 0
 //  else   // FAB - debug
 //  {
    //   int x = 0;
    //   x = x +1;
    //}

   return true;
}
Example #2
0
//------------------------------------------------------------------------------
// onRfEmissionEventAntenna() -- process events for RF Emission not sent by us.
//
// 1) Build a list of emission packets from the queue and compute the
//    Line-Of-Sight (LOS) vectors back to the transmitter.
//
// 2) Transform LOS vectors to antenna coordinates
//
// 3) Compute antenna gains in the direction of the transmitter
//
// 4) Compute Antenna Effective Gains
//
// 5) Compute Antenna Effective Area and Polarization Gains
//
// 6) Compute total receiving antenaa gain and send the emission to our sensor
//------------------------------------------------------------------------------
bool Antenna::onRfEmissionEvent(Emission* const em)
{
   // Is this emission from a player of interest?
   if (fromPlayerOfInterest(em)) {

      Player* ownship = getOwnship();
      RfSystem* sys1 = getSystem();
      if (ownship != 0 && sys1 != 0) {
         sys1->ref();

         // Line-Of-Sight (LOS) vectors back to the transmitter.
         osg::Vec3d xlos = em->getTgtLosVec();
         osg::Vec4d los0( xlos.x(), xlos.y(), xlos.z(), 0.0);

         // 2) Transform local NED LOS vectors to antenna coordinates
         osg::Matrixd mm = getRotMat();
         mm *= ownship->getRotMat();
         osg::Vec4d losA = mm * los0;

         // ---
         // Compute antenna gains in the direction of the transmitter
         // ---
         double rGainDb = 0.0f;
         if (gainPattern != 0) {

            Basic::Func1* gainFunc1 = dynamic_cast<Basic::Func1*>(gainPattern);
            Basic::Func2* gainFunc2 = dynamic_cast<Basic::Func2*>(gainPattern);
            if (gainFunc2 != 0) {
               // ---
               // 3-a) Antenna pattern: 2D table (az & el off antenna boresight)
               // ---

               // Get component arrays and ground range squared
               double xa =  losA.x();
               double ya =  losA.y();
               double za = -losA.z();
               double ra2 = xa*xa + ya*ya;

               // Compute range along antenna x-y plane
               double ra = sqrt(ra2);

               // Compute azimuth off boresight
               double aazr = atan2(ya,xa);

               // Compute elevation off boresight
               double aelr = atan2(za,ra);

               // Lookup gain in 2D table and convert from dB
               if (gainPatternDeg)
                  rGainDb = gainFunc2->f( aazr * Basic::Angle::R2DCC, aelr * Basic::Angle::R2DCC );
               else
                  rGainDb = gainFunc2->f( aazr, aelr );

            }

            else if (gainFunc1 != 0) {
               // ---
                  // 3-b) Antenna Pattern: 1D table (off antenna boresight only
                  // ---

                  // Compute angle off antenna boresight
                  double aar = acos(losA.x());

                  // Lookup gain in 1D table and convert from dB
                  if (gainPatternDeg)
                     rGainDb = gainFunc1->f( aar * Basic::Angle::R2DCC );
                  else
                     rGainDb = gainFunc1->f(aar);

            }
         }

         // Compute off-boresight gain
         double rGain = pow(10.0,rGainDb/10.0);

         // Compute Antenna Effective Gain
         double aeGain = rGain * getGain();
         double lambda = em->getWavelength();
         double aea = getEffectiveArea(aeGain, lambda);

         double pGain = getPolarizationGain(em->getPolarization());
         double raGain = aea * pGain;

         sys1->rfReceivedEmission(em, this, LCreal(raGain));

         sys1->unref();
      }

   }

   return BaseClass::onRfEmissionEvent(em);
}