GNU Radio Manual and C++ API Reference  3.8.1.0
The Free & Open Software Radio Ecosystem
control_loop.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2011,2013 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 GR_BLOCKS_CONTROL_LOOP
24 #define GR_BLOCKS_CONTROL_LOOP
25 
26 #include <gnuradio/blocks/api.h>
27 
28 namespace gr {
29 namespace blocks {
30 
31 /*!
32  * \brief A second-order control loop implementation class.
33  *
34  * \details
35  * This class implements a second order control loop and is
36  * intended to act as a parent class to blocks which need a control
37  * loop (e.g., gr::digital::costas_loop_cc,
38  * gr::analog::pll_refout_cc, etc.). It takes in a loop bandwidth
39  * as well as a max and min frequency and provides the functions
40  * that control the update of the loop.
41  *
42  * The loop works of alpha and beta gains. These gains are
43  * calculated using the input loop bandwidth and a pre-set damping
44  * factor. The damping factor can be changed using the
45  * #set_damping_factor after the block is
46  * constructed. The alpha and beta values can be set using their
47  * respective #set_alpha or #set_beta functions if very precise
48  * control over these is required.
49  *
50  * The class tracks both phase and frequency of a signal based on
51  * an error signal. The error calculation is unique for each
52  * algorithm and is calculated externally and passed to the
53  * advance_loop function, which uses this to update its phase and
54  * frequency estimates.
55  *
56  * This class also provides the functions #phase_wrap and
57  * #frequency_limit to easily keep the phase and frequency
58  * estimates within our set bounds (phase_wrap keeps it within
59  * +/-2pi).
60  */
62 {
63 protected:
64  float d_phase, d_freq;
65  float d_max_freq, d_min_freq;
66  float d_damping, d_loop_bw;
67  float d_alpha, d_beta;
68 
69 public:
70  control_loop(void) {}
71  control_loop(float loop_bw, float max_freq, float min_freq);
72  virtual ~control_loop();
73 
74  /*! \brief Update the system gains from the loop bandwidth and damping factor.
75  *
76  * \details
77  * This function updates the system gains based on the loop
78  * bandwidth and damping factor of the system. These two
79  * factors can be set separately through their own set
80  * functions.
81  */
82  void update_gains();
83 
84  /*! \brief Advance the control loop based on the current gain
85  * settings and the inputted error signal.
86  */
87  void advance_loop(float error);
88 
89  /*! \brief Keep the phase between -2pi and 2pi.
90  *
91  * \details
92  * This function keeps the phase between -2pi and 2pi. If the
93  * phase is greater than 2pi by d, it wraps around to be -2pi+d;
94  * similarly if it is less than -2pi by d, it wraps around to
95  * 2pi-d.
96  *
97  * This function should be called after advance_loop to keep the
98  * phase in a good operating region. It is set as a separate
99  * method in case another way is desired as this is fairly
100  * heavy-handed.
101  */
102  void phase_wrap();
103 
104  /*! \brief Keep the frequency between d_min_freq and d_max_freq.
105  *
106  * \details
107  * This function keeps the frequency between d_min_freq and
108  * d_max_freq. If the frequency is greater than d_max_freq, it
109  * is set to d_max_freq. If the frequency is less than
110  * d_min_freq, it is set to d_min_freq.
111  *
112  * This function should be called after advance_loop to keep the
113  * frequency in the specified region. It is set as a separate
114  * method in case another way is desired as this is fairly
115  * heavy-handed.
116  */
117  void frequency_limit();
118 
119  /*******************************************************************
120  * SET FUNCTIONS
121  *******************************************************************/
122 
123  /*!
124  * \brief Set the loop bandwidth.
125  *
126  * \details
127  * Set the loop filter's bandwidth to \p bw. This should be
128  * between 2*pi/200 and 2*pi/100 (in rads/samp). It must also be
129  * a positive number.
130  *
131  * When a new damping factor is set, the gains, alpha and beta,
132  * of the loop are recalculated by a call to update_gains().
133  *
134  * \param bw (float) new bandwidth
135  */
136  virtual void set_loop_bandwidth(float bw);
137 
138  /*!
139  * \brief Set the loop damping factor.
140  *
141  * \details
142  * Set the loop filter's damping factor to \p df. The damping
143  * factor should be sqrt(2)/2.0 for critically damped systems.
144  * Set it to anything else only if you know what you are
145  * doing. It must be a number between 0 and 1.
146  *
147  * When a new damping factor is set, the gains, alpha and beta,
148  * of the loop are recalculated by a call to update_gains().
149  *
150  * \param df (float) new damping factor
151  */
152  void set_damping_factor(float df);
153 
154  /*!
155  * \brief Set the loop gain alpha.
156  *
157  * \details
158  * Sets the loop filter's alpha gain parameter.
159  *
160  * This value should really only be set by adjusting the loop
161  * bandwidth and damping factor.
162  *
163  * \param alpha (float) new alpha gain
164  */
165  void set_alpha(float alpha);
166 
167  /*!
168  * \brief Set the loop gain beta.
169  *
170  * \details
171  * Sets the loop filter's beta gain parameter.
172  *
173  * This value should really only be set by adjusting the loop
174  * bandwidth and damping factor.
175  *
176  * \param beta (float) new beta gain
177  */
178  void set_beta(float beta);
179 
180  /*!
181  * \brief Set the control loop's frequency.
182  *
183  * \details
184  * Sets the control loop's frequency. While this is normally
185  * updated by the inner loop of the algorithm, it could be
186  * useful to manually initialize, set, or reset this under
187  * certain circumstances.
188  *
189  * \param freq (float) new frequency
190  */
191  void set_frequency(float freq);
192 
193  /*!
194  * \brief Set the control loop's phase.
195  *
196  * \details
197  * Sets the control loop's phase. While this is normally
198  * updated by the inner loop of the algorithm, it could be
199  * useful to manually initialize, set, or reset this under
200  * certain circumstances.
201  *
202  * \param phase (float) new phase
203  */
204  void set_phase(float phase);
205 
206  /*!
207  * \brief Set the control loop's maximum frequency.
208  *
209  * \details
210  * Set the maximum frequency the control loop can track.
211  *
212  * \param freq (float) new max frequency
213  */
214  void set_max_freq(float freq);
215 
216  /*!
217  * \brief Set the control loop's minimum frequency.
218  *
219  * \details
220  * Set the minimum frequency the control loop can track.
221  *
222  * \param freq (float) new min frequency
223  */
224  void set_min_freq(float freq);
225 
226  /*******************************************************************
227  * GET FUNCTIONS
228  *******************************************************************/
229 
230  /*!
231  * \brief Returns the loop bandwidth.
232  */
233  float get_loop_bandwidth() const;
234 
235  /*!
236  * \brief Returns the loop damping factor.
237  */
238  float get_damping_factor() const;
239 
240  /*!
241  * \brief Returns the loop gain alpha.
242  */
243  float get_alpha() const;
244 
245  /*!
246  * \brief Returns the loop gain beta.
247  */
248  float get_beta() const;
249 
250  /*!
251  * \brief Get the control loop's frequency estimate.
252  */
253  float get_frequency() const;
254 
255  /*!
256  * \brief Get the control loop's phase estimate.
257  */
258  float get_phase() const;
259 
260  /*!
261  * \brief Get the control loop's maximum frequency.
262  */
263  float get_max_freq() const;
264 
265  /*!
266  * \brief Get the control loop's minimum frequency.
267  */
268  float get_min_freq() const;
269 };
270 
271 // This is a table of tanh(x) for x in [-2, 2] used in tanh_lut.
272 static float tanh_lut_table[256] = {
273  -0.96402758, -0.96290241, -0.96174273, -0.96054753, -0.95931576, -0.95804636,
274  -0.95673822, -0.95539023, -0.95400122, -0.95257001, -0.95109539, -0.9495761,
275  -0.94801087, -0.94639839, -0.94473732, -0.94302627, -0.94126385, -0.93944862,
276  -0.93757908, -0.93565374, -0.93367104, -0.93162941, -0.92952723, -0.92736284,
277  -0.92513456, -0.92284066, -0.92047938, -0.91804891, -0.91554743, -0.91297305,
278  -0.91032388, -0.90759795, -0.9047933, -0.90190789, -0.89893968, -0.89588656,
279  -0.89274642, -0.88951709, -0.88619637, -0.88278203, -0.87927182, -0.87566342,
280  -0.87195453, -0.86814278, -0.86422579, -0.86020115, -0.85606642, -0.85181914,
281  -0.84745683, -0.84297699, -0.83837709, -0.83365461, -0.82880699, -0.82383167,
282  -0.81872609, -0.81348767, -0.80811385, -0.80260204, -0.7969497, -0.79115425,
283  -0.78521317, -0.77912392, -0.772884, -0.76649093, -0.75994227, -0.75323562,
284  -0.74636859, -0.73933889, -0.73214422, -0.7247824, -0.71725127, -0.70954876,
285  -0.70167287, -0.6936217, -0.68539341, -0.67698629, -0.66839871, -0.65962916,
286  -0.65067625, -0.64153871, -0.6322154, -0.62270534, -0.61300768, -0.60312171,
287  -0.59304692, -0.58278295, -0.57232959, -0.56168685, -0.55085493, -0.53983419,
288  -0.52862523, -0.51722883, -0.50564601, -0.49387799, -0.48192623, -0.46979241,
289  -0.45747844, -0.44498647, -0.4323189, -0.41947836, -0.40646773, -0.39329014,
290  -0.37994896, -0.36644782, -0.35279057, -0.33898135, -0.32502449, -0.31092459,
291  -0.2966865, -0.28231527, -0.26781621, -0.25319481, -0.23845682, -0.22360817,
292  -0.208655, -0.19360362, -0.17846056, -0.16323249, -0.14792623, -0.13254879,
293  -0.11710727, -0.10160892, -0.08606109, -0.07047123, -0.05484686, -0.0391956,
294  -0.02352507, -0.00784298, 0.00784298, 0.02352507, 0.0391956, 0.05484686,
295  0.07047123, 0.08606109, 0.10160892, 0.11710727, 0.13254879, 0.14792623,
296  0.16323249, 0.17846056, 0.19360362, 0.208655, 0.22360817, 0.23845682,
297  0.25319481, 0.26781621, 0.28231527, 0.2966865, 0.31092459, 0.32502449,
298  0.33898135, 0.35279057, 0.36644782, 0.37994896, 0.39329014, 0.40646773,
299  0.41947836, 0.4323189, 0.44498647, 0.45747844, 0.46979241, 0.48192623,
300  0.49387799, 0.50564601, 0.51722883, 0.52862523, 0.53983419, 0.55085493,
301  0.56168685, 0.57232959, 0.58278295, 0.59304692, 0.60312171, 0.61300768,
302  0.62270534, 0.6322154, 0.64153871, 0.65067625, 0.65962916, 0.66839871,
303  0.67698629, 0.68539341, 0.6936217, 0.70167287, 0.70954876, 0.71725127,
304  0.7247824, 0.73214422, 0.73933889, 0.74636859, 0.75323562, 0.75994227,
305  0.76649093, 0.772884, 0.77912392, 0.78521317, 0.79115425, 0.7969497,
306  0.80260204, 0.80811385, 0.81348767, 0.81872609, 0.82383167, 0.82880699,
307  0.83365461, 0.83837709, 0.84297699, 0.84745683, 0.85181914, 0.85606642,
308  0.86020115, 0.86422579, 0.86814278, 0.87195453, 0.87566342, 0.87927182,
309  0.88278203, 0.88619637, 0.88951709, 0.89274642, 0.89588656, 0.89893968,
310  0.90190789, 0.9047933, 0.90759795, 0.91032388, 0.91297305, 0.91554743,
311  0.91804891, 0.92047938, 0.92284066, 0.92513456, 0.92736284, 0.92952723,
312  0.93162941, 0.93367104, 0.93565374, 0.93757908, 0.93944862, 0.94126385,
313  0.94302627, 0.94473732, 0.94639839, 0.94801087, 0.9495761, 0.95109539,
314  0.95257001, 0.95400122, 0.95539023, 0.95673822, 0.95804636, 0.95931576,
315  0.96054753, 0.96174273, 0.96290241, 0.96402758
316 };
317 
318 /*!
319  * A look-up table (LUT) tanh calcuation. This function returns an
320  * estimate to tanh(x) based on a 256-point LUT between -2 and
321  * 2. If x < -2, it returns -1; if > 2, it returns 1.
322  *
323  * This LUT form of the tanh is "hidden" in this code because it
324  * is likely too coarse an estimate for any real uses of a
325  * tanh. It is useful, however, in certain control loop
326  * applications where the input is expected to be within these
327  * bounds and the noise will be greater than the quanitzation of
328  * this small LUT. For more accurate forms of tanh, see
329  * volk_32f_tanh_32f.
330  */
331 static inline float tanhf_lut(float x)
332 {
333  if (x > 2)
334  return 1;
335  else if (x <= -2)
336  return -1;
337  else {
338  int index = 128 + 64 * x;
339  return tanh_lut_table[index];
340  }
341 }
342 
343 } /* namespace blocks */
344 } /* namespace gr */
345 
346 #endif /* GR_BLOCKS_CONTROL_LOOP */
static float tanhf_lut(float x)
Definition: control_loop.h:331
float d_loop_bw
Definition: control_loop.h:66
float d_beta
Definition: control_loop.h:67
GNU Radio logging wrapper for log4cpp library (C++ port of log4j)
Definition: basic_block.h:43
#define BLOCKS_API
Definition: gr-blocks/include/gnuradio/blocks/api.h:30
static float tanh_lut_table[256]
Definition: control_loop.h:272
float d_phase
Definition: control_loop.h:64
A second-order control loop implementation class.
Definition: control_loop.h:61
float d_min_freq
Definition: control_loop.h:65
control_loop(void)
Definition: control_loop.h:70