kopia lustrzana https://github.com/f4exb/sdrangel
				
				
				
			AGC in .cpp
							rodzic
							
								
									15c050c360
								
							
						
					
					
						commit
						f5809b95c0
					
				|  | @ -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 | ||||
|  |  | |||
|  | @ -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<Real> 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<Real> 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<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; | ||||
| 	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<Real> 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<Real> m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC.
 | ||||
| }; | ||||
| 
 | ||||
| #endif /* INCLUDE_GPL_DSP_AGC_H_ */ | ||||
|  |  | |||
|  | @ -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; | ||||
| } | ||||
		Ładowanie…
	
		Reference in New Issue
	
	 f4exb
						f4exb