GNU Radio Manual and C++ API Reference  3.10.9.1
The Free & Open Software Radio Ecosystem
pfb_arb_resampler.h
Go to the documentation of this file.
1 /* -*- c++ -*- */
2 /*
3  * Copyright 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 
12 #ifndef INCLUDED_PFB_ARB_RESAMPLER_H
13 #define INCLUDED_PFB_ARB_RESAMPLER_H
14 
16 
17 namespace gr {
18 namespace filter {
19 namespace kernel {
20 
21 /*!
22  * \brief Polyphase filterbank arbitrary resampler with
23  * gr_complex input, gr_complex output and float taps
24  * \ingroup resamplers_blk
25  *
26  * \details
27  * This takes in a signal stream and performs arbitrary
28  * resampling. The resampling rate can be any real number
29  * <EM>r</EM>. The resampling is done by constructing <EM>N</EM>
30  * filters where <EM>N</EM> is the interpolation rate. We then
31  * calculate <EM>D</EM> where <EM>D = floor(N/r)</EM>.
32  *
33  * Using <EM>N</EM> and <EM>D</EM>, we can perform rational
34  * resampling where <EM>N/D</EM> is a rational number close to
35  * the input rate <EM>r</EM> where we have <EM>N</EM> filters
36  * and we cycle through them as a polyphase filterbank with a
37  * stride of <EM>D</EM> so that <EM>i+1 = (i + D) % N</EM>.
38  *
39  * To get the arbitrary rate, we want to interpolate between two
40  * points. For each value out, we take an output from the
41  * current filter, <EM>i</EM>, and the next filter <EM>i+1</EM>
42  * and then linearly interpolate between the two based on the
43  * real resampling rate we want.
44  *
45  * The linear interpolation only provides us with an
46  * approximation to the real sampling rate specified. The error
47  * is a quantization error between the two filters we used as
48  * our interpolation points. To this end, the number of
49  * filters, <EM>N</EM>, used determines the quantization error;
50  * the larger <EM>N</EM>, the smaller the noise. You can design
51  * for a specified noise floor by setting the filter size
52  * (parameters <EM>filter_size</EM>). The size defaults to 32
53  * filters, which is about as good as most implementations need.
54  *
55  * The trick with designing this filter is in how to specify the
56  * taps of the prototype filter. Like the PFB interpolator, the
57  * taps are specified using the interpolated filter rate. In
58  * this case, that rate is the input sample rate multiplied by
59  * the number of filters in the filterbank, which is also the
60  * interpolation rate. All other values should be relative to
61  * this rate.
62  *
63  * For example, for a 32-filter arbitrary resampler and using
64  * the GNU Radio's firdes utility to build the filter, we build
65  * a low-pass filter with a sampling rate of <EM>fs</EM>, a 3-dB
66  * bandwidth of <EM>BW</EM> and a transition bandwidth of
67  * <EM>TB</EM>. We can also specify the out-of-band attenuation
68  * to use, <EM>ATT</EM>, and the filter window function (a
69  * Blackman-harris window in this case). The first input is the
70  * gain of the filter, which we specify here as the
71  * interpolation rate (<EM>32</EM>).
72  *
73  * <B><EM>self._taps = filter.firdes.low_pass_2(32, 32*fs, BW, TB,
74  * attenuation_dB=ATT, window=fft.window.WIN_BLACKMAN_hARRIS)</EM></B>
75  *
76  * The theory behind this block can be found in Chapter 7.5 of
77  * the following book:
78  *
79  * <B><EM>f. harris, "Multirate Signal Processing for Communication
80  * Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
81  */
83 {
84 private:
85  std::vector<fir_filter_ccf> d_filters;
86  std::vector<fir_filter_ccf> d_diff_filters;
87  std::vector<std::vector<float>> d_taps;
88  std::vector<std::vector<float>> d_dtaps;
89  unsigned int d_int_rate; // the number of filters (interpolation rate)
90  unsigned int d_dec_rate; // the stride through the filters (decimation rate)
91  float d_flt_rate; // residual rate for the linear interpolation
92  float d_acc; // accumulator; holds fractional part of sample
93  unsigned int d_last_filter; // stores filter for re-entry
94  unsigned int d_taps_per_filter; // num taps for each arm of the filterbank
95  int d_delay; // filter's group delay
96  float d_est_phase_change; // est. of phase change of a sine wave through filt.
97 
98  /*!
99  * Takes in the taps and convolves them with [-1,0,1], which
100  * creates a differential set of taps that are used in the
101  * difference filterbank.
102  * \param newtaps (vector of floats) The prototype filter.
103  * \param difftaps (vector of floats) (out) The differential filter taps.
104  */
105  void create_diff_taps(const std::vector<float>& newtaps,
106  std::vector<float>& difftaps);
107 
108  /*!
109  * Resets the filterbank's filter taps with the new prototype filter
110  * \param newtaps (vector of floats) The prototype filter to populate the
111  * filterbank. The taps should be generated at the interpolated sampling rate. \param
112  * ourtaps (vector of floats) Reference to our internal member of holding the taps.
113  * \param ourfilter (vector of filters) Reference to our internal filter to set the
114  * taps for.
115  */
116  void create_taps(const std::vector<float>& newtaps,
117  std::vector<std::vector<float>>& ourtaps,
118  std::vector<kernel::fir_filter_ccf>& ourfilter);
119 
120 public:
121  /*!
122  * Creates a kernel to perform arbitrary resampling on a set of samples.
123  * \param rate (float) Specifies the resampling rate to use
124  * \param taps (vector/list of floats) The prototype filter to populate the
125  * filterbank. The taps * should be generated at the filter_size
126  * sampling rate. \param filter_size (unsigned int) The number of filters in the
127  * filter bank. This is directly related to quantization noise introduced during the
128  * resampling. Defaults to 32 filters.
129  */
131  const std::vector<float>& taps,
132  unsigned int filter_size);
133 
134  // Don't allow copy.
137 
138  /*!
139  * Resets the filterbank's filter taps with the new prototype filter
140  * \param taps (vector/list of floats) The prototype filter to populate the
141  * filterbank.
142  */
143  void set_taps(const std::vector<float>& taps);
144 
145  /*!
146  * Return a vector<vector<>> of the filterbank taps
147  */
148  std::vector<std::vector<float>> taps() const;
149 
150  /*!
151  * Print all of the filterbank taps to screen.
152  */
153  void print_taps();
154 
155  /*!
156  * Sets the resampling rate of the block.
157  */
158  void set_rate(float rate);
159 
160  /*!
161  * Sets the current phase offset in radians (0 to 2pi).
162  */
163  void set_phase(float ph);
164 
165  /*!
166  * Gets the current phase of the resampler in radians (2 to 2pi).
167  */
168  float phase() const;
169 
170  /*!
171  * Gets the number of taps per filter.
172  */
173  unsigned int taps_per_filter() const;
174 
175  unsigned int interpolation_rate() const { return d_int_rate; }
176  unsigned int decimation_rate() const { return d_dec_rate; }
177  float fractional_rate() const { return d_flt_rate; }
178 
179  /*!
180  * Get the group delay of the filter.
181  */
182  int group_delay() const { return d_delay; }
183 
184  /*!
185  * Calculates the phase offset expected by a sine wave of
186  * frequency \p freq and sampling rate \p fs (assuming input
187  * sine wave has 0 degree phase).
188  */
189  float phase_offset(float freq, float fs);
190 
191  /*!
192  * Performs the filter operation that resamples the signal.
193  *
194  * This block takes in a stream of samples and outputs a
195  * resampled and filtered stream. This block should be called
196  * such that the output has \p rate * \p n_to_read amount of
197  * space available in the \p output buffer.
198  *
199  * \param output The output samples at the new sample rate.
200  * \param input An input vector of samples to be resampled
201  * \param n_to_read Number of samples to read from \p input.
202  * \param n_read (out) Number of samples actually read from \p input.
203  * \return Number of samples put into \p output.
204  */
205  int filter(gr_complex* output, gr_complex* input, int n_to_read, int& n_read);
206 };
207 
208 
209 /**************************************************************/
210 
211 
213 {
214 private:
215  std::vector<fir_filter_ccc> d_filters;
216  std::vector<fir_filter_ccc> d_diff_filters;
217  std::vector<std::vector<gr_complex>> d_taps;
218  std::vector<std::vector<gr_complex>> d_dtaps;
219  unsigned int d_int_rate; // the number of filters (interpolation rate)
220  unsigned int d_dec_rate; // the stride through the filters (decimation rate)
221  float d_flt_rate; // residual rate for the linear interpolation
222  float d_acc; // accumulator; holds fractional part of sample
223  unsigned int d_last_filter; // stores filter for re-entry
224  unsigned int d_taps_per_filter; // num taps for each arm of the filterbank
225  int d_delay; // filter's group delay
226  float d_est_phase_change; // est. of phase change of a sine wave through filt.
227 
228  /*!
229  * Takes in the taps and convolves them with [-1,0,1], which
230  * creates a differential set of taps that are used in the
231  * difference filterbank.
232  * \param newtaps (vector of complex) The prototype filter.
233  * \param difftaps (vector of complex) (out) The differential filter taps.
234  */
235  void create_diff_taps(const std::vector<gr_complex>& newtaps,
236  std::vector<gr_complex>& difftaps);
237 
238  /*!
239  * Resets the filterbank's filter taps with the new prototype filter
240  * \param newtaps (vector of complex) The prototype filter to populate the
241  * filterbank. The taps should be generated at the interpolated sampling rate. \param
242  * ourtaps (vector of complex) Reference to our internal member of holding the
243  * taps. \param ourfilter (vector of ccc filters) Reference to our internal filter to
244  * set the taps for.
245  */
246  void create_taps(const std::vector<gr_complex>& newtaps,
247  std::vector<std::vector<gr_complex>>& ourtaps,
248  std::vector<kernel::fir_filter_ccc>& ourfilter);
249 
250 public:
251  /*!
252  * Creates a kernel to perform arbitrary resampling on a set of samples.
253  * \param rate (float) Specifies the resampling rate to use
254  * \param taps (vector/list of complex) The prototype filter to populate the
255  * filterbank. The taps * should be generated at the filter_size
256  * sampling rate. \param filter_size (unsigned int) The number of filters in the
257  * filter bank. This is directly related to quantization noise introduced during the
258  * resampling. Defaults to 32 filters.
259  */
261  const std::vector<gr_complex>& taps,
262  unsigned int filter_size);
263 
264  // Don't allow copy.
267 
268  /*!
269  * Resets the filterbank's filter taps with the new prototype filter
270  * \param taps (vector/list of complex) The prototype filter to populate the
271  * filterbank.
272  */
273  void set_taps(const std::vector<gr_complex>& taps);
274 
275  /*!
276  * Return a vector<vector<>> of the filterbank taps
277  */
278  std::vector<std::vector<gr_complex>> taps() const;
279 
280  /*!
281  * Print all of the filterbank taps to screen.
282  */
283  void print_taps();
284 
285  /*!
286  * Sets the resampling rate of the block.
287  */
288  void set_rate(float rate);
289 
290  /*!
291  * Sets the current phase offset in radians (0 to 2pi).
292  */
293  void set_phase(float ph);
294 
295  /*!
296  * Gets the current phase of the resampler in radians (2 to 2pi).
297  */
298  float phase() const;
299 
300  /*!
301  * Gets the number of taps per filter.
302  */
303  unsigned int taps_per_filter() const;
304 
305  unsigned int interpolation_rate() const { return d_int_rate; }
306  unsigned int decimation_rate() const { return d_dec_rate; }
307  float fractional_rate() const { return d_flt_rate; }
308 
309  /*!
310  * Get the group delay of the filter.
311  */
312  int group_delay() const { return d_delay; }
313 
314  /*!
315  * Calculates the phase offset expected by a sine wave of
316  * frequency \p freq and sampling rate \p fs (assuming input
317  * sine wave has 0 degree phase).
318  */
319  float phase_offset(float freq, float fs);
320 
321  /*!
322  * Performs the filter operation that resamples the signal.
323  *
324  * This block takes in a stream of samples and outputs a
325  * resampled and filtered stream. This block should be called
326  * such that the output has \p rate * \p n_to_read amount of
327  * space available in the \p output buffer.
328  *
329  * \param output The output samples at the new sample rate.
330  * \param input An input vector of samples to be resampled
331  * \param n_to_read Number of samples to read from \p input.
332  * \param n_read (out) Number of samples actually read from \p input.
333  * \return Number of samples put into \p output.
334  */
335  int filter(gr_complex* output, gr_complex* input, int n_to_read, int& n_read);
336 };
337 
338 
339 /**************************************************************/
340 
341 
342 /*!
343  * \brief Polyphase filterbank arbitrary resampler with
344  * float input, float output and float taps
345  * \ingroup resamplers_blk
346  *
347  * \details
348  * This takes in a signal stream and performs arbitrary
349  * resampling. The resampling rate can be any real number
350  * <EM>r</EM>. The resampling is done by constructing <EM>N</EM>
351  * filters where <EM>N</EM> is the interpolation rate. We then
352  * calculate <EM>D</EM> where <EM>D = floor(N/r)</EM>.
353  *
354  * Using <EM>N</EM> and <EM>D</EM>, we can perform rational
355  * resampling where <EM>N/D</EM> is a rational number close to
356  * the input rate <EM>r</EM> where we have <EM>N</EM> filters
357  * and we cycle through them as a polyphase filterbank with a
358  * stride of <EM>D</EM> so that <EM>i+1 = (i + D) % N</EM>.
359  *
360  * To get the arbitrary rate, we want to interpolate between two
361  * points. For each value out, we take an output from the
362  * current filter, <EM>i</EM>, and the next filter <EM>i+1</EM>
363  * and then linearly interpolate between the two based on the
364  * real resampling rate we want.
365  *
366  * The linear interpolation only provides us with an
367  * approximation to the real sampling rate specified. The error
368  * is a quantization error between the two filters we used as
369  * our interpolation points. To this end, the number of
370  * filters, <EM>N</EM>, used determines the quantization error;
371  * the larger <EM>N</EM>, the smaller the noise. You can design
372  * for a specified noise floor by setting the filter size
373  * (parameters <EM>filter_size</EM>). The size defaults to 32
374  * filters, which is about as good as most implementations need.
375  *
376  * The trick with designing this filter is in how to specify the
377  * taps of the prototype filter. Like the PFB interpolator, the
378  * taps are specified using the interpolated filter rate. In
379  * this case, that rate is the input sample rate multiplied by
380  * the number of filters in the filterbank, which is also the
381  * interpolation rate. All other values should be relative to
382  * this rate.
383  *
384  * For example, for a 32-filter arbitrary resampler and using
385  * the GNU Radio's firdes utility to build the filter, we build
386  * a low-pass filter with a sampling rate of <EM>fs</EM>, a 3-dB
387  * bandwidth of <EM>BW</EM> and a transition bandwidth of
388  * <EM>TB</EM>. We can also specify the out-of-band attenuation
389  * to use, <EM>ATT</EM>, and the filter window function (a
390  * Blackman-harris window in this case). The first input is the
391  * gain of the filter, which we specify here as the
392  * interpolation rate (<EM>32</EM>).
393  *
394  * <B><EM>self._taps = filter.firdes.low_pass_2(32, 32*fs, BW, TB,
395  * attenuation_dB=ATT, window=fft.window.WIN_BLACKMAN_hARRIS)</EM></B>
396  *
397  * The theory behind this block can be found in Chapter 7.5 of
398  * the following book:
399  *
400  * <B><EM>f. harris, "Multirate Signal Processing for Communication
401  * Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
402  */
404 {
405 private:
406  std::vector<fir_filter_fff> d_filters;
407  std::vector<fir_filter_fff> d_diff_filters;
408  std::vector<std::vector<float>> d_taps;
409  std::vector<std::vector<float>> d_dtaps;
410  unsigned int d_int_rate; // the number of filters (interpolation rate)
411  unsigned int d_dec_rate; // the stride through the filters (decimation rate)
412  float d_flt_rate; // residual rate for the linear interpolation
413  float d_acc; // accumulator; holds fractional part of sample
414  unsigned int d_last_filter; // stores filter for re-entry
415  unsigned int d_taps_per_filter; // num taps for each arm of the filterbank
416  int d_delay; // filter's group delay
417  float d_est_phase_change; // est. of phase change of a sine wave through filt.
418 
419  /*!
420  * Takes in the taps and convolves them with [-1,0,1], which
421  * creates a differential set of taps that are used in the
422  * difference filterbank.
423  * \param newtaps (vector of floats) The prototype filter.
424  * \param difftaps (vector of floats) (out) The differential filter taps.
425  */
426  void create_diff_taps(const std::vector<float>& newtaps,
427  std::vector<float>& difftaps);
428 
429  /*!
430  * Resets the filterbank's filter taps with the new prototype filter
431  * \param newtaps (vector of floats) The prototype filter to populate the
432  * filterbank. The taps should be generated at the interpolated sampling rate. \param
433  * ourtaps (vector of floats) Reference to our internal member of holding the taps.
434  * \param ourfilter (vector of filters) Reference to our internal filter to set the
435  * taps for.
436  */
437  void create_taps(const std::vector<float>& newtaps,
438  std::vector<std::vector<float>>& ourtaps,
439  std::vector<kernel::fir_filter_fff>& ourfilter);
440 
441 public:
442  /*!
443  * Creates a kernel to perform arbitrary resampling on a set of samples.
444  * \param rate (float) Specifies the resampling rate to use
445  * \param taps (vector/list of floats) The prototype filter to populate the
446  * filterbank. The taps * should be generated at the filter_size
447  * sampling rate. \param filter_size (unsigned int) The number of filters in the
448  * filter bank. This is directly related to quantization noise introduced during the
449  * resampling. Defaults to 32 filters.
450  */
452  const std::vector<float>& taps,
453  unsigned int filter_size);
454 
455  // Don't allow copy.
458 
459 
460  /*!
461  * Resets the filterbank's filter taps with the new prototype filter
462  * \param taps (vector/list of floats) The prototype filter to populate the
463  * filterbank.
464  */
465  void set_taps(const std::vector<float>& taps);
466 
467  /*!
468  * Return a vector<vector<>> of the filterbank taps
469  */
470  std::vector<std::vector<float>> taps() const;
471 
472  /*!
473  * Print all of the filterbank taps to screen.
474  */
475  void print_taps();
476 
477  /*!
478  * Sets the resampling rate of the block.
479  */
480  void set_rate(float rate);
481 
482  /*!
483  * Sets the current phase offset in radians (0 to 2pi).
484  */
485  void set_phase(float ph);
486 
487  /*!
488  * Gets the current phase of the resampler in radians (2 to 2pi).
489  */
490  float phase() const;
491 
492  /*!
493  * Gets the number of taps per filter.
494  */
495  unsigned int taps_per_filter() const;
496 
497  unsigned int interpolation_rate() const { return d_int_rate; }
498  unsigned int decimation_rate() const { return d_dec_rate; }
499  float fractional_rate() const { return d_flt_rate; }
500 
501  /*!
502  * Get the group delay of the filter.
503  */
504  int group_delay() const { return d_delay; }
505 
506  /*!
507  * Calculates the phase offset expected by a sine wave of
508  * frequency \p freq and sampling rate \p fs (assuming input
509  * sine wave has 0 degree phase).
510  */
511  float phase_offset(float freq, float fs);
512 
513  /*!
514  * Performs the filter operation that resamples the signal.
515  *
516  * This block takes in a stream of samples and outputs a
517  * resampled and filtered stream. This block should be called
518  * such that the output has \p rate * \p n_to_read amount of
519  * space available in the \p output buffer.
520  *
521  * \param output The output samples at the new sample rate.
522  * \param input An input vector of samples to be resampled
523  * \param n_to_read Number of samples to read from \p input.
524  * \param n_read (out) Number of samples actually read from \p input.
525  * \return Number of samples put into \p output.
526  */
527  int filter(float* output, float* input, int n_to_read, int& n_read);
528 };
529 
530 } /* namespace kernel */
531 } /* namespace filter */
532 } /* namespace gr */
533 
534 #endif /* INCLUDED_PFB_ARB_RESAMPLER_H */
Definition: pfb_arb_resampler.h:213
pfb_arb_resampler_ccc & operator=(const pfb_arb_resampler_ccc &)=delete
pfb_arb_resampler_ccc(const pfb_arb_resampler_ccc &)=delete
int group_delay() const
Definition: pfb_arb_resampler.h:312
unsigned int interpolation_rate() const
Definition: pfb_arb_resampler.h:305
int filter(gr_complex *output, gr_complex *input, int n_to_read, int &n_read)
unsigned int decimation_rate() const
Definition: pfb_arb_resampler.h:306
float fractional_rate() const
Definition: pfb_arb_resampler.h:307
void set_taps(const std::vector< gr_complex > &taps)
float phase_offset(float freq, float fs)
pfb_arb_resampler_ccc(float rate, const std::vector< gr_complex > &taps, unsigned int filter_size)
std::vector< std::vector< gr_complex > > taps() const
Polyphase filterbank arbitrary resampler with gr_complex input, gr_complex output and float taps.
Definition: pfb_arb_resampler.h:83
int filter(gr_complex *output, gr_complex *input, int n_to_read, int &n_read)
void set_taps(const std::vector< float > &taps)
pfb_arb_resampler_ccf(float rate, const std::vector< float > &taps, unsigned int filter_size)
pfb_arb_resampler_ccf & operator=(const pfb_arb_resampler_ccf &)=delete
unsigned int decimation_rate() const
Definition: pfb_arb_resampler.h:176
float fractional_rate() const
Definition: pfb_arb_resampler.h:177
int group_delay() const
Definition: pfb_arb_resampler.h:182
unsigned int interpolation_rate() const
Definition: pfb_arb_resampler.h:175
pfb_arb_resampler_ccf(const pfb_arb_resampler_ccf &)=delete
std::vector< std::vector< float > > taps() const
float phase_offset(float freq, float fs)
Polyphase filterbank arbitrary resampler with float input, float output and float taps.
Definition: pfb_arb_resampler.h:404
unsigned int decimation_rate() const
Definition: pfb_arb_resampler.h:498
pfb_arb_resampler_fff & operator=(const pfb_arb_resampler_fff &)=delete
pfb_arb_resampler_fff(float rate, const std::vector< float > &taps, unsigned int filter_size)
std::vector< std::vector< float > > taps() const
void set_taps(const std::vector< float > &taps)
pfb_arb_resampler_fff(const pfb_arb_resampler_fff &)=delete
float phase_offset(float freq, float fs)
float fractional_rate() const
Definition: pfb_arb_resampler.h:499
int filter(float *output, float *input, int n_to_read, int &n_read)
int group_delay() const
Definition: pfb_arb_resampler.h:504
unsigned int interpolation_rate() const
Definition: pfb_arb_resampler.h:497
#define FILTER_API
Definition: gr-filter/include/gnuradio/filter/api.h:18
std::complex< float > gr_complex
Definition: gr_complex.h:15
static constexpr float taps[NSTEPS+1][NTAPS]
Definition: interpolator_taps.h:9
GNU Radio logging wrapper.
Definition: basic_block.h:29