1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006,2012 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  *
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifndef INCLUDED_ANALOG_AGC2_H
24 #define INCLUDED_ANALOG_AGC2_H
25 
26 #include <gnuradio/analog/api.h>
27 #include <gnuradio/gr_complex.h>
28 #include <math.h>
29 
30 namespace gr {
31 namespace analog {
32 namespace kernel {
33 
34 /*!
35  * \brief high performance Automatic Gain Control class
36  * \ingroup level_controllers_blk
37  *
38  * \details
39  * For Power the absolute value of the complex number is used.
40  */
41 class ANALOG_API agc2_cc
42 {
43 public:
44     /*!
45      * Construct a comple value AGC loop implementation object.
46      *
47      * \param attack_rate the update rate of the loop when in attack mode.
48      * \param decay_rate the update rate of the loop when in decay mode.
49      * \param reference reference value to adjust signal power to.
50      * \param gain initial gain value.
51      * \param max_gain maximum gain value (0 for unlimited).
52      */
53     agc2_cc(float attack_rate = 1e-1,
54             float decay_rate = 1e-2,
55             float reference = 1.0,
56             float gain = 1.0,
57             float max_gain = 0.0)
_attack_rate(attack_rate)58         : _attack_rate(attack_rate),
59           _decay_rate(decay_rate),
60           _reference(reference),
61           _gain(gain),
62           _max_gain(max_gain){};
63 
decay_rate()64     float decay_rate() const { return _decay_rate; }
attack_rate()65     float attack_rate() const { return _attack_rate; }
reference()66     float reference() const { return _reference; }
gain()67     float gain() const { return _gain; }
max_gain()68     float max_gain() const { return _max_gain; }
69 
set_decay_rate(float rate)70     void set_decay_rate(float rate) { _decay_rate = rate; }
set_attack_rate(float rate)71     void set_attack_rate(float rate) { _attack_rate = rate; }
set_reference(float reference)72     void set_reference(float reference) { _reference = reference; }
set_gain(float gain)73     void set_gain(float gain) { _gain = gain; }
set_max_gain(float max_gain)74     void set_max_gain(float max_gain) { _max_gain = max_gain; }
75 
scale(gr_complex input)76     gr_complex scale(gr_complex input)
77     {
78         gr_complex output = input * _gain;
79 
80         float tmp = -_reference +
81                     sqrt(output.real() * output.real() + output.imag() * output.imag());
82         float rate = _decay_rate;
83         if ((tmp) > _gain) {
84             rate = _attack_rate;
85         }
86         _gain -= tmp * rate;
87 
88         // Not sure about this; will blow up if _gain < 0 (happens
89         // when rates are too high), but is this the solution?
90         if (_gain < 0.0)
91             _gain = 10e-5;
92 
93         if (_max_gain > 0.0 && _gain > _max_gain) {
94             _gain = _max_gain;
95         }
96         return output;
97     }
98 
scaleN(gr_complex output[],const gr_complex input[],unsigned n)99     void scaleN(gr_complex output[], const gr_complex input[], unsigned n)
100     {
101         for (unsigned i = 0; i < n; i++)
102             output[i] = scale(input[i]);
103     }
104 
105 protected:
106     float _attack_rate; // attack rate for fast changing signals
107     float _decay_rate;  // decay rate for slow changing signals
108     float _reference;   // reference value
109     float _gain;        // current gain
110     float _max_gain;    // max allowable gain
111 };
112 
113 
114 class ANALOG_API agc2_ff
115 {
116 public:
117     /*!
118      * Construct a floating point value AGC loop implementation object.
119      *
120      * \param attack_rate the update rate of the loop when in attack mode.
121      * \param decay_rate the update rate of the loop when in decay mode.
122      * \param reference reference value to adjust signal power to.
123      * \param gain initial gain value.
124      * \param max_gain maximum gain value (0 for unlimited).
125      */
126     agc2_ff(float attack_rate = 1e-1,
127             float decay_rate = 1e-2,
128             float reference = 1.0,
129             float gain = 1.0,
130             float max_gain = 0.0)
_attack_rate(attack_rate)131         : _attack_rate(attack_rate),
132           _decay_rate(decay_rate),
133           _reference(reference),
134           _gain(gain),
135           _max_gain(max_gain){};
136 
attack_rate()137     float attack_rate() const { return _attack_rate; }
decay_rate()138     float decay_rate() const { return _decay_rate; }
reference()139     float reference() const { return _reference; }
gain()140     float gain() const { return _gain; }
max_gain()141     float max_gain() const { return _max_gain; }
142 
set_attack_rate(float rate)143     void set_attack_rate(float rate) { _attack_rate = rate; }
set_decay_rate(float rate)144     void set_decay_rate(float rate) { _decay_rate = rate; }
set_reference(float reference)145     void set_reference(float reference) { _reference = reference; }
set_gain(float gain)146     void set_gain(float gain) { _gain = gain; }
set_max_gain(float max_gain)147     void set_max_gain(float max_gain) { _max_gain = max_gain; }
148 
scale(float input)149     float scale(float input)
150     {
151         float output = input * _gain;
152 
153         float tmp = (fabsf(output)) - _reference;
154         float rate = _decay_rate;
155         if (fabsf(tmp) > _gain) {
156             rate = _attack_rate;
157         }
158         _gain -= tmp * rate;
159 
160         // Not sure about this
161         if (_gain < 0.0)
162             _gain = 10e-5;
163 
164         if (_max_gain > 0.0 && _gain > _max_gain) {
165             _gain = _max_gain;
166         }
167         return output;
168     }
169 
scaleN(float output[],const float input[],unsigned n)170     void scaleN(float output[], const float input[], unsigned n)
171     {
172         for (unsigned i = 0; i < n; i++)
173             output[i] = scale(input[i]);
174     }
175 
176 protected:
177     float _attack_rate; // attack_rate for fast changing signals
178     float _decay_rate;  // decay rate for slow changing signals
179     float _reference;   // reference value
180     float _gain;        // current gain
181     float _max_gain;    // maximum gain
182 };
183 
184 } /* namespace kernel */
185 } /* namespace analog */
186 } /* namespace gr */
187 
188 #endif /* INCLUDED_ANALOG_AGC2_H */
189