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