commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 06/10: filter: added a ccc version of the p


From: git
Subject: [Commit-gnuradio] [gnuradio] 06/10: filter: added a ccc version of the pfb_arb_resampler block.
Date: Tue, 11 Feb 2014 21:11:22 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

trondeau pushed a commit to branch master
in repository gnuradio.

commit f80ed7a1ce2396e954d42a47e80a57d8975fcc3a
Author: Tom Rondeau <address@hidden>
Date:   Tue Feb 11 14:08:26 2014 -0500

    filter: added a ccc version of the pfb_arb_resampler block.
---
 gr-filter/grc/filter_pfb_arb_resampler.xml         |   7 +
 gr-filter/include/gnuradio/filter/CMakeLists.txt   |   3 +-
 .../include/gnuradio/filter/pfb_arb_resampler.h    | 126 +++++++++++
 .../gnuradio/filter/pfb_arb_resampler_ccc.h        | 132 ++++++++++++
 gr-filter/lib/CMakeLists.txt                       |  11 +-
 gr-filter/lib/pfb_arb_resampler.cc                 | 231 ++++++++++++++++++++-
 gr-filter/lib/pfb_arb_resampler_ccc_impl.cc        | 183 ++++++++++++++++
 gr-filter/lib/pfb_arb_resampler_ccc_impl.h         |  75 +++++++
 gr-filter/python/filter/pfb.py                     |  83 ++++++--
 gr-filter/python/filter/qa_pfb_arb_resampler.py    |  80 ++++++-
 gr-filter/swig/filter_swig.i                       |   3 +
 11 files changed, 900 insertions(+), 34 deletions(-)

diff --git a/gr-filter/grc/filter_pfb_arb_resampler.xml 
b/gr-filter/grc/filter_pfb_arb_resampler.xml
index e163874..7bceeac 100644
--- a/gr-filter/grc/filter_pfb_arb_resampler.xml
+++ b/gr-filter/grc/filter_pfb_arb_resampler.xml
@@ -38,6 +38,13 @@
                        <opt>output:float</opt>
                        <opt>taps:real_vector</opt>
                </option>
+               <option>
+                       <name>Complex->Complex (Complex Taps)</name>
+                       <key>ccc</key>
+                       <opt>input:complex</opt>
+                       <opt>output:complex</opt>
+                       <opt>taps:complex_vector</opt>
+               </option>
        </param>
        <param>
                <name>Resampling Rate</name>
diff --git a/gr-filter/include/gnuradio/filter/CMakeLists.txt 
b/gr-filter/include/gnuradio/filter/CMakeLists.txt
index 3135688..d039af9 100644
--- a/gr-filter/include/gnuradio/filter/CMakeLists.txt
+++ b/gr-filter/include/gnuradio/filter/CMakeLists.txt
@@ -47,7 +47,7 @@ macro(expand_h root)
     string(REGEX REPLACE "X+" ${sig} name ${root})
     list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
   endforeach(sig)
