[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);
- [Commit-gnuradio] [gnuradio] branch master updated (67882ee -> 103ca46), git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 01/06: blocks: allow subtract block to take a single input to invert the sign., git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 06/06: Merge branch 'pfb_reconstruction', git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 02/06: blocks: allows null source/sink to output/input multiple streams., git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 04/06: filter: use fft_filter inside pfb_decimator., git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 05/06: filters: fixing up some minor issues with the analysis/synthesis filterbanks., git, 2014/02/28
- [Commit-gnuradio] [gnuradio] 03/06: filter: adds a ccf version of the fft filter.,
git <=