From b31e62e73c6ecf819aa4ca2167e68b1186474b65 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 7 Sep 2015 01:15:55 +0200 Subject: [PATCH 1/3] Fixed NFM strong signals handling --- include-gpl/dsp/agc.h | 80 ++++++++++++++++++++++++++------ plugins/channel/nfm/nfmdemod.cpp | 8 ++-- plugins/channel/nfm/nfmdemod.h | 2 +- sdrbase/dsp/channelizer.cpp | 2 + 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/include-gpl/dsp/agc.h b/include-gpl/dsp/agc.h index 48a463b49..684193a98 100644 --- a/include-gpl/dsp/agc.h +++ b/include-gpl/dsp/agc.h @@ -87,19 +87,25 @@ public: EvenSimplerAGC() : m_u0(1.0), m_R(1.0), - m_moving_average() + m_moving_average(), + m_historySize(0), + m_count(0) {} EvenSimplerAGC(int historySize, Real R) : m_u0(1.0), m_R(R), - m_moving_average(historySize, m_R) + m_moving_average(historySize, m_R), + m_historySize(historySize), + m_count(0) {} void resize(int historySize, Real R) { m_R = R; m_moving_average.resize(historySize, R); + m_historySize = historySize; + m_count = 0; } Real getValue() @@ -107,28 +113,49 @@ public: return m_u0; } + Real getDelayedValue() + { + if (m_count < m_historySize*m_mult) + { + return 0; + } + else + { + return m_u0; + } + } + void feed(Complex& ci) { ci *= m_u0; - Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); - m_moving_average.feed(magsq); + Real mag = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag()); + m_moving_average.feed(mag); } void openedSquelch() { + if (m_count < m_historySize*m_mult) + { + m_count++; + } + m_u0 = m_R / m_moving_average.average(); } void closedSquelch() { //m_moving_average.fill(m_R); // Valgrind optim - m_u0 = 1.0; + m_count = 0; + m_u0 = m_R / m_moving_average.average(); } private: Real m_u0; - Real m_R; // objective magsq + Real m_R; // objective mag MovingAverage m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC. + int m_historySize; + int m_count; + static const int m_mult = 4; }; class AlphaAGC @@ -140,7 +167,9 @@ public: m_R(1.0), m_alpha(0.1), m_squelchOpen(true), - m_moving_average() + m_moving_average(), + m_historySize(0), + m_count(0) {} AlphaAGC(int historySize, Real R, Real alpha) : @@ -148,7 +177,9 @@ public: m_R(R), m_alpha(alpha), m_squelchOpen(true), - m_moving_average(historySize, m_R) + m_moving_average(historySize, m_R), + m_historySize(historySize), + m_count(0) {} void resize(int historySize, Real R, Real alpha) @@ -157,6 +188,8 @@ public: m_alpha = alpha; m_squelchOpen = true; m_moving_average.resize(historySize, R); + m_historySize = historySize; + m_count = 0; } Real getValue() @@ -164,25 +197,42 @@ public: return m_u0; } + Real getDelayedValue() + { + if (m_count < m_historySize) + { + return 0; + } + else + { + return m_u0; + } + } + void feed(Complex& ci) { ci *= m_u0; - Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); + Real mag = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag()); - if (m_squelchOpen && (magsq < m_moving_average.average())) + if (m_squelchOpen && (mag < m_moving_average.average())) { - m_moving_average.feed(m_moving_average.average() - m_alpha*(m_moving_average.average() - magsq)); + m_moving_average.feed(m_moving_average.average() - m_alpha*(m_moving_average.average() - mag)); } else { //m_squelchOpen = true; - m_moving_average.feed(magsq); + m_moving_average.feed(mag); } } void openedSquelch() { + if (m_count < m_historySize) + { + m_count++; + } + m_u0 = m_R / m_moving_average.average(); m_squelchOpen = true; } @@ -190,7 +240,9 @@ public: void closedSquelch() { //m_moving_average.fill(m_R); // Valgrind optim - m_u0 = 1.0; + m_count = 0; + //m_u0 = 1.0; + m_u0 = m_R / m_moving_average.average(); m_squelchOpen = false; } @@ -200,6 +252,8 @@ private: Real m_alpha; bool m_squelchOpen; MovingAverage m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC. + int m_historySize; + int m_count; }; diff --git a/plugins/channel/nfm/nfmdemod.cpp b/plugins/channel/nfm/nfmdemod.cpp index 944596fc5..fc36144e1 100644 --- a/plugins/channel/nfm/nfmdemod.cpp +++ b/plugins/channel/nfm/nfmdemod.cpp @@ -55,9 +55,9 @@ NFMDemod::NFMDemod() : m_audioBufferFill = 0; m_movingAverage.resize(16, 0); - m_agcLevel = 0.003; // 0.003 + m_agcLevel = 0.25; // 0.003 //m_AGC.resize(480, m_agcLevel, 0, 0.1*m_agcLevel); - m_AGC.resize(240, m_agcLevel*m_agcLevel, 0.3); + m_AGC.resize(600, m_agcLevel*m_agcLevel); //, 0.3); m_ctcssDetector.setCoefficients(3000, 6000.0); // 0.5s / 2 Hz resolution m_afSquelch.setCoefficients(24, 48000.0, 5, 1); // 4000 Hz span, 250us @@ -165,7 +165,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto Real qp = ci.imag() - m_m2Sample.imag(); Real h1 = m_m1Sample.real() * qp; Real h2 = m_m1Sample.imag() * ip; - Real demod = (h1 - h2) * 10000; + Real demod = (h1 - h2) * 30; // 10000 m_m2Sample = m_m1Sample; m_m1Sample = ci; @@ -218,7 +218,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto { demod = m_bandpass.filter(demod); demod *= m_running.m_volume; - sample = demod * ((1<<15)/301); // denominator = bandpass filter number of taps + sample = demod * ((1<<15)/301) * m_AGC.getDelayedValue(); // denominator = bandpass filter number of taps } m_AGC.openedSquelch(); diff --git a/plugins/channel/nfm/nfmdemod.h b/plugins/channel/nfm/nfmdemod.h index 6bd64cebf..f31329cad 100644 --- a/plugins/channel/nfm/nfmdemod.h +++ b/plugins/channel/nfm/nfmdemod.h @@ -163,7 +163,7 @@ private: Complex m_m1Sample; Complex m_m2Sample; MovingAverage m_movingAverage; - AlphaAGC m_AGC; + EvenSimplerAGC m_AGC; Real m_agcLevel; // AGC will aim to this level Real m_agcFloor; // AGC will not go below this level diff --git a/sdrbase/dsp/channelizer.cpp b/sdrbase/dsp/channelizer.cpp index 1481cd3fc..a94bad8dd 100644 --- a/sdrbase/dsp/channelizer.cpp +++ b/sdrbase/dsp/channelizer.cpp @@ -86,6 +86,8 @@ bool Channelizer::handleMessage(const Message& cmd) { qDebug() << "Channelizer::handleMessage: " << cmd.getIdentifier(); + // TODO: apply changes only if input sample rate or requested output sample rate change. Change of center frequency has no impact. + if (DSPSignalNotification::match(cmd)) { DSPSignalNotification& notif = (DSPSignalNotification&) cmd; From 15c050c360884eb1182df9fb515a5975963e475c Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 7 Sep 2015 09:32:29 +0200 Subject: [PATCH 2/3] Fixed NFM strong signals handling: adjusted parameters --- include-gpl/dsp/agc.h | 84 ++++++++++++++++++++++++++++++-- plugins/channel/nfm/nfmdemod.cpp | 8 +-- plugins/channel/nfm/nfmdemod.h | 2 +- 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/include-gpl/dsp/agc.h b/include-gpl/dsp/agc.h index 684193a98..170dc4682 100644 --- a/include-gpl/dsp/agc.h +++ b/include-gpl/dsp/agc.h @@ -80,11 +80,11 @@ private: }; -class EvenSimplerAGC +class MagSquaredAGC { public: - EvenSimplerAGC() : + MagSquaredAGC() : m_u0(1.0), m_R(1.0), m_moving_average(), @@ -92,7 +92,85 @@ public: m_count(0) {} - EvenSimplerAGC(int historySize, Real R) : + MagSquaredAGC(int historySize, Real R) : + m_u0(1.0), + m_R(R), + m_moving_average(historySize, m_R), + m_historySize(historySize), + m_count(0) + {} + + void resize(int historySize, Real R) + { + m_R = R; + m_moving_average.resize(historySize, R); + m_historySize = historySize; + m_count = 0; + } + + Real getValue() + { + return m_u0; + } + + Real getDelayedValue() + { + if (m_count < m_historySize*m_mult) + { + return 0; + } + else + { + return 1; + } + } + + void feed(Complex& ci) + { + ci *= m_u0; + Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); + m_moving_average.feed(magsq); + } + + void openedSquelch() + { + if (m_count < m_historySize*m_mult) + { + m_count++; + } + + m_u0 = m_R / m_moving_average.average(); + } + + void closedSquelch() + { + //m_moving_average.fill(m_R); // Valgrind optim + m_count = 0; + m_u0 = m_R / m_moving_average.average(); + } + +private: + Real m_u0; + Real m_R; // objective mag + MovingAverage m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC. + int m_historySize; + int m_count; + static const int m_mult = 4; // squelch delay multiplicator +}; + +class MagAGC +{ +public: + + MagAGC() : + m_u0(1.0), + m_R(1.0), + m_moving_average(), + m_historySize(0), + m_count(0) + {} + + MagAGC(int historySize, Real R) : m_u0(1.0), m_R(R), m_moving_average(historySize, m_R), diff --git a/plugins/channel/nfm/nfmdemod.cpp b/plugins/channel/nfm/nfmdemod.cpp index fc36144e1..d6a4f537a 100644 --- a/plugins/channel/nfm/nfmdemod.cpp +++ b/plugins/channel/nfm/nfmdemod.cpp @@ -26,7 +26,7 @@ #include "dsp/pidcontroller.h" #include "dsp/dspengine.h" -static const Real afSqTones[2] = {1200.0, 6000.0}; // {1200.0, 8000.0}; +static const Real afSqTones[2] = {1200.0, 8000.0}; // {1200.0, 8000.0}; MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureNFMDemod, Message) @@ -55,7 +55,7 @@ NFMDemod::NFMDemod() : m_audioBufferFill = 0; m_movingAverage.resize(16, 0); - m_agcLevel = 0.25; // 0.003 + m_agcLevel = 0.0625; // 0.003 //m_AGC.resize(480, m_agcLevel, 0, 0.1*m_agcLevel); m_AGC.resize(600, m_agcLevel*m_agcLevel); //, 0.3); @@ -165,7 +165,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto Real qp = ci.imag() - m_m2Sample.imag(); Real h1 = m_m1Sample.real() * qp; Real h2 = m_m1Sample.imag() * ip; - Real demod = (h1 - h2) * 30; // 10000 + Real demod = (h1 - h2) * 16; // 10000 (multiply by 2^16 after demod) m_m2Sample = m_m1Sample; m_m1Sample = ci; @@ -218,7 +218,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto { demod = m_bandpass.filter(demod); demod *= m_running.m_volume; - sample = demod * ((1<<15)/301) * m_AGC.getDelayedValue(); // denominator = bandpass filter number of taps + sample = demod * ((1<<16)/301) * m_AGC.getDelayedValue(); // denominator = bandpass filter number of taps } m_AGC.openedSquelch(); diff --git a/plugins/channel/nfm/nfmdemod.h b/plugins/channel/nfm/nfmdemod.h index f31329cad..b7eff886b 100644 --- a/plugins/channel/nfm/nfmdemod.h +++ b/plugins/channel/nfm/nfmdemod.h @@ -163,7 +163,7 @@ private: Complex m_m1Sample; Complex m_m2Sample; MovingAverage m_movingAverage; - EvenSimplerAGC m_AGC; + MagSquaredAGC m_AGC; Real m_agcLevel; // AGC will aim to this level Real m_agcFloor; // AGC will not go below this level From f5809b95c0e1e38c6d73782994aefe1bf6b7f989 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 7 Sep 2015 23:31:34 +0200 Subject: [PATCH 3/3] AGC in .cpp --- CMakeLists.txt | 1 + include-gpl/dsp/agc.h | 398 +++++++++++------------------------------- sdrbase/dsp/agc.cpp | 167 ++++++++++++++++++ 3 files changed, 267 insertions(+), 299 deletions(-) create mode 100644 sdrbase/dsp/agc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1df2582d1..513231032 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,7 @@ set(sdrbase_SOURCES sdrbase/audio/audiofifo.cpp sdrbase/audio/audiooutput.cpp + sdrbase/dsp/agc.cpp sdrbase/dsp/afsquelch.cpp sdrbase/dsp/channelizer.cpp sdrbase/dsp/channelmarker.cpp diff --git a/include-gpl/dsp/agc.h b/include-gpl/dsp/agc.h index 170dc4682..7ed2e9356 100644 --- a/include-gpl/dsp/agc.h +++ b/include-gpl/dsp/agc.h @@ -10,146 +10,22 @@ #include "movingaverage.h" -class SimpleAGC +class AGC { public: - SimpleAGC() : - m_squelchOpen(false), - m_fill(0), - m_cutoff(0), - m_clip(0), - m_moving_average() - {} + AGC(); + AGC(int historySize, Real R); + virtual ~AGC(); - SimpleAGC(int historySize, Real initial, Real cutoff=0, Real clip=0) : - m_squelchOpen(false), - m_fill(initial), - m_cutoff(cutoff), - m_clip(clip), - m_moving_average(historySize, initial) - {} + void resize(int historySize, Real R); + Real getValue(); + Real getDelayedValue(); + virtual void feed(Complex& ci) = 0; + void openedSquelch(); + void closedSquelch(); - void resize(int historySize, Real initial, Real cutoff=0, Real clip=0) - { - m_fill = initial; - m_cutoff = cutoff; - m_clip = clip; - m_moving_average.resize(historySize, initial); - } - - Real getValue() - { - if (m_moving_average.average() > m_clip) - { - return m_moving_average.average(); - } else - { - return m_clip; - } - } - - void feed(Real value) - { - if (value > m_cutoff) - { - m_moving_average.feed(value); - } - } - - void openedSquelch() - { - m_squelchOpen = true; - } - - void closedSquelch() - { - if (m_squelchOpen) - { - //m_moving_average.fill(m_fill); // Valgrind optim - m_squelchOpen = false; - } - } - -private: - bool m_squelchOpen; // open for processing - Real m_fill; // refill average at this level - Real m_cutoff; // consider samples only above this level - Real m_clip; // never go below this level - MovingAverage m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC. -}; - - -class MagSquaredAGC -{ -public: - - MagSquaredAGC() : - m_u0(1.0), - m_R(1.0), - m_moving_average(), - m_historySize(0), - m_count(0) - {} - - MagSquaredAGC(int historySize, Real R) : - m_u0(1.0), - m_R(R), - m_moving_average(historySize, m_R), - m_historySize(historySize), - m_count(0) - {} - - void resize(int historySize, Real R) - { - m_R = R; - m_moving_average.resize(historySize, R); - m_historySize = historySize; - m_count = 0; - } - - Real getValue() - { - return m_u0; - } - - Real getDelayedValue() - { - if (m_count < m_historySize*m_mult) - { - return 0; - } - else - { - return 1; - } - } - - void feed(Complex& ci) - { - ci *= m_u0; - Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); - m_moving_average.feed(magsq); - } - - void openedSquelch() - { - if (m_count < m_historySize*m_mult) - { - m_count++; - } - - m_u0 = m_R / m_moving_average.average(); - } - - void closedSquelch() - { - //m_moving_average.fill(m_R); // Valgrind optim - m_count = 0; - m_u0 = m_R / m_moving_average.average(); - } - -private: +protected: Real m_u0; Real m_R; // objective mag MovingAverage m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC. @@ -158,182 +34,106 @@ private: static const int m_mult = 4; // squelch delay multiplicator }; -class MagAGC +class MagSquaredAGC : public AGC { public: - - MagAGC() : - m_u0(1.0), - m_R(1.0), - m_moving_average(), - m_historySize(0), - m_count(0) - {} - - MagAGC(int historySize, Real R) : - m_u0(1.0), - m_R(R), - m_moving_average(historySize, m_R), - m_historySize(historySize), - m_count(0) - {} - - void resize(int historySize, Real R) - { - m_R = R; - m_moving_average.resize(historySize, R); - m_historySize = historySize; - m_count = 0; - } - - Real getValue() - { - return m_u0; - } - - Real getDelayedValue() - { - if (m_count < m_historySize*m_mult) - { - return 0; - } - else - { - return m_u0; - } - } - - void feed(Complex& ci) - { - ci *= m_u0; - Real mag = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag()); - m_moving_average.feed(mag); - } - - void openedSquelch() - { - if (m_count < m_historySize*m_mult) - { - m_count++; - } - - m_u0 = m_R / m_moving_average.average(); - } - - void closedSquelch() - { - //m_moving_average.fill(m_R); // Valgrind optim - m_count = 0; - m_u0 = m_R / m_moving_average.average(); - } - -private: - Real m_u0; - Real m_R; // objective mag - MovingAverage m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC. - int m_historySize; - int m_count; - static const int m_mult = 4; + MagSquaredAGC(); + MagSquaredAGC(int historySize, Real R); + virtual ~MagSquaredAGC(); + virtual void feed(Complex& ci); }; -class AlphaAGC +class MagAGC : public AGC { public: + MagAGC(); + MagAGC(int historySize, Real R); + virtual ~MagAGC(); + virtual void feed(Complex& ci); +}; - AlphaAGC() : - m_u0(1.0), - m_R(1.0), - m_alpha(0.1), - m_squelchOpen(true), - m_moving_average(), - m_historySize(0), - m_count(0) - {} - - AlphaAGC(int historySize, Real R, Real alpha) : - m_u0(1.0), - m_R(R), - m_alpha(alpha), - m_squelchOpen(true), - m_moving_average(historySize, m_R), - m_historySize(historySize), - m_count(0) - {} - - void resize(int historySize, Real R, Real alpha) - { - m_R = R; - m_alpha = alpha; - m_squelchOpen = true; - m_moving_average.resize(historySize, R); - m_historySize = historySize; - m_count = 0; - } - - Real getValue() - { - return m_u0; - } - - Real getDelayedValue() - { - if (m_count < m_historySize) - { - return 0; - } - else - { - return m_u0; - } - } - - void feed(Complex& ci) - { - ci *= m_u0; - Real mag = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag()); - - if (m_squelchOpen && (mag < m_moving_average.average())) - { - m_moving_average.feed(m_moving_average.average() - m_alpha*(m_moving_average.average() - mag)); - } - else - { - //m_squelchOpen = true; - m_moving_average.feed(mag); - } - - } - - void openedSquelch() - { - if (m_count < m_historySize) - { - m_count++; - } - - m_u0 = m_R / m_moving_average.average(); - m_squelchOpen = true; - } - - void closedSquelch() - { - //m_moving_average.fill(m_R); // Valgrind optim - m_count = 0; - //m_u0 = 1.0; - m_u0 = m_R / m_moving_average.average(); - m_squelchOpen = false; - } - +class AlphaAGC : public AGC +{ +public: + AlphaAGC(); + AlphaAGC(int historySize, Real R); + AlphaAGC(int historySize, Real R, Real alpha); + virtual ~AlphaAGC(); + void resize(int historySize, Real R, Real alpha); + virtual void feed(Complex& ci); + void openedSquelch(); + void closedSquelch(); private: - Real m_u0; - Real m_R; // objective magsq Real m_alpha; bool m_squelchOpen; - MovingAverage m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC. - int m_historySize; - int m_count; }; +class SimpleAGC +{ +public: + SimpleAGC() : + m_squelchOpen(false), + m_fill(0), + m_cutoff(0), + m_clip(0), + m_moving_average() + {} + SimpleAGC(int historySize, Real initial, Real cutoff=0, Real clip=0) : + m_squelchOpen(false), + m_fill(initial), + m_cutoff(cutoff), + m_clip(clip), + m_moving_average(historySize, initial) + {} + + void resize(int historySize, Real initial, Real cutoff=0, Real clip=0) + { + m_fill = initial; + m_cutoff = cutoff; + m_clip = clip; + m_moving_average.resize(historySize, initial); + } + + Real getValue() + { + if (m_moving_average.average() > m_clip) + { + return m_moving_average.average(); + } else + { + return m_clip; + } + } + + void feed(Real value) + { + if (value > m_cutoff) + { + m_moving_average.feed(value); + } + } + + void openedSquelch() + { + m_squelchOpen = true; + } + + void closedSquelch() + { + if (m_squelchOpen) + { + //m_moving_average.fill(m_fill); // Valgrind optim + m_squelchOpen = false; + } + } + +private: + bool m_squelchOpen; // open for processing + Real m_fill; // refill average at this level + Real m_cutoff; // consider samples only above this level + Real m_clip; // never go below this level + MovingAverage m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC. +}; #endif /* INCLUDE_GPL_DSP_AGC_H_ */ diff --git a/sdrbase/dsp/agc.cpp b/sdrbase/dsp/agc.cpp new file mode 100644 index 000000000..1cd0c0180 --- /dev/null +++ b/sdrbase/dsp/agc.cpp @@ -0,0 +1,167 @@ +/* + * agc.cpp + * + * Created on: Sep 7, 2015 + * Author: f4exb + */ + +#include "dsp/agc.h" + + +AGC::AGC() : + m_u0(1.0), + m_R(1.0), + m_moving_average(), + m_historySize(0), + m_count(0) +{} + +AGC::AGC(int historySize, Real R) : + m_u0(1.0), + m_R(R), + m_moving_average(historySize, m_R), + m_historySize(historySize), + m_count(0) +{} + +AGC::~AGC() +{} + +void AGC::resize(int historySize, Real R) +{ + m_R = R; + m_moving_average.resize(historySize, R); + m_historySize = historySize; + m_count = 0; +} + +Real AGC::getValue() +{ + return m_u0; +} + +Real AGC::getDelayedValue() +{ + if (m_count < m_historySize*m_mult) + { + return 0; + } + else + { + return 1; + } +} + +void AGC::openedSquelch() +{ + if (m_count < m_historySize*m_mult) + { + m_count++; + } + + m_u0 = m_R / m_moving_average.average(); +} + +void AGC::closedSquelch() +{ + //m_moving_average.fill(m_R); // Valgrind optim + m_count = 0; + m_u0 = m_R / m_moving_average.average(); +} + + +MagSquaredAGC::MagSquaredAGC() : + AGC() +{} + +MagSquaredAGC::MagSquaredAGC(int historySize, Real R) : + AGC(historySize, R) +{} + +MagSquaredAGC::~MagSquaredAGC() +{} + +void MagSquaredAGC::feed(Complex& ci) +{ + ci *= m_u0; + Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); + m_moving_average.feed(magsq); +} + + +MagAGC::MagAGC() : + AGC() +{} + +MagAGC::MagAGC(int historySize, Real R) : + AGC(historySize, R) +{} + +MagAGC::~MagAGC() +{} + +void MagAGC::feed(Complex& ci) +{ + ci *= m_u0; + Real mag = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag()); + m_moving_average.feed(mag); +} + + +AlphaAGC::AlphaAGC() : + AGC(), + m_alpha(0.5), + m_squelchOpen(true) +{} + +AlphaAGC::AlphaAGC(int historySize, Real R) : + AGC(historySize, R), + m_alpha(0.5), + m_squelchOpen(true) +{} + + +AlphaAGC::AlphaAGC(int historySize, Real R, Real alpha) : + AGC(historySize, R), + m_alpha(alpha), + m_squelchOpen(true) +{} + +AlphaAGC::~AlphaAGC() +{} + +void AlphaAGC::resize(int historySize, Real R, Real alpha) +{ + m_R = R; + m_alpha = alpha; + m_squelchOpen = true; + m_moving_average.resize(historySize, R); +} + +void AlphaAGC::feed(Complex& ci) +{ + ci *= m_u0; + Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); + + if (m_squelchOpen && (magsq)) + { + m_moving_average.feed(m_moving_average.average() - m_alpha*(m_moving_average.average() - magsq)); + } + else + { + //m_squelchOpen = true; + m_moving_average.feed(magsq); + } +} + +void AlphaAGC::openedSquelch() +{ + AGC::openedSquelch(); + m_squelchOpen = true; +} + +void AlphaAGC::closedSquelch() +{ + AGC::closedSquelch(); + m_squelchOpen = false; +}