kopia lustrzana https://github.com/f4exb/sdrangel
NFM demod: back to the basics
rodzic
c6b2730456
commit
34942340a3
|
@ -168,5 +168,5 @@ Assuming Debian Jessie is used:
|
|||
- Tx support with the BladeRF
|
||||
- Enhance WFM (stereo, RDS?)
|
||||
- Even more demods ...
|
||||
- Support for Airspy
|
||||
- Support for Hack-RF
|
||||
|
||||
|
|
|
@ -27,7 +27,10 @@ public:
|
|||
// Constructors and Destructor
|
||||
AFSquelch();
|
||||
// allows user defined tone pair
|
||||
AFSquelch(unsigned int nbTones, const Real *tones);
|
||||
AFSquelch(unsigned int nbTones,
|
||||
const Real *tones,
|
||||
int samplesAttack = 0,
|
||||
int samplesDecay = 0);
|
||||
virtual ~AFSquelch();
|
||||
|
||||
// setup the basic parameters and coefficients
|
||||
|
@ -39,7 +42,7 @@ public:
|
|||
|
||||
// set the detection threshold
|
||||
void setThreshold(double _threshold) {
|
||||
threshold = _threshold;
|
||||
m_threshold = _threshold;
|
||||
}
|
||||
|
||||
// analyze a sample set and optionally filter
|
||||
|
@ -49,11 +52,11 @@ public:
|
|||
// get the tone set
|
||||
const Real *getToneSet() const
|
||||
{
|
||||
return toneSet;
|
||||
return m_toneSet;
|
||||
}
|
||||
|
||||
bool open() const {
|
||||
return isOpen;
|
||||
return m_isOpen;
|
||||
}
|
||||
|
||||
void reset(); // reset the analysis algorithm
|
||||
|
@ -64,23 +67,23 @@ protected:
|
|||
void evaluate();
|
||||
|
||||
private:
|
||||
int N;
|
||||
int sampleRate;
|
||||
int samplesProcessed;
|
||||
int maxPowerIndex;
|
||||
int nTones;
|
||||
int samplesAttack;
|
||||
int attackCount;
|
||||
int samplesDecay;
|
||||
int decayCount;
|
||||
bool isOpen;
|
||||
double threshold;
|
||||
double *k;
|
||||
double *coef;
|
||||
Real *toneSet;
|
||||
double *u0;
|
||||
double *u1;
|
||||
double *power;
|
||||
int m_N;
|
||||
int m_sampleRate;
|
||||
int m_samplesProcessed;
|
||||
int m_maxPowerIndex;
|
||||
int m_nTones;
|
||||
int m_samplesAttack;
|
||||
int m_attackCount;
|
||||
int m_samplesDecay;
|
||||
int m_decayCount;
|
||||
bool m_isOpen;
|
||||
double m_threshold;
|
||||
double *m_k;
|
||||
double *m_coef;
|
||||
Real *m_toneSet;
|
||||
double *m_u0;
|
||||
double *m_u1;
|
||||
double *m_power;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -20,11 +20,8 @@ public:
|
|||
|
||||
void resize(int historySize, Real R);
|
||||
Real getValue();
|
||||
Real getDelayedValue();
|
||||
Real getAverage();
|
||||
virtual void feed(Complex& ci) = 0;
|
||||
virtual Real returnedDelayedValue() const = 0;
|
||||
void openedSquelch();
|
||||
void closedSquelch();
|
||||
|
||||
protected:
|
||||
Real m_u0;
|
||||
|
@ -32,7 +29,6 @@ protected:
|
|||
MovingAverage<Real> 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 MagSquaredAGC : public AGC
|
||||
|
@ -42,7 +38,6 @@ public:
|
|||
MagSquaredAGC(int historySize, Real R);
|
||||
virtual ~MagSquaredAGC();
|
||||
virtual void feed(Complex& ci);
|
||||
virtual Real returnedDelayedValue() const { return m_u0; }
|
||||
};
|
||||
|
||||
class MagAGC : public AGC
|
||||
|
@ -52,7 +47,6 @@ public:
|
|||
MagAGC(int historySize, Real R);
|
||||
virtual ~MagAGC();
|
||||
virtual void feed(Complex& ci);
|
||||
virtual Real returnedDelayedValue() const { return m_u0; }
|
||||
};
|
||||
|
||||
class AlphaAGC : public AGC
|
||||
|
@ -64,9 +58,6 @@ public:
|
|||
virtual ~AlphaAGC();
|
||||
void resize(int historySize, Real R, Real alpha);
|
||||
virtual void feed(Complex& ci);
|
||||
virtual Real returnedDelayedValue() const { return 1; }
|
||||
void openedSquelch();
|
||||
void closedSquelch();
|
||||
private:
|
||||
Real m_alpha;
|
||||
bool m_squelchOpen;
|
||||
|
@ -118,20 +109,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -113,7 +113,6 @@ void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector
|
|||
}
|
||||
else
|
||||
{
|
||||
m_volumeAGC.closedSquelch();
|
||||
sample = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,13 @@
|
|||
#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)
|
||||
|
||||
NFMDemod::NFMDemod() :
|
||||
m_ctcssIndex(0),
|
||||
m_sampleCount(0),
|
||||
m_afSquelch(2, afSqTones),
|
||||
m_squelchOpen(false),
|
||||
m_audioFifo(4, 48000),
|
||||
m_settingsMutex(QMutex::Recursive)
|
||||
|
@ -54,14 +53,11 @@ NFMDemod::NFMDemod() :
|
|||
m_audioBuffer.resize(1<<14);
|
||||
m_audioBufferFill = 0;
|
||||
|
||||
m_movingAverage.resize(16, 0);
|
||||
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);
|
||||
m_movingAverage.resize(240, 0);
|
||||
m_agcLevel = 1.0;
|
||||
m_AGC.resize(240, m_agcLevel);
|
||||
|
||||
m_ctcssDetector.setCoefficients(3000, 6000.0); // 0.5s / 2 Hz resolution
|
||||
m_afSquelch.setCoefficients(24, 48000.0, 5, 1); // 4000 Hz span, 250us
|
||||
m_afSquelch.setThreshold(0.001);
|
||||
|
||||
DSPEngine::instance()->addAudioSink(&m_audioFifo);
|
||||
}
|
||||
|
@ -165,7 +161,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) * 2; // 10000 (multiply by 2^16 after demod)
|
||||
Real demod = (h1 - h2) * 1; // 10000 (multiply by 2^16 after demod)
|
||||
|
||||
m_m2Sample = m_m1Sample;
|
||||
m_m1Sample = ci;
|
||||
|
@ -173,12 +169,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
|
|||
|
||||
// AF processing
|
||||
|
||||
if(m_afSquelch.analyze(&demod))
|
||||
{
|
||||
m_squelchOpen = m_afSquelch.open();
|
||||
}
|
||||
|
||||
if (m_squelchOpen)
|
||||
if (m_AGC.getAverage() > m_squelchLevel)
|
||||
{
|
||||
if (m_running.m_ctcssOn)
|
||||
{
|
||||
|
@ -218,10 +209,8 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
|
|||
{
|
||||
demod = m_bandpass.filter(demod);
|
||||
demod *= m_running.m_volume;
|
||||
sample = demod * ((1<<18)/301) * m_AGC.getDelayedValue(); // denominator = bandpass filter number of taps
|
||||
sample = demod * 4; // denominator = bandpass filter number of taps
|
||||
}
|
||||
|
||||
m_AGC.openedSquelch();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -231,7 +220,6 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
|
|||
m_ctcssIndex = 0;
|
||||
}
|
||||
|
||||
m_AGC.closedSquelch();
|
||||
sample = 0;
|
||||
}
|
||||
|
||||
|
@ -354,10 +342,11 @@ void NFMDemod::apply()
|
|||
|
||||
if (m_config.m_squelch != m_running.m_squelch)
|
||||
{
|
||||
m_squelchLevel = pow(10.0, m_config.m_squelch / 10.0);
|
||||
m_squelchLevel *= m_squelchLevel;
|
||||
m_afSquelch.setThreshold(m_squelchLevel);
|
||||
m_afSquelch.reset();
|
||||
// input is a power level in dB
|
||||
// m_squelchLevel = pow(10.0, m_config.m_squelch / 10.0);
|
||||
m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0); // to magnitude
|
||||
|
||||
//m_squelchLevel *= m_squelchLevel;
|
||||
}
|
||||
|
||||
m_running.m_inputSampleRate = m_config.m_inputSampleRate;
|
||||
|
|
|
@ -156,14 +156,13 @@ private:
|
|||
|
||||
double m_squelchLevel;
|
||||
//int m_squelchState;
|
||||
AFSquelch m_afSquelch;
|
||||
bool m_squelchOpen;
|
||||
|
||||
Real m_lastArgument;
|
||||
Complex m_m1Sample;
|
||||
Complex m_m2Sample;
|
||||
MovingAverage<Real> m_movingAverage;
|
||||
MagSquaredAGC m_AGC;
|
||||
MagAGC m_AGC;
|
||||
Real m_agcLevel; // AGC will aim to this level
|
||||
Real m_agcFloor; // AGC will not go below this level
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
<item row="4" column="4">
|
||||
<widget class="QSlider" name="squelch">
|
||||
<property name="minimum">
|
||||
<number>-60</number>
|
||||
<number>-100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
|
|
|
@ -18,73 +18,73 @@
|
|||
#include "dsp/afsquelch.h"
|
||||
|
||||
AFSquelch::AFSquelch() :
|
||||
N(0),
|
||||
sampleRate(0),
|
||||
samplesProcessed(0),
|
||||
maxPowerIndex(0),
|
||||
nTones(2),
|
||||
samplesAttack(0),
|
||||
attackCount(0),
|
||||
samplesDecay(0),
|
||||
decayCount(0),
|
||||
isOpen(false),
|
||||
threshold(0.0)
|
||||
m_N(0),
|
||||
m_sampleRate(0),
|
||||
m_samplesProcessed(0),
|
||||
m_maxPowerIndex(0),
|
||||
m_nTones(2),
|
||||
m_samplesAttack(0),
|
||||
m_attackCount(0),
|
||||
m_samplesDecay(0),
|
||||
m_decayCount(0),
|
||||
m_isOpen(false),
|
||||
m_threshold(0.0)
|
||||
{
|
||||
k = new double[nTones];
|
||||
coef = new double[nTones];
|
||||
toneSet = new Real[nTones];
|
||||
u0 = new double[nTones];
|
||||
u1 = new double[nTones];
|
||||
power = new double[nTones];
|
||||
m_k = new double[m_nTones];
|
||||
m_coef = new double[m_nTones];
|
||||
m_toneSet = new Real[m_nTones];
|
||||
m_u0 = new double[m_nTones];
|
||||
m_u1 = new double[m_nTones];
|
||||
m_power = new double[m_nTones];
|
||||
|
||||
toneSet[0] = 2000.0;
|
||||
toneSet[1] = 10000.0;
|
||||
m_toneSet[0] = 2000.0;
|
||||
m_toneSet[1] = 10000.0;
|
||||
}
|
||||
|
||||
AFSquelch::AFSquelch(unsigned int nbTones, const Real *tones) :
|
||||
N(0),
|
||||
sampleRate(0),
|
||||
samplesProcessed(0),
|
||||
maxPowerIndex(0),
|
||||
nTones(nbTones),
|
||||
samplesAttack(0),
|
||||
attackCount(0),
|
||||
samplesDecay(0),
|
||||
decayCount(0),
|
||||
isOpen(false),
|
||||
threshold(0.0)
|
||||
AFSquelch::AFSquelch(unsigned int nbTones, const Real *tones, int samplesAttack, int samplesDecay) :
|
||||
m_N(0),
|
||||
m_sampleRate(0),
|
||||
m_samplesProcessed(0),
|
||||
m_maxPowerIndex(0),
|
||||
m_nTones(nbTones),
|
||||
m_samplesAttack(samplesAttack),
|
||||
m_attackCount(0),
|
||||
m_samplesDecay(samplesDecay),
|
||||
m_decayCount(0),
|
||||
m_isOpen(false),
|
||||
m_threshold(0.0)
|
||||
{
|
||||
k = new double[nTones];
|
||||
coef = new double[nTones];
|
||||
toneSet = new Real[nTones];
|
||||
u0 = new double[nTones];
|
||||
u1 = new double[nTones];
|
||||
power = new double[nTones];
|
||||
m_k = new double[m_nTones];
|
||||
m_coef = new double[m_nTones];
|
||||
m_toneSet = new Real[m_nTones];
|
||||
m_u0 = new double[m_nTones];
|
||||
m_u1 = new double[m_nTones];
|
||||
m_power = new double[m_nTones];
|
||||
|
||||
for (int j = 0; j < nTones; ++j)
|
||||
for (int j = 0; j < m_nTones; ++j)
|
||||
{
|
||||
toneSet[j] = tones[j];
|
||||
m_toneSet[j] = tones[j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AFSquelch::~AFSquelch()
|
||||
{
|
||||
delete[] k;
|
||||
delete[] coef;
|
||||
delete[] toneSet;
|
||||
delete[] u0;
|
||||
delete[] u1;
|
||||
delete[] power;
|
||||
delete[] m_k;
|
||||
delete[] m_coef;
|
||||
delete[] m_toneSet;
|
||||
delete[] m_u0;
|
||||
delete[] m_u1;
|
||||
delete[] m_power;
|
||||
}
|
||||
|
||||
|
||||
void AFSquelch::setCoefficients(int _N, int _samplerate, int _samplesAttack, int _samplesDecay )
|
||||
{
|
||||
N = _N; // save the basic parameters for use during analysis
|
||||
sampleRate = _samplerate;
|
||||
samplesAttack = _samplesAttack;
|
||||
samplesDecay = _samplesDecay;
|
||||
m_N = _N; // save the basic parameters for use during analysis
|
||||
m_sampleRate = _samplerate;
|
||||
m_samplesAttack = _samplesAttack;
|
||||
m_samplesDecay = _samplesDecay;
|
||||
|
||||
// for each of the frequencies (tones) of interest calculate
|
||||
// k and the associated filter coefficient as per the Goertzel
|
||||
|
@ -93,10 +93,10 @@ void AFSquelch::setCoefficients(int _N, int _samplerate, int _samplesAttack, int
|
|||
// for later display. The tone set is specified in the
|
||||
// constructor. Notice that the resulting coefficients are
|
||||
// independent of N.
|
||||
for (int j = 0; j < nTones; ++j)
|
||||
for (int j = 0; j < m_nTones; ++j)
|
||||
{
|
||||
k[j] = ((double)N * toneSet[j]) / (double)sampleRate;
|
||||
coef[j] = 2.0 * cos((2.0 * M_PI * toneSet[j])/(double)sampleRate);
|
||||
m_k[j] = ((double)m_N * m_toneSet[j]) / (double)m_sampleRate;
|
||||
m_coef[j] = 2.0 * cos((2.0 * M_PI * m_toneSet[j])/(double)m_sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,12 +106,12 @@ bool AFSquelch::analyze(Real *sample)
|
|||
{
|
||||
|
||||
feedback(*sample); // Goertzel feedback
|
||||
samplesProcessed += 1;
|
||||
m_samplesProcessed += 1;
|
||||
|
||||
if (samplesProcessed == N) // completed a block of N
|
||||
if (m_samplesProcessed == m_N) // completed a block of N
|
||||
{
|
||||
feedForward(); // calculate the power at each tone
|
||||
samplesProcessed = 0;
|
||||
m_samplesProcessed = 0;
|
||||
return true; // have a result
|
||||
}
|
||||
else
|
||||
|
@ -126,21 +126,21 @@ void AFSquelch::feedback(Real in)
|
|||
double t;
|
||||
|
||||
// feedback for each tone
|
||||
for (int j = 0; j < nTones; ++j)
|
||||
for (int j = 0; j < m_nTones; ++j)
|
||||
{
|
||||
t = u0[j];
|
||||
u0[j] = in + (coef[j] * u0[j]) - u1[j];
|
||||
u1[j] = t;
|
||||
t = m_u0[j];
|
||||
m_u0[j] = in + (m_coef[j] * m_u0[j]) - m_u1[j];
|
||||
m_u1[j] = t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AFSquelch::feedForward()
|
||||
{
|
||||
for (int j = 0; j < nTones; ++j)
|
||||
for (int j = 0; j < m_nTones; ++j)
|
||||
{
|
||||
power[j] = (u0[j] * u0[j]) + (u1[j] * u1[j]) - (coef[j] * u0[j] * u1[j]);
|
||||
u0[j] = u1[j] = 0.0; // reset for next block.
|
||||
m_power[j] = (m_u0[j] * m_u0[j]) + (m_u1[j] * m_u1[j]) - (m_coef[j] * m_u0[j] * m_u1[j]);
|
||||
m_u0[j] = m_u1[j] = 0.0; // reset for next block.
|
||||
}
|
||||
|
||||
evaluate();
|
||||
|
@ -149,14 +149,14 @@ void AFSquelch::feedForward()
|
|||
|
||||
void AFSquelch::reset()
|
||||
{
|
||||
for (int j = 0; j < nTones; ++j)
|
||||
for (int j = 0; j < m_nTones; ++j)
|
||||
{
|
||||
power[j] = u0[j] = u1[j] = 0.0; // reset
|
||||
m_power[j] = m_u0[j] = m_u1[j] = 0.0; // reset
|
||||
}
|
||||
|
||||
samplesProcessed = 0;
|
||||
maxPowerIndex = 0;
|
||||
isOpen = false;
|
||||
m_samplesProcessed = 0;
|
||||
m_maxPowerIndex = 0;
|
||||
m_isOpen = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -166,49 +166,51 @@ void AFSquelch::evaluate()
|
|||
double minPower;
|
||||
int minIndex = 0, maxIndex = 0;
|
||||
|
||||
for (int j = 0; j < nTones; ++j)
|
||||
for (int j = 0; j < m_nTones; ++j)
|
||||
{
|
||||
if (power[j] > maxPower) {
|
||||
maxPower = power[j];
|
||||
if (m_power[j] > maxPower) {
|
||||
maxPower = m_power[j];
|
||||
maxIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
minPower = maxPower;
|
||||
|
||||
for (int j = 0; j < nTones; ++j)
|
||||
for (int j = 0; j < m_nTones; ++j)
|
||||
{
|
||||
if (power[j] < minPower) {
|
||||
minPower = power[j];
|
||||
if (m_power[j] < minPower) {
|
||||
minPower = m_power[j];
|
||||
minIndex = j;
|
||||
}
|
||||
}
|
||||
|
||||
// principle is to open if power is uneven because noise gives even power
|
||||
bool open = ((maxPower - minPower) > threshold) && (minIndex > maxIndex);
|
||||
bool open = ((maxPower - minPower) > m_threshold); // && (minIndex > maxIndex);
|
||||
|
||||
if (open)
|
||||
{
|
||||
if (samplesAttack && (attackCount < samplesAttack))
|
||||
if (m_samplesAttack && (m_attackCount < m_samplesAttack))
|
||||
{
|
||||
attackCount++;
|
||||
m_isOpen = false;
|
||||
m_attackCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
isOpen = true;
|
||||
decayCount = 0;
|
||||
m_isOpen = true;
|
||||
m_decayCount = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (samplesDecay && (decayCount < samplesDecay))
|
||||
if (m_samplesDecay && (m_decayCount < m_samplesDecay))
|
||||
{
|
||||
decayCount++;
|
||||
m_isOpen = true;
|
||||
m_decayCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
isOpen = false;
|
||||
attackCount = 0;
|
||||
m_isOpen = false;
|
||||
m_attackCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,36 +40,11 @@ Real AGC::getValue()
|
|||
return m_u0;
|
||||
}
|
||||
|
||||
Real AGC::getDelayedValue()
|
||||
Real AGC::getAverage()
|
||||
{
|
||||
if (m_count < m_historySize*m_mult)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return returnedDelayedValue();
|
||||
}
|
||||
return m_moving_average.average();
|
||||
}
|
||||
|
||||
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()
|
||||
{}
|
||||
|
@ -83,9 +58,10 @@ 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);
|
||||
m_u0 = m_R / m_moving_average.average();
|
||||
ci *= m_u0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,9 +78,10 @@ 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);
|
||||
m_u0 = m_R / m_moving_average.average();
|
||||
ci *= m_u0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,7 +117,6 @@ void AlphaAGC::resize(int historySize, Real R, Real alpha)
|
|||
|
||||
void AlphaAGC::feed(Complex& ci)
|
||||
{
|
||||
ci *= m_u0;
|
||||
Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
|
||||
|
||||
if (m_squelchOpen && (magsq))
|
||||
|
@ -152,16 +128,5 @@ void AlphaAGC::feed(Complex& ci)
|
|||
//m_squelchOpen = true;
|
||||
m_moving_average.feed(magsq);
|
||||
}
|
||||
}
|
||||
|
||||
void AlphaAGC::openedSquelch()
|
||||
{
|
||||
AGC::openedSquelch();
|
||||
m_squelchOpen = true;
|
||||
}
|
||||
|
||||
void AlphaAGC::closedSquelch()
|
||||
{
|
||||
AGC::closedSquelch();
|
||||
m_squelchOpen = false;
|
||||
ci *= m_u0;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue