diff --git a/plugins/channelrx/demodssb/ssbdemodsink.cpp b/plugins/channelrx/demodssb/ssbdemodsink.cpp index 43d9e0d73..ffb462960 100644 --- a/plugins/channelrx/demodssb/ssbdemodsink.cpp +++ b/plugins/channelrx/demodssb/ssbdemodsink.cpp @@ -69,10 +69,12 @@ SSBDemodSink::SSBDemodSink() : m_demodBufferFill = 0; m_usb = true; - m_magsq = 0.0f; - m_magsqSum = 0.0f; - m_magsqPeak = 0.0f; + m_magsq = 0.0; + m_magsqSum = 0.0; + m_magsqPeak = 0.0; m_magsqCount = 0; + m_magsqCur = 0.0; + m_magsqPrev = 0.0; m_agc.setClampMax(SDR_RX_SCALED/100.0); m_agc.setClamping(m_agcClamping); @@ -170,10 +172,24 @@ void SSBDemodSink::processOneSample(Complex &ci) m_sum.imag(0.0); } - float agcVal = m_agcActive ? m_agc.feedAndGetValue(sideband[i]) : 0.1; + float agcVal = m_agcActive ? m_agc.feedAndGetValue(sideband[i]) : 1.0; fftfilt::cmplx& delayedSample = m_squelchDelayLine.readBack(m_agc.getStepDownDelay()); m_audioActive = delayedSample.real() != 0.0; - m_squelchDelayLine.write(sideband[i]*agcVal); + m_magsqCur = std::norm(sideband[i]*agcVal); + + // Prevent overload if squared magnitude variation is 90% full scale (0.9*.0.9 = 0.81) + // Only if AGC is active + if (m_agcActive && (m_magsqCur - m_magsqPrev > m_agcTarget*m_agcTarget*8.1)) + { + m_agc.reset(m_agcTarget*100.0); // Quench AGC at -20dB the target + m_squelchDelayLine.write(sideband[i]); + } + else + { + m_squelchDelayLine.write(sideband[i]*agcVal); + } + + m_magsqPrev = m_magsqCur; if (m_audioMute) { diff --git a/plugins/channelrx/demodssb/ssbdemodsink.h b/plugins/channelrx/demodssb/ssbdemodsink.h index 92f3e9e1c..5c98e3d8c 100644 --- a/plugins/channelrx/demodssb/ssbdemodsink.h +++ b/plugins/channelrx/demodssb/ssbdemodsink.h @@ -101,6 +101,8 @@ private: double m_magsqSum; double m_magsqPeak; int m_magsqCount; + double m_magsqCur; + double m_magsqPrev; MagSqLevelsStore m_magSqLevelStore; MagAGC m_agc; bool m_agcActive; diff --git a/sdrbase/dsp/agc.h b/sdrbase/dsp/agc.h index 006d7ba40..38b544a3e 100644 --- a/sdrbase/dsp/agc.h +++ b/sdrbase/dsp/agc.h @@ -32,6 +32,7 @@ public: void setOrder(double R) { m_R = R; } Real getValue(); Real getAverage(); + void reset(double R) { m_moving_average.fill(R); } virtual void feed(Complex& ci) = 0; protected: diff --git a/sdrbase/dsp/projector.cpp b/sdrbase/dsp/projector.cpp index 820ae2ddb..e0845b80f 100644 --- a/sdrbase/dsp/projector.cpp +++ b/sdrbase/dsp/projector.cpp @@ -60,6 +60,15 @@ Real Projector::run(const Sample& s) v = re*re + im*im; } break; + case ProjectionDMagSq: + { + Real re = s.m_real / SDR_RX_SCALEF; + Real im = s.m_imag / SDR_RX_SCALEF; + Real curMagSq = re*re + im*im; + v = curMagSq - m_prevVal; + m_prevVal = curMagSq; + } + break; case ProjectionMagDB: { Real re = s.m_real / SDR_RX_SCALEF; @@ -235,6 +244,13 @@ Real Projector::run(const std::complex& s) case ProjectionMagSq: v = std::norm(s); break; + case ProjectionDMagSq: + { + Real curMagSq = std::norm(s); + v = curMagSq - m_prevVal; + m_prevVal = curMagSq; + } + break; case ProjectionMagDB: { Real magsq = std::norm(s); diff --git a/sdrbase/dsp/projector.h b/sdrbase/dsp/projector.h index d31bedb3d..cc5a58c7c 100644 --- a/sdrbase/dsp/projector.h +++ b/sdrbase/dsp/projector.h @@ -33,6 +33,7 @@ public: ProjectionImag, //!< Extract imaginary part ProjectionMagLin, //!< Calculate linear magnitude or modulus ProjectionMagSq, //!< Calculate linear squared magnitude or power + ProjectionDMagSq, //!< Calculate time derivative of linear squared magnitude or power ProjectionMagDB, //!< Calculate logarithmic (dB) of squared magnitude ProjectionPhase, //!< Calculate phase ProjectionDOAP, //!< Calculate ambiguous DOA from phase as phase difference (assuming positive) @@ -60,6 +61,7 @@ private: static Real normalizeAngle(Real angle); ProjectionType m_projectionType; Real m_prevArg; + Real m_prevVal; Real *m_cache; bool m_cacheMaster; }; diff --git a/sdrgui/gui/glscope.cpp b/sdrgui/gui/glscope.cpp index 04cdce1b6..d036f9cf5 100644 --- a/sdrgui/gui/glscope.cpp +++ b/sdrgui/gui/glscope.cpp @@ -1893,6 +1893,7 @@ void GLScope::setYScale(ScaleEngine &scale, uint32_t highlightedTraceIndex) break; case Projector::ProjectionMagLin: case Projector::ProjectionMagSq: + case Projector::ProjectionDMagSq: if (amp_range < 1e-9) { scale.setRange(Unit::None, amp_ofs * 1e12, amp_range * 1e12 + amp_ofs * 1e12); } else if (amp_range < 1e-6) { diff --git a/sdrgui/gui/glscopegui.cpp b/sdrgui/gui/glscopegui.cpp index 0e050472d..8d6aa7589 100644 --- a/sdrgui/gui/glscopegui.cpp +++ b/sdrgui/gui/glscopegui.cpp @@ -1315,6 +1315,7 @@ void GLScopeGUI::fillProjectionCombo(QComboBox* comboBox) comboBox->addItem("Imag", Projector::ProjectionImag); comboBox->addItem("Mag", Projector::ProjectionMagLin); comboBox->addItem("MagSq", Projector::ProjectionMagSq); + comboBox->addItem("dMagSq", Projector::ProjectionDMagSq); comboBox->addItem("MagdB", Projector::ProjectionMagDB); comboBox->addItem("Phi", Projector::ProjectionPhase); comboBox->addItem("DOAP", Projector::ProjectionDOAP);