GNU Radio 3.7.1 C++ API
pfb_arb_resampler.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /*
00003  * Copyright 2013 Free Software Foundation, Inc.
00004  *
00005  * This file is part of GNU Radio
00006  *
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3, or (at your option)
00010  * any later version.
00011  *
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with GNU Radio; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 51 Franklin Street,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022 
00023 
00024 #ifndef INCLUDED_PFB_ARB_RESAMPLER_H
00025 #define INCLUDED_PFB_ARB_RESAMPLER_H
00026 
00027 #include <gnuradio/filter/fir_filter.h>
00028 
00029 namespace gr {
00030   namespace filter {
00031     namespace kernel {
00032 
00033       /*!
00034        * \brief Polyphase filterbank arbitrary resampler with
00035        *        gr_complex input, gr_complex output and float taps
00036        * \ingroup resamplers_blk
00037        *
00038        * \details
00039        * This  takes in a signal stream and performs arbitrary
00040        * resampling. The resampling rate can be any real number
00041        * <EM>r</EM>. The resampling is done by constructing <EM>N</EM>
00042        * filters where <EM>N</EM> is the interpolation rate.  We then
00043        * calculate <EM>D</EM> where <EM>D = floor(N/r)</EM>.
00044        *
00045        * Using <EM>N</EM> and <EM>D</EM>, we can perform rational
00046        * resampling where <EM>N/D</EM> is a rational number close to
00047        * the input rate <EM>r</EM> where we have <EM>N</EM> filters
00048        * and we cycle through them as a polyphase filterbank with a
00049        * stride of <EM>D</EM> so that <EM>i+1 = (i + D) % N</EM>.
00050        *
00051        * To get the arbitrary rate, we want to interpolate between two
00052        * points. For each value out, we take an output from the
00053        * current filter, <EM>i</EM>, and the next filter <EM>i+1</EM>
00054        * and then linearly interpolate between the two based on the
00055        * real resampling rate we want.
00056        *
00057        * The linear interpolation only provides us with an
00058        * approximation to the real sampling rate specified. The error
00059        * is a quantization error between the two filters we used as
00060        * our interpolation points.  To this end, the number of
00061        * filters, <EM>N</EM>, used determines the quantization error;
00062        * the larger <EM>N</EM>, the smaller the noise. You can design
00063        * for a specified noise floor by setting the filter size
00064        * (parameters <EM>filter_size</EM>). The size defaults to 32
00065        * filters, which is about as good as most implementations need.
00066        *
00067        * The trick with designing this filter is in how to specify the
00068        * taps of the prototype filter. Like the PFB interpolator, the
00069        * taps are specified using the interpolated filter rate. In
00070        * this case, that rate is the input sample rate multiplied by
00071        * the number of filters in the filterbank, which is also the
00072        * interpolation rate. All other values should be relative to
00073        * this rate.
00074        *
00075        * For example, for a 32-filter arbitrary resampler and using
00076        * the GNU Radio's firdes utility to build the filter, we build
00077        * a low-pass filter with a sampling rate of <EM>fs</EM>, a 3-dB
00078        * bandwidth of <EM>BW</EM> and a transition bandwidth of
00079        * <EM>TB</EM>. We can also specify the out-of-band attenuation
00080        * to use, <EM>ATT</EM>, and the filter window function (a
00081        * Blackman-harris window in this case). The first input is the
00082        * gain of the filter, which we specify here as the
00083        * interpolation rate (<EM>32</EM>).
00084        *
00085        *   <B><EM>self._taps = filter.firdes.low_pass_2(32, 32*fs, BW, TB,
00086        *      attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B>
00087        *
00088        * The theory behind this block can be found in Chapter 7.5 of
00089        * the following book.
00090        *
00091        *   <B><EM>f. harris, "Multirate Signal Processing for Communication
00092        *      Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
00093        */
00094       class FILTER_API pfb_arb_resampler_ccf
00095       {
00096       private:
00097         std::vector<fir_filter_ccf*> d_filters;
00098         std::vector<fir_filter_ccf*> d_diff_filters;
00099         std::vector< std::vector<float> > d_taps;
00100         std::vector< std::vector<float> > d_dtaps;
00101         unsigned int d_int_rate;          // the number of filters (interpolation rate)
00102         unsigned int d_dec_rate;          // the stride through the filters (decimation rate)
00103         float        d_flt_rate;          // residual rate for the linear interpolation
00104         float        d_acc;               // accumulator; holds fractional part of sample
00105         unsigned int d_last_filter;       // stores filter for re-entry
00106         unsigned int d_taps_per_filter;   // num taps for each arm of the filterbank
00107         int d_delay;                      // filter's group delay
00108         float d_est_phase_change;         // est. of phase change of a sine wave through filt.
00109 
00110         /*!
00111          * Takes in the taps and convolves them with [-1,0,1], which
00112          * creates a differential set of taps that are used in the
00113          * difference filterbank.
00114          * \param newtaps (vector of floats) The prototype filter.
00115          * \param difftaps (vector of floats) (out) The differential filter taps.
00116          */
00117         void create_diff_taps(const std::vector<float> &newtaps,
00118                               std::vector<float> &difftaps);
00119 
00120         /*!
00121          * Resets the filterbank's filter taps with the new prototype filter
00122          * \param newtaps    (vector of floats) The prototype filter to populate the filterbank.
00123          *                   The taps should be generated at the interpolated sampling rate.
00124          * \param ourtaps    (vector of floats) Reference to our internal member of holding the taps.
00125          * \param ourfilter  (vector of filters) Reference to our internal filter to set the taps for.
00126          */
00127         void create_taps(const std::vector<float> &newtaps,
00128                          std::vector< std::vector<float> > &ourtaps,
00129                          std::vector<kernel::fir_filter_ccf*> &ourfilter);
00130 
00131       public:
00132         /*!
00133          * Creates a kernel to perform arbitrary resampling on a set of samples.
00134          * \param rate  (float) Specifies the resampling rate to use
00135          * \param taps  (vector/list of floats) The prototype filter to populate the filterbank. The taps       *              should be generated at the filter_size sampling rate.
00136          * \param filter_size (unsigned int) The number of filters in the filter bank. This is directly
00137          *                    related to quantization noise introduced during the resampling.
00138          *                    Defaults to 32 filters.
00139          */
00140         pfb_arb_resampler_ccf(float rate,
00141                               const std::vector<float> &taps,
00142                               unsigned int filter_size);
00143 
00144         ~pfb_arb_resampler_ccf();
00145 
00146         /*!
00147          * Resets the filterbank's filter taps with the new prototype filter
00148          * \param taps (vector/list of floats) The prototype filter to populate the filterbank.
00149          */
00150         void set_taps(const std::vector<float> &taps);
00151 
00152         /*!
00153          * Return a vector<vector<>> of the filterbank taps
00154          */
00155         std::vector<std::vector<float> > taps() const;
00156 
00157         /*!
00158          * Print all of the filterbank taps to screen.
00159          */
00160         void print_taps();
00161 
00162         /*!
00163          * Sets the resampling rate of the block.
00164          */
00165         void set_rate(float rate);
00166 
00167         /*!
00168          * Sets the current phase offset in radians (0 to 2pi).
00169          */
00170         void set_phase(float ph);
00171 
00172         /*!
00173          * Gets the current phase of the resampler in radians (2 to 2pi).
00174          */
00175         float phase() const;
00176 
00177         /*!
00178          * Gets the number of taps per filter.
00179          */
00180         unsigned int taps_per_filter() const;
00181 
00182         unsigned int interpolation_rate() const { return d_int_rate; }
00183         unsigned int decimation_rate() const { return d_dec_rate; }
00184         float fractional_rate() const { return d_flt_rate; }
00185 
00186         /*!
00187          * Get the group delay of the filter.
00188          */
00189         int group_delay() const { return d_delay; }
00190 
00191         /*!
00192          * Calculates the phase offset expected by a sine wave of
00193          * frequency \p freq and sampling rate \p fs (assuming input
00194          * sine wave has 0 degree phase).
00195          */
00196         float phase_offset(float freq, float fs);
00197 
00198         /*!
00199          * Performs the filter operation that resamples the signal.
00200          *
00201          * This block takes in a stream of samples and outputs a
00202          * resampled and filtered stream. This block should be called
00203          * such that the output has \p rate * \p n_to_read amount of
00204          * space available in the \p output buffer.
00205          *
00206          * \param input An input vector of samples to be resampled
00207          * \param output The output samples at the new sample rate.
00208          * \param n_to_read Number of samples to read from \p input.
00209          * \param n_read (out) Number of samples actually read from \p input.
00210          * \return Number of samples put into \p output.
00211          */
00212         int filter(gr_complex *input, gr_complex *output,
00213                    int n_to_read, int &n_read);
00214       };
00215 
00216 
00217       /**************************************************************/
00218 
00219 
00220       /*!
00221        * \brief Polyphase filterbank arbitrary resampler with
00222        *        float input, float output and float taps
00223        * \ingroup resamplers_blk
00224        *
00225        * \details
00226        * This  takes in a signal stream and performs arbitrary
00227        * resampling. The resampling rate can be any real number
00228        * <EM>r</EM>. The resampling is done by constructing <EM>N</EM>
00229        * filters where <EM>N</EM> is the interpolation rate.  We then
00230        * calculate <EM>D</EM> where <EM>D = floor(N/r)</EM>.
00231        *
00232        * Using <EM>N</EM> and <EM>D</EM>, we can perform rational
00233        * resampling where <EM>N/D</EM> is a rational number close to
00234        * the input rate <EM>r</EM> where we have <EM>N</EM> filters
00235        * and we cycle through them as a polyphase filterbank with a
00236        * stride of <EM>D</EM> so that <EM>i+1 = (i + D) % N</EM>.
00237        *
00238        * To get the arbitrary rate, we want to interpolate between two
00239        * points. For each value out, we take an output from the
00240        * current filter, <EM>i</EM>, and the next filter <EM>i+1</EM>
00241        * and then linearly interpolate between the two based on the
00242        * real resampling rate we want.
00243        *
00244        * The linear interpolation only provides us with an
00245        * approximation to the real sampling rate specified. The error
00246        * is a quantization error between the two filters we used as
00247        * our interpolation points.  To this end, the number of
00248        * filters, <EM>N</EM>, used determines the quantization error;
00249        * the larger <EM>N</EM>, the smaller the noise. You can design
00250        * for a specified noise floor by setting the filter size
00251        * (parameters <EM>filter_size</EM>). The size defaults to 32
00252        * filters, which is about as good as most implementations need.
00253        *
00254        * The trick with designing this filter is in how to specify the
00255        * taps of the prototype filter. Like the PFB interpolator, the
00256        * taps are specified using the interpolated filter rate. In
00257        * this case, that rate is the input sample rate multiplied by
00258        * the number of filters in the filterbank, which is also the
00259        * interpolation rate. All other values should be relative to
00260        * this rate.
00261        *
00262        * For example, for a 32-filter arbitrary resampler and using
00263        * the GNU Radio's firdes utility to build the filter, we build
00264        * a low-pass filter with a sampling rate of <EM>fs</EM>, a 3-dB
00265        * bandwidth of <EM>BW</EM> and a transition bandwidth of
00266        * <EM>TB</EM>. We can also specify the out-of-band attenuation
00267        * to use, <EM>ATT</EM>, and the filter window function (a
00268        * Blackman-harris window in this case). The first input is the
00269        * gain of the filter, which we specify here as the
00270        * interpolation rate (<EM>32</EM>).
00271        *
00272        *   <B><EM>self._taps = filter.firdes.low_pass_2(32, 32*fs, BW, TB,
00273        *      attenuation_dB=ATT, window=filter.firdes.WIN_BLACKMAN_hARRIS)</EM></B>
00274        *
00275        * The theory behind this block can be found in Chapter 7.5 of
00276        * the following book.
00277        *
00278        *   <B><EM>f. harris, "Multirate Signal Processing for Communication
00279        *      Systems", Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
00280        */
00281       class FILTER_API pfb_arb_resampler_fff
00282       {
00283       private:
00284         std::vector<fir_filter_fff*> d_filters;
00285         std::vector<fir_filter_fff*> d_diff_filters;
00286         std::vector< std::vector<float> > d_taps;
00287         std::vector< std::vector<float> > d_dtaps;
00288         unsigned int d_int_rate;          // the number of filters (interpolation rate)
00289         unsigned int d_dec_rate;          // the stride through the filters (decimation rate)
00290         float        d_flt_rate;          // residual rate for the linear interpolation
00291         float        d_acc;               // accumulator; holds fractional part of sample
00292         unsigned int d_last_filter;       // stores filter for re-entry
00293         unsigned int d_taps_per_filter;   // num taps for each arm of the filterbank
00294         int d_delay;                      // filter's group delay
00295         float d_est_phase_change;         // est. of phase change of a sine wave through filt.
00296 
00297         /*!
00298          * Takes in the taps and convolves them with [-1,0,1], which
00299          * creates a differential set of taps that are used in the
00300          * difference filterbank.
00301          * \param newtaps (vector of floats) The prototype filter.
00302          * \param difftaps (vector of floats) (out) The differential filter taps.
00303          */
00304         void create_diff_taps(const std::vector<float> &newtaps,
00305                               std::vector<float> &difftaps);
00306 
00307         /*!
00308          * Resets the filterbank's filter taps with the new prototype filter
00309          * \param newtaps    (vector of floats) The prototype filter to populate the filterbank.
00310          *                   The taps should be generated at the interpolated sampling rate.
00311          * \param ourtaps    (vector of floats) Reference to our internal member of holding the taps.
00312          * \param ourfilter  (vector of filters) Reference to our internal filter to set the taps for.
00313          */
00314         void create_taps(const std::vector<float> &newtaps,
00315                          std::vector< std::vector<float> > &ourtaps,
00316                          std::vector<kernel::fir_filter_fff*> &ourfilter);
00317 
00318       public:
00319         /*!
00320          * Creates a kernel to perform arbitrary resampling on a set of samples.
00321          * \param rate  (float) Specifies the resampling rate to use
00322          * \param taps  (vector/list of floats) The prototype filter to populate the filterbank. The taps       *              should be generated at the filter_size sampling rate.
00323          * \param filter_size (unsigned int) The number of filters in the filter bank. This is directly
00324          *                    related to quantization noise introduced during the resampling.
00325          *                    Defaults to 32 filters.
00326          */
00327         pfb_arb_resampler_fff(float rate,
00328                               const std::vector<float> &taps,
00329                               unsigned int filter_size);
00330 
00331         ~pfb_arb_resampler_fff();
00332 
00333         /*!
00334          * Resets the filterbank's filter taps with the new prototype filter
00335          * \param taps (vector/list of floats) The prototype filter to populate the filterbank.
00336          */
00337         void set_taps(const std::vector<float> &taps);
00338 
00339         /*!
00340          * Return a vector<vector<>> of the filterbank taps
00341          */
00342         std::vector<std::vector<float> > taps() const;
00343 
00344         /*!
00345          * Print all of the filterbank taps to screen.
00346          */
00347         void print_taps();
00348 
00349         /*!
00350          * Sets the resampling rate of the block.
00351          */
00352         void set_rate(float rate);
00353 
00354         /*!
00355          * Sets the current phase offset in radians (0 to 2pi).
00356          */
00357         void set_phase(float ph);
00358 
00359         /*!
00360          * Gets the current phase of the resampler in radians (2 to 2pi).
00361          */
00362         float phase() const;
00363 
00364         /*!
00365          * Gets the number of taps per filter.
00366          */
00367         unsigned int taps_per_filter() const;
00368 
00369         unsigned int interpolation_rate() const { return d_int_rate; }
00370         unsigned int decimation_rate() const { return d_dec_rate; }
00371         float fractional_rate() const { return d_flt_rate; }
00372 
00373         /*!
00374          * Get the group delay of the filter.
00375          */
00376         int group_delay() const { return d_delay; }
00377 
00378         /*!
00379          * Calculates the phase offset expected by a sine wave of
00380          * frequency \p freq and sampling rate \p fs (assuming input
00381          * sine wave has 0 degree phase).
00382          */
00383         float phase_offset(float freq, float fs);
00384 
00385         /*!
00386          * Performs the filter operation that resamples the signal.
00387          *
00388          * This block takes in a stream of samples and outputs a
00389          * resampled and filtered stream. This block should be called
00390          * such that the output has \p rate * \p n_to_read amount of
00391          * space available in the \p output buffer.
00392          *
00393          * \param input An input vector of samples to be resampled
00394          * \param output The output samples at the new sample rate.
00395          * \param n_to_read Number of samples to read from \p input.
00396          * \param n_read (out) Number of samples actually read from \p input.
00397          * \return Number of samples put into \p output.
00398          */
00399         int filter(float *input, float *output,
00400                    int n_to_read, int &n_read);
00401       };
00402 
00403     } /* namespace kernel */
00404   } /* namespace filter */
00405 } /* namespace gr */
00406 
00407 #endif /* INCLUDED_PFB_ARB_RESAMPLER_H */