commit-gnuradio
[Top][All Lists]
Advanced

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

[Commit-gnuradio] [gnuradio] 04/06: filter: use fft_filter inside pfb_de


From: git
Subject: [Commit-gnuradio] [gnuradio] 04/06: filter: use fft_filter inside pfb_decimator.
Date: Fri, 28 Feb 2014 16:53:15 +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 22ab16842e30ca9280e62415754018a0d521acb1
Author: Tom Rondeau <address@hidden>
Date:   Wed Feb 26 15:02:05 2014 -0500

    filter: use fft_filter inside pfb_decimator.
    
    Depending on the decimation rate and filter size, filtering with time 
domain or freq domain can be slower/faster and rotating using expj or fft can 
be slower/faster. This enables users to decide which features to use.
---
 gr-filter/grc/filter_pfb_decimator.xml             |  34 +++-
 .../include/gnuradio/filter/pfb_decimator_ccf.h    |  13 +-
 .../include/gnuradio/filter/polyphase_filterbank.h |  12 +-
 gr-filter/lib/pfb_decimator_ccf_impl.cc            | 183 +++++++++++++++++----
 gr-filter/lib/pfb_decimator_ccf_impl.h             |  26 ++-
 gr-filter/lib/pfb_interpolator_ccf_impl.cc         |   4 +-
 gr-filter/lib/polyphase_filterbank.cc              |  31 ++--
 gr-filter/python/filter/pfb.py                     |  12 +-
 gr-filter/python/filter/qa_pfb_decimator.py        |  66 ++++++--
 9 files changed, 298 insertions(+), 83 deletions(-)

diff --git a/gr-filter/grc/filter_pfb_decimator.xml 
b/gr-filter/grc/filter_pfb_decimator.xml
index d571196..3a82876 100644
--- a/gr-filter/grc/filter_pfb_decimator.xml
+++ b/gr-filter/grc/filter_pfb_decimator.xml
@@ -13,7 +13,9 @@
          $decim,
          $taps,
          $channel,
-         $atten)
+         $atten,
+          $fft_rot,
+          $fft_filts)
        </make>
     <callback>set_taps($taps)</callback>
     <callback>set_channel(int($channel))</callback>
@@ -40,6 +42,36 @@
                <value>100</value>
                <type>real</type>
        </param>
+       <param>
+               <name>Use FFT Rotator</name>
+                <key>fft_rot</key>
+               <value>True</value>
+               <type>raw</type>
+                <hide>part</hide>
+               <option>
+                  <name>True</name>
+                  <key>True</key>
+               </option>
+               <option>
+                  <name>False</name>
+                  <key>False</key>
+               </option>
+       </param>
+       <param>
+               <name>Use FFT Filters</name>
+                <key>fft_filts</key>
+               <value>True</value>
+               <type>raw</type>
+                <hide>part</hide>
+               <option>
+                  <name>True</name>
+                  <key>True</key>
+               </option>
+               <option>
+                  <name>False</name>
+                  <key>False</key>
+               </option>
+       </param>
        <sink>
                <name>in</name>
                <type>complex</type>
