GNU Radio Manual and C++ API Reference  3.7.13.4
The Free & Open Software Radio Ecosystem
pfb_clock_sync_ccf.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2009,2010,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 
24 #ifndef INCLUDED_DIGITAL_PFB_CLOCK_SYNC_CCF_H
25 #define INCLUDED_DIGITAL_PFB_CLOCK_SYNC_CCF_H
26 
27 #include <gnuradio/digital/api.h>
29 #include <gnuradio/block.h>
30 
31 namespace gr {
32  namespace digital {
33 
34  /*!
35  * \brief Timing synchronizer using polyphase filterbanks
36  * \ingroup synchronizers_blk
37  *
38  * \details
39  * This block performs timing synchronization for PAM signals by
40  * minimizing the derivative of the filtered signal, which in turn
41  * maximizes the SNR and minimizes ISI.
42  *
43  * This approach works by setting up two filterbanks; one
44  * filterbank contains the signal's pulse shaping matched filter
45  * (such as a root raised cosine filter), where each branch of the
46  * filterbank contains a different phase of the filter. The
47  * second filterbank contains the derivatives of the filters in
48  * the first filterbank. Thinking of this in the time domain, the
49  * first filterbank contains filters that have a sinc shape to
50  * them. We want to align the output signal to be sampled at
51  * exactly the peak of the sinc shape. The derivative of the sinc
52  * contains a zero at the maximum point of the sinc (sinc(0) = 1,
53  * sinc(0)' = 0). Furthermore, the region around the zero point
54  * is relatively linear. We make use of this fact to generate the
55  * error signal.
56  *
57  * If the signal out of the derivative filters is d_i[n] for the
58  * ith filter, and the output of the matched filter is x_i[n], we
59  * calculate the error as: e[n] = (Re{x_i[n]} * Re{d_i[n]} +
60  * Im{x_i[n]} * Im{d_i[n]}) / 2.0 This equation averages the error
61  * in the real and imaginary parts. There are two reasons we
62  * multiply by the signal itself. First, if the symbol could be
63  * positive or negative going, but we want the error term to
64  * always tell us to go in the same direction depending on which
65  * side of the zero point we are on. The sign of x_i[n] adjusts
66  * the error term to do this. Second, the magnitude of x_i[n]
67  * scales the error term depending on the symbol's amplitude, so
68  * larger signals give us a stronger error term because we have
69  * more confidence in that symbol's value. Using the magnitude of
70  * x_i[n] instead of just the sign is especially good for signals
71  * with low SNR.
72  *
73  * The error signal, e[n], gives us a value proportional to how
74  * far away from the zero point we are in the derivative
75  * signal. We want to drive this value to zero, so we set up a
76  * second order loop. We have two variables for this loop; d_k is
77  * the filter number in the filterbank we are on and d_rate is the
78  * rate which we travel through the filters in the steady
79  * state. That is, due to the natural clock differences between
80  * the transmitter and receiver, d_rate represents that difference
81  * and would traverse the filter phase paths to keep the receiver
82  * locked. Thinking of this as a second-order PLL, the d_rate is
83  * the frequency and d_k is the phase. So we update d_rate and d_k
84  * using the standard loop equations based on two error signals,
85  * d_alpha and d_beta. We have these two values set based on each
86  * other for a critically damped system, so in the block
87  * constructor, we just ask for "gain," which is d_alpha while
88  * d_beta is equal to (gain^2)/4.
89  *
90  * The block's parameters are:
91  *
92  * \li \p sps: The clock sync block needs to know the number of
93  * samples per symbol, because it defaults to return a single
94  * point representing the symbol. The sps can be any positive real
95  * number and does not need to be an integer.
96  *
97  * \li \p loop_bw: The loop bandwidth is used to set the gain of
98  * the inner control loop (see:
99  * http://gnuradio.squarespace.com/blog/2011/8/13/control-loop-gain-values.html).
100  * This should be set small (a value of around 2pi/100 is
101  * suggested in that blog post as the step size for the number of
102  * radians around the unit circle to move relative to the error).
103  *
104  * \li \p taps: One of the most important parameters for this
105  * block is the taps of the filter. One of the benefits of this
106  * algorithm is that you can put the matched filter in here as the
107  * taps, so you get both the matched filter and sample timing
108  * correction in one go. So create your normal matched filter. For
109  * a typical digital modulation, this is a root raised cosine
110  * filter. The number of taps of this filter is based on how long
111  * you expect the channel to be; that is, how many symbols do you
112  * want to combine to get the current symbols energy back (there's
113  * probably a better way of stating that). It's usually 5 to 10 or
114  * so. That gives you your filter, but now we need to think about
115  * it as a filter with different phase profiles in each filter. So
116  * take this number of taps and multiply it by the number of
117  * filters. This is the number you would use to create your
118  * prototype filter. When you use this in the PFB filerbank, it
119  * segments these taps into the filterbanks in such a way that
120  * each bank now represents the filter at different phases,
121  * equally spaced at 2pi/N, where N is the number of filters.
122  *
123  * \li \p filter_size (default=32): The number of filters can also
124  * be set and defaults to 32. With 32 filters, you get a good
125  * enough resolution in the phase to produce very small, almost
126  * unnoticeable, ISI. Going to 64 filters can reduce this more,
127  * but after that there is very little gained for the extra
128  * complexity.
129  *
130  * \li \p init_phase (default=0): The initial phase is another
131  * settable parameter and refers to the filter path the algorithm
132  * initially looks at (i.e., d_k starts at init_phase). This value
133  * defaults to zero, but it might be useful to start at a
134  * different phase offset, such as the mid-point of the filters.
135  *
136  * \li \p max_rate_deviation (default=1.5): The next parameter is
137  * the max_rate_devitation, which defaults to 1.5. This is how far
138  * we allow d_rate to swing, positive or negative, from
139  * 0. Constraining the rate can help keep the algorithm from
140  * walking too far away to lock during times when there is no
141  * signal.
142  *
143  * \li \p osps (default=1): The osps is the number of output
144  * samples per symbol. By default, the algorithm produces 1 sample
145  * per symbol, sampled at the exact sample value. This osps value
146  * was added to better work with equalizers, which do a better job
147  * of modeling the channel if they have 2 samps/sym.
148  *
149  * Reference:
150  * f. j. harris and M. Rice, "Multirate Digital Filters for Symbol
151  * Timing Synchronization in Software Defined Radios", IEEE
152  * Selected Areas in Communications, Vol. 19, No. 12, Dec., 2001.
153  *
154  * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.127.1757
155  */
156  class DIGITAL_API pfb_clock_sync_ccf : virtual public block
157  {
158  public:
159  // gr::digital::pfb_clock_sync_ccf::sptr
160  typedef boost::shared_ptr<pfb_clock_sync_ccf> sptr;
161 
162  /*!
163  * Build the polyphase filterbank timing synchronizer.
164  * \param sps (double) The number of samples per symbol in the incoming signal
165  * \param loop_bw (float) The bandwidth of the control loop; set's alpha and beta.
166  * \param taps (vector<int>) The filter taps.
167  * \param filter_size (uint) The number of filters in the filterbank (default = 32).
168  * \param init_phase (float) The initial phase to look at, or which filter to start
169  * with (default = 0).
170  * \param max_rate_deviation (float) Distance from 0 d_rate can get (default = 1.5).
171  * \param osps (int) The number of output samples per symbol (default=1).
172  */
173  static sptr make(double sps, float loop_bw,
174  const std::vector<float> &taps,
175  unsigned int filter_size=32,
176  float init_phase=0,
177  float max_rate_deviation=1.5,
178  int osps=1);
179 
180  /*! \brief update the system gains from omega and eta
181  *
182  * This function updates the system gains based on the loop
183  * bandwidth and damping factor of the system.
184  * These two factors can be set separately through their own
185  * set functions.
186  */
187  virtual void update_gains() = 0;
188 
189  /*!
190  * Resets the filterbank's filter taps with the new prototype filter.
191  */
192  virtual void update_taps(const std::vector<float> &taps) = 0;
193 
194  /*!
195  * Used to set the taps of the filters in the filterbank and
196  * differential filterbank.
197  *
198  * WARNING: this should not be used externally and will be moved
199  * to a private function in the next API.
200  */
201  virtual void set_taps(const std::vector<float> &taps,
202  std::vector< std::vector<float> > &ourtaps,
203  std::vector<gr::filter::kernel::fir_filter_ccf*> &ourfilter) = 0;
204 
205  /*!
206  * Returns all of the taps of the matched filter
207  */
208  virtual std::vector< std::vector<float> > taps() const = 0;
209 
210  /*!
211  * Returns all of the taps of the derivative filter
212  */
213  virtual std::vector< std::vector<float> > diff_taps() const = 0;
214 
215  /*!
216  * Returns the taps of the matched filter for a particular channel
217  */
218  virtual std::vector<float> channel_taps(int channel) const = 0;
219 
220  /*!
221  * Returns the taps in the derivative filter for a particular channel
222  */
223  virtual std::vector<float> diff_channel_taps(int channel) const = 0;
224 
225  /*!
226  * Return the taps as a formatted string for printing
227  */
228  virtual std::string taps_as_string() const = 0;
229 
230  /*!
231  * Return the derivative filter taps as a formatted string for printing
232  */
233  virtual std::string diff_taps_as_string() const = 0;
234 
235 
236  /*******************************************************************
237  SET FUNCTIONS
238  *******************************************************************/
239 
240  /*!
241  * \brief Set the loop bandwidth
242  *
243  * Set the loop filter's bandwidth to \p bw. This should be
244  * between 2*pi/200 and 2*pi/100 (in rads/samp). It must also be
245  * a positive number.
246  *
247  * When a new damping factor is set, the gains, alpha and beta,
248  * of the loop are recalculated by a call to update_gains().
249  *
250  * \param bw (float) new bandwidth
251  */
252  virtual void set_loop_bandwidth(float bw) = 0;
253 
254  /*!
255  * \brief Set the loop damping factor
256  *
257  * Set the loop filter's damping factor to \p df. The damping
258  * factor should be sqrt(2)/2.0 for critically damped systems.
259  * Set it to anything else only if you know what you are
260  * doing. It must be a number between 0 and 1.
261  *
262  * When a new damping factor is set, the gains, alpha and beta,
263  * of the loop are recalculated by a call to update_gains().
264  *
265  * \param df (float) new damping factor
266  */
267  virtual void set_damping_factor(float df) = 0;
268 
269  /*!
270  * \brief Set the loop gain alpha
271  *
272  * Set's the loop filter's alpha gain parameter.
273  *
274  * This value should really only be set by adjusting the loop
275  * bandwidth and damping factor.
276  *
277  * \param alpha (float) new alpha gain
278  */
279  virtual void set_alpha(float alpha) = 0;
280 
281  /*!
282  * \brief Set the loop gain beta
283  *
284  * Set's the loop filter's beta gain parameter.
285  *
286  * This value should really only be set by adjusting the loop
287  * bandwidth and damping factor.
288  *
289  * \param beta (float) new beta gain
290  */
291  virtual void set_beta(float beta) = 0;
292 
293  /*!
294  * Set the maximum deviation from 0 d_rate can have
295  */
296  virtual void set_max_rate_deviation(float m) = 0;
297 
298  /*******************************************************************
299  GET FUNCTIONS
300  *******************************************************************/
301 
302  /*!
303  * \brief Returns the loop bandwidth
304  */
305  virtual float loop_bandwidth() const = 0;
306 
307  /*!
308  * \brief Returns the loop damping factor
309  */
310  virtual float damping_factor() const = 0;
311 
312  /*!
313  * \brief Returns the loop gain alpha
314  */
315  virtual float alpha() const = 0;
316 
317  /*!
318  * \brief Returns the loop gain beta
319  */
320  virtual float beta() const = 0;
321 
322  /*!
323  * \brief Returns the current clock rate
324  */
325  virtual float clock_rate() const = 0;
326 
327  /*!
328  * \brief Returns the current error of the control loop.
329  */
330  virtual float error() const = 0;
331 
332  /*!
333  * \brief Returns the current rate of the control loop.
334  */
335  virtual float rate() const = 0;
336 
337  /*!
338  * \brief Returns the current phase arm of the control loop.
339  */
340  virtual float phase() const = 0;
341  };
342 
343  } /* namespace digital */
344 } /* namespace gr */
345 
346 #endif /* INCLUDED_DIGITAL_PFB_CLOCK_SYNC_CCF_H */
#define DIGITAL_API
Definition: gr-digital/include/gnuradio/digital/api.h:30
Timing synchronizer using polyphase filterbanks.
Definition: pfb_clock_sync_ccf.h:156
Include this header to use the message passing features.
Definition: logger.h:695
boost::shared_ptr< pfb_clock_sync_ccf > sptr
Definition: pfb_clock_sync_ccf.h:160
static const float taps[NSTEPS+1][NTAPS]
Definition: interpolator_taps.h:9
The abstract base class for all &#39;terminal&#39; processing blocks.A signal processing flow is constructed ...
Definition: block.h:65