commit-gnuradio
[Top][All Lists]
Advanced

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

[Commit-gnuradio] [gnuradio] 03/06: filter: adds a ccf version of the ff


From: git
Subject: [Commit-gnuradio] [gnuradio] 03/06: filter: adds a ccf version of the fft filter.
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 c84a69b74e8c8be65bc146c85b6e735ba2c4fb50
Author: Tom Rondeau <address@hidden>
Date:   Wed Feb 26 14:55:05 2014 -0500

    filter: adds a ccf version of the fft filter.
    
    Taps are converted to complex still, so no computational savings here. Just 
for convinience of setting taps (mostly in c++).
---
 gr-filter/grc/filter_fft_filter_xxx.xml            |   9 +-
 gr-filter/include/gnuradio/filter/CMakeLists.txt   |   3 +-
 gr-filter/include/gnuradio/filter/fft_filter.h     | 110 ++++++++-
 gr-filter/include/gnuradio/filter/fft_filter_ccf.h |  89 +++++++
 gr-filter/lib/CMakeLists.txt                       |  11 +-
 gr-filter/lib/fft_filter.cc                        | 256 +++++++++++++++++----
 gr-filter/lib/fft_filter_ccf_impl.cc               | 120 ++++++++++
 gr-filter/lib/fft_filter_ccf_impl.h                |  62 +++++
 gr-filter/python/filter/qa_fft_filter.py           | 131 +++++++++++
 gr-filter/swig/filter_swig.i                       |   3 +
 10 files changed, 730 insertions(+), 64 deletions(-)

diff --git a/gr-filter/grc/filter_fft_filter_xxx.xml 
b/gr-filter/grc/filter_fft_filter_xxx.xml
index 99b02cb..f843af2 100644
--- a/gr-filter/grc/filter_fft_filter_xxx.xml
+++ b/gr-filter/grc/filter_fft_filter_xxx.xml
@@ -26,11 +26,18 @@ self.$(id).declare_sample_delay($samp_delay)
                        <opt>taps:complex_vector</opt>
                </option>
                <option>
+                       <name>Complex->Complex (Real Taps)</name>
+                       <key>ccf</key>
+                       <opt>input:complex</opt>
+                       <opt>output:complex</opt>
+                       <opt>taps:float_vector</opt>
+               </option>
+               <option>
                        <name>Float->Float (Real Taps)</name>
                        <key>fff</key>
                        <opt>input:float</opt>
                        <opt>output:float</opt>
-                       <opt>taps:real_vector</opt>
+                       <opt>taps:float_vector</opt>
                </option>
        </param>
        <param>