diff --git a/gr-filter/include/gnuradio/filter/pfb_decimator_ccf.h 
b/gr-filter/include/gnuradio/filter/pfb_decimator_ccf.h
index da4eb2b..06f329a 100644
--- a/gr-filter/include/gnuradio/filter/pfb_decimator_ccf.h
+++ b/gr-filter/include/gnuradio/filter/pfb_decimator_ccf.h
@@ -99,10 +99,19 @@ namespace gr {
        * \param decim   (unsigned integer) Specifies the decimation rate to use
        * \param taps    (vector/list of floats) The prototype filter to 
populate the filterbank.
        * \param channel (unsigned integer) Selects the channel to return 
[default=0].
+       * \param use_fft_rotator (bool) Rotate channels using FFT method 
instead of exp(phi).
+       *                For larger values of \p channel, the FFT method will 
perform better.
+       *                Generally, this value of \p channel is small (~5), but 
could be
+       *                architecture-specific (Default: true).
+       * \param use_fft_filters (bool) Use FFT filters (fast convolution) 
instead of FIR filters.
+       *                FFT filters perform better for larger numbers of taps 
but is
+       *                architecture-specific (Default: true).
        */
       static sptr make(unsigned int decim,
-                                 const std::vector<float> &taps,
-                                 unsigned int channel);
+                       const std::vector<float> &taps,
+                       unsigned int channel,
+                       bool use_fft_rotator=true,
+                       bool use_fft_filters=true);
 
       /*!
        * Resets the filterbank's filter taps with the new prototype filter
diff --git a/gr-filter/include/gnuradio/filter/polyphase_filterbank.h 
b/gr-filter/include/gnuradio/filter/polyphase_filterbank.h
index fad04e3..1745a47 100644
--- a/gr-filter/include/gnuradio/filter/polyphase_filterbank.h
+++ b/gr-filter/include/gnuradio/filter/polyphase_filterbank.h
@@ -26,6 +26,7 @@
 
 #include <gnuradio/filter/api.h>
 #include <gnuradio/filter/fir_filter.h>
+#include <gnuradio/filter/fft_filter.h>
 #include <gnuradio/fft/fft.h>
 
 namespace gr {
@@ -101,11 +102,12 @@ namespace gr {
       {
       protected:
        unsigned int             d_nfilts;
-       std::vector<kernel::fir_filter_ccf*> d_filters;
+       std::vector<kernel::fir_filter_ccf*> d_fir_filters;
+        std::vector<kernel::fft_filter_ccf*> d_fft_filters;
        std::vector< std::vector<float> > d_taps;
        unsigned int             d_taps_per_filter;
        fft::fft_complex        *d_fft;
-       
+
       public:
        /*!
         * Build the polyphase filterbank decimator.
@@ -113,9 +115,11 @@ namespace gr {
         *               channels <EM>M</EM>
         * \param taps (vector/list of floats) The prototype filter to
         *             populate the filterbank.
+         * \param fft_forward (bool) use a forward or inverse FFT 
(default=false).
         */
        polyphase_filterbank(unsigned int nfilts,
-                            const std::vector<float> &taps);
+                            const std::vector<float> &taps,
+                             bool fft_forward=false);
 
        ~polyphase_filterbank();
 