-  
+
   #create a command to generate the files
   add_custom_command(
     OUTPUT ${expanded_files_h}
@@ -103,6 +103,7 @@ install(FILES
     iir_filter_ffd.h
     pfb_arb_resampler.h
     pfb_arb_resampler_ccf.h
+    pfb_arb_resampler_ccc.h
     pfb_arb_resampler_fff.h
     pfb_channelizer_ccf.h
     pfb_decimator_ccf.h
diff --git a/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h 
b/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h
index 47f55ad..9ced0b3 100644
--- a/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h
+++ b/gr-filter/include/gnuradio/filter/pfb_arb_resampler.h
@@ -217,6 +217,132 @@ namespace gr {
       /**************************************************************/
 
 
+      class FILTER_API pfb_arb_resampler_ccc
+      {
+      private:
+        std::vector<fir_filter_ccc*> d_filters;
+        std::vector<fir_filter_ccc*> d_diff_filters;
+        std::vector< std::vector<gr_complex> > d_taps;
+        std::vector< std::vector<gr_complex> > d_dtaps;
+        unsigned int d_int_rate;          // the number of filters 
(interpolation rate)
+        unsigned int d_dec_rate;          // the stride through the filters 
(decimation rate)
+        float        d_flt_rate;          // residual rate for the linear 
interpolation
+        float        d_acc;               // accumulator; holds fractional 
part of sample
+        unsigned int d_last_filter;       // stores filter for re-entry
+        unsigned int d_taps_per_filter;   // num taps for each arm of the 
filterbank
+        int d_delay;                      // filter's group delay
+        float d_est_phase_change;         // est. of phase change of a sine 
wave through filt.
+
+        /*!
+         * Takes in the taps and convolves them with [-1,0,1], which
+         * creates a differential set of taps that are used in the
+         * difference filterbank.
+         * \param newtaps (vector of complex) The prototype filter.
+         * \param difftaps (vector of complex) (out) The differential filter 
taps.
+         */
+        void create_diff_taps(const std::vector<gr_complex> &newtaps,
+                              std::vector<gr_complex> &difftaps);
+
+        /*!
+         * Resets the filterbank's filter taps with the new prototype filter
+         * \param newtaps    (vector of complex) The prototype filter to 
populate the filterbank.
+         *                   The taps should be generated at the interpolated 
sampling rate.
+         * \param ourtaps    (vector of complex) Reference to our internal 
member of holding the taps.
+         * \param ourfilter  (vector of ccc filters) Reference to our internal 
filter to set the taps for.
+         */
+        void create_taps(const std::vector<gr_complex> &newtaps,
+                         std::vector< std::vector<gr_complex> > &ourtaps,
+                         std::vector<kernel::fir_filter_ccc*> &ourfilter);
+
+      public:
+        /*!
+         * Creates a kernel to perform arbitrary resampling on a set of 
samples.
+         * \param rate  (float) Specifies the resampling rate to use
+         * \param taps  (vector/list of complex) The prototype filter to 
populate the filterbank. The taps       *              should be generated at 
the filter_size sampling rate.
+         * \param filter_size (unsigned int) The number of filters in the 
filter bank. This is directly
+         *                    related to quantization noise introduced during 
the resampling.
+         *                    Defaults to 32 filters.
+         */
+        pfb_arb_resampler_ccc(float rate,
+                              const std::vector<gr_complex> &taps,
+                              unsigned int filter_size);
+
+        ~pfb_arb_resampler_ccc();
+
+        /*!
+         * Resets the filterbank's filter taps with the new prototype filter
+         * \param taps (vector/list of complex) The prototype filter to 
populate the filterbank.
+         */
+        void set_taps(const std::vector<gr_complex> &taps);
+
+        /*!
+         * Return a vector<vector<>> of the filterbank taps
+         */
+        std::vector<std::vector<gr_complex> > taps() const;
+
+        /*!
+         * Print all of the filterbank taps to screen.
+         */
+        void print_taps();
+
+        /*!
+         * Sets the resampling rate of the block.
+         */
+        void set_rate(float rate);
+
+        /*!
+         * Sets the current phase offset in radians (0 to 2pi).
+         */
+        void set_phase(float ph);
+
+        /*!
+         * Gets the current phase of the resampler in radians (2 to 2pi).
+         */
+        float phase() const;
+
+        /*!
+         * Gets the number of taps per filter.
+         */
+        unsigned int taps_per_filter() const;
+
+        unsigned int interpolation_rate() const { return d_int_rate; }
+        unsigned int decimation_rate() const { return d_dec_rate; }
+        float fractional_rate() const { return d_flt_rate; }
+
+        /*!
+         * Get the group delay of the filter.
+         */
+        int group_delay() const { return d_delay; }
+
+        /*!
+         * Calculates the phase offset expected by a sine wave of
+         * frequency \p freq and sampling rate \p fs (assuming input
+         * sine wave has 0 degree phase).
+         */
+        float phase_offset(float freq, float fs);
+
+        /*!
+         * Performs the filter operation that resamples the signal.
+         *
+         * This block takes in a stream of samples and outputs a
+         * resampled and filtered stream. This block should be called
+         * such that the output has \p rate * \p n_to_read amount of
+         * space available in the \p output buffer.
+         *
+         * \param input An input vector of samples to be resampled
+         * \param output The output samples at the new sample rate.
+         * \param n_to_read Number of samples to read from \p input.
+         * \param n_read (out) Number of samples actually read from \p input.
+         * \return Number of samples put into \p output.
+         */
+        int filter(gr_complex *input, gr_complex *output,
+                   int n_to_read, int &n_read);
+      };
+
+
+      /**************************************************************/
+
+
       /*!
        * \brief Polyphase filterbank arbitrary resampler with
        *        float input, float output and float taps
diff --git a/gr-filter/include/gnuradio/filter/pfb_arb_resampler_ccc.h 
b/gr-filter/include/gnuradio/filter/pfb_arb_resampler_ccc.h
new file mode 100644
index 0000000..c473846
--- /dev/null
+++ b/gr-filter/include/gnuradio/filter/pfb_arb_resampler_ccc.h
@@ -0,0 +1,132 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef INCLUDED_PFB_ARB_RESAMPLER_CCC_H
+#define        INCLUDED_PFB_ARB_RESAMPLER_CCC_H
+
+#include <gnuradio/filter/api.h>
+#include <gnuradio/block.h>
+
+namespace gr {
+  namespace filter {
+
+    /*!
+     * \brief Polyphase filterbank arbitrary resampler with
+     *        gr_complex input, gr_complex output and gr_complex taps
+     * \ingroup resamplers_blk
+     *
+     * \details
+
+     * This block takes in a signal stream and calls
+     * gr::filter::kernel::pfb_arb_resampler_ccc to perform
+     * arbitrary resampling on the stream.
+     *
+     * Output sampling rate is \p rate * input rate.
+     */
+    class FILTER_API pfb_arb_resampler_ccc : virtual public block
+    {
+    public:
+      // gr::filter::pfb_arb_resampler_ccc::sptr
+      typedef boost::shared_ptr<pfb_arb_resampler_ccc> sptr;
+
+      /*!
+       * Build the polyphase filterbank arbitray resampler.
+       * \param rate  (float) Specifies the resampling rate to use
+       * \param taps  (vector/list of complex) The prototype filter to 
populate the filterbank. The taps
+       *              should be generated at the filter_size sampling rate.
+       * \param filter_size (unsigned int) The number of filters in the filter 
bank. This is directly
+       *                    related to quantization noise introduced during 
the resampling.
+       *                    Defaults to 32 filters.
+       */
+      static sptr make(float rate,
+                       const std::vector<gr_complex> &taps,
+                       unsigned int filter_size=32);
+
+      /*!
+       * Resets the filterbank's filter taps with the new prototype filter
+       * \param taps    (vector/list of complex) The prototype filter to 
populate the filterbank.
+       */
+      virtual void set_taps(const std::vector<gr_complex> &taps) = 0;
+
+      /*!
+       * Return a vector<vector<>> of the filterbank taps
+       */
+      virtual std::vector<std::vector<gr_complex> > taps() const = 0;
+
+      /*!
+       * Print all of the filterbank taps to screen.
+       */
+      virtual void print_taps() = 0;
+
+      /*!
+       * Sets the resampling rate of the block.
+       */
+      virtual void set_rate (float rate) = 0;
+
+      /*!
+       * Sets the current phase offset in radians (0 to 2pi).
+       */
+      virtual void set_phase(float ph) = 0;
+
+      /*!
+       * Gets the current phase of the resampler in radians (2 to 2pi).
+       */
+      virtual float phase() const = 0;
+
+      /*!
+       * Gets the number of taps per filter.
+       */
+      virtual unsigned int taps_per_filter() const = 0;
+
+      /*!
+       * Gets the interpolation rate of the filter.
+       */
+      virtual unsigned int interpolation_rate() const = 0;
+
+      /*!
+       * Gets the decimation rate of the filter.
+       */
+      virtual unsigned int decimation_rate() const =0;
+
+      /*!
+       * Gets the fractional rate of the filter.
+       */
+      virtual float fractional_rate() const = 0;
+
+      /*!
+       * Get the group delay of the filter.
+       */
+      virtual int group_delay() const = 0;
+
+      /*!
+       * Calculates the phase offset expected by a sine wave of
+       * frequency \p freq and sampling rate \p fs (assuming input
+       * sine wave has 0 degree phase).
+       */
+      virtual float phase_offset(float freq, float fs) = 0;
+    };
+
+  } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_PFB_ARB_RESAMPLER_CCC_H */
diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt
index 58000bb..9f17092 100644
--- a/gr-filter/lib/CMakeLists.txt
+++ b/gr-filter/lib/CMakeLists.txt
@@ -48,7 +48,7 @@ macro(expand_cc root)
     list(APPEND expanded_files_cc ${CMAKE_CURRENT_BINARY_DIR}/${name}.cc)
     list(APPEND expanded_files_h  ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
   endforeach(sig)
-  
+
   #create a command to generate the source files
   add_custom_command(
     OUTPUT ${expanded_files_cc}
@@ -66,15 +66,15 @@ macro(expand_cc root)
     ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
     ${root} ${root}.h.t ${ARGN}
   )
-  
+
   #make source files depends on headers to force generation
   set_source_files_properties(${expanded_files_cc}
     PROPERTIES OBJECT_DEPENDS "${expanded_files_h}"
   )
-  
+
   #install rules for the generated cc files
-  list(APPEND generated_sources ${expanded_files_cc})  
-  list(APPEND generated_headers ${expanded_files_h})  
+  list(APPEND generated_sources ${expanded_files_cc})
+  list(APPEND generated_headers ${expanded_files_h})
 endmacro(expand_cc)
 
 ########################################################################
@@ -137,6 +137,7 @@ list(APPEND filter_sources
   iir_filter_ffd_impl.cc
   pfb_arb_resampler.cc
   pfb_arb_resampler_ccf_impl.cc
+  pfb_arb_resampler_ccc_impl.cc
   pfb_arb_resampler_fff_impl.cc
   pfb_channelizer_ccf_impl.cc
   pfb_decimator_ccf_impl.cc
diff --git a/gr-filter/lib/pfb_arb_resampler.cc 
b/gr-filter/lib/pfb_arb_resampler.cc
index 541f1a9..0ebc788 100644
--- a/gr-filter/lib/pfb_arb_resampler.cc
+++ b/gr-filter/lib/pfb_arb_resampler.cc
@@ -33,7 +33,7 @@
 namespace gr {
   namespace filter {
     namespace kernel {
-    
+
       pfb_arb_resampler_ccf::pfb_arb_resampler_ccf(float rate,
                                                    const std::vector<float> 
&taps,
                                                    unsigned int filter_size)
@@ -53,7 +53,7 @@ namespace gr {
         set_rate(rate);
 
         d_last_filter = (taps.size()/2) % filter_size;
-        
+
         d_filters = std::vector<fir_filter_ccf*>(d_int_rate);
         d_diff_filters = std::vector<fir_filter_ccf*>(d_int_rate);
 
@@ -153,7 +153,7 @@ namespace gr {
         create_taps(taps, d_taps, d_filters);
         create_taps(dtaps, d_dtaps, d_diff_filters);
       }
- 
+
       std::vector<std::vector<float> >
       pfb_arb_resampler_ccf::taps() const
       {
@@ -186,7 +186,7 @@ namespace gr {
         if((ph < 0) || (ph >= 2.0*M_PI)) {
           throw std::runtime_error("pfb_arb_resampler_ccf: set_phase value out 
of bounds [0, 2pi).\n");
         }
-        
+
         float ph_diff = 2.0*M_PI / (float)d_filters.size();
         d_last_filter = static_cast<int>(ph / ph_diff);
       }
@@ -218,7 +218,7 @@ namespace gr {
         int i_out = 0, i_in = 0;
         unsigned int j = d_last_filter;;
         gr_complex o0, o1;
-        
+
         while(i_in < n_to_read) {
           // start j by wrapping around mod the number of channels
           while(j < d_int_rate) {
@@ -242,7 +242,218 @@ namespace gr {
         n_read = i_in;   // return how much we've actually read
         return i_out;    // return how much we've produced
       }
-    
+
+      /****************************************************************/
+
+      pfb_arb_resampler_ccc::pfb_arb_resampler_ccc(float rate,
+                                                   const 
std::vector<gr_complex> &taps,
+                                                   unsigned int filter_size)
+      {
+        d_acc = 0; // start accumulator at 0
+
+        /* The number of filters is specified by the user as the
+           filter size; this is also the interpolation rate of the
+           filter. We use it and the rate provided to determine the
+           decimation rate. This acts as a rational resampler. The
+           flt_rate is calculated as the residual between the integer
+           decimation rate and the real decimation rate and will be
+           used to determine to interpolation point of the resampling
+           process.
+        */
+        d_int_rate = filter_size;
+        set_rate(rate);
+
+        d_last_filter = (taps.size()/2) % filter_size;
+
+        d_filters = std::vector<fir_filter_ccc*>(d_int_rate);
+        d_diff_filters = std::vector<fir_filter_ccc*>(d_int_rate);
+
+        // Create an FIR filter for each channel and zero out the taps
+        std::vector<gr_complex> vtaps(0, d_int_rate);
+        for(unsigned int i = 0; i < d_int_rate; i++) {
+          d_filters[i] = new fir_filter_ccc(1, vtaps);
+          d_diff_filters[i] = new fir_filter_ccc(1, vtaps);
+        }
+
+        // Now, actually set the filters' taps
+        set_taps(taps);
+
+        // Delay is based on number of taps per filter arm. Round to
+        // the nearest integer.
+        float delay = -rate * (taps_per_filter() - 1.0) / 2.0;
+        d_delay = static_cast<int>(boost::math::iround(delay));
+
+        // This calculation finds the phase offset induced by the
+        // arbitrary resampling. It's based on which filter arm we are
+        // at the filter's group delay plus the fractional offset
+        // between the samples. Calculated here based on the rotation
+        // around nfilts starting at start_filter.
+        float accum = -d_delay * d_flt_rate;
+        int   accum_int = static_cast<int>(accum);
+        float accum_frac = accum - accum_int;
+        int end_filter = static_cast<int>
+          (boost::math::iround(fmodf(d_last_filter - d_delay * d_dec_rate + 
accum_int, \
+                                     static_cast<float>(d_int_rate))));
+
+        d_est_phase_change = d_last_filter - (end_filter + accum_frac);
+      }
+
+      pfb_arb_resampler_ccc::~pfb_arb_resampler_ccc()
+      {
+        for(unsigned int i = 0; i < d_int_rate; i++) {
+          delete d_filters[i];
+          delete d_diff_filters[i];
+        }
+      }
+
+      void
+      pfb_arb_resampler_ccc::create_taps(const std::vector<gr_complex> 
&newtaps,
+                                         std::vector< std::vector<gr_complex> 
> &ourtaps,
+                                         std::vector<fir_filter_ccc*> 
&ourfilter)
+      {
+        unsigned int ntaps = newtaps.size();
+        d_taps_per_filter = (unsigned 
int)ceil((double)ntaps/(double)d_int_rate);
+
+        // Create d_numchan vectors to store each channel's taps
+        ourtaps.resize(d_int_rate);
+
+        // Make a vector of the taps plus fill it out with 0's to fill
+        // each polyphase filter with exactly d_taps_per_filter
+        std::vector<gr_complex> tmp_taps;
+        tmp_taps = newtaps;
+        while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) {
+          tmp_taps.push_back(0.0);
+        }
+
+        for(unsigned int i = 0; i < d_int_rate; i++) {
+          // Each channel uses all d_taps_per_filter with 0's if not enough 
taps to fill out
+          ourtaps[i] = std::vector<gr_complex>(d_taps_per_filter, 0);
+          for(unsigned int j = 0; j < d_taps_per_filter; j++) {
+            ourtaps[i][j] = tmp_taps[i + j*d_int_rate];
+          }
+
+          // Build a filter for each channel and add it's taps to it
+          ourfilter[i]->set_taps(ourtaps[i]);
+        }
+      }
+
+      void
+      pfb_arb_resampler_ccc::create_diff_taps(const std::vector<gr_complex> 
&newtaps,
+                                              std::vector<gr_complex> 
&difftaps)
+      {
+        // Calculate the differential taps using a derivative filter
+        std::vector<gr_complex> diff_filter(2);
+        diff_filter[0] = -1;
+        diff_filter[1] = 1;
+
+        for(unsigned int i = 0; i < newtaps.size()-1; i++) {
+          gr_complex tap = 0;
+          for(unsigned int j = 0; j < diff_filter.size(); j++) {
+            tap += diff_filter[j]*newtaps[i+j];
+          }
+          difftaps.push_back(tap);
+        }
+        difftaps.push_back(0);
+      }
+
+      void
+      pfb_arb_resampler_ccc::set_taps(const std::vector<gr_complex> &taps)
+      {
+        std::vector<gr_complex> dtaps;
+        create_diff_taps(taps, dtaps);
+        create_taps(taps, d_taps, d_filters);
+        create_taps(dtaps, d_dtaps, d_diff_filters);
+      }
+
+      std::vector<std::vector<gr_complex> >
+      pfb_arb_resampler_ccc::taps() const
+      {
+        return d_taps;
+      }
+
+      void
+      pfb_arb_resampler_ccc::print_taps()
+      {
+        unsigned int i, j;
+        for(i = 0; i < d_int_rate; i++) {
+          printf("filter[%d]: [", i);
+          for(j = 0; j < d_taps_per_filter; j++) {
+            printf(" %.4e + j%.4e", d_taps[i][j].real(), d_taps[i][j].imag());
+          }
+          printf("]\n");
+        }
+      }
+
+      void
+      pfb_arb_resampler_ccc::set_rate(float rate)
+      {
+        d_dec_rate = (unsigned int)floor(d_int_rate/rate);
+        d_flt_rate = (d_int_rate/rate) - d_dec_rate;
+      }
+
+      void
+      pfb_arb_resampler_ccc::set_phase(float ph)
+      {
+        if((ph < 0) || (ph >= 2.0*M_PI)) {
+          throw std::runtime_error("pfb_arb_resampler_ccc: set_phase value out 
of bounds [0, 2pi).\n");
+        }
+
+        float ph_diff = 2.0*M_PI / (float)d_filters.size();
+        d_last_filter = static_cast<int>(ph / ph_diff);
+      }
+
+      float
+      pfb_arb_resampler_ccc::phase() const
+      {
+        float ph_diff = 2.0*M_PI / static_cast<float>(d_filters.size());
+        return d_last_filter * ph_diff;
+      }
+
+      unsigned int
+      pfb_arb_resampler_ccc::taps_per_filter() const
+      {
+        return d_taps_per_filter;
+      }
+
+      float
+      pfb_arb_resampler_ccc::phase_offset(float freq, float fs)
+      {
+        float adj = (2.0*M_PI)*(freq/fs)/static_cast<float>(d_int_rate);
+        return -adj * d_est_phase_change;
+      }
+
+      int
+      pfb_arb_resampler_ccc::filter(gr_complex *output, gr_complex *input,
+                                    int n_to_read, int &n_read)
+      {
+        int i_out = 0, i_in = 0;
+        unsigned int j = d_last_filter;;
+        gr_complex o0, o1;
+
+        while(i_in < n_to_read) {
+          // start j by wrapping around mod the number of channels
+          while(j < d_int_rate) {
+            // Take the current filter and derivative filter output
+            o0 = d_filters[j]->filter(&input[i_in]);
+            o1 = d_diff_filters[j]->filter(&input[i_in]);
+
+            output[i_out] = o0 + o1*d_acc;     // linearly interpolate between 
samples
+            i_out++;
+
+            // Adjust accumulator and index into filterbank
+            d_acc += d_flt_rate;
+            j += d_dec_rate + (int)floor(d_acc);
+            d_acc = fmodf(d_acc, 1.0);
+          }
+          i_in += (int)(j / d_int_rate);
+          j = j % d_int_rate;
+        }
+        d_last_filter = j; // save last filter state for re-entry
+
+        n_read = i_in;   // return how much we've actually read
+        return i_out;    // return how much we've produced
+      }
+
       /****************************************************************/
 
       pfb_arb_resampler_fff::pfb_arb_resampler_fff(float rate,
@@ -264,7 +475,7 @@ namespace gr {
         set_rate(rate);
 
         d_last_filter = (taps.size()/2) % filter_size;
-        
+
         d_filters = std::vector<fir_filter_fff*>(d_int_rate);
         d_diff_filters = std::vector<fir_filter_fff*>(d_int_rate);
 
@@ -364,7 +575,7 @@ namespace gr {
         create_taps(taps, d_taps, d_filters);
         create_taps(dtaps, d_dtaps, d_diff_filters);
       }
- 
+
       std::vector<std::vector<float> >
       pfb_arb_resampler_fff::taps() const
       {
@@ -397,7 +608,7 @@ namespace gr {
         if((ph < 0) || (ph >= 2.0*M_PI)) {
           throw std::runtime_error("pfb_arb_resampler_fff: set_phase value out 
of bounds [0, 2pi).\n");
         }
-        
+
         float ph_diff = 2.0*M_PI / (float)d_filters.size();
         d_last_filter = static_cast<int>(ph / ph_diff);
       }
@@ -429,7 +640,7 @@ namespace gr {
         int i_out = 0, i_in = 0;
         unsigned int j = d_last_filter;;
         float o0, o1;
-        
+
         while(i_in < n_to_read) {
           // start j by wrapping around mod the number of channels
           while(j < d_int_rate) {
diff --git a/gr-filter/lib/pfb_arb_resampler_ccc_impl.cc 
b/gr-filter/lib/pfb_arb_resampler_ccc_impl.cc
new file mode 100644
index 0000000..3437524
--- /dev/null
+++ b/gr-filter/lib/pfb_arb_resampler_ccc_impl.cc
@@ -0,0 +1,183 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pfb_arb_resampler_ccc_impl.h"
+#include <gnuradio/io_signature.h>
+#include <cstdio>
+
+namespace gr {
+  namespace filter {
+
+    pfb_arb_resampler_ccc::sptr
+    pfb_arb_resampler_ccc::make(float rate,
+                                const std::vector<gr_complex> &taps,
+                                unsigned int filter_size)
+    {
+      return gnuradio::get_initial_sptr
+        (new pfb_arb_resampler_ccc_impl(rate, taps, filter_size));
+    }
+
+
+    pfb_arb_resampler_ccc_impl::pfb_arb_resampler_ccc_impl(float rate,
+                                                           const 
std::vector<gr_complex> &taps,
+                                                           unsigned int 
filter_size)
+      : block("pfb_arb_resampler_ccc",
+              io_signature::make(1, 1, sizeof(gr_complex)),
+              io_signature::make(1, 1, sizeof(gr_complex)))
+    {
+      d_updated = false;
+
+      d_resamp = new kernel::pfb_arb_resampler_ccc(rate, taps, filter_size);
+      set_history(d_resamp->taps_per_filter());
+      set_relative_rate(rate);
+    }
+
+    pfb_arb_resampler_ccc_impl::~pfb_arb_resampler_ccc_impl()
+    {
+      delete d_resamp;
+    }
+
+    void
+    pfb_arb_resampler_ccc_impl::forecast(int noutput_items,
+                                         gr_vector_int &ninput_items_required)
+    {
+      unsigned ninputs = ninput_items_required.size();
+      if(noutput_items / relative_rate() < 1) {
+        for(unsigned i = 0; i < ninputs; i++)
+          ninput_items_required[i] = relative_rate() + history() - 1;
+      }
+      else {
+        for(unsigned i = 0; i < ninputs; i++)
+          ninput_items_required[i] = noutput_items/relative_rate() + history() 
- 1;
+      }
+    }
+
+    void
+    pfb_arb_resampler_ccc_impl::set_taps(const std::vector<gr_complex> &taps)
+    {
+      gr::thread::scoped_lock guard(d_mutex);
+
+      d_resamp->set_taps(taps);
+      set_history(d_resamp->taps_per_filter());
+      d_updated = true;
+    }
+
+    std::vector<std::vector<gr_complex> >
+    pfb_arb_resampler_ccc_impl::taps() const
+    {
+      return d_resamp->taps();
+    }
+
+    void
+    pfb_arb_resampler_ccc_impl::print_taps()
+    {
+      d_resamp->print_taps();
+    }
+
+    void
+    pfb_arb_resampler_ccc_impl::set_rate(float rate)
+    {
+      gr::thread::scoped_lock guard(d_mutex);
+
+      d_resamp->set_rate(rate);
+      set_relative_rate(rate);
+    }
+
+    void
+    pfb_arb_resampler_ccc_impl::set_phase(float ph)
+    {
+      gr::thread::scoped_lock guard(d_mutex);
+      d_resamp->set_phase(ph);
+    }
+
+    float
+    pfb_arb_resampler_ccc_impl::phase() const
+    {
+      return d_resamp->phase();
+    }
+
+    unsigned int
+    pfb_arb_resampler_ccc_impl::interpolation_rate() const
+    {
+      return d_resamp->interpolation_rate();
+    }
+
+    unsigned int
+    pfb_arb_resampler_ccc_impl::decimation_rate() const
+    {
+      return d_resamp->decimation_rate();
+    }
+
+    float
+    pfb_arb_resampler_ccc_impl::fractional_rate() const
+    {
+      return d_resamp->fractional_rate();
+    }
+
+    unsigned int
+    pfb_arb_resampler_ccc_impl::taps_per_filter() const
+    {
+      return d_resamp->taps_per_filter();
+    }
+
+    int
+    pfb_arb_resampler_ccc_impl::group_delay() const
+    {
+      return d_resamp->group_delay();
+    }
+
+    float
+    pfb_arb_resampler_ccc_impl::phase_offset(float freq, float fs)
+    {
+      return d_resamp->phase_offset(freq, fs);
+    }
+
+    int
+    pfb_arb_resampler_ccc_impl::general_work(int noutput_items,
+                                             gr_vector_int &ninput_items,
+                                             gr_vector_const_void_star 
&input_items,
+                                             gr_vector_void_star &output_items)
+    {
+      gr::thread::scoped_lock guard(d_mutex);
+
+      gr_complex *in = (gr_complex*)input_items[0];
+      gr_complex *out = (gr_complex*)output_items[0];
+
+      if(d_updated) {
+        d_updated = false;
+        return 0;              // history requirements may have changed.
+      }
+
+      int nitems_read;
+      int nitems = floorf((float)noutput_items / relative_rate());
+      int processed = d_resamp->filter(out, in, nitems, nitems_read);
+
+      consume_each(nitems_read);
+      return processed;
+    }
+
+  } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/pfb_arb_resampler_ccc_impl.h 
b/gr-filter/lib/pfb_arb_resampler_ccc_impl.h
new file mode 100644
index 0000000..b4ad6dd
--- /dev/null
+++ b/gr-filter/lib/pfb_arb_resampler_ccc_impl.h
@@ -0,0 +1,75 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2014 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef INCLUDED_PFB_ARB_RESAMPLER_CCC_IMPL_H
+#define        INCLUDED_PFB_ARB_RESAMPLER_CCC_IMPL_H
+
+#include <gnuradio/filter/pfb_arb_resampler_ccc.h>
+#include <gnuradio/filter/pfb_arb_resampler.h>
+#include <gnuradio/thread/thread.h>
+
+namespace gr {
+  namespace filter {
+
+    class FILTER_API pfb_arb_resampler_ccc_impl : public pfb_arb_resampler_ccc
+    {
+    private:
+      kernel::pfb_arb_resampler_ccc *d_resamp;
+      bool d_updated;
+      gr::thread::mutex d_mutex; // mutex to protect set/work access
+
+    public:
+      pfb_arb_resampler_ccc_impl(float rate,
+                                 const std::vector<gr_complex> &taps,
+                                 unsigned int filter_size);
+
+      ~pfb_arb_resampler_ccc_impl();
+
+      void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+
+      void set_taps(const std::vector<gr_complex> &taps);
+      std::vector<std::vector<gr_complex> > taps() const;
+      void print_taps();
+
+      void set_rate(float rate);
+      void set_phase(float ph);
+      float phase() const;
+
+      unsigned int interpolation_rate() const;
+      unsigned int decimation_rate() const;
+      float fractional_rate() const;
+      unsigned int taps_per_filter() const;
+
+      int group_delay() const;
+      float phase_offset(float freq, float fs);
+
+      int general_work(int noutput_items,
+                       gr_vector_int &ninput_items,
+                       gr_vector_const_void_star &input_items,
+                       gr_vector_void_star &output_items);
+    };
+
+  } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_PFB_ARB_RESAMPLER_CCC_IMPL_H */
diff --git a/gr-filter/python/filter/pfb.py b/gr-filter/python/filter/pfb.py
index 2ddf659..7f7375c 100644
--- a/gr-filter/python/filter/pfb.py
+++ b/gr-filter/python/filter/pfb.py
@@ -37,9 +37,9 @@ class channelizer_ccf(gr.hier_block2):
     It will then output a stream for each channel.
     '''
     def __init__(self, numchans, taps=None, oversample_rate=1, atten=100):
-       gr.hier_block2.__init__(self, "pfb_channelizer_ccf",
-                               gr.io_signature(1, 1, gr.sizeof_gr_complex),
-                               gr.io_signature(numchans, numchans, 
gr.sizeof_gr_complex))
+        gr.hier_block2.__init__(self, "pfb_channelizer_ccf",
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
+                                gr.io_signature(numchans, numchans, 
gr.sizeof_gr_complex))
 
         self._nchans = numchans
         self._oversample_rate = oversample_rate
@@ -89,9 +89,9 @@ class interpolator_ccf(gr.hier_block2):
     other PFB block.
     '''
     def __init__(self, interp, taps=None, atten=100):
-       gr.hier_block2.__init__(self, "pfb_interpolator_ccf",
-                               gr.io_signature(1, 1, gr.sizeof_gr_complex),
-                               gr.io_signature(1, 1, gr.sizeof_gr_complex))
+        gr.hier_block2.__init__(self, "pfb_interpolator_ccf",
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex))
 
         self._interp = interp
         self._taps = taps
@@ -131,9 +131,9 @@ class decimator_ccf(gr.hier_block2):
     It will then output a stream that is the decimated output stream.
     '''
     def __init__(self, decim, taps=None, channel=0, atten=100):
-       gr.hier_block2.__init__(self, "pfb_decimator_ccf",
-                               gr.io_signature(1, 1, gr.sizeof_gr_complex),
-                               gr.io_signature(1, 1, gr.sizeof_gr_complex))
+        gr.hier_block2.__init__(self, "pfb_decimator_ccf",
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex),
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex))
 
         self._decim = decim
         self._channel = channel
@@ -186,9 +186,9 @@ class arb_resampler_ccf(gr.hier_block2):
     other PFB block.
     '''
     def __init__(self, rate, taps=None, flt_size=32, atten=100):
-       gr.hier_block2.__init__(self, "pfb_arb_resampler_ccf",
-                               gr.io_signature(1, 1, gr.sizeof_gr_complex), # 
Input signature
-                               gr.io_signature(1, 1, gr.sizeof_gr_complex)) # 
Output signature
+        gr.hier_block2.__init__(self, "pfb_arb_resampler_ccf",
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex), # 
Input signature
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex)) # 
Output signature
 
         self._rate = rate
         self._size = flt_size
@@ -239,9 +239,9 @@ class arb_resampler_fff(gr.hier_block2):
     other PFB block.
     '''
     def __init__(self, rate, taps=None, flt_size=32, atten=100):
-       gr.hier_block2.__init__(self, "pfb_arb_resampler_fff",
-                               gr.io_signature(1, 1, gr.sizeof_float), # Input 
signature
-                               gr.io_signature(1, 1, gr.sizeof_float)) # 
Output signature
+        gr.hier_block2.__init__(self, "pfb_arb_resampler_fff",
+                                gr.io_signature(1, 1, gr.sizeof_float), # 
Input signature
+                                gr.io_signature(1, 1, gr.sizeof_float)) # 
Output signature
 
         self._rate = rate
         self._size = flt_size
@@ -280,3 +280,56 @@ class arb_resampler_fff(gr.hier_block2):
 
     def set_rate(self, rate):
         self.pfb.set_rate(rate)
+
+
+class arb_resampler_ccc(gr.hier_block2):
+    '''
+    Convenience wrapper for the polyphase filterbank arbitrary resampler.
+
+    The block takes a single complex stream in and outputs a single complex
+    stream out. As such, it requires no extra glue to handle the input/output
+    streams. This block is provided to be consistent with the interface to the
+    other PFB block.
+    '''
+    def __init__(self, rate, taps=None, flt_size=32, atten=100):
+        gr.hier_block2.__init__(self, "pfb_arb_resampler_ccc",
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex), # 
Input signature
+                                gr.io_signature(1, 1, gr.sizeof_gr_complex)) # 
Output signature
+
+        self._rate = rate
+        self._size = flt_size
+
+        if (taps is not None) and (len(taps) > 0):
+            self._taps = taps
+        else:
+            # Create a filter that covers the full bandwidth of the input 
signal
+            bw = 0.4
+            tb = 0.2
+            ripple = 0.1
+            #self._taps = filter.firdes.low_pass_2(self._size, self._size, bw, 
tb, atten)
+            made = False
+            while not made:
+                try:
+                    self._taps = optfir.low_pass(self._size, self._size, bw, 
bw+tb, ripple, atten)
+                    made = True
+                except RuntimeError:
+                    ripple += 0.01
+                    made = False
+                    print("Warning: set ripple to %.4f dB. If this is a 
problem, adjust the attenuation or create your own filter taps." % (ripple))
+
+                    # Build in an exit strategy; if we've come this far, it 
ain't working.
+                    if(ripple >= 1.0):
+                        raise RuntimeError("optfir could not generate an 
appropriate filter.")
+
+        self.pfb = filter.pfb_arb_resampler_ccc(self._rate, self._taps, 
self._size)
+        #print "PFB has %d taps\n" % (len(self._taps),)
+
+        self.connect(self, self.pfb)
+        self.connect(self.pfb, self)
+
+    # Note -- set_taps not implemented in base class yet
+    def set_taps(self, taps):
+        self.pfb.set_taps(taps)
+
+    def set_rate(self, rate):
+        self.pfb.set_rate(rate)
diff --git a/gr-filter/python/filter/qa_pfb_arb_resampler.py 
b/gr-filter/python/filter/qa_pfb_arb_resampler.py
index bdc54b3..9dbef7d 100755
--- a/gr-filter/python/filter/qa_pfb_arb_resampler.py
+++ b/gr-filter/python/filter/qa_pfb_arb_resampler.py
@@ -59,7 +59,7 @@ class test_pfb_arb_resampler(gr_unittest.TestCase):
         snk = blocks.vector_sink_f()
 
         self.tb.connect(signal, pfb, snk)
-        self.tb.run() 
+        self.tb.run()
 
         Ntest = 50
         L = len(snk.data())
@@ -67,7 +67,7 @@ class test_pfb_arb_resampler(gr_unittest.TestCase):
         # Get group delay and estimate of phase offset from the filter itself.
         delay = pfb.group_delay()
         phase = pfb.phase_offset(freq, fs)
-        
+
         # Create a timeline offset by the filter's group delay
         t = map(lambda x: float(x)/(fs*rrate), xrange(delay, L+delay))
 
@@ -93,7 +93,7 @@ class test_pfb_arb_resampler(gr_unittest.TestCase):
         signal = blocks.vector_source_c(data)
         pfb = filter.pfb_arb_resampler_ccf(rrate, taps, nfilts)
         snk = blocks.vector_sink_c()
-        
+
         self.tb.connect(signal, pfb, snk)
         self.tb.run()
 
@@ -152,5 +152,79 @@ class test_pfb_arb_resampler(gr_unittest.TestCase):
 
         self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], 
dst_data[-Ntest:], 2)
 
+    def test_ccc_000(self):
+        N = 5000         # number of samples to use
+        fs = 5000.0      # baseband sampling rate
+        rrate = 3.4321   # resampling rate
+
+        nfilts = 32
+        taps = filter.firdes.complex_band_pass_2(nfilts, nfilts*fs, 50, 400, 
fs/10,
+                                                 attenuation_dB=80,
+                                                 
window=filter.firdes.WIN_BLACKMAN_hARRIS)
+
+        freq = 211.123
+        data = sig_source_c(fs, freq, 1, N)
+        signal = blocks.vector_source_c(data)
+        pfb = filter.pfb_arb_resampler_ccc(rrate, taps, nfilts)
+        snk = blocks.vector_sink_c()
+
+        self.tb.connect(signal, pfb, snk)
+        self.tb.run()
+
+        Ntest = 50
+        L = len(snk.data())
+
+        # Get group delay and estimate of phase offset from the filter itself.
+        delay = pfb.group_delay()
+        phase = pfb.phase_offset(freq, fs)
+
+        # Create a timeline offset by the filter's group delay
+        t = map(lambda x: float(x)/(fs*rrate), xrange(delay, L+delay))
+
+        # Data of the sinusoid at frequency freq with the delay and phase 
offset.
+        expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \
+                                1j*math.sin(2.*math.pi*freq*x+phase), t)
+
+        dst_data = snk.data()
+
+        self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], 
dst_data[-Ntest:], 2)
+
+    def test_ccc_001(self):
+        N = 50000        # number of samples to use
+        fs = 5000.0      # baseband sampling rate
+        rrate = 0.715    # resampling rate
+
+        nfilts = 32
+        taps = filter.firdes.complex_band_pass_2(nfilts, nfilts*fs, 50, 400, 
fs/10,
+                                                 attenuation_dB=80,
+                                                 
window=filter.firdes.WIN_BLACKMAN_hARRIS)
+
+        freq = 211.123
+        data = sig_source_c(fs, freq, 1, N)
+        signal = blocks.vector_source_c(data)
+        pfb = filter.pfb_arb_resampler_ccc(rrate, taps, nfilts)
+        snk = blocks.vector_sink_c()
+
+        self.tb.connect(signal, pfb, snk)
+        self.tb.run()
+
+        Ntest = 50
+        L = len(snk.data())
+
+        # Get group delay and estimate of phase offset from the filter itself.
+        delay = pfb.group_delay()
+        phase = pfb.phase_offset(freq, fs)
+
+        # Create a timeline offset by the filter's group delay
+        t = map(lambda x: float(x)/(fs*rrate), xrange(delay, L+delay))
+
+        # Data of the sinusoid at frequency freq with the delay and phase 
offset.
+        expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \
+                                1j*math.sin(2.*math.pi*freq*x+phase), t)
+
+        dst_data = snk.data()
+
+        self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], 
dst_data[-Ntest:], 2)
+
 if __name__ == '__main__':
     gr_unittest.run(test_pfb_arb_resampler, "test_pfb_arb_resampler.xml")
diff --git a/gr-filter/swig/filter_swig.i b/gr-filter/swig/filter_swig.i
index aad96e5..bc9f204 100644
--- a/gr-filter/swig/filter_swig.i
+++ b/gr-filter/swig/filter_swig.i
@@ -60,6 +60,7 @@
 #include "gnuradio/filter/interp_fir_filter_fsf.h"
 #include "gnuradio/filter/interp_fir_filter_scc.h"
 #include "gnuradio/filter/pfb_arb_resampler_ccf.h"
+#include "gnuradio/filter/pfb_arb_resampler_ccc.h"
 #include "gnuradio/filter/pfb_arb_resampler_fff.h"
 #include "gnuradio/filter/pfb_channelizer_ccf.h"
 #include "gnuradio/filter/pfb_decimator_ccf.h"
@@ -107,6 +108,7 @@
 %include "gnuradio/filter/interp_fir_filter_fsf.h"
 %include "gnuradio/filter/interp_fir_filter_scc.h"
 %include "gnuradio/filter/pfb_arb_resampler_ccf.h"
+%include "gnuradio/filter/pfb_arb_resampler_ccc.h"
 %include "gnuradio/filter/pfb_arb_resampler_fff.h"
 %include "gnuradio/filter/pfb_channelizer_ccf.h"
 %include "gnuradio/filter/pfb_decimator_ccf.h"
@@ -151,6 +153,7 @@ GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_fff);
 GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_fsf);
 GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_scc);
 GR_SWIG_BLOCK_MAGIC2(filter, pfb_arb_resampler_ccf);
+GR_SWIG_BLOCK_MAGIC2(filter, pfb_arb_resampler_ccc);
 GR_SWIG_BLOCK_MAGIC2(filter, pfb_arb_resampler_fff);
 GR_SWIG_BLOCK_MAGIC2(filter, pfb_channelizer_ccf);
 GR_SWIG_BLOCK_MAGIC2(filter, pfb_decimator_ccf);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]