diff --git a/gr-filter/include/gnuradio/filter/CMakeLists.txt 
b/gr-filter/include/gnuradio/filter/CMakeLists.txt
index 3135688..8805c53 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}
@@ -94,6 +94,7 @@ install(FILES
     dc_blocker_ff.h
     filter_delay_fc.h
     fft_filter_ccc.h
+    fft_filter_ccf.h
     fft_filter_fff.h
     fractional_interpolator_cc.h
     fractional_interpolator_ff.h
diff --git a/gr-filter/include/gnuradio/filter/fft_filter.h 
b/gr-filter/include/gnuradio/filter/fft_filter.h
index 76271d9..24f6ce3 100644
--- a/gr-filter/include/gnuradio/filter/fft_filter.h
+++ b/gr-filter/include/gnuradio/filter/fft_filter.h
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2010,2012 Free Software Foundation, Inc.
+ * Copyright 2010,2012,2014 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -49,7 +49,7 @@ namespace gr {
        std::vector<float>       d_tail;            // state carried between 
blocks for overlap-add
        std::vector<float>       d_taps;            // stores time domain taps
        gr_complex              *d_xformed_taps;    // Fourier xformed taps
-       
+
        void compute_sizes(int ntaps);
        int tailsize() const { return d_ntaps - 1; }
 
@@ -77,7 +77,7 @@ namespace gr {
         * \param taps       The filter taps (complex)
         */
        int set_taps(const std::vector<float> &taps);
-       
+
        /*!
         * \brief Set number of threads to use.
         */
@@ -92,12 +92,12 @@ namespace gr {
         * \brief Returns the number of taps in the filter.
         */
         unsigned int ntaps() const;
-       
+
        /*!
         * \brief Get number of threads being used.
         */
        int nthreads() const;
-       
+
        /*!
 l       * \brief Perform the filter operation
         *
@@ -108,7 +108,7 @@ l    * \brief Perform the filter operation
        int filter(int nitems, const float *input, float *output);
       };
 
-    
+
       /*!
        * \brief Fast FFT filter with gr_complex input, gr_complex output and 
gr_complex taps
        * \ingroup filter_blk
@@ -126,7 +126,7 @@ l    * \brief Perform the filter operation
        std::vector<gr_complex>  d_tail;            // state carried between 
blocks for overlap-add
        std::vector<gr_complex>  d_taps;            // stores time domain taps
        gr_complex              *d_xformed_taps;    // Fourier xformed taps
-       
+
        void compute_sizes(int ntaps);
        int tailsize() const { return d_ntaps - 1; }
 
@@ -154,12 +154,12 @@ l  * \brief Perform the filter operation
         * \param taps       The filter taps (complex)
         */
        int set_taps(const std::vector<gr_complex> &taps);
-       
+
        /*!
         * \brief Set number of threads to use.
         */
        void set_nthreads(int n);
-       
+
        /*!
         * \brief Returns the taps.
         */
@@ -169,12 +169,100 @@ l         * \brief Perform the filter operation
         * \brief Returns the number of taps in the filter.
         */
         unsigned int ntaps() const;
-       
+
+       /*!
+        * \brief Get number of threads being used.
+        */
+       int nthreads() const;
+
+       /*!
+        * \brief Perform the filter operation
+        *
+        * \param nitems  The number of items to produce
+        * \param input   The input vector to be filtered
+        * \param output  The result of the filter operation
+        */
+       int filter(int nitems, const gr_complex *input, gr_complex *output);
+      };
+
+
+
+      /*!
+       * \brief Fast FFT filter with gr_complex input, gr_complex output and 
float taps
+       * \ingroup filter_blk
+       */
+      class FILTER_API fft_filter_ccf
+      {
+      private:
+       int                      d_ntaps;
+       int                      d_nsamples;
+       int                      d_fftsize;         // fftsize = ntaps + 
nsamples - 1
+       int                      d_decimation;
+       fft::fft_complex        *d_fwdfft;          // forward "plan"
+       fft::fft_complex        *d_invfft;          // inverse "plan"
+       int                      d_nthreads;        // number of FFTW threads 
to use
+       std::vector<gr_complex>  d_tail;            // state carried between 
blocks for overlap-add
+       std::vector<float>       d_taps;            // stores time domain taps
+       gr_complex              *d_xformed_taps;    // Fourier xformed taps
+
+       void compute_sizes(int ntaps);
+       int tailsize() const { return d_ntaps - 1; }
+
+      public:
+       /*!
+        * \brief Construct an FFT filter for complex vectors with the given 
taps and decimation rate.
+        *
+        * This is the basic implementation for performing FFT filter for fast 
convolution
+        * in other blocks for complex vectors (such as fft_filter_ccf).
+        *
+        * \param decimation The decimation rate of the filter (int)
+        * \param taps       The filter taps (complex)
+        * \param nthreads   The number of threads for the FFT to use (int)
+        */
+       fft_filter_ccf(int decimation,
+                      const std::vector<float> &taps,
+                      int nthreads=1);
+
+       ~fft_filter_ccf();
+
+       /*!
+        * \brief Set new taps for the filter.
+        *
+        * Sets new taps and resets the class properties to handle different 
sizes
+        * \param taps       The filter taps (complex)
+        */
+       int set_taps(const std::vector<float> &taps);
+
+       /*!
+        * \brief Set number of threads to use.
+        */
+       void set_nthreads(int n);
+
+       /*!
+        * \brief Returns the taps.
+        */
+       std::vector<float> taps() const;
+
+       /*!
+        * \brief Returns the number of taps in the filter.
+        */
+        unsigned int ntaps() const;
+
+       /*!
+        * \brief Returns the actual size of the filter.
+         *
+         * \details This value could be equal to ntaps, but we ofter
+         * build a longer filter to allow us to calculate a more
+         * efficient FFT. This value is the actual size of the filters
+         * used in the calculation of the overlap-and-save operation.
+        */
+        unsigned int filtersize() const;
+
        /*!
         * \brief Get number of threads being used.
         */
        int nthreads() const;
-       
+
        /*!
         * \brief Perform the filter operation
         *
diff --git a/gr-filter/include/gnuradio/filter/fft_filter_ccf.h 
b/gr-filter/include/gnuradio/filter/fft_filter_ccf.h
new file mode 100644
index 0000000..b0230f8
--- /dev/null
+++ b/gr-filter/include/gnuradio/filter/fft_filter_ccf.h
@@ -0,0 +1,89 @@
+/* -*- 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_FILTER_FFT_FILTER_CCF_H
+#define INCLUDED_FILTER_FFT_FILTER_CCF_H
+
+#include <gnuradio/filter/api.h>
+#include <gnuradio/sync_decimator.h>
+
+namespace gr {
+  namespace filter {
+
+    /*!
+     * \brief Fast FFT filter with gr_complex input, gr_complex output and 
float taps
+     * \ingroup filter_blk
+     *
+     * \details
+     * This block implements a complex decimating filter using the
+     * fast convolution method via an FFT. The decimation factor is an
+     * interger that is greater than or equal to 1.
+     *
+     * The filter takes a set of complex (or real) taps to use in the
+     * filtering operation. These taps can be defined as anything that
+     * satisfies the user's filtering needs. For standard filters such
+     * as lowpass, highpass, bandpass, etc., the filter.firdes and
+     * filter.optfir classes provide convenient generating methods.
+     *
+     * This filter is implemented by using the FFTW package to perform
+     * the required FFTs. An optional argument, nthreads, may be
+     * passed to the constructor (or set using the set_nthreads member
+     * function) to split the FFT among N number of threads. This can
+     * improve performance on very large FFTs (that is, if the number
+     * of taps used is very large) if you have enough threads/cores to
+     * support it.
+     */
+    class FILTER_API fft_filter_ccf : virtual public sync_decimator
+    {
+    public:
+      // gr::filter::fft_filter_ccf::sptr
+      typedef boost::shared_ptr<fft_filter_ccf> sptr;
+
+      /*!
+       * Build an FFT filter blocks.
+       *
+       * \param decimation  >= 1
+       * \param taps        complex filter taps
+       * \param nthreads    number of threads for the FFT to use
+       */
+      static sptr make(int decimation,
+                       const std::vector<float> &taps,
+                       int nthreads=1);
+
+      virtual void set_taps(const std::vector<float> &taps) = 0;
+      virtual std::vector<float> taps() const = 0;
+
+      /*!
+       * \brief Set number of threads to use.
+       */
+      virtual void set_nthreads(int n) = 0;
+
+      /*!
+       * \brief Get number of threads being used.
+       */
+      virtual int nthreads() const = 0;
+    };
+
+  } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_FILTER_FFT_FILTER_CCF_H */
diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt
index 58000bb..d32e51b 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)
 
 ########################################################################
@@ -128,6 +128,7 @@ list(APPEND filter_sources
   dc_blocker_ff_impl.cc
   filter_delay_fc_impl.cc
   fft_filter_ccc_impl.cc
+  fft_filter_ccf_impl.cc
   fft_filter_fff_impl.cc
   fractional_interpolator_cc_impl.cc
   fractional_interpolator_ff_impl.cc
diff --git a/gr-filter/lib/fft_filter.cc b/gr-filter/lib/fft_filter.cc
index b45344d..d2b1f4c 100644
--- a/gr-filter/lib/fft_filter.cc
+++ b/gr-filter/lib/fft_filter.cc
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2010,2012 Free Software Foundation, Inc.
+ * Copyright 2010,2012,2014 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -43,7 +43,7 @@ namespace gr {
       {
        set_taps(taps);
       }
-      
+
       fft_filter_fff::~fft_filter_fff()
       {
        delete d_fwdfft;
@@ -61,33 +61,33 @@ namespace gr {
        int i = 0;
         d_taps = taps;
        compute_sizes(taps.size());
-       
+
        d_tail.resize(tailsize());
        for(i = 0; i < tailsize(); i++)
          d_tail[i] = 0;
-       
+
        float *in = d_fwdfft->get_inbuf();
        gr_complex *out = d_fwdfft->get_outbuf();
-       
+
        float scale = 1.0 / d_fftsize;
-       
+
        // Compute forward xform of taps.
        // Copy taps into first ntaps slots, then pad with zeros
        for (i = 0; i < d_ntaps; i++)
          in[i] = taps[i] * scale;
-       
+
        for (; i < d_fftsize; i++)
          in[i] = 0;
-       
+
        d_fwdfft->execute();            // do the xform
-       
+
        // now copy output to d_xformed_taps
        for (i = 0; i < d_fftsize/2+1; i++)
          d_xformed_taps[i] = out[i];
-       
+
        return d_nsamples;
       }
-      
+
       // determine and set d_ntaps, d_nsamples, d_fftsize
       void
       fft_filter_fff::compute_sizes(int ntaps)
@@ -96,7 +96,7 @@ namespace gr {
        d_ntaps = ntaps;
        d_fftsize = (int) (2 * pow(2.0, ceil(log(double(ntaps)) / log(2.0))));
        d_nsamples = d_fftsize - d_ntaps + 1;
-       
+
        if(VERBOSE) {
          std::cerr << "fft_filter_fff: ntaps = " << d_ntaps
                    << " fftsize = " << d_fftsize
@@ -143,35 +143,35 @@ namespace gr {
       {
        return d_nthreads;
       }
-      
+
       int
       fft_filter_fff::filter(int nitems, const float *input, float *output)
       {
        int dec_ctr = 0;
        int j = 0;
        int ninput_items = nitems * d_decimation;
-       
+
        for (int i = 0; i < ninput_items; i += d_nsamples){
-         
+
          memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * sizeof(float));
-         
+
          for (j = d_nsamples; j < d_fftsize; j++)
            d_fwdfft->get_inbuf()[j] = 0;
-         
+
          d_fwdfft->execute();  // compute fwd xform
-         
+
          gr_complex *a = d_fwdfft->get_outbuf();
          gr_complex *b = d_xformed_taps;
          gr_complex *c = d_invfft->get_inbuf();
-         
+
          volk_32fc_x2_multiply_32fc_a(c, a, b, d_fftsize/2+1);
-         
+
          d_invfft->execute();  // compute inv xform
-         
-         // add in the overlapping tail          
+
+         // add in the overlapping tail
          for (j = 0; j < tailsize(); j++)
            d_invfft->get_outbuf()[j] += d_tail[j];
-         
+
          // copy nsamples to output
          j = dec_ctr;
          while (j < d_nsamples) {
@@ -179,19 +179,19 @@ namespace gr {
            j += d_decimation;
          }
          dec_ctr = (j - d_nsamples);
-         
+
          // stash the tail
          memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
                 tailsize() * sizeof(float));
        }
-       
+
        return nitems;
       }
 
 
       /**************************************************************/
 
-    
+
       fft_filter_ccc::fft_filter_ccc(int decimation,
                                     const std::vector<gr_complex> &taps,
                                     int nthreads)
@@ -200,7 +200,7 @@ namespace gr {
       {
        set_taps(taps);
       }
-      
+
       fft_filter_ccc::~fft_filter_ccc()
       {
        delete d_fwdfft;
@@ -218,33 +218,33 @@ namespace gr {
        int i = 0;
         d_taps = taps;
        compute_sizes(taps.size());
-       
+
        d_tail.resize(tailsize());
        for(i = 0; i < tailsize(); i++)
          d_tail[i] = 0;
-       
+
        gr_complex *in = d_fwdfft->get_inbuf();
        gr_complex *out = d_fwdfft->get_outbuf();
-       
+
        float scale = 1.0 / d_fftsize;
-       
+
        // Compute forward xform of taps.
        // Copy taps into first ntaps slots, then pad with zeros
        for(i = 0; i < d_ntaps; i++)
          in[i] = taps[i] * scale;
-       
+
        for(; i < d_fftsize; i++)
          in[i] = 0;
-       
+
        d_fwdfft->execute();            // do the xform
-       
+
        // now copy output to d_xformed_taps
        for(i = 0; i < d_fftsize; i++)
          d_xformed_taps[i] = out[i];
-       
+
        return d_nsamples;
       }
-      
+
       // determine and set d_ntaps, d_nsamples, d_fftsize
       void
       fft_filter_ccc::compute_sizes(int ntaps)
@@ -253,7 +253,7 @@ namespace gr {
        d_ntaps = ntaps;
        d_fftsize = (int) (2 * pow(2.0, ceil(log(double(ntaps)) / log(2.0))));
        d_nsamples = d_fftsize - d_ntaps + 1;
-       
+
        if(VERBOSE) {
          std::cerr << "fft_filter_ccc: ntaps = " << d_ntaps
                    << " fftsize = " << d_fftsize
@@ -300,17 +300,17 @@ namespace gr {
       {
        return d_nthreads;
       }
-      
+
       int
       fft_filter_ccc::filter(int nitems, const gr_complex *input, gr_complex 
*output)
       {
        int dec_ctr = 0;
        int j = 0;
        int ninput_items = nitems * d_decimation;
-       
+
        for(int i = 0; i < ninput_items; i += d_nsamples) {
          memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * 
sizeof(gr_complex));
-         
+
          for(j = d_nsamples; j < d_fftsize; j++)
            d_fwdfft->get_inbuf()[j] = 0;
 
@@ -319,16 +319,16 @@ namespace gr {
          gr_complex *a = d_fwdfft->get_outbuf();
          gr_complex *b = d_xformed_taps;
          gr_complex *c = d_invfft->get_inbuf();
-         
+
          volk_32fc_x2_multiply_32fc_a(c, a, b, d_fftsize);
-         
+
          d_invfft->execute();  // compute inv xform
-         
+
          // add in the overlapping tail
-         
+
          for(j = 0; j < tailsize(); j++)
            d_invfft->get_outbuf()[j] += d_tail[j];
-         
+
          // copy nsamples to output
          j = dec_ctr;
          while(j < d_nsamples) {
@@ -336,7 +336,7 @@ namespace gr {
            j += d_decimation;
          }
          dec_ctr = (j - d_nsamples);
-         
+
          // stash the tail
          memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
                 tailsize() * sizeof(gr_complex));
@@ -345,6 +345,170 @@ namespace gr {
        return nitems;
       }
 
+
+      /**************************************************************/
+
+
+      fft_filter_ccf::fft_filter_ccf(int decimation,
+                                    const std::vector<float> &taps,
+                                    int nthreads)
+       : d_fftsize(-1), d_decimation(decimation), d_fwdfft(0),
+         d_invfft(0), d_nthreads(nthreads), d_xformed_taps(NULL)
+      {
+       set_taps(taps);
+      }
+
+      fft_filter_ccf::~fft_filter_ccf()
+      {
+       delete d_fwdfft;
+       delete d_invfft;
+        if(d_xformed_taps != NULL)
+          volk_free(d_xformed_taps);
+      }
+
+      /*
+       * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps
+       */
+      int
+      fft_filter_ccf::set_taps(const std::vector<float> &taps)
+      {
+       int i = 0;
+        d_taps = taps;
+       compute_sizes(taps.size());
+
+       d_tail.resize(tailsize());
+       for(i = 0; i < tailsize(); i++)
+         d_tail[i] = 0;
+
+       gr_complex *in = d_fwdfft->get_inbuf();
+       gr_complex *out = d_fwdfft->get_outbuf();
+
+       float scale = 1.0 / d_fftsize;
+
+       // Compute forward xform of taps.
+       // Copy taps into first ntaps slots, then pad with zeros
+       for(i = 0; i < d_ntaps; i++)
+         in[i] = gr_complex(taps[i] * scale, 0.0f);
+
+       for(; i < d_fftsize; i++)
+         in[i] = gr_complex(0.0f, 0.0f);
+
+       d_fwdfft->execute();            // do the xform
+
+       // now copy output to d_xformed_taps
+       for(i = 0; i < d_fftsize; i++)
+         d_xformed_taps[i] = out[i];
+
+       return d_nsamples;
+      }
+
+      // determine and set d_ntaps, d_nsamples, d_fftsize
+      void
+      fft_filter_ccf::compute_sizes(int ntaps)
+      {
+       int old_fftsize = d_fftsize;
+       d_ntaps = ntaps;
+       d_fftsize = (int) (2 * pow(2.0, ceil(log(double(ntaps)) / log(2.0))));
+       d_nsamples = d_fftsize - d_ntaps + 1;
+
+       if(VERBOSE) {
+         std::cerr << "fft_filter_ccf: ntaps = " << d_ntaps
+                   << " fftsize = " << d_fftsize
+                   << " nsamples = " << d_nsamples << std::endl;
+       }
+
+       // compute new plans
+       if(d_fftsize != old_fftsize) {
+         delete d_fwdfft;
+         delete d_invfft;
+          if(d_xformed_taps != NULL)
+            volk_free(d_xformed_taps);
+         d_fwdfft = new fft::fft_complex(d_fftsize, true, d_nthreads);
+         d_invfft = new fft::fft_complex(d_fftsize, false, d_nthreads);
+         d_xformed_taps = 
(gr_complex*)volk_malloc(sizeof(gr_complex)*d_fftsize,
+                                                    volk_get_alignment());
+       }
+      }
+
+      void
+      fft_filter_ccf::set_nthreads(int n)
+      {
+       d_nthreads = n;
+       if(d_fwdfft)
+         d_fwdfft->set_nthreads(n);
+       if(d_invfft)
+         d_invfft->set_nthreads(n);
+      }
+
+      std::vector<float>
+      fft_filter_ccf::taps() const
+      {
+        return d_taps;
+      }
+
+      unsigned int
+      fft_filter_ccf::ntaps() const
+      {
+        return d_ntaps;
+      }
+
+      unsigned int
+      fft_filter_ccf::filtersize() const
+      {
+        return d_fftsize;
+      }
+
+      int
+      fft_filter_ccf::nthreads() const
+      {
+       return d_nthreads;
+      }
+
+      int
+      fft_filter_ccf::filter(int nitems, const gr_complex *input, gr_complex 
*output)
+      {
+       int dec_ctr = 0;
+       int j = 0;
+       int ninput_items = nitems * d_decimation;
+
+       for(int i = 0; i < ninput_items; i += d_nsamples) {
+         memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * 
sizeof(gr_complex));
+
+         for(j = d_nsamples; j < d_fftsize; j++)
+           d_fwdfft->get_inbuf()[j] = 0;
+
+         d_fwdfft->execute();  // compute fwd xform
+
+         gr_complex *a = d_fwdfft->get_outbuf();
+         gr_complex *b = d_xformed_taps;
+         gr_complex *c = d_invfft->get_inbuf();
+
+         volk_32fc_x2_multiply_32fc_a(c, a, b, d_fftsize);
+
+         d_invfft->execute();  // compute inv xform
+
+         // add in the overlapping tail
+
+         for(j = 0; j < tailsize(); j++)
+           d_invfft->get_outbuf()[j] += d_tail[j];
+
+         // copy nsamples to output
+         j = dec_ctr;
+         while(j < d_nsamples) {
+           *output++ = d_invfft->get_outbuf()[j];
+           j += d_decimation;
+         }
+         dec_ctr = (j - d_nsamples);
+
+         // stash the tail
+         memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
+                tailsize() * sizeof(gr_complex));
+       }
+
+       return nitems;
+      }
+
+
     } /* namespace kernel */
   } /* namespace filter */
 } /* namespace gr */
diff --git a/gr-filter/lib/fft_filter_ccf_impl.cc 
b/gr-filter/lib/fft_filter_ccf_impl.cc
new file mode 100644
index 0000000..00e1842
--- /dev/null
+++ b/gr-filter/lib/fft_filter_ccf_impl.cc
@@ -0,0 +1,120 @@
+/* -*- 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 "fft_filter_ccf_impl.h"
+#include <gnuradio/io_signature.h>
+
+#include <math.h>
+#include <assert.h>
+#include <stdexcept>
+
+namespace gr {
+  namespace filter {
+
+    fft_filter_ccf::sptr
+    fft_filter_ccf::make(int decimation,
+                         const std::vector<float> &taps,
+                         int nthreads)
+    {
+      return gnuradio::get_initial_sptr
+        (new fft_filter_ccf_impl
+         (decimation, taps, nthreads));
+    }
+
+    fft_filter_ccf_impl::fft_filter_ccf_impl(int decimation,
+                                            const std::vector<float> &taps,
+                                            int nthreads)
+      : sync_decimator("fft_filter_ccf",
+                       io_signature::make(1, 1, sizeof(gr_complex)),
+                       io_signature::make(1, 1, sizeof(gr_complex)),
+                       decimation),
+       d_updated(false)
+    {
+      set_history(1);
+
+      d_filter = new kernel::fft_filter_ccf(decimation, taps, nthreads);
+
+      d_new_taps = taps;
+      d_nsamples = d_filter->set_taps(taps);
+      set_output_multiple(d_nsamples);
+    }
+
+    fft_filter_ccf_impl::~fft_filter_ccf_impl()
+    {
+      delete d_filter;
+    }
+
+    void
+    fft_filter_ccf_impl::set_taps(const std::vector<float> &taps)
+    {
+      d_new_taps = taps;
+      d_updated = true;
+    }
+
+    std::vector<float>
+    fft_filter_ccf_impl::taps() const
+    {
+      return d_new_taps;
+    }
+
+    void
+    fft_filter_ccf_impl::set_nthreads(int n)
+    {
+      if(d_filter)
+       d_filter->set_nthreads(n);
+    }
+
+    int
+    fft_filter_ccf_impl::nthreads() const
+    {
+      if(d_filter)
+       return d_filter->nthreads();
+      else
+       return 0;
+    }
+
+    int
+    fft_filter_ccf_impl::work(int noutput_items,
+                             gr_vector_const_void_star &input_items,
+                             gr_vector_void_star &output_items)
+    {
+      const gr_complex *in = (const gr_complex *) input_items[0];
+      gr_complex *out = (gr_complex *) output_items[0];
+
+      if (d_updated){
+       d_nsamples = d_filter->set_taps(d_new_taps);
+       d_updated = false;
+       set_output_multiple(d_nsamples);
+       return 0;                               // output multiple may have 
changed
+      }
+
+      d_filter->filter(noutput_items, in, out);
+
+      return noutput_items;
+    }
+
+  } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/fft_filter_ccf_impl.h 
b/gr-filter/lib/fft_filter_ccf_impl.h
new file mode 100644
index 0000000..2e0ddd4
--- /dev/null
+++ b/gr-filter/lib/fft_filter_ccf_impl.h
@@ -0,0 +1,62 @@
+/* -*- 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_FILTER_FFT_FILTER_CCF_IMPL_H
+#define INCLUDED_FILTER_FFT_FILTER_CCF_IMPL_H
+
+#include <gnuradio/filter/api.h>
+#include <gnuradio/filter/fft_filter.h>
+#include <gnuradio/filter/fft_filter_ccf.h>
+
+namespace gr {
+  namespace filter {
+
+    class FILTER_API fft_filter_ccf_impl : public fft_filter_ccf
+    {
+    private:
+      int d_nsamples;
+      bool d_updated;
+      kernel::fft_filter_ccf *d_filter;
+      std::vector<float> d_new_taps;
+
+    public:
+      fft_filter_ccf_impl(int decimation,
+                         const std::vector<float> &taps,
+                         int nthreads=1);
+
+      ~fft_filter_ccf_impl();
+
+      void set_taps(const std::vector<float> &taps);
+      std::vector<float> taps() const;
+
+      void set_nthreads(int n);
+      int nthreads() const;
+
+      int work(int noutput_items,
+              gr_vector_const_void_star &input_items,
+              gr_vector_void_star &output_items);
+    };
+
+  } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_FILTER_FFT_FILTER_CCF_IMPL_H */
diff --git a/gr-filter/python/filter/qa_fft_filter.py 
b/gr-filter/python/filter/qa_fft_filter.py
index fafd233..172b945 100755
--- a/gr-filter/python/filter/qa_fft_filter.py
+++ b/gr-filter/python/filter/qa_fft_filter.py
@@ -65,6 +65,18 @@ def reference_filter_fff(dec, taps, input):
     tb.run()
     return dst.data()
 
+def reference_filter_ccf(dec, taps, input):
+    """
+    compute result using conventional fir filter
+    """
+    tb = gr.top_block()
+    src = blocks.vector_source_c(input)
+    op = filter.fir_filter_ccf(dec, taps)
+    dst = blocks.vector_sink_c()
+    tb.connect(src, op, dst)
+    tb.run()
+    return dst.data()
+
 
 def print_complex(x):
     for i in x:
@@ -207,6 +219,125 @@ class test_fft_filter(gr_unittest.TestCase):
             self.assert_fft_ok2(expected_result, result_data)
 
     # ----------------------------------------------------------------
+    # test _ccf version
+    # ----------------------------------------------------------------
+
+    def test_ccf_001(self):
+       tb = gr.top_block()
+        src_data = (0,1,2,3,4,5,6,7)
+        taps = (1,)
+        expected_result = tuple([complex(x) for x in (0,1,2,3,4,5,6,7)])
+        src = blocks.vector_source_c(src_data)
+        op =  filter.fft_filter_ccf(1, taps)
+        dst = blocks.vector_sink_c()
+        tb.connect(src, op, dst)
+        tb.run()
+        result_data = dst.data()
+        #print 'expected:', expected_result
+        #print 'results: ', result_data
+        self.assertComplexTuplesAlmostEqual (expected_result, result_data, 5)
+
+
+    def test_ccf_002(self):
+        # Test nthreads
+       tb = gr.top_block()
+        src_data = (0,1,2,3,4,5,6,7)
+        taps = (2,)
+        nthreads = 2
+        expected_result = tuple([2 * complex(x) for x in (0,1,2,3,4,5,6,7)])
+        src = blocks.vector_source_c(src_data)
+        op = filter.fft_filter_ccf(1, taps, nthreads)
+        dst = blocks.vector_sink_c()
+        tb.connect(src, op, dst)
+        tb.run()
+        result_data = dst.data()
+        #print 'expected:', expected_result
+        #print 'results: ', result_data
+        self.assertComplexTuplesAlmostEqual (expected_result, result_data, 5)
+
+    def test_ccf_003(self):
+       tb = gr.top_block()
+        src_data = (0,1,2,3,4,5,6,7)
+        taps = (2,)
+        expected_result = tuple([2 * complex(x) for x in (0,1,2,3,4,5,6,7)])
+        src = blocks.vector_source_c(src_data)
+        op = filter.fft_filter_ccf(1, taps)
+        dst = blocks.vector_sink_c()
+        tb.connect(src, op, dst)
+        tb.run()
+        result_data = dst.data()
+        #print 'expected:', expected_result
+        #print 'results: ', result_data
+        self.assertComplexTuplesAlmostEqual (expected_result, result_data, 5)
+
+
+    def test_ccf_004(self):
+        random.seed(0)
+        for i in xrange(25):
+            # sys.stderr.write("\n>>> Loop = %d\n" % (i,))
+            src_len = 4*1024
+            src_data = make_random_complex_tuple(src_len)
+            ntaps = int(random.uniform(2, 1000))
+            taps = make_random_float_tuple(ntaps)
+            expected_result = reference_filter_ccf(1, taps, src_data)
+
+            src = blocks.vector_source_c(src_data)
+            op = filter.fft_filter_ccf(1, taps)
+            dst = blocks.vector_sink_c()
+           tb = gr.top_block()
+            tb.connect(src, op, dst)
+            tb.run()
+            result_data = dst.data()
+           del tb
+            self.assert_fft_ok2(expected_result, result_data)
+
+    def test_ccf_005(self):
+        random.seed(0)
+        for i in xrange(25):
+            # sys.stderr.write("\n>>> Loop = %d\n" % (i,))
+            dec = i + 1
+            src_len = 4*1024
+            src_data = make_random_complex_tuple(src_len)
+            ntaps = int(random.uniform(2, 100))
+            taps = make_random_float_tuple(ntaps)
+            expected_result = reference_filter_ccf(dec, taps, src_data)
+
+            src = blocks.vector_source_c(src_data)
+            op = filter.fft_filter_ccf(dec, taps)
+            dst = blocks.vector_sink_c()
+            tb = gr.top_block()
+           tb.connect(src, op, dst)
+            tb.run()
+            del tb
+           result_data = dst.data()
+
+            self.assert_fft_ok2(expected_result, result_data)
+
+    def test_ccf_006(self):
+        # Test decimating with nthreads=2
+        random.seed(0)
+        nthreads = 2
+        for i in xrange(25):
+            # sys.stderr.write("\n>>> Loop = %d\n" % (i,))
+            dec = i + 1
+            src_len = 4*1024
+            src_data = make_random_complex_tuple(src_len)
+            ntaps = int(random.uniform(2, 100))
+            taps = make_random_float_tuple(ntaps)
+            expected_result = reference_filter_ccf(dec, taps, src_data)
+
+            src = blocks.vector_source_c(src_data)
+            op = filter.fft_filter_ccc(dec, taps, nthreads)
+            dst = blocks.vector_sink_c()
+            tb = gr.top_block()
+           tb.connect(src, op, dst)
+            tb.run()
+            del tb
+           result_data = dst.data()
+
+            self.assert_fft_ok2(expected_result, result_data)
+
+    # ----------------------------------------------------------------
     # test _fff version
     # ----------------------------------------------------------------
 
diff --git a/gr-filter/swig/filter_swig.i b/gr-filter/swig/filter_swig.i
index aad96e5..07c4cf3 100644
--- a/gr-filter/swig/filter_swig.i
+++ b/gr-filter/swig/filter_swig.i
@@ -40,6 +40,7 @@
 #include "gnuradio/filter/fir_filter_fsf.h"
 #include "gnuradio/filter/fir_filter_scc.h"
 #include "gnuradio/filter/fft_filter_ccc.h"
+#include "gnuradio/filter/fft_filter_ccf.h"
 #include "gnuradio/filter/fft_filter_fff.h"
 #include "gnuradio/filter/fractional_interpolator_cc.h"
 #include "gnuradio/filter/fractional_interpolator_ff.h"
@@ -87,6 +88,7 @@
 %include "gnuradio/filter/fir_filter_fsf.h"
 %include "gnuradio/filter/fir_filter_scc.h"
 %include "gnuradio/filter/fft_filter_ccc.h"
+%include "gnuradio/filter/fft_filter_ccf.h"
 %include "gnuradio/filter/fft_filter_fff.h"
 %include "gnuradio/filter/fractional_interpolator_cc.h"
 %include "gnuradio/filter/fractional_interpolator_ff.h"
@@ -131,6 +133,7 @@ GR_SWIG_BLOCK_MAGIC2(filter, fir_filter_fff);
 GR_SWIG_BLOCK_MAGIC2(filter, fir_filter_fsf);
 GR_SWIG_BLOCK_MAGIC2(filter, fir_filter_scc);
 GR_SWIG_BLOCK_MAGIC2(filter, fft_filter_ccc);
+GR_SWIG_BLOCK_MAGIC2(filter, fft_filter_ccf);
 GR_SWIG_BLOCK_MAGIC2(filter, fft_filter_fff);
 GR_SWIG_BLOCK_MAGIC2(filter, fractional_interpolator_cc);
 GR_SWIG_BLOCK_MAGIC2(filter, fractional_interpolator_ff);



reply via email to

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