GNU Radio Manual and C++ API Reference 3.8.5.0
The Free & Open Software Radio Ecosystem
 
Loading...
Searching...
No Matches
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/block.h>
30
31namespace gr {
32namespace 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 */
157{
158public:
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,
174 float loop_bw,
175 const std::vector<float>& taps,
176 unsigned int filter_size = 32,
177 float init_phase = 0,
178 float max_rate_deviation = 1.5,
179 int osps = 1);
180
181 /*! \brief update the system gains from omega and eta
182 *
183 * This function updates the system gains based on the loop
184 * bandwidth and damping factor of the system.
185 * These two factors can be set separately through their own
186 * set functions.
187 */
188 virtual void update_gains() = 0;
189
190 /*!
191 * Resets the filterbank's filter taps with the new prototype filter.
192 */
193 virtual void update_taps(const std::vector<float>& taps) = 0;
194
195 /*!
196 * Used to set the taps of the filters in the filterbank and
197 * differential filterbank.
198 *
199 * WARNING: this should not be used externally and will be moved
200 * to a private function in the next API.
201 */
202 virtual void
203 set_taps(const std::vector<float>& taps,
204 std::vector<std::vector<float>>& ourtaps,
205 std::vector<gr::filter::kernel::fir_filter_ccf*>& ourfilter) = 0;
206
207 /*!
208 * Returns all of the taps of the matched filter
209 */
210 virtual std::vector<std::vector<float>> taps() const = 0;
211
212 /*!
213 * Returns all of the taps of the derivative filter
214 */
215 virtual std::vector<std::vector<float>> diff_taps() const = 0;
216
217 /*!
218 * Returns the taps of the matched filter for a particular channel
219 */
220 virtual std::vector<float> channel_taps(int channel) const = 0;
221
222 /*!
223 * Returns the taps in the derivative filter for a particular channel
224 */
225 virtual std::vector<float> diff_channel_taps(int channel) const = 0;
226
227 /*!
228 * Return the taps as a formatted string for printing
229 */
230 virtual std::string taps_as_string() const = 0;
231
232 /*!
233 * Return the derivative filter taps as a formatted string for printing
234 */
235 virtual std::string diff_taps_as_string() const = 0;
236
237
238 /*******************************************************************
239 SET FUNCTIONS
240 *******************************************************************/
241
242 /*!
243 * \brief Set the loop bandwidth
244 *
245 * Set the loop filter's bandwidth to \p bw. This should be
246 * between 2*pi/200 and 2*pi/100 (in rads/samp). It must also be
247 * a positive number.
248 *
249 * When a new damping factor is set, the gains, alpha and beta,
250 * of the loop are recalculated by a call to update_gains().
251 *
252 * \param bw (float) new bandwidth
253 */
254 virtual void set_loop_bandwidth(float bw) = 0;
255
256 /*!
257 * \brief Set the loop damping factor
258 *
259 * Set the loop filter's damping factor to \p df. The damping
260 * factor should be sqrt(2)/2.0 for critically damped systems.
261 * Set it to anything else only if you know what you are
262 * doing. It must be a number between 0 and 1.
263 *
264 * When a new damping factor is set, the gains, alpha and beta,
265 * of the loop are recalculated by a call to update_gains().
266 *
267 * \param df (float) new damping factor
268 */
269 virtual void set_damping_factor(float df) = 0;
270
271 /*!
272 * \brief Set the loop gain alpha
273 *
274 * Set's the loop filter's alpha gain parameter.
275 *
276 * This value should really only be set by adjusting the loop
277 * bandwidth and damping factor.
278 *
279 * \param alpha (float) new alpha gain
280 */
281 virtual void set_alpha(float alpha) = 0;
282
283 /*!
284 * \brief Set the loop gain beta
285 *
286 * Set's the loop filter's beta gain parameter.
287 *
288 * This value should really only be set by adjusting the loop
289 * bandwidth and damping factor.
290 *
291 * \param beta (float) new beta gain
292 */
293 virtual void set_beta(float beta) = 0;
294
295 /*!
296 * Set the maximum deviation from 0 d_rate can have
297 */
298 virtual void set_max_rate_deviation(float m) = 0;
299
300 /*******************************************************************
301 GET FUNCTIONS
302 *******************************************************************/
303
304 /*!
305 * \brief Returns the loop bandwidth
306 */
307 virtual float loop_bandwidth() const = 0;
308
309 /*!
310 * \brief Returns the loop damping factor
311 */
312 virtual float damping_factor() const = 0;
313
314 /*!
315 * \brief Returns the loop gain alpha
316 */
317 virtual float alpha() const = 0;
318
319 /*!
320 * \brief Returns the loop gain beta
321 */
322 virtual float beta() const = 0;
323
324 /*!
325 * \brief Returns the current clock rate
326 */
327 virtual float clock_rate() const = 0;
328
329 /*!
330 * \brief Returns the current error of the control loop.
331 */
332 virtual float error() const = 0;
333
334 /*!
335 * \brief Returns the current rate of the control loop.
336 */
337 virtual float rate() const = 0;
338
339 /*!
340 * \brief Returns the current phase arm of the control loop.
341 */
342 virtual float phase() const = 0;
343};
344
345} /* namespace digital */
346} /* namespace gr */
347
348#endif /* INCLUDED_DIGITAL_PFB_CLOCK_SYNC_CCF_H */
The abstract base class for all 'terminal' processing blocks.
Definition block.h:72
Timing synchronizer using polyphase filterbanks.
Definition pfb_clock_sync_ccf.h:157
static sptr make(double sps, float loop_bw, const std::vector< float > &taps, unsigned int filter_size=32, float init_phase=0, float max_rate_deviation=1.5, int osps=1)
virtual std::vector< float > channel_taps(int channel) const =0
virtual void set_damping_factor(float df)=0
Set the loop damping factor.
virtual float beta() const =0
Returns the loop gain beta.
virtual std::vector< std::vector< float > > taps() const =0
virtual void update_taps(const std::vector< float > &taps)=0
virtual void set_loop_bandwidth(float bw)=0
Set the loop bandwidth.
virtual std::string diff_taps_as_string() const =0
virtual std::vector< std::vector< float > > diff_taps() const =0
virtual void set_taps(const std::vector< float > &taps, std::vector< std::vector< float > > &ourtaps, std::vector< gr::filter::kernel::fir_filter_ccf * > &ourfilter)=0
virtual float loop_bandwidth() const =0
Returns the loop bandwidth.
virtual float phase() const =0
Returns the current phase arm of the control loop.
virtual std::string taps_as_string() const =0
virtual float rate() const =0
Returns the current rate of the control loop.
virtual float damping_factor() const =0
Returns the loop damping factor.
virtual std::vector< float > diff_channel_taps(int channel) const =0
virtual float clock_rate() const =0
Returns the current clock rate.
virtual void set_alpha(float alpha)=0
Set the loop gain alpha.
virtual void update_gains()=0
update the system gains from omega and eta
boost::shared_ptr< pfb_clock_sync_ccf > sptr
Definition pfb_clock_sync_ccf.h:160
virtual void set_max_rate_deviation(float m)=0
virtual float alpha() const =0
Returns the loop gain alpha.
virtual float error() const =0
Returns the current error of the control loop.
virtual void set_beta(float beta)=0
Set the loop gain beta.
#define DIGITAL_API
Definition gr-digital/include/gnuradio/digital/api.h:30
static const float taps[NSTEPS+1][NTAPS]
Definition interpolator_taps.h:9
GNU Radio logging wrapper for log4cpp library (C++ port of log4j)
Definition basic_block.h:46