diff --git a/plugins/channelrx/demodssb/ssbdemod.cpp b/plugins/channelrx/demodssb/ssbdemod.cpp index 1a39b0c8e..dde581f3d 100644 --- a/plugins/channelrx/demodssb/ssbdemod.cpp +++ b/plugins/channelrx/demodssb/ssbdemod.cpp @@ -24,6 +24,7 @@ #include #include "audio/audiooutput.h" #include "dsp/dspengine.h" +#include "util/db.h" MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message) @@ -32,7 +33,10 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) : m_audioFlipChannels(false), m_dsb(false), m_audioMute(false), - m_agc(12000, 40.0, 1e-2), + m_agc(12000, agcTarget, 1e-2), + m_agcActive(false), + m_agcNbSamples(12000), + m_agcPowerThreshold(1e-2), m_sampleSink(sampleSink), m_audioFifo(4, 24000), m_settingsMutex(QMutex::Recursive) @@ -181,25 +185,25 @@ void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto } else { - double agcVal = m_agc.feedAndGetValue(sideband[i]); + double agcVal = m_agcActive ? m_agc.feedAndGetValue(sideband[i]) : 1.0; if (m_audioBinaual) { if (m_audioFlipChannels) { - m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].imag() * m_volume * agcVal * 10); - m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].real() * m_volume * agcVal * 10); + m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].imag() * m_volume * agcVal); + m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].real() * m_volume * agcVal); } else { - m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].real() * m_volume * agcVal * 10); - m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].imag() * m_volume * agcVal * 10); + m_audioBuffer[m_audioBufferFill].r = (qint16)(sideband[i].real() * m_volume * agcVal); + m_audioBuffer[m_audioBufferFill].l = (qint16)(sideband[i].imag() * m_volume * agcVal); } } else { Real demod = (sideband[i].real() + sideband[i].imag()) * 0.7; - qint16 sample = (qint16)(demod * m_volume * agcVal * 10); + qint16 sample = (qint16)(demod * m_volume * agcVal); m_audioBuffer[m_audioBufferFill].l = sample; m_audioBuffer[m_audioBufferFill].r = sample; } @@ -305,6 +309,22 @@ bool SSBDemod::handleMessage(const Message& cmd) m_audioFlipChannels = cfg.getAudioFlipChannels(); m_dsb = cfg.getDSB(); m_audioMute = cfg.getAudioMute(); + m_agcActive = cfg.getAGC(); + + int agcNbSamples = 48 * (1< -40 dB power: center of normal signal class SSBDemod : public BasebandSampleSink { public: @@ -173,6 +174,9 @@ private: double m_magsqPeak; int m_magsqCount; MagAGC m_agc; + bool m_agcActive; + int m_agcNbSamples; //!< number of audio (48 kHz) samples for AGC averaging + double m_agcPowerThreshold; //!< AGC power threshold (linear) NCOF m_nco; Interpolator m_interpolator; diff --git a/plugins/channelrx/demodssb/ssbdemodgui.cpp b/plugins/channelrx/demodssb/ssbdemodgui.cpp index 222cdf0c7..f8d775e5e 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.cpp +++ b/plugins/channelrx/demodssb/ssbdemodgui.cpp @@ -79,6 +79,9 @@ QByteArray SSBDemodGUI::serialize() const s.writeBool(8, m_audioBinaural); s.writeBool(9, m_audioFlipChannels); s.writeBool(10, m_dsb); + s.writeBool(11, ui->agc->isChecked()); + s.writeS32(12, ui->agcTimeLog2->value()); + s.writeS32(13, ui->agcPowerThreshold->value()); return s.final(); } @@ -97,6 +100,7 @@ bool SSBDemodGUI::deserialize(const QByteArray& data) QByteArray bytetmp; quint32 u32tmp; qint32 tmp; + bool booltmp; blockApplySettings(true); m_channelMarker.blockSignals(true); @@ -122,6 +126,12 @@ bool SSBDemodGUI::deserialize(const QByteArray& data) ui->audioFlipChannels->setChecked(m_audioFlipChannels); d.readBool(10, &m_dsb); ui->dsb->setChecked(m_dsb); + d.readBool(11, &booltmp, false); + ui->agc->setChecked(booltmp); + d.readS32(12, &tmp, 7); + ui->agcTimeText->setText(QString("%1").arg((1<agcPowerThresholdText->setText(QString("%1").arg(tmp, 0, 'f', 0)); blockApplySettings(false); m_channelMarker.blockSignals(false); @@ -265,6 +275,23 @@ void SSBDemodGUI::on_volume_valueChanged(int value) applySettings(); } +void SSBDemodGUI::on_agc_stateChanged(int state) +{ + applySettings(); +} + +void SSBDemodGUI::on_agcTimeLog2_valueChanged(int value) +{ + ui->agcTimeText->setText(QString("%1").arg((1<agcPowerThresholdText->setText(QString("%1").arg(value, 0, 'f', 0)); + applySettings(); +} + void SSBDemodGUI::on_audioMute_toggled(bool checked) { m_audioMute = checked; diff --git a/plugins/channelrx/demodssb/ssbdemodgui.ui b/plugins/channelrx/demodssb/ssbdemodgui.ui index c9125c99b..c65ef4a00 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.ui +++ b/plugins/channelrx/demodssb/ssbdemodgui.ui @@ -433,6 +433,9 @@ 24 + + 1 + @@ -489,6 +492,12 @@ + + + 30 + 0 + + AGC time constant (ms) @@ -521,12 +530,18 @@ 1 - -40 + -50 - + + + + 20 + 0 + + AGC power threshold (dB) @@ -677,6 +692,14 @@ + + + + + + + + diff --git a/sdrbase/dsp/agc.cpp b/sdrbase/dsp/agc.cpp index acb731910..7f36a3a58 100644 --- a/sdrbase/dsp/agc.cpp +++ b/sdrbase/dsp/agc.cpp @@ -45,7 +45,8 @@ Real AGC::getAverage() MagSquaredAGC::MagSquaredAGC(int historySize, double R, double threshold) : AGC(historySize, R), m_magsq(0.0), - m_threshold(threshold) + m_threshold(threshold), + m_thresholdCount(0) {} MagSquaredAGC::~MagSquaredAGC() @@ -64,7 +65,19 @@ double MagSquaredAGC::feedAndGetValue(const Complex& ci) m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); m_moving_average.feed(m_magsq); m_u0 = m_R / m_moving_average.average(); - return m_magsq > m_threshold ? m_u0 : 1.0; + + if (m_magsq > m_threshold) + { + m_thresholdCount = 0; + } + else + { + if (m_thresholdCount < m_moving_average.historySize()) { + m_thresholdCount++; + } + } + + return (m_thresholdCount < m_moving_average.historySize()) ? m_u0 : 0.0; } //MagAGC::MagAGC() : @@ -75,7 +88,8 @@ double MagSquaredAGC::feedAndGetValue(const Complex& ci) MagAGC::MagAGC(int historySize, double R, double threshold) : AGC(historySize, R), m_magsq(0.0), - m_threshold(threshold) + m_threshold(threshold), + m_thresholdCount(0) {} MagAGC::~MagAGC() @@ -94,7 +108,19 @@ double MagAGC::feedAndGetValue(const Complex& ci) m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); m_moving_average.feed(m_magsq); m_u0 = m_R / sqrt(m_moving_average.average()); - return m_magsq > m_threshold ? m_u0 : 1.0; + + if (m_magsq > m_threshold) + { + m_thresholdCount = 0; + } + else + { + if (m_thresholdCount < m_moving_average.historySize()) { + m_thresholdCount++; + } + } + + return (m_thresholdCount < m_moving_average.historySize()) ? m_u0 : 0.0; } //AlphaAGC::AlphaAGC() : diff --git a/sdrbase/dsp/agc.h b/sdrbase/dsp/agc.h index 1556ea025..99eab76d4 100644 --- a/sdrbase/dsp/agc.h +++ b/sdrbase/dsp/agc.h @@ -37,9 +37,11 @@ public: virtual void feed(Complex& ci); double feedAndGetValue(const Complex& ci); double getMagSq() const { return m_magsq; } + void setThreshold(double threshold) { m_threshold = threshold; } private: double m_magsq; - double m_threshold; + double m_threshold; //!< squelch on magsq average with transition from +3dB + int m_thresholdCount; }; class MagAGC : public AGC @@ -50,9 +52,11 @@ public: virtual void feed(Complex& ci); double feedAndGetValue(const Complex& ci); Real getMagSq() const { return m_magsq; } + void setThreshold(double threshold) { m_threshold = threshold; } private: double m_magsq; - double m_threshold; + double m_threshold; //!< squelch on magsq average + int m_thresholdCount; }; class AlphaAGC : public AGC diff --git a/sdrbase/dsp/movingaverage.h b/sdrbase/dsp/movingaverage.h index 175443c5e..7813b0f3b 100644 --- a/sdrbase/dsp/movingaverage.h +++ b/sdrbase/dsp/movingaverage.h @@ -50,6 +50,11 @@ public: return m_sum; } + int historySize() const + { + return m_history.size(); + } + protected: std::vector m_history; Type m_sum; diff --git a/sdrbase/util/db.cpp b/sdrbase/util/db.cpp index 3ccccd913..8e8a86ce4 100644 --- a/sdrbase/util/db.cpp +++ b/sdrbase/util/db.cpp @@ -28,3 +28,8 @@ double CalcDb::dbPower(double magsq, double floordB) return floordB; } } + +double CalcDb::powerFromdB(double powerdB) +{ + return pow(10.0, powerdB / 10.0); +} diff --git a/sdrbase/util/db.h b/sdrbase/util/db.h index 68ec40ed2..05fc7a297 100644 --- a/sdrbase/util/db.h +++ b/sdrbase/util/db.h @@ -23,6 +23,7 @@ class CalcDb { public: static double dbPower(double magsq, double floordB = -100.0); + static double powerFromdB(double powerdB); }; #endif /* INCLUDE_UTIL_DB_H_ */