GNU Radio Manual and C++ API Reference 3.8.5.0
The Free & Open Software Radio Ecosystem
 
Loading...
Searching...
No Matches
pfb_clock_sync_fff.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#ifndef INCLUDED_DIGITAL_PFB_CLOCK_SYNC_FFF_H
24#define INCLUDED_DIGITAL_PFB_CLOCK_SYNC_FFF_H
25
26#include <gnuradio/block.h>
29
30namespace gr {
31namespace digital {
32
33/*!
34 * \brief Timing synchronizer using polyphase filterbanks
35 * \ingroup synchronizers_blk
36 *
37 * \details
38 * This block performs timing synchronization for PAM signals by
39 * minimizing the derivative of the filtered signal, which in turn
40 * maximizes the SNR and minimizes ISI.
41 *
42 * This approach works by setting up two filterbanks; one
43 * filterbank contains the signal's pulse shaping matched filter
44 * (such as a root raised cosine filter), where each branch of the
45 * filterbank contains a different phase of the filter. The
46 * second filterbank contains the derivatives of the filters in
47 * the first filterbank. Thinking of this in the time domain, the
48 * first filterbank contains filters that have a sinc shape to
49 * them. We want to align the output signal to be sampled at
50 * exactly the peak of the sinc shape. The derivative of the sinc
51 * contains a zero at the maximum point of the sinc (sinc(0) = 1,
52 * sinc(0)' = 0). Furthermore, the region around the zero point
53 * is relatively linear. We make use of this fact to generate the
54 * error signal.
55 *
56 * If the signal out of the derivative filters is d_i[n] for the
57 * ith filter, and the output of the matched filter is x_i[n], we
58 * calculate the error as: e[n] = (Re{x_i[n]} * Re{d_i[n]} +
59 * Im{x_i[n]} * Im{d_i[n]}) / 2.0 This equation averages the error
60 * in the real and imaginary parts. There are two reasons we
61 * multiply by the signal itself. First, if the symbol could be
62 * positive or negative going, but we want the error term to
63 * always tell us to go in the same direction depending on which
64 * side of the zero point we are on. The sign of x_i[n] adjusts
65 * the error term to do this. Second, the magnitude of x_i[n]
66 * scales the error term depending on the symbol's amplitude, so
67 * larger signals give us a stronger error term because we have
68 * more confidence in that symbol's value. Using the magnitude of
69 * x_i[n] instead of just the sign is especially good for signals
70 * with low SNR.
71 *
72 * The error signal, e[n], gives us a value proportional to how
73 * far away from the zero point we are in the derivative
74 * signal. We want to drive this value to zero, so we set up a
75 * second order loop. We have two variables for this loop; d_k is
76 * the filter number in the filterbank we are on and d_rate is the
77 * rate which we travel through the filters in the steady
78 * state. That is, due to the natural clock differences between
79 * the transmitter and receiver, d_rate represents that difference
80 * and would traverse the filter phase paths to keep the receiver
81 * locked. Thinking of this as a second-order PLL, the d_rate is
82 * the frequency and d_k is the phase. So we update d_rate and d_k
83 * using the standard loop equations based on two error signals,
84 * d_alpha and d_beta. We have these two values set based on each
85 * other for a critically damped system, so in the block
86 * constructor, we just ask for "gain," which is d_alpha while
87 * d_beta is equal to (gain^2)/4.
88 *
89 * The block's parameters are:
90 *
91 * \li \p sps: The clock sync block needs to know the number of
92 * samples per symbol, because it defaults to return a single
93 * point representing the symbol. The sps can be any positive real
94 * number and does not need to be an integer.
95 *
96 * \li \p loop_bw: The loop bandwidth is used to set the gain of
97 * the inner control loop (see:
98 * http://gnuradio.squarespace.com/blog/2011/8/13/control-loop-gain-values.html).
99 * This should be set small (a value of around 2pi/100 is
100 * suggested in that blog post as the step size for the number of
101 * radians around the unit circle to move relative to the error).
102 *
103 * \li \p taps: One of the most important parameters for this
104 * block is the taps of the filter. One of the benefits of this
105 * algorithm is that you can put the matched filter in here as the
106 * taps, so you get both the matched filter and sample timing
107 * correction in one go. So create your normal matched filter. For
108 * a typical digital modulation, this is a root raised cosine
109 * filter. The number of taps of this filter is based on how long
110 * you expect the channel to be; that is, how many symbols do you
111 * want to combine to get the current symbols energy back (there's
112 * probably a better way of stating that). It's usually 5 to 10 or
113 * so. That gives you your filter, but now we need to think about
114 * it as a filter with different phase profiles in each filter. So
115 * take this number of taps and multiply it by the number of
116 * filters. This is the number you would use to create your
117 * prototype filter. When you use this in the PFB filerbank, it
118 * segments these taps into the filterbanks in such a way that
119 * each bank now represents the filter at different phases,
120 * equally spaced at 2pi/N, where N is the number of filters.
121 *
122 * \li \p filter_size (default=32): The number of filters can also
123 * be set and defaults to 32. With 32 filters, you get a good
124 * enough resolution in the phase to produce very small, almost
125 * unnoticeable, ISI. Going to 64 filters can reduce this more,
126 * but after that there is very little gained for the extra
127 * complexity.
128 *
129 * \li \p init_phase (default=0): The initial phase is another
130 * settable parameter and refers to the filter path the algorithm
131 * initially looks at (i.e., d_k starts at init_phase). This value
132 * defaults to zero, but it might be useful to start at a
133 * different phase offset, such as the mid-point of the filters.
134 *
135 * \li \p max_rate_deviation (default=1.5): The next parameter is
136 * the max_rate_devitation, which defaults to 1.5. This is how far
137 * we allow d_rate to swing, positive or negative, from
138 * 0. Constraining the rate can help keep the algorithm from
139 * walking too far away to lock during times when there is no
140 * signal.
141 *
142 * \li \p osps (default=1): The osps is the number of output
143 * samples per symbol. By default, the algorithm produces 1 sample
144 * per symbol, sampled at the exact sample value. This osps value
145 * was added to better work with equalizers, which do a better job
146 * of modeling the channel if they have 2 samps/sym.
147 *
148 * Reference:
149 * f. j. harris and M. Rice, "Multirate Digital Filters for Symbol
150 * Timing Synchronization in Software Defined Radios", IEEE
151 * Selected Areas in Communications, Vol. 19, No. 12, Dec., 2001.
152 *
153 * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.127.1757
154 */
156{
157public:
158 // gr::digital::pfb_clock_sync_fff::sptr
159 typedef boost::shared_ptr<pfb_clock_sync_fff> sptr;
160
161 /*!
162 * Build the polyphase filterbank timing synchronizer.
163 * \param sps (double) The number of samples per second in the incoming signal
164 * \param gain (float) The alpha gain of the control loop; beta = (gain^2)/4 by
165 * default. \param taps (vector<int>) The filter taps. \param filter_size (uint) The
166 * number of filters in the filterbank (default = 32). \param init_phase (float) The
167 * initial phase to look at, or which filter to start with (default = 0). \param
168 * max_rate_deviation (float) Distance from 0 d_rate can get (default = 1.5). \param
169 * osps (int) The number of output samples per symbol (default=1).
170 *
171 */
172 static sptr make(double sps,
173 float gain,
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
202 set_taps(const std::vector<float>& taps,
203 std::vector<std::vector<float>>& ourtaps,
204 std::vector<gr::filter::kernel::fir_filter_fff*>& ourfilter) = 0;
205
206 /*!
207 * Returns all of the taps of the matched filter
208 */
209 virtual std::vector<std::vector<float>> taps() const = 0;
210
211 /*!
212 * Returns all of the taps of the derivative filter
213 */
214 virtual std::vector<std::vector<float>> diff_taps() const = 0;
215
216 /*!
217 * Returns the taps of the matched filter for a particular channel
218 */
219 virtual std::vector<float> channel_taps(int channel) const = 0;
220
221 /*!
222 * Returns the taps in the derivative filter for a particular channel
223 */
224 virtual std::vector<float> diff_channel_taps(int channel) const = 0;
225
226 /*!
227 * Return the taps as a formatted string for printing
228 */
229 virtual std::string taps_as_string() const = 0;
230
231 /*!
232 * Return the derivative filter taps as a formatted string for printing
233 */
234 virtual std::string diff_taps_as_string() const = 0;
235
236
237 /*******************************************************************
238 SET FUNCTIONS
239 *******************************************************************/
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} /* namespace digital */
331} /* namespace gr */
332
333#endif /* INCLUDED_DIGITAL_PFB_CLOCK_SYNC_FFF_H */
The abstract base class for all 'terminal' processing blocks.
Definition block.h:72
Timing synchronizer using polyphase filterbanks.
Definition pfb_clock_sync_fff.h:156
virtual void set_taps(const std::vector< float > &taps, std::vector< std::vector< float > > &ourtaps, std::vector< gr::filter::kernel::fir_filter_fff * > &ourfilter)=0
virtual std::string taps_as_string() const =0
virtual void set_beta(float beta)=0
Set the loop gain beta.
virtual void set_max_rate_deviation(float m)=0
virtual void set_damping_factor(float df)=0
Set the loop damping factor.
virtual void update_taps(const std::vector< float > &taps)=0
virtual void set_loop_bandwidth(float bw)=0
Set the loop bandwidth.
boost::shared_ptr< pfb_clock_sync_fff > sptr
Definition pfb_clock_sync_fff.h:159
virtual std::vector< std::vector< float > > taps() const =0
virtual void set_alpha(float alpha)=0
Set the loop gain alpha.
virtual std::string diff_taps_as_string() const =0
virtual float loop_bandwidth() const =0
Returns the loop bandwidth.
static sptr make(double sps, float gain, 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 > diff_channel_taps(int channel) const =0
virtual float beta() const =0
Returns the loop gain beta.
virtual float clock_rate() const =0
Returns the current clock rate.
virtual std::vector< float > channel_taps(int channel) const =0
virtual float alpha() const =0
Returns the loop gain alpha.
virtual void update_gains()=0
update the system gains from omega and eta
virtual float damping_factor() const =0
Returns the loop damping factor.
virtual std::vector< std::vector< float > > diff_taps() const =0
#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