//------------------------------------------------------------------------------ // process() -- Process phase //------------------------------------------------------------------------------ void IrSeeker::process(const LCreal dt) { BaseClass::process(dt); // --- // Update IR query queues: from 'in-use' to 'free' // --- lcLock(inUseQueryLock); int n = inUseQueryQueue.entries(); for (int i = 0; i < n; i++) { IrQueryMsg* query = inUseQueryQueue.get(); if (query != 0) { if (query->getRefCount() <= 1) { // No one else is referencing the query, push on free stack query->clear(); lcLock(freeQueryLock); if (freeQueryStack.isNotFull()) { freeQueryStack.push(query); } else { query->unref(); } lcUnlock(freeQueryLock); } else { // Others are still referencing the query, put back on in-use queue inUseQueryQueue.put(query); } } } lcUnlock(inUseQueryLock); }
//------------------------------------------------------------------------------ // receive() -- process received emissions //------------------------------------------------------------------------------ void Radio::receive(const LCreal dt) { BaseClass::receive(dt); // Receiver losses LCreal noise = getRfRecvNoise(); // --- // Process Emissions // --- Emission* em = nullptr; LCreal signal = 0; // Get an emission from the queue lcLock(packetLock); if (np > 0) { np--; // Decrement 'np', now the array index em = packets[np]; signal = signals[np]; } lcUnlock(packetLock); while (em != nullptr) { // Signal/Noise (Equation 2-9) LCreal sn = signal / noise; LCreal snDbl = 10.0 * lcLog10(sn); // Is S/N above receiver threshold? if ( snDbl >= getRfThreshold() ) { // Report this valid emission to the radio model ... receivedEmissionReport(em); } em->unref(); em = nullptr; // Get another emission from the queue lcLock(packetLock); if (np > 0) { np--; em = packets[np]; signal = signals[np]; } lcUnlock(packetLock); } }
//------------------------------------------------------------------------------ // clearQueues() -- clear out all queues //------------------------------------------------------------------------------ void IrSeeker::clearQueues() { lcLock(freeQueryLock); IrQueryMsg* query = freeQueryStack.pop(); while (query != 0) { query->unref(); query = freeQueryStack.pop(); } lcUnlock(freeQueryLock); lcLock(inUseQueryLock); query = inUseQueryQueue.get(); while (query != 0) { query->unref(); query = inUseQueryQueue.get(); } lcUnlock(inUseQueryLock); }
//------------------------------------------------------------------------------ // clearQueues() -- clear out all queues //------------------------------------------------------------------------------ void Antenna::clearQueues() { lcLock(freeEmLock); Emission* em = freeEmStack.pop(); while (em != 0) { em->unref(); em = freeEmStack.pop(); } lcUnlock(freeEmLock); lcLock(inUseEmLock); em = inUseEmQueue.get(); while (em != 0) { em->unref(); em = inUseEmQueue.get(); } lcUnlock(inUseEmLock); }
// ----------------------------------------------------------------- // Update all timers in the list // ----------------------------------------------------------------- void Timer::updateTimers(const double dt) { if (!frz) { lcLock( semaphore ); for (unsigned int i = 0; i < nTimers; i++) { timers[i]->update(dt); } lcUnlock( semaphore ); } }
//------------------------------------------------------------------------------ // clearTracksAndQueues() -- clear out tracks and queues //------------------------------------------------------------------------------ void Radar::clearTracksAndQueues() { // Clear reports lcLock(myLock); for (unsigned int i = 0; i < numReports && i < MAX_REPORTS; i++) { if (reports[i] != nullptr) { reports[i]->unref(); reports[i] = nullptr; } } numReports = 0; lcUnlock(myLock); // --- // Clear out the queues // --- lcLock(myLock); for (Emission* em = rptQueue.get(); em != nullptr; em = rptQueue.get()) { em->unref(); } while (rptSnQueue.isNotEmpty()) { rptSnQueue.get(); } lcUnlock(myLock); }
// ----------------------------------------------------------------- // Add a new timer to the list // ----------------------------------------------------------------- void Timer::addToTimerList(Timer* timer) { bool ok = false; lcLock( semaphore ); if (nTimers < MAX_TIMERS) { timers[nTimers++] = timer; ok = true; } lcUnlock( semaphore ); if (!ok) { std::cerr << "Timer::addToTimerList() ERROR failed to add a new timer to static timer list" << std::endl; } }
//------------------------------------------------------------------------------ // rfReceivedEmission() -- process returned RF Emission //------------------------------------------------------------------------------ void RfSystem::rfReceivedEmission(Emission* const em, Antenna* const, LCreal raGain) { // Queue up emissions for receive() to process if (em != 0 && isReceiverEnabled()) { // Test to make sure the received emission is in-band before proceeding if (affectsRfSystem(em)) { // Pulses this radar frame (from emission) //LCreal pulses = LCreal( em->getPulses() ); //if (pulses <= 0) pulses = 1.0f; // Compute signal losses // Basically, we're simulation Hannen's S/I equation from page 356 of his notes. // Where I is N + J. J is noise from jamming. // Receiver Loss affects the total I, so we have to wait until J is added to N in Radar. LCreal losses = getRfSignalProcessLoss() * em->getAtmosphericAttenuationLoss() * em->getTransmitLoss(); if (losses < 1.0f) losses = 1.0f; // Range loss LCreal rl = em->getRangeLoss(); // Signal Equation (one way signal) // Signal Equation (Part of equation 2-7) // Signal (equation 3-3) LCreal signal = em->getPower() * rl * raGain / losses; // Noise Jammer -- add this signal to the total interferance signal (noise) if (em->isECM()) { // CGB part of the noise jamming equation says we're only affected by the ratio of the // transmitter and receiver bandwidths. // It's possible that we'll want to account for this in the signal calculation above. // But, for now, it is sufficient right here. jamSignal += (signal * getBandwidth() / em->getBandwidth()); } // Save packet and signal for receive() lcLock(packetLock); if (np < MAX_EMISSIONS) { em->ref(); packets[np] = em; signals[np] = signal; np++; } lcUnlock(packetLock); } } }
//------------------------------------------------------------------------------ // process() -- Process phase //------------------------------------------------------------------------------ void Antenna::process(const LCreal dt) { BaseClass::process(dt); // --- // Recycle emissions ... // Update emission queues: from 'in-use' to 'free' // --- if (recycle) { unsigned int n = inUseEmQueue.entries(); for (unsigned int i = 0; i < n; i++) { lcLock(inUseEmLock); Emission* em = inUseEmQueue.get(); lcUnlock(inUseEmLock); if (em != 0 && em->getRefCount() > 1) { // Others are still referencing the emission, put back on in-use queue lcLock(inUseEmLock); inUseEmQueue.put(em); lcUnlock(inUseEmLock); } else if (em != 0 && em->getRefCount() <= 1) { // No one else is referencing the emission, push to the free stack em->clear(); lcLock(freeEmLock); if (freeEmStack.isNotFull()) freeEmStack.push(em); else em->unref(); lcUnlock(freeEmLock); } } } }
//------------------------------------------------------------------------------ // getReports() -- returns a list of prereferenced pointers to emission reports //------------------------------------------------------------------------------ unsigned int Radar::getReports(const Emission** list, const unsigned int max) const { unsigned int num = 0; if (list != nullptr && max > 0 && numReports > 0) { lcLock(myLock); num = numReports; if (num > max) num = max; for (unsigned int i = 0; i < num; i++) { reports[i]->ref(); list[i] = reports[i]; } lcUnlock(myLock); } return num; }
// ----------------------------------------------------------------- // Remove a timer from the list // ----------------------------------------------------------------- void Timer::removeFromTimerList(Timer* timer) { lcLock( semaphore ); // Find this timer in the list unsigned int found = MAX_TIMERS; for (unsigned int i = 0; i < nTimers && found == MAX_TIMERS; i++) { if (timers[i] == timer) found = i; } // If found then remove it by moving all timer in the list that are // beyond this timer down position if (found != MAX_TIMERS) { --nTimers; // One less timer for (unsigned int i = found; i < nTimers; i++) { timers[i] = timers[i+1]; } } lcUnlock( semaphore ); }
void MergingIrSensor::mergeIrReturns() { int numRecords = storedMessagesQueue.entries(); if (numRecords > 0) { //int* deleteArray = new int [numRecords]; //if (deleteArray == 0) { // if (isMessageEnabled(MSG_ERROR)) { // std::cerr << "Error: Allocation memory failure in IrSensor::mergeIrReturns" << std::endl; // } //} //else { //for (int i=0; i < numRecords; i++) { // deleteArray[i] = 0; //} lcLock(storedMessagesLock); // Traverse the stored message queue using peek (). Examine every // message. Compare every stored message against every OTHER stored // message. If the two are too close together, merge the two signals // and mark the second message in the delete array. // Proceed through the loop, ignoring all messages marked "deleted" // in the delete array. numRecords = storedMessagesQueue.entries(); if (isMessageEnabled(MSG_DEBUG)) { std::cout << "IrSensor: numRecords returned " << numRecords << std::endl; } for (int i=0; i < numRecords; i++) { //if (deleteArray[i] == 0) { // Do not bother processing those marked // for deletion -- these have already been // merged and must be ignored. IrQueryMsg* currentMsg = storedMessagesQueue.peek0(i); // Do not bother processing those marked // for deletion -- these have already been // merged and must be ignored. if (currentMsg->getQueryMergeStatus()!= IrQueryMsg::MERGED_OUT) { for (int j = i+1; j < numRecords; j++) { IrQueryMsg* nextMsg = storedMessagesQueue.peek0(j); LCreal azimuthDelta = currentMsg->getRelativeAzimuth() - nextMsg->getRelativeAzimuth(); LCreal elevationDelta = currentMsg->getRelativeElevation() - nextMsg->getRelativeElevation(); if (azimuthDelta < 0) azimuthDelta = -azimuthDelta; if (elevationDelta < 0) elevationDelta = -elevationDelta; if ((azimuthDelta < azimuthBin) && (elevationDelta < elevationBin)) { // two signals are too close together // for the sensor to distinguish between them; // we will merge the two signals based // on their weighted signal-to-noise. LCreal currentRatio = 0.0; LCreal nextRatio = 0.0; // find current ratio. if (isMessageEnabled(MSG_DEBUG)) { std::cout << "IrSensor: merging target " << nextMsg->getTarget()->getName()->getString() << " into target " <<currentMsg->getTarget()->getName()->getString() << std::endl; } if (currentMsg->getSignalToNoiseRatio() > currentMsg->getBackgroundNoiseRatio()) { currentRatio = currentMsg->getSignalToNoiseRatio() + currentMsg->getBackgroundNoiseRatio(); } else { if (currentMsg->getSignalToNoiseRatio() < 0) { currentRatio = -currentMsg->getSignalToNoiseRatio() - currentMsg->getBackgroundNoiseRatio(); } else { currentRatio = -currentMsg->getSignalToNoiseRatio() - currentMsg->getBackgroundNoiseRatio(); } // signaltonoise < 0 } // if current signal > background //now do the same thing for the next message. if (nextMsg->getSignalToNoiseRatio() > nextMsg->getBackgroundNoiseRatio()) { nextRatio = nextMsg->getSignalToNoiseRatio() + nextMsg->getBackgroundNoiseRatio(); } else { if (nextMsg->getSignalToNoiseRatio() < 0) { nextRatio = -nextMsg->getSignalToNoiseRatio() - nextMsg->getBackgroundNoiseRatio(); } else { nextRatio = -nextMsg->getSignalToNoiseRatio() - nextMsg->getBackgroundNoiseRatio(); } // signaltonoise < 0 } // if next signal > background // use ratios to find weights. LCreal sumRatio = currentRatio + nextRatio; const LCreal currentWeight = currentRatio / sumRatio; const LCreal nextWeight = 1.0 - currentWeight; //combine line-of-sight vector using weights currentMsg->setLosVec((currentMsg->getLosVec() * currentWeight) + (nextMsg->getLosVec() * nextWeight)); // combine position currentMsg->setPosVec((currentMsg->getPosVec() * currentWeight) + (nextMsg->getPosVec() * nextWeight)); // combine velocity currentMsg->setVelocityVec((currentMsg->getVelocityVec() * currentWeight) + (nextMsg->getVelocityVec() * nextWeight)); // combine acceleration currentMsg->setAccelVec((currentMsg->getAccelVec() * currentWeight) + (nextMsg->getAccelVec() * nextWeight)); // combine signal to noise ratios. sumRatio = sumRatio - currentMsg->getBackgroundNoiseRatio(); if (sumRatio < 0) sumRatio = -sumRatio; currentMsg->setSignalToNoiseRatio(sumRatio); //combine Azimuth and Elevation. currentMsg->setAzimuthAoi((currentMsg->getAzimuthAoi() * currentWeight) + nextMsg->getAzimuthAoi() * nextWeight); currentMsg->setElevationAoi((currentMsg->getElevationAoi()* currentWeight) + (nextMsg->getElevationAoi() * nextWeight)); currentMsg->setAngleAspect((currentMsg->getAngleAspect() * currentWeight) + (nextMsg->getAngleAspect() * nextWeight)); currentMsg->setRelativeAzimuth((currentMsg->getRelativeAzimuth() * currentWeight) + (nextMsg->getRelativeAzimuth() * nextWeight)); currentMsg->setRelativeElevation((currentMsg->getRelativeElevation() * currentWeight) + (nextMsg->getRelativeElevation() * nextWeight)); // signal that this report has merged targets currentMsg->setQueryMergeStatus(IrQueryMsg::MERGED); nextMsg->setQueryMergeStatus(IrQueryMsg::MERGED_OUT); //deleteArray[j] = 1; // now that we have merged this signal with the // Ith signal, it must be deleted. It will not // be passed on to the track manager. //if (isMessageEnabled(MSG_INFO)) { //std::cout << "IrSensor: End Merge" << std::endl; //} } // if we merge } // end for j = i + 1; } // End if delete Array else { // debug - this target ws merged into another int x=0; x=x+1; } } // end for i = 0; lcUnlock(storedMessagesLock); //delete[] deleteArray; //} // newArray is not null. } // numRecords > 0 }
//------------------------------------------------------------------------------ // irRequestSignature() -- Send an IR query packet at all active players to request an IR signature //------------------------------------------------------------------------------ void IrSeeker::irRequestSignature(IrQueryMsg* const irQuery) { // Need something to store the required data for the IR signatures and someone to send to Tdb* tdb0 = getCurrentTDB(); Player* ownship = getOwnship(); if (irQuery == 0 || tdb0 == 0 || ownship == 0) { // Clean up and leave if (tdb0 != 0) tdb0->unref(); return; } // --- // Compute gimbal boresight data for our targets // --- // FAB - cannot use ownHdgOnly unsigned int ntgts = tdb0->computeBoresightData(); if (ntgts > MAX_PLAYERS) ntgts = MAX_PLAYERS; // --- // If we have targets // --- const osg::Vec3d* losG = tdb0->getGimbalLosVectors(); if (ntgts > 0 && losG != 0) { // Fetch the required data arrays from the TargetDataBlock const double* ranges = tdb0->getTargetRanges(); const double* rngRates = tdb0->getTargetRangeRates(); const double* anglesOffBoresight = tdb0->getBoresightErrorAngles(); const osg::Vec3d* losO2T = tdb0->getLosVectors(); const osg::Vec3d* losT2O = tdb0->getTargetLosVectors(); Player** targets = tdb0->getTargets(); LCreal maximumRange = irQuery->getMaxRangeNM()*Basic::Distance::NM2M; // --- // Send query packets to the targets // --- for (unsigned int i = 0; i < ntgts; i++) { // filter on sensor max range // can't filter on sensor range in processPlayers - different sensors can have different max range if (maximumRange > 0.0 && ranges[i] > maximumRange) continue; // Get a free query packet lcLock(freeQueryLock); IrQueryMsg* query = freeQueryStack.pop(); lcUnlock(freeQueryLock); if (query == 0) { query = new IrQueryMsg(); //if (ownship->getID() != 1) { // static tcnt = 0; // tcnt++; //if (isMessageEnabled(MSG_INFO)) { // std::cout << "new IrQueryMsg(" << this << "): " << tcnt << ", inused: " << inUseEmQueue.entries() << ", em = " << em << std::endl; //} //} } // Send the IR query message to the other player if (query != 0) { // a) Copy the template query msg *query = *irQuery; // b) Set target unique data query->setGimbal(this); query->setOwnship(ownship); query->setRange( LCreal(ranges[i]) ); query->setLosVec( losO2T[i] ); query->setTgtLosVec( losT2O[i] ); query->setRangeRate( LCreal(rngRates[i]) ); query->setTarget(targets[i]); query->setAngleOffBoresight( LCreal(anglesOffBoresight[i]) ); query->setGimbalAzimuth( LCreal(getAzimuth()) ); query->setGimbalElevation( LCreal(getElevation()) ); // c) Send the query to the target targets[i]->event(IR_QUERY, query); // d) Dispose of the query if (query->getRefCount() <= 1) { // Recycle the query packet query->clear(); lcLock(freeQueryLock); if (freeQueryStack.isNotFull()) { freeQueryStack.push(query); } else { query->unref(); } lcUnlock(freeQueryLock); } else { // Store for future reference lcLock(inUseQueryLock); if (inUseQueryQueue.isNotFull()) { inUseQueryQueue.put(query); } else { // Just forget it query->unref(); } lcUnlock(inUseQueryLock); } } else { // When we couldn't get a free query packet if (isMessageEnabled(MSG_WARNING)) { std::cerr << "Iw Seeker: OUT OF Query messages!" << std::endl; } } } } // Unref() the TDB tdb0->unref(); }
//------------------------------------------------------------------------------ // rfTransmit() -- Transmit a RF emission packet at all active players. //------------------------------------------------------------------------------ void Antenna::rfTransmit(Emission* const xmit) { // Need something to transmit and someone to send to Tdb* tdb = getCurrentTDB(); Player* ownship = getOwnship(); if (xmit == 0 || tdb == 0 || ownship == 0) { // Clean up and leave if (tdb != 0) tdb->unref(); return; } // --- // Compute gimbal boresight data for our targets // --- unsigned int ntgts = tdb->computeBoresightData(); if (ntgts > MAX_PLAYERS) ntgts = MAX_PLAYERS; // --- // If we have targets // --- const osg::Vec3d* losG = tdb->getGimbalLosVectors(); if (ntgts > 0 && losG != 0) { // --- // Lookup gain from antenna gain pattern, compute antenna // effective gain and effective radiated power. // --- bool haveGainTgt = false; double gainTgt[MAX_PLAYERS]; if (gainPattern != 0) { Basic::Func1* gainFunc1 = dynamic_cast<Basic::Func1*>(gainPattern); Basic::Func2* gainFunc2 = dynamic_cast<Basic::Func2*>(gainPattern); if (gainFunc2 != 0) { // --- // Antenna pattern: 2D table (az & el off antenna boresight) // --- // Compute azimuth off boresight (radians) const double* aazr = tdb->getBoresightAzimuthErrors(); // Compute elevation off boresight (radians) const double* aelr = tdb->getBoresightElevationErrors(); // Lookup gain in 2D table and convert from dB double gainTgt0[MAX_PLAYERS]; if (gainPatternDeg) { for (unsigned int i1 = 0; i1 < ntgts; i1++) { gainTgt0[i1] = gainFunc2->f( (aazr[i1] * Basic::Angle::R2DCC), (aelr[i1] * Basic::Angle::R2DCC) )/10.0; } } else { for (unsigned int i1 = 0; i1 < ntgts; i1++) { gainTgt0[i1] = gainFunc2->f( aazr[i1], aelr[i1] )/10.0f; } } pow10Array(gainTgt0, gainTgt, ntgts); haveGainTgt = true; } else if (gainFunc1 != 0) { // --- // Antenna Pattern: 1D table (off antenna boresight only // --- // Compute angles off antenna boresight (radians) const double* aar = tdb->getBoresightErrorAngles(); // Lookup gain in 1D table and convert from dB double gainTgt0[MAX_PLAYERS]; if (gainPatternDeg) { for (unsigned int i2 = 0; i2 < ntgts; i2++) { gainTgt0[i2] = gainFunc1->f( aar[i2]*Basic::Angle::R2DCC )/10.0; } } else { for (unsigned int i2 = 0; i2 < ntgts; i2++) { gainTgt0[i2] = gainFunc1->f( aar[i2] )/10.0f; } } pow10Array(gainTgt0, gainTgt, ntgts); haveGainTgt = true; } } if (!haveGainTgt) { // --- // No antenna pattern table // --- for (unsigned int i = 0; i < ntgts; i++) { gainTgt[i] = 1.0f; } } // Compute antenna effective gain double aeGain[MAX_PLAYERS]; multArrayConst(gainTgt, getGain(), aeGain, ntgts); // Compute Effective Radiated Power (watts) (Equation 2-1) double erp[MAX_PLAYERS]; multArrayConst(aeGain, xmit->getPower(), erp, ntgts); // Fetch the required data arrays from the TargetDataBlock const double* ranges = tdb->getTargetRanges(); const double* rngRates = tdb->getTargetRangeRates(); const osg::Vec3d* losO2T = tdb->getLosVectors(); const osg::Vec3d* losT2O = tdb->getTargetLosVectors(); Player** targets = tdb->getTargets(); // --- // Send emission packets to the targets // --- for (unsigned int i = 0; i < ntgts; i++) { // Only of power exceeds an optional threshold if (erp[i] > threshold) { // Get a free emission packet Emission* em(0); if (recycle) { lcLock(freeEmLock); em = freeEmStack.pop(); lcUnlock(freeEmLock); } bool cloned = false; if (em == 0) { // Otherwise, clone a new one em = xmit->clone(); cloned = true; } // Send the emission to the other player if (em != 0) { // a) Copy the template emission if (!cloned) *em = *xmit; // b) Set target unique data em->setGimbal(this); em->setOwnship(ownship); em->setRange( LCreal(ranges[i]) ); em->setLosVec(losO2T[i]); em->setTgtLosVec(losT2O[i]); em->setRangeRate( LCreal(rngRates[i]) ); em->setTarget(targets[i]); em->setGimbalAzimuth( LCreal(getAzimuth()) ); em->setGimbalElevation( LCreal(getElevation()) ); em->setPower( LCreal(erp[i]) ); em->setGain( LCreal(aeGain[i]) ); em->setPolarization(getPolarization()); em->setLocalPlayersOnly( isLocalPlayersOfInterestOnly() ); // c) Send the emission to the target targets[i]->event(RF_EMISSION, em); // d) Recycle the emission bool recycled = false; if (recycle) { lcLock(inUseEmLock); if (inUseEmQueue.isNotFull()) { // Store for future reference inUseEmQueue.put(em); recycled = true; } lcUnlock(inUseEmLock); } // or just forget it else { em->unref(); } } else { // When we couldn't get a free emission packet if (isMessageEnabled(MSG_ERROR)) { std::cerr << "Antenna: OUT OF EMISSIONS!" << std::endl; } } } } } // Unref() the TDB tdb->unref(); }
//------------------------------------------------------------------------------ // receive() -- process received emissions //------------------------------------------------------------------------------ void Rwr::receive(const LCreal dt) { BaseClass::receive(dt); // clear the back buffer clearRays(0); // Receiver losses #if 0 LCreal noise = getRfRecvNoise(); #else LCreal noise = getRfRecvNoise() * getRfReceiveLoss(); #endif // Process received emissions TrackManager* tm = getTrackManager(); Emission* em = 0; LCreal signal = 0; // Get an emission from the queue lcLock(packetLock); if (np > 0) { np--; // Decrement 'np', now the array index em = packets[np]; signal = signals[np]; } lcUnlock(packetLock); while (em != 0) { //std::cout << "Rwr::receive(" << em->getOwnship() << "): "; //std::cout << " pwr=" << em->getPower(); //std::cout << " gain=" << em->getGain(); //std::cout << " rl=" << rl; //std::cout << " pulses=" << pulses; //std::cout << " losses=" << losses; //std::cout << " signal=" << signal; //std::cout << " recvN=" << getRfRecvNoise(); //std::cout << " sn=" << sn; //std::cout << " snDbl=" << snDbl; //std::cout << " thrs=" << getRfThreshold(); //std::cout << std::endl; // CGB, if "signal <= 0.0", then "snDbl" is probably invalid if (signal > 0.0 && dt != 0.0) { // Signal over noise (equation 3-5) LCreal sn = signal / noise; LCreal snDbl = 10.0f * lcLog10(sn); // Is S/N above receiver threshold ## dpg -- for now, don't include ECM emissions if (snDbl > getRfThreshold() && !em->isECM() && rptQueue.isNotFull()) { // Send report to the track manager if (tm != 0) { tm->newReport(em, snDbl); } // Get Angle Of Arrival LCreal aoa= em->getAzimuthAoi(); // Store received power for real-beam display LCreal sigDbl = 10.0f * lcLog10(signal); LCreal signal10 = (sigDbl + 50.0f)/50.f; int idx = getRayIndex( static_cast<LCreal>(Basic::Angle::R2DCC * aoa) ); rays[0][idx] = lim01(rays[0][idx] + signal10); //if (idx == 0 && getOwnship()->getID() == 1011) { // std::cout << "sig = " << signal10 << std::endl; //} // Send to the track list processor em->ref(); // ref() for track list processing rptQueue.put(em); } } // finished em->unref(); // this unref() undoes the ref() done by RfSystem::rfReceivedEmission em = 0; // Get another emission from the queue lcLock(packetLock); if (np > 0) { np--; em = packets[np]; signal = signals[np]; } lcUnlock(packetLock); } // Transfer the rays xferRays(); }
//------------------------------------------------------------------------------ // process() -- process the TWS reports //------------------------------------------------------------------------------ void Radar::process(const LCreal dt) { BaseClass::process(dt); // Find the track manager TrackManager* tm = getTrackManager(); if (tm == nullptr) { // No track manager! Then just flush the input queue. lcLock(myLock); for (Emission* em = rptQueue.get(); em != nullptr; em = rptQueue.get()) { em->unref(); rptSnQueue.get(); } lcUnlock(myLock); } // --- // When end of scan, send all unsent reports to the track manager // --- if (endOfScanFlg) { endOfScanFlg = false; lcLock(myLock); for (unsigned int i = 0; i < numReports && i < MAX_REPORTS; i++) { if (tm != nullptr) { tm->newReport(reports[i], rptMaxSn[i]); } reports[i]->unref(); reports[i] = nullptr; rptMaxSn[i] = 0; } numReports = 0; lcUnlock(myLock); } // --- // Process our returned emissions into reports for the track manager // 1) Match each emission with existing reports // 2) On emission/report matches, if the S/N value of the new emission // is greater than the report, use the new emission // 3) Create new reports for unmatched emissions // --- lcLock(myLock); while (rptQueue.isNotEmpty()) { // Get the emission Emission* em = rptQueue.get(); LCreal snDbl = rptSnQueue.get(); if (em != nullptr) { // --- // 1) Match the emission with existing reports // --- int matched = -1; for (unsigned int i = 0; i < numReports && matched < 0; i++) { // Compare targets if ( em->getTarget() == reports[i]->getTarget() ) { // We have a match!!! matched = i; } } // --- // 2) On emission/report match // --- if (matched >= 0) { if (snDbl > rptMaxSn[matched]) { // When the S/N value of the new emission is greater than the report, // we use the new emission reports[matched]->unref(); em->ref(); reports[matched] = em; rptMaxSn[matched] = snDbl; } } // --- // 3) Create a new report entry for the unmatched emission // --- if (matched < 0 && numReports < MAX_REPORTS) { em->ref(); reports[numReports] = em; rptMaxSn[numReports] = snDbl; numReports++; } // finished em->unref(); } } lcUnlock(myLock); }
//------------------------------------------------------------------------------ // receive() -- process received emissions //------------------------------------------------------------------------------ void Radar::receive(const LCreal dt) { BaseClass::receive(dt); // Can't do anything without an antenna if (getAntenna() == nullptr) return; // Clear the next sweep csweep = computeSweepIndex( static_cast<LCreal>(Basic::Angle::R2DCC * getAntenna()->getAzimuth()) ); clearSweep(csweep); // Compute noise level // CGB moved here from RfSystem // Basically, we're simulation Hannen's S/I equation from page 356 of his notes. // Where I is N + J. J is noise from jamming. // Receiver Loss affects the total I, so we have to wait until this point to account for it. const LCreal interference = (getRfRecvNoise() + jamSignal) * getRfReceiveLoss(); const LCreal noise = getRfRecvNoise() * getRfReceiveLoss(); currentJamSignal = jamSignal * getRfReceiveLoss(); int countNumJammedEm = 0; // --- // Process Returned Emissions // --- Emission* em = nullptr; LCreal signal = 0; // Get an emission from the queue lcLock(packetLock); if (np > 0) { np--; // Decrement 'np', now the array index em = packets[np]; signal = signals[np]; } lcUnlock(packetLock); while (em != nullptr) { // exclude noise jammers (accounted for already in RfSystem::rfReceivedEmission) if (em->getTransmitter() == this || (em->isECM() && !em->isECMType(Emission::ECM_NOISE)) ) { // compute the return trip loss ... // Compute signal received LCreal rcs = em->getRCS(); // Signal Equation (Equation 2-7) LCreal rl = em->getRangeLoss(); signal *= (rcs * rl); // Integration gain signal *= rfIGain; // Range attenuation: we don't want the strong signal from short range targets LCreal maxRng = getRange() * Basic::Distance::NM2M; //LCreal maxRng4 = (maxRng*maxRng*maxRng*maxRng); //LCreal rng = (em->getRange()); const LCreal s1 = 1.0; //if (rng > 0) { // LCreal rng4 = (rng*rng*rng*rng); // s1 = (rng4/maxRng4); // if (s1 > 1.0f) s1 = 1.0f; //} signal *= s1; if (signal > 0.0) { // Signal/Noise (Equation 2-9) const LCreal signalToInterferenceRatio = signal / interference; const LCreal signalToInterferenceRatioDbl = 10.0f * lcLog10(signalToInterferenceRatio); const LCreal signalToNoiseRatio = signal / noise; const LCreal signalToNoiseRatioDbl = 10.0f * lcLog10(signalToNoiseRatio); //std::cout << "Radar::receive(" << em->getTarget() << "): "; //std::cout << " pwr=" << em->getPower(); //std::cout << " gain=" << em->getGain(); //std::cout << " rl=" << rl; //std::cout << " rcs=" << rcs; //std::cout << " signal=" << signal; //std::cout << " recvN=" << getRfRecvNoise(); //std::cout << " signalToInterferenceRatio=" << signalToInterferenceRatio; //std::cout << " signalToInterferenceRatioDbl=" << signalToInterferenceRatioDbl; //std::cout << " thrs=" << getRfThreshold(); //std::cout << std::endl; // Is S/N above receiver threshold and within 125% of max range? // CGB, if "signal <= 0.0", then "signalToInterferenceRatioDbl" is probably invalid // we should probably do something smart with "signalToInterferenceRatioDbl" above as well. lcLock(myLock); if (signalToInterferenceRatioDbl >= getRfThreshold() && em->getRange() <= (maxRng*1.25) && rptQueue.isNotFull()) { // send the report to the track manager em->ref(); rptQueue.put(em); rptSnQueue.put(signalToInterferenceRatioDbl); //std::cout << " (" << em->getRange() << ", " << signalToInterferenceRatioDbl << ", " << signalToInterferenceRatio << ", " << signalToInterferenceRatioDbl << ")"; // Save signal for real-beam display int iaz = csweep; int irng = computeRangeIndex( em->getRange() ); sweeps[iaz][irng] += (signalToInterferenceRatioDbl/100.0f); vclos[iaz][irng] = em->getRangeRate(); } else if (signalToInterferenceRatioDbl < getRfThreshold() && signalToNoiseRatioDbl >= getRfThreshold()) { countNumJammedEm++; } lcUnlock(myLock); } } em->unref(); // this unref() undoes the ref() done by RfSystem::rfReceivedEmission em = nullptr; //if (np >= 0 && np < MAX_EMISSIONS) { // packets[np] = 0; // signals[np] = 0; //} // Get another emission from the queue lcLock(packetLock); if (np > 0) { np--; em = packets[np]; signal = signals[np]; } lcUnlock(packetLock); } //std::cout << std::endl; numberOfJammedEmissions = countNumJammedEm; // Set interference signal back to zero jamSignal = 0; }