@@ -126,7 +130,7 @@ namespace gr {
         * \param taps (vector/list of floats) The prototype filter to
         *             populate the filterbank.
         */
-       void set_taps(const std::vector<float> &taps);
+       virtual void set_taps(const std::vector<float> &taps);
 
        /*!
         * Print all of the filterbank taps to screen.
diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.cc 
b/gr-filter/lib/pfb_decimator_ccf_impl.cc
index 19cf20f..7b4bf73 100644
--- a/gr-filter/lib/pfb_decimator_ccf_impl.cc
+++ b/gr-filter/lib/pfb_decimator_ccf_impl.cc
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2009,2010,2012 Free Software Foundation, Inc.
+ * Copyright 2009,2010,2012,2014 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -26,34 +26,53 @@
 
 #include "pfb_decimator_ccf_impl.h"
 #include <gnuradio/io_signature.h>
+#include <gnuradio/expj.h>
+#include <volk/volk.h>
 
 namespace gr {
   namespace filter {
-    
+
     pfb_decimator_ccf::sptr
     pfb_decimator_ccf::make(unsigned int decim,
                            const std::vector<float> &taps,
-                           unsigned int channel)
+                           unsigned int channel,
+                            bool use_fft_rotator,
+                            bool use_fft_filters)
     {
       return gnuradio::get_initial_sptr
-       (new pfb_decimator_ccf_impl(decim, taps, channel));
+       (new pfb_decimator_ccf_impl(decim, taps, channel,
+                                    use_fft_rotator,
+                                    use_fft_filters));
     }
 
-
     pfb_decimator_ccf_impl::pfb_decimator_ccf_impl(unsigned int decim,
                                                   const std::vector<float> 
&taps,
-                                                  unsigned int channel)
+                                                  unsigned int channel,
+                                                   bool use_fft_rotator,
+                                                   bool use_fft_filters)
       : sync_block("pfb_decimator_ccf",
-                     io_signature::make(decim, decim, sizeof(gr_complex)),
-                     io_signature::make(1, 1, sizeof(gr_complex))),
+                   io_signature::make(decim, decim, sizeof(gr_complex)),
+                   io_signature::make(1, 1, sizeof(gr_complex))),
        polyphase_filterbank(decim, taps),
-       d_updated(false), d_chan(channel)
+       d_updated(false), d_chan(channel),
+        d_use_fft_rotator(use_fft_rotator),
+        d_use_fft_filters(use_fft_filters)
     {
       d_rate = decim;
       d_rotator = new gr_complex[d_rate];
+      for(unsigned int i = 0; i < d_rate; i++) {
+        d_rotator[i] = gr_expj(i*d_chan*2*M_PI/d_rate);
+      }
 
       set_relative_rate(1.0/(float)decim);
-      set_history(d_taps_per_filter);
+
+      if(d_use_fft_filters) {
+        set_history(1);
+        set_output_multiple(d_fft_filters[0]->filtersize() - 
d_fft_filters[0]->ntaps() + 1);
+      }
+      else {
+        set_history(d_taps_per_filter);
+      }
     }
 
     pfb_decimator_ccf_impl::~pfb_decimator_ccf_impl()
@@ -90,8 +109,6 @@ namespace gr {
         d_chan = chan;
     }
 
-#define ROTATEFFT
-
     int
     pfb_decimator_ccf_impl::work(int noutput_items,
                                 gr_vector_const_void_star &input_items,
@@ -99,47 +116,145 @@ namespace gr {
     {
       gr::thread::scoped_lock guard(d_mutex);
 
-      gr_complex *in;
-      gr_complex *out = (gr_complex *)output_items[0];
-
       if(d_updated) {
        d_updated = false;
        return 0;                    // history requirements may have changed.
       }
 
+      if(d_use_fft_rotator) {
+        if(d_use_fft_filters) {
+          return work_fft_fft(noutput_items, input_items, output_items);
+        }
+        else {
+          return work_fir_fft(noutput_items, input_items, output_items);
+        }
+      }
+      else {
+        if(d_use_fft_filters) {
+          return work_fft_exp(noutput_items, input_items, output_items);
+        }
+        else {
+          return work_fir_exp(noutput_items, input_items, output_items);
+        }
+      }
+    }
+
+    int
+    pfb_decimator_ccf_impl::work_fir_exp(int noutput_items,
+                                         gr_vector_const_void_star 
&input_items,
+                                         gr_vector_void_star &output_items)
+    {
+      gr_complex *in;
+      gr_complex *out = (gr_complex *)output_items[0];
+
       int i;
       for(i = 0; i < noutput_items; i++) {
        // Move through filters from bottom to top
        out[i] = 0;
        for(int j = d_rate-1; j >= 0; j--) {
-         // Take in the items from the first input stream to d_rate
+         // Take items from M-1 to 0; filter and rotate
          in = (gr_complex*)input_items[d_rate - 1 - j];
+          out[i] += d_fir_filters[j]->filter(&in[i])*d_rotator[j];
+       }
+      }
 
-         // Filter current input stream from bottom filter to top
-         // The rotate them by expj(j*k*2pi/M) where M is the number of filters
-         // (the decimation rate) and k is the channel number to extract
-
-         // This is the real math that goes on; we abuse the FFT to do this 
quickly
-         // for decimation rates > N where N is a small number (~5):
-         //       out[i] += 
d_filters[j]->filter(&in[i])*gr_expj(j*d_chan*2*M_PI/d_rate);
-#ifdef ROTATEFFT
-         d_fft->get_inbuf()[j] = d_filters[j]->filter(&in[i]);
-#else
-         out[i] += d_filters[j]->filter(&in[i])*d_rotator[i];
-#endif
+      return noutput_items;
+    }
+
+    int
+    pfb_decimator_ccf_impl::work_fir_fft(int noutput_items,
+                                         gr_vector_const_void_star 
&input_items,
+                                         gr_vector_void_star &output_items)
+    {
+      gr_complex *in;
+      gr_complex *out = (gr_complex *)output_items[0];
+
+      int i;
+      for(i = 0; i < noutput_items; i++) {
+       // Move through filters from bottom to top
+       out[i] = 0;
+       for(unsigned int j = 0; j < d_rate; j++) {
+         // Take in the items from the first input stream to d_rate
+         in = (gr_complex*)input_items[d_rate-1-j];
+          d_fft->get_inbuf()[j] = d_fir_filters[j]->filter(&in[i]);
        }
 
-#ifdef ROTATEFFT
-       // Perform the FFT to do the complex multiply despinning for all 
channels
-       d_fft->execute();
+        // Perform the FFT to do the complex multiply despinning for all 
channels
+        d_fft->execute();
 
-       // Select only the desired channel out
-       out[i] = d_fft->get_outbuf()[d_chan];
-#endif
+        // Select only the desired channel out
+        out[i] = d_fft->get_outbuf()[d_chan];
+      }
+
+      return noutput_items;
+    }
+
+    int
+    pfb_decimator_ccf_impl::work_fft_exp(int noutput_items,
+                                         gr_vector_const_void_star 
&input_items,
+                                         gr_vector_void_star &output_items)
+    {
+      gr_complex *in;
+      gr_complex *out = (gr_complex *)output_items[0];
+
+      int i;
+      gr_complex *tmp = fft::malloc_complex(noutput_items*d_rate);
+
+      // Filter each input stream by the FFT filters; do all
+      // noutput_items at once to avoid repeated calls to the FFT
+      // setup and operation.
+      for(unsigned int j = 0; j < d_rate; j++) {
+        in = (gr_complex*)input_items[d_rate-j-1];
+        d_fft_filters[j]->filter(noutput_items, in, &(tmp[j*noutput_items]));
+      }
+
+      // Rotate and add filter outputs (k=channel number; M=number of
+      // channels; and x[j] is the output of filter j.
+      //   y[i] = \sum_{j=0}{M-1} (x[j][i]*exp(2j \pi j k / M))
+      for(i = 0; i < noutput_items; i++) {
+        out[i] = 0;
+        for(unsigned int j = 0; j < d_rate; j++) {
+          out[i] += tmp[j*noutput_items+i]*d_rotator[j];
+        }
       }
 
       return noutput_items;
     }
 
+    int
+    pfb_decimator_ccf_impl::work_fft_fft(int noutput_items,
+                                         gr_vector_const_void_star 
&input_items,
+                                         gr_vector_void_star &output_items)
+    {
+      gr_complex *in;
+      gr_complex *out = (gr_complex *)output_items[0];
+
+      int i;
+      gr_complex *tmp = fft::malloc_complex(noutput_items*d_rate);
+
+      for(unsigned int j = 0; j < d_rate; j++) {
+        in = (gr_complex*)input_items[d_rate-j-1];
+        d_fft_filters[j]->filter(noutput_items, in, &tmp[j*noutput_items]);
+      }
+
+      // Performs the rotate and add operations by implementing it as
+      // an FFT.
+      for(i = 0; i < noutput_items; i++) {
+        for(unsigned int j = 0; j < d_rate; j++) {
+          d_fft->get_inbuf()[j] = tmp[j*noutput_items + i];
+        }
+
+        // Perform the FFT to do the complex multiply despinning for all 
channels
+        d_fft->execute();
+
+        // Select only the desired channel out
+        out[i] = d_fft->get_outbuf()[d_chan];
+      }
+
+      fft::free(tmp);
+      return noutput_items;
+    }
+
+
   } /* namespace filter */
 } /* namespace gr */
diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.h 
b/gr-filter/lib/pfb_decimator_ccf_impl.h
index 2df8a50..3397701 100644
--- a/gr-filter/lib/pfb_decimator_ccf_impl.h
+++ b/gr-filter/lib/pfb_decimator_ccf_impl.h
@@ -26,26 +26,42 @@
 
 #include <gnuradio/filter/pfb_decimator_ccf.h>
 #include <gnuradio/filter/polyphase_filterbank.h>
-#include <gnuradio/filter/fir_filter.h>
-#include <gnuradio/fft/fft.h>
 #include <gnuradio/thread/thread.h>
 
 namespace gr {
   namespace filter {
-    
+
     class FILTER_API pfb_decimator_ccf_impl : public pfb_decimator_ccf, 
kernel::polyphase_filterbank
     {
     private:
       bool         d_updated;
       unsigned int d_rate;
       unsigned int d_chan;
+      bool         d_use_fft_rotator;
+      bool         d_use_fft_filters;
       gr_complex  *d_rotator;
       gr::thread::mutex d_mutex; // mutex to protect set/work access
-    
+
+      inline int work_fir_exp(int noutput_items,
+                              gr_vector_const_void_star &input_items,
+                              gr_vector_void_star &output_items);
+      inline int work_fir_fft(int noutput_items,
+                              gr_vector_const_void_star &input_items,
+                              gr_vector_void_star &output_items);
+      inline int work_fft_exp(int noutput_items,
+                              gr_vector_const_void_star &input_items,
+                              gr_vector_void_star &output_items);
+      inline int work_fft_fft(int noutput_items,
+                              gr_vector_const_void_star &input_items,
+                              gr_vector_void_star &output_items);
+
+
     public:
       pfb_decimator_ccf_impl(unsigned int decim,
                             const std::vector<float> &taps,
-                            unsigned int channel);
+                            unsigned int channel,
+                             bool use_fft_rotator=true,
+                             bool use_fft_filters=true);
 
       ~pfb_decimator_ccf_impl();
 
diff --git a/gr-filter/lib/pfb_interpolator_ccf_impl.cc 
b/gr-filter/lib/pfb_interpolator_ccf_impl.cc
index a0ed73f..cf79c10 100644
--- a/gr-filter/lib/pfb_interpolator_ccf_impl.cc
+++ b/gr-filter/lib/pfb_interpolator_ccf_impl.cc
@@ -29,7 +29,7 @@
 
 namespace gr {
   namespace filter {
-    
+
     pfb_interpolator_ccf::sptr
     pfb_interpolator_ccf::make(unsigned int interp,
                               const std::vector<float> &taps)
@@ -94,7 +94,7 @@ namespace gr {
 
       while(i < noutput_items) {
        for(unsigned int j = 0; j < d_rate; j++) {
-         out[i] = d_filters[j]->filter(&in[count]);
+         out[i] = d_fir_filters[j]->filter(&in[count]);
          i++;
        }
        count++;
diff --git a/gr-filter/lib/polyphase_filterbank.cc 
b/gr-filter/lib/polyphase_filterbank.cc
index ab978e8..ac20eb4 100644
--- a/gr-filter/lib/polyphase_filterbank.cc
+++ b/gr-filter/lib/polyphase_filterbank.cc
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2012 Free Software Foundation, Inc.
+ * Copyright 2012,2014 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -32,29 +32,33 @@ namespace gr {
     namespace kernel {
 
       polyphase_filterbank::polyphase_filterbank(unsigned int nfilts,
-                                                const std::vector<float> &taps)
+                                                const std::vector<float> &taps,
+                                                 bool fft_forward)
        : d_nfilts(nfilts)
     {
-      d_filters = std::vector<kernel::fir_filter_ccf*>(d_nfilts);
+      d_fir_filters = std::vector<kernel::fir_filter_ccf*>(d_nfilts);
+      d_fft_filters = std::vector<kernel::fft_filter_ccf*>(d_nfilts);
 
       // Create an FIR filter for each channel and zero out the taps
-      std::vector<float> vtaps(0, d_nfilts);
+      std::vector<float> vtaps(1, 0.0f);
       for(unsigned int i = 0; i < d_nfilts; i++) {
-       d_filters[i] = new kernel::fir_filter_ccf(1, vtaps);
+       d_fir_filters[i] = new kernel::fir_filter_ccf(1, vtaps);
+        d_fft_filters[i] = new kernel::fft_filter_ccf(1, vtaps);
       }
 
       // Now, actually set the filters' taps
       set_taps(taps);
 
       // Create the FFT to handle the output de-spinning of the channels
-      d_fft = new fft::fft_complex(d_nfilts, false);
+      d_fft = new fft::fft_complex(d_nfilts, fft_forward);
     }
 
     polyphase_filterbank::~polyphase_filterbank()
     {
       delete d_fft;
       for(unsigned int i = 0; i < d_nfilts; i++) {
-       delete d_filters[i];
+        delete d_fir_filters[i];
+        delete d_fft_filters[i];
       }
     }
 
@@ -62,7 +66,6 @@ namespace gr {
     polyphase_filterbank::set_taps(const std::vector<float> &taps)
     {
       unsigned int i,j;
-
       unsigned int ntaps = taps.size();
       d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilts);
 
@@ -71,14 +74,11 @@ namespace gr {
 
       // 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<float> tmp_taps;
-      tmp_taps = taps;
+      std::vector<float> tmp_taps = taps;
       while((float)(tmp_taps.size()) < d_nfilts*d_taps_per_filter) {
-       tmp_taps.push_back(0.0);
+        tmp_taps.push_back(0.0);
       }
 
-      // Reverse taps here; set_taps in filter will then re-reverse,
-      // but order them propely, anyways.
       std::reverse(tmp_taps.begin(), tmp_taps.end());
 
       // Partition the filter
@@ -89,8 +89,9 @@ namespace gr {
          d_taps[i][j] = tmp_taps[i + j*d_nfilts];
        }
 
-       // Build a filter for each channel and add it's taps to it
-       d_filters[i]->set_taps(d_taps[i]);
+       // Set the filter taps for each channel
+       d_fir_filters[i]->set_taps(d_taps[i]);
+       d_fft_filters[i]->set_taps(d_taps[i]);
       }
     }
 
diff --git a/gr-filter/python/filter/pfb.py b/gr-filter/python/filter/pfb.py
index 2ddf659..0ee0136 100644
--- a/gr-filter/python/filter/pfb.py
+++ b/gr-filter/python/filter/pfb.py
@@ -77,7 +77,11 @@ class channelizer_ccf(gr.hier_block2):
     def set_channel_map(self, newmap):
         self.pfb.set_channel_map(newmap)
 
+    def set_taps(self, taps):
+        self.pfb.set_taps(taps)
 
+    def taps(self):
+        return self.pfb.taps()
 
 class interpolator_ccf(gr.hier_block2):
     '''
@@ -122,6 +126,8 @@ class interpolator_ccf(gr.hier_block2):
         self.connect(self, self.pfb)
         self.connect(self.pfb, self)
 
+    def set_taps(self, taps):
+        self.pfb.set_taps(taps)
 
 class decimator_ccf(gr.hier_block2):
     '''
@@ -130,7 +136,8 @@ class decimator_ccf(gr.hier_block2):
     This simplifies the interface by allowing a single input stream to connect 
to this block.
     It will then output a stream that is the decimated output stream.
     '''
-    def __init__(self, decim, taps=None, channel=0, atten=100):
+    def __init__(self, decim, taps=None, channel=0, atten=100,
+                 use_fft_rotators=True, use_fft_filters=True):
        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))
@@ -160,7 +167,8 @@ class decimator_ccf(gr.hier_block2):
                         raise RuntimeError("optfir could not generate an 
appropriate filter.")
 
         self.s2ss = blocks.stream_to_streams(gr.sizeof_gr_complex, self._decim)
-        self.pfb = filter.pfb_decimator_ccf(self._decim, self._taps, 
self._channel)
+        self.pfb = filter.pfb_decimator_ccf(self._decim, self._taps, 
self._channel,
+                                            use_fft_rotators, use_fft_filters)
 
         self.connect(self, self.s2ss)
 
diff --git a/gr-filter/python/filter/qa_pfb_decimator.py 
b/gr-filter/python/filter/qa_pfb_decimator.py
index ea7a155..745ee53 100755
--- a/gr-filter/python/filter/qa_pfb_decimator.py
+++ b/gr-filter/python/filter/qa_pfb_decimator.py
@@ -29,7 +29,7 @@ def sig_source_c(samp_rate, freq, amp, N):
                 1j*math.sin(2.*math.pi*freq*x), t)
     return y
 
-def run_test(tb, channel):
+def run_test(tb, channel, fft_rotate, fft_filter):
         N = 1000         # number of samples to use
         M = 5            # Number of channels
         fs = 5000.0      # baseband sampling rate
@@ -50,14 +50,14 @@ def run_test(tb, channel):
             tb.connect(signals[i], (add,i))
 
         s2ss = blocks.stream_to_streams(gr.sizeof_gr_complex, M)
-        pfb = filter.pfb_decimator_ccf(M, taps, channel)
+        pfb = filter.pfb_decimator_ccf(M, taps, channel, fft_rotate, 
fft_filter)
         snk = blocks.vector_sink_c()
 
         tb.connect(add, s2ss)
         for i in xrange(M):
             tb.connect((s2ss,i), (pfb,i))
         tb.connect(pfb, snk)
-        tb.run() 
+        tb.run()
 
         L = len(snk.data())
 
@@ -90,33 +90,63 @@ class test_pfb_decimator(gr_unittest.TestCase):
 
     def test_000(self):
         Ntest = 50
-        dst_data, expected_data = run_test(self.tb, 0)
-        
-        self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], 
dst_data[-Ntest:], 4)
+        dst_data0, expected_data0 = run_test(self.tb, 0, False, False)
+        dst_data1, expected_data1 = run_test(self.tb, 0, False, True)
+        dst_data2, expected_data2 = run_test(self.tb, 0, True, False)
+        dst_data3, expected_data3 = run_test(self.tb, 0, True, True)
+
+        self.assertComplexTuplesAlmostEqual(expected_data0[-Ntest:], 
dst_data0[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data1[-Ntest:], 
dst_data1[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data2[-Ntest:], 
dst_data2[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data3[-Ntest:], 
dst_data3[-Ntest:], 4)
 
     def test_001(self):
         Ntest = 50
-        dst_data, expected_data = run_test(self.tb, 1)
-        
-        self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], 
dst_data[-Ntest:], 4)
+        dst_data0, expected_data0 = run_test(self.tb, 1, False, False)
+        dst_data1, expected_data1 = run_test(self.tb, 1, False, True)
+        dst_data2, expected_data2 = run_test(self.tb, 1, True, False)
+        dst_data3, expected_data3 = run_test(self.tb, 1, True, True)
+
+        self.assertComplexTuplesAlmostEqual(expected_data0[-Ntest:], 
dst_data0[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data1[-Ntest:], 
dst_data1[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data2[-Ntest:], 
dst_data2[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data3[-Ntest:], 
dst_data3[-Ntest:], 4)
 
     def test_002(self):
         Ntest = 50
-        dst_data, expected_data = run_test(self.tb, 2)
-        
-        self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], 
dst_data[-Ntest:], 4)
+        dst_data0, expected_data0 = run_test(self.tb, 2, False, False)
+        dst_data1, expected_data1 = run_test(self.tb, 2, False, True)
+        dst_data2, expected_data2 = run_test(self.tb, 2, True, False)
+        dst_data3, expected_data3 = run_test(self.tb, 2, True, True)
+
+        self.assertComplexTuplesAlmostEqual(expected_data0[-Ntest:], 
dst_data0[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data1[-Ntest:], 
dst_data1[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data2[-Ntest:], 
dst_data2[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data3[-Ntest:], 
dst_data3[-Ntest:], 4)
 
     def test_003(self):
         Ntest = 50
-        dst_data, expected_data = run_test(self.tb, 3)
-        
-        self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], 
dst_data[-Ntest:], 4)
+        dst_data0, expected_data0 = run_test(self.tb, 3, False, False)
+        dst_data1, expected_data1 = run_test(self.tb, 3, False, True)
+        dst_data2, expected_data2 = run_test(self.tb, 3, True, False)
+        dst_data3, expected_data3 = run_test(self.tb, 3, True, True)
+
+        self.assertComplexTuplesAlmostEqual(expected_data0[-Ntest:], 
dst_data0[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data1[-Ntest:], 
dst_data1[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data2[-Ntest:], 
dst_data2[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data3[-Ntest:], 
dst_data3[-Ntest:], 4)
 
     def test_004(self):
         Ntest = 50
-        dst_data, expected_data = run_test(self.tb, 4)
-        
-        self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], 
dst_data[-Ntest:], 4)
+        dst_data0, expected_data0 = run_test(self.tb, 4, False, False)
+        dst_data1, expected_data1 = run_test(self.tb, 4, False, True)
+        dst_data2, expected_data2 = run_test(self.tb, 4, True, False)
+        dst_data3, expected_data3 = run_test(self.tb, 4, True, True)
+
+        self.assertComplexTuplesAlmostEqual(expected_data0[-Ntest:], 
dst_data0[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data1[-Ntest:], 
dst_data1[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data2[-Ntest:], 
dst_data2[-Ntest:], 4)
+        self.assertComplexTuplesAlmostEqual(expected_data3[-Ntest:], 
dst_data3[-Ntest:], 4)
 
 if __name__ == '__main__':
     gr_unittest.run(test_pfb_decimator, "test_pfb_decimator.xml")



reply via email to

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