2015-05-12 06:12:13 -04:00
|
|
|
/*
|
|
|
|
* kissagc.h
|
|
|
|
*
|
|
|
|
* Created on: May 12, 2015
|
|
|
|
* Author: f4exb
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef INCLUDE_GPL_DSP_AGC_H_
|
|
|
|
#define INCLUDE_GPL_DSP_AGC_H_
|
|
|
|
|
|
|
|
#include "movingaverage.h"
|
|
|
|
|
|
|
|
class SimpleAGC
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
SimpleAGC() :
|
2015-08-29 03:41:39 -04:00
|
|
|
m_squelchOpen(false),
|
2015-05-12 06:12:13 -04:00
|
|
|
m_fill(0),
|
|
|
|
m_cutoff(0),
|
2015-05-14 11:19:06 -04:00
|
|
|
m_clip(0),
|
2015-05-12 06:12:13 -04:00
|
|
|
m_moving_average()
|
|
|
|
{}
|
|
|
|
|
2015-05-14 11:19:06 -04:00
|
|
|
SimpleAGC(int historySize, Real initial, Real cutoff=0, Real clip=0) :
|
2015-08-29 03:41:39 -04:00
|
|
|
m_squelchOpen(false),
|
2015-05-12 06:12:13 -04:00
|
|
|
m_fill(initial),
|
|
|
|
m_cutoff(cutoff),
|
2015-05-14 11:19:06 -04:00
|
|
|
m_clip(clip),
|
2015-05-12 06:12:13 -04:00
|
|
|
m_moving_average(historySize, initial)
|
|
|
|
{}
|
|
|
|
|
2015-05-14 11:19:06 -04:00
|
|
|
void resize(int historySize, Real initial, Real cutoff=0, Real clip=0)
|
2015-05-12 06:12:13 -04:00
|
|
|
{
|
|
|
|
m_fill = initial;
|
|
|
|
m_cutoff = cutoff;
|
2015-05-14 11:19:06 -04:00
|
|
|
m_clip = clip;
|
2015-05-12 06:12:13 -04:00
|
|
|
m_moving_average.resize(historySize, initial);
|
|
|
|
}
|
|
|
|
|
|
|
|
Real getValue()
|
|
|
|
{
|
2015-08-29 03:41:39 -04:00
|
|
|
if (m_moving_average.average() > m_clip)
|
|
|
|
{
|
2015-05-14 11:19:06 -04:00
|
|
|
return m_moving_average.average();
|
2015-08-29 03:41:39 -04:00
|
|
|
} else
|
|
|
|
{
|
2015-05-14 11:19:06 -04:00
|
|
|
return m_clip;
|
|
|
|
}
|
2015-05-12 06:12:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void feed(Real value)
|
|
|
|
{
|
|
|
|
if (value > m_cutoff)
|
|
|
|
{
|
|
|
|
m_moving_average.feed(value);
|
|
|
|
}
|
2015-08-29 03:41:39 -04:00
|
|
|
}
|
2015-05-12 06:12:13 -04:00
|
|
|
|
2015-08-29 03:41:39 -04:00
|
|
|
void openedSquelch()
|
|
|
|
{
|
|
|
|
m_squelchOpen = true;
|
2015-05-12 06:12:13 -04:00
|
|
|
}
|
|
|
|
|
2015-08-29 03:41:39 -04:00
|
|
|
void closedSquelch()
|
2015-05-12 06:12:13 -04:00
|
|
|
{
|
2015-08-29 03:41:39 -04:00
|
|
|
if (m_squelchOpen)
|
2015-05-12 06:12:13 -04:00
|
|
|
{
|
2015-08-29 03:41:39 -04:00
|
|
|
//m_moving_average.fill(m_fill); // Valgrind optim
|
|
|
|
m_squelchOpen = false;
|
2015-05-12 06:12:13 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-08-29 03:41:39 -04:00
|
|
|
bool m_squelchOpen; // open for processing
|
2015-05-14 11:19:06 -04:00
|
|
|
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
|
2015-06-20 03:28:57 -04:00
|
|
|
MovingAverage<Real> m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC.
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class EvenSimplerAGC
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
EvenSimplerAGC() :
|
|
|
|
m_u0(1.0),
|
|
|
|
m_R(1.0),
|
2015-09-06 19:15:55 -04:00
|
|
|
m_moving_average(),
|
|
|
|
m_historySize(0),
|
|
|
|
m_count(0)
|
2015-06-20 03:28:57 -04:00
|
|
|
{}
|
|
|
|
|
|
|
|
EvenSimplerAGC(int historySize, Real R) :
|
|
|
|
m_u0(1.0),
|
|
|
|
m_R(R),
|
2015-09-06 19:15:55 -04:00
|
|
|
m_moving_average(historySize, m_R),
|
|
|
|
m_historySize(historySize),
|
|
|
|
m_count(0)
|
2015-06-20 03:28:57 -04:00
|
|
|
{}
|
|
|
|
|
|
|
|
void resize(int historySize, Real R)
|
|
|
|
{
|
|
|
|
m_R = R;
|
|
|
|
m_moving_average.resize(historySize, R);
|
2015-09-06 19:15:55 -04:00
|
|
|
m_historySize = historySize;
|
|
|
|
m_count = 0;
|
2015-06-20 03:28:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Real getValue()
|
|
|
|
{
|
|
|
|
return m_u0;
|
|
|
|
}
|
|
|
|
|
2015-09-06 19:15:55 -04:00
|
|
|
Real getDelayedValue()
|
|
|
|
{
|
|
|
|
if (m_count < m_historySize*m_mult)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return m_u0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-20 03:28:57 -04:00
|
|
|
void feed(Complex& ci)
|
|
|
|
{
|
|
|
|
ci *= m_u0;
|
2015-09-06 19:15:55 -04:00
|
|
|
Real mag = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag());
|
|
|
|
m_moving_average.feed(mag);
|
2015-08-29 03:41:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void openedSquelch()
|
|
|
|
{
|
2015-09-06 19:15:55 -04:00
|
|
|
if (m_count < m_historySize*m_mult)
|
|
|
|
{
|
|
|
|
m_count++;
|
|
|
|
}
|
|
|
|
|
2015-06-20 03:28:57 -04:00
|
|
|
m_u0 = m_R / m_moving_average.average();
|
|
|
|
}
|
|
|
|
|
2015-08-29 03:41:39 -04:00
|
|
|
void closedSquelch()
|
2015-06-20 03:28:57 -04:00
|
|
|
{
|
2015-08-29 03:41:39 -04:00
|
|
|
//m_moving_average.fill(m_R); // Valgrind optim
|
2015-09-06 19:15:55 -04:00
|
|
|
m_count = 0;
|
|
|
|
m_u0 = m_R / m_moving_average.average();
|
2015-06-20 03:28:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Real m_u0;
|
2015-09-06 19:15:55 -04:00
|
|
|
Real m_R; // objective mag
|
2015-06-20 03:28:57 -04:00
|
|
|
MovingAverage<Real> m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC.
|
2015-09-06 19:15:55 -04:00
|
|
|
int m_historySize;
|
|
|
|
int m_count;
|
|
|
|
static const int m_mult = 4;
|
2015-06-20 03:28:57 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
class AlphaAGC
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
AlphaAGC() :
|
|
|
|
m_u0(1.0),
|
|
|
|
m_R(1.0),
|
|
|
|
m_alpha(0.1),
|
2015-08-29 03:41:39 -04:00
|
|
|
m_squelchOpen(true),
|
2015-09-06 19:15:55 -04:00
|
|
|
m_moving_average(),
|
|
|
|
m_historySize(0),
|
|
|
|
m_count(0)
|
2015-06-20 03:28:57 -04:00
|
|
|
{}
|
|
|
|
|
|
|
|
AlphaAGC(int historySize, Real R, Real alpha) :
|
|
|
|
m_u0(1.0),
|
|
|
|
m_R(R),
|
|
|
|
m_alpha(alpha),
|
2015-08-29 03:41:39 -04:00
|
|
|
m_squelchOpen(true),
|
2015-09-06 19:15:55 -04:00
|
|
|
m_moving_average(historySize, m_R),
|
|
|
|
m_historySize(historySize),
|
|
|
|
m_count(0)
|
2015-06-20 03:28:57 -04:00
|
|
|
{}
|
|
|
|
|
|
|
|
void resize(int historySize, Real R, Real alpha)
|
|
|
|
{
|
|
|
|
m_R = R;
|
|
|
|
m_alpha = alpha;
|
2015-08-29 03:41:39 -04:00
|
|
|
m_squelchOpen = true;
|
2015-06-20 03:28:57 -04:00
|
|
|
m_moving_average.resize(historySize, R);
|
2015-09-06 19:15:55 -04:00
|
|
|
m_historySize = historySize;
|
|
|
|
m_count = 0;
|
2015-06-20 03:28:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Real getValue()
|
|
|
|
{
|
|
|
|
return m_u0;
|
|
|
|
}
|
|
|
|
|
2015-09-06 19:15:55 -04:00
|
|
|
Real getDelayedValue()
|
|
|
|
{
|
|
|
|
if (m_count < m_historySize)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return m_u0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-20 03:28:57 -04:00
|
|
|
void feed(Complex& ci)
|
|
|
|
{
|
|
|
|
ci *= m_u0;
|
2015-09-06 19:15:55 -04:00
|
|
|
Real mag = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag());
|
2015-06-20 03:28:57 -04:00
|
|
|
|
2015-09-06 19:15:55 -04:00
|
|
|
if (m_squelchOpen && (mag < m_moving_average.average()))
|
2015-06-20 03:28:57 -04:00
|
|
|
{
|
2015-09-06 19:15:55 -04:00
|
|
|
m_moving_average.feed(m_moving_average.average() - m_alpha*(m_moving_average.average() - mag));
|
2015-06-20 03:28:57 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-08-29 03:41:39 -04:00
|
|
|
//m_squelchOpen = true;
|
2015-09-06 19:15:55 -04:00
|
|
|
m_moving_average.feed(mag);
|
2015-06-20 03:28:57 -04:00
|
|
|
}
|
|
|
|
|
2015-08-29 03:41:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void openedSquelch()
|
|
|
|
{
|
2015-09-06 19:15:55 -04:00
|
|
|
if (m_count < m_historySize)
|
|
|
|
{
|
|
|
|
m_count++;
|
|
|
|
}
|
|
|
|
|
2015-06-20 03:28:57 -04:00
|
|
|
m_u0 = m_R / m_moving_average.average();
|
2015-08-29 03:41:39 -04:00
|
|
|
m_squelchOpen = true;
|
2015-06-20 03:28:57 -04:00
|
|
|
}
|
|
|
|
|
2015-08-29 03:41:39 -04:00
|
|
|
void closedSquelch()
|
2015-06-20 03:28:57 -04:00
|
|
|
{
|
2015-08-29 03:41:39 -04:00
|
|
|
//m_moving_average.fill(m_R); // Valgrind optim
|
2015-09-06 19:15:55 -04:00
|
|
|
m_count = 0;
|
|
|
|
//m_u0 = 1.0;
|
|
|
|
m_u0 = m_R / m_moving_average.average();
|
2015-08-29 03:41:39 -04:00
|
|
|
m_squelchOpen = false;
|
2015-06-20 03:28:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Real m_u0;
|
|
|
|
Real m_R; // objective magsq
|
|
|
|
Real m_alpha;
|
2015-08-29 03:41:39 -04:00
|
|
|
bool m_squelchOpen;
|
2015-06-20 03:28:57 -04:00
|
|
|
MovingAverage<Real> m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC.
|
2015-09-06 19:15:55 -04:00
|
|
|
int m_historySize;
|
|
|
|
int m_count;
|
2015-05-12 06:12:13 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* INCLUDE_GPL_DSP_AGC_H_ */
|