| 
									
										
										
										
											2015-05-12 12:12:13 +02: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() : | 
					
						
							|  |  |  | 		m_squelch(false), | 
					
						
							|  |  |  | 		m_fill(0), | 
					
						
							|  |  |  | 		m_cutoff(0), | 
					
						
							| 
									
										
										
										
											2015-05-14 17:19:06 +02:00
										 |  |  | 		m_clip(0), | 
					
						
							| 
									
										
										
										
											2015-05-12 12:12:13 +02:00
										 |  |  | 		m_moving_average() | 
					
						
							|  |  |  | 	{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-14 17:19:06 +02:00
										 |  |  | 	SimpleAGC(int historySize, Real initial, Real cutoff=0, Real clip=0) : | 
					
						
							| 
									
										
										
										
											2015-05-12 12:12:13 +02:00
										 |  |  | 		m_squelch(false), | 
					
						
							|  |  |  | 		m_fill(initial), | 
					
						
							|  |  |  | 		m_cutoff(cutoff), | 
					
						
							| 
									
										
										
										
											2015-05-14 17:19:06 +02:00
										 |  |  | 		m_clip(clip), | 
					
						
							| 
									
										
										
										
											2015-05-12 12:12:13 +02:00
										 |  |  | 		m_moving_average(historySize, initial) | 
					
						
							|  |  |  | 	{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-14 17:19:06 +02:00
										 |  |  | 	void resize(int historySize, Real initial, Real cutoff=0, Real clip=0) | 
					
						
							| 
									
										
										
										
											2015-05-12 12:12:13 +02:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		m_fill = initial; | 
					
						
							|  |  |  | 		m_cutoff = cutoff; | 
					
						
							| 
									
										
										
										
											2015-05-14 17:19:06 +02:00
										 |  |  | 		m_clip = clip; | 
					
						
							| 
									
										
										
										
											2015-05-12 12:12:13 +02:00
										 |  |  | 		m_moving_average.resize(historySize, initial); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Real getValue() | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2015-05-14 17:19:06 +02:00
										 |  |  | 		if (m_moving_average.average() > m_clip) { | 
					
						
							|  |  |  | 			return m_moving_average.average(); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return m_clip; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-05-12 12:12:13 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void feed(Real value) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (value > m_cutoff) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			m_moving_average.feed(value); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		m_squelch = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void close() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (m_squelch) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			m_moving_average.fill(m_fill); | 
					
						
							|  |  |  | 			m_squelch = false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2015-05-14 17:19:06 +02:00
										 |  |  | 	bool m_squelch; // 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
 | 
					
						
							| 
									
										
										
										
											2015-06-20 09:28:57 +02: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), | 
					
						
							|  |  |  | 		m_moving_average() | 
					
						
							|  |  |  | 	{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	EvenSimplerAGC(int historySize, Real R) : | 
					
						
							|  |  |  | 		m_u0(1.0), | 
					
						
							|  |  |  | 		m_R(R), | 
					
						
							|  |  |  | 		m_moving_average(historySize, m_R) | 
					
						
							|  |  |  | 	{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void resize(int historySize, Real R) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_R = R; | 
					
						
							|  |  |  | 		m_moving_average.resize(historySize, R); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Real getValue() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		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); | 
					
						
							|  |  |  | 		m_u0 = m_R / m_moving_average.average(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void close() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_moving_average.fill(m_R); | 
					
						
							|  |  |  | 		m_u0 = 1.0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 	Real m_u0; | 
					
						
							|  |  |  | 	Real m_R;       // objective magsq
 | 
					
						
							|  |  |  | 	MovingAverage<Real> m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC.
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AlphaAGC | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AlphaAGC() : | 
					
						
							|  |  |  | 		m_u0(1.0), | 
					
						
							|  |  |  | 		m_R(1.0), | 
					
						
							|  |  |  | 		m_alpha(0.1), | 
					
						
							|  |  |  | 		m_squelch(false), | 
					
						
							|  |  |  | 		m_moving_average() | 
					
						
							|  |  |  | 	{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AlphaAGC(int historySize, Real R, Real alpha) : | 
					
						
							|  |  |  | 		m_u0(1.0), | 
					
						
							|  |  |  | 		m_R(R), | 
					
						
							|  |  |  | 		m_alpha(alpha), | 
					
						
							|  |  |  | 		m_squelch(false), | 
					
						
							|  |  |  | 		m_moving_average(historySize, m_R) | 
					
						
							|  |  |  | 	{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void resize(int historySize, Real R, Real alpha) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_R = R; | 
					
						
							|  |  |  | 		m_alpha = alpha; | 
					
						
							|  |  |  | 		m_squelch = false; | 
					
						
							|  |  |  | 		m_moving_average.resize(historySize, R); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Real getValue() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return m_u0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void feed(Complex& ci) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		ci *= m_u0; | 
					
						
							|  |  |  | 		Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (m_squelch && (magsq < m_moving_average.average())) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			m_moving_average.feed(m_moving_average.average() - m_alpha*(m_moving_average.average() - magsq)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			m_squelch = true; | 
					
						
							|  |  |  | 			m_moving_average.feed(magsq); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		m_u0 = m_R / m_moving_average.average(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void close() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_moving_average.fill(m_R); | 
					
						
							|  |  |  | 		m_u0 = 1.0; | 
					
						
							|  |  |  | 		m_squelch = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 	Real m_u0; | 
					
						
							|  |  |  | 	Real m_R;       // objective magsq
 | 
					
						
							|  |  |  | 	Real m_alpha; | 
					
						
							|  |  |  | 	bool m_squelch; | 
					
						
							|  |  |  | 	MovingAverage<Real> m_moving_average; // Averaging engine. The stack length conditions the smoothness of AGC.
 | 
					
						
							| 
									
										
										
										
											2015-05-12 12:12:13 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* INCLUDE_GPL_DSP_AGC_H_ */
 |