summaryrefslogtreecommitdiff
path: root/gr-filter
diff options
context:
space:
mode:
authorTom Rondeau2012-05-02 18:59:23 -0400
committerTom Rondeau2012-05-02 18:59:23 -0400
commit26531c2da601a1c21c50e3644350c604c27f8658 (patch)
tree1ddb4469afc96e508cc54b236c79657dd0c73363 /gr-filter
parent32f807a8c8f1bcadfd8f8ad4c5a46c1b099f8c8f (diff)
downloadgnuradio-26531c2da601a1c21c50e3644350c604c27f8658.tar.gz
gnuradio-26531c2da601a1c21c50e3644350c604c27f8658.tar.bz2
gnuradio-26531c2da601a1c21c50e3644350c604c27f8658.zip
filter: fixed FIR filter taps and added complex FFT filter.
Diffstat (limited to 'gr-filter')
-rwxr-xr-xgr-filter/examples/fft_filter_ccc.py107
-rwxr-xr-xgr-filter/examples/fir_filter_ccc.py101
-rwxr-xr-xgr-filter/examples/fir_filter_fff.py7
-rw-r--r--gr-filter/include/filter/CMakeLists.txt2
-rw-r--r--gr-filter/include/filter/fft_filter.h105
-rw-r--r--gr-filter/include/filter/fft_filter_ccc.h67
-rw-r--r--gr-filter/include/filter/fft_filter_fff.h88
-rw-r--r--gr-filter/include/filter/fir_filter.h7
-rw-r--r--gr-filter/lib/CMakeLists.txt2
-rw-r--r--gr-filter/lib/fft_filter.cc174
-rw-r--r--gr-filter/lib/fft_filter_ccc_impl.cc119
-rw-r--r--gr-filter/lib/fft_filter_ccc_impl.h61
-rw-r--r--gr-filter/lib/fft_filter_fff_impl.cc123
-rw-r--r--gr-filter/lib/fft_filter_fff_impl.h88
-rw-r--r--gr-filter/lib/fir_filter.cc14
-rw-r--r--gr-filter/lib/fir_filter_XXX_impl.cc.t8
-rw-r--r--gr-filter/lib/fir_filter_XXX_impl.h.t2
-rwxr-xr-xgr-filter/python/qa_fft_filter.py380
-rwxr-xr-xgr-filter/python/qa_fir_filter.py22
-rw-r--r--gr-filter/swig/filter_swig.i3
20 files changed, 1463 insertions, 17 deletions
diff --git a/gr-filter/examples/fft_filter_ccc.py b/gr-filter/examples/fft_filter_ccc.py
new file mode 100755
index 000000000..0844c88ef
--- /dev/null
+++ b/gr-filter/examples/fft_filter_ccc.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, filter
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+try:
+ import scipy
+except ImportError:
+ print "Error: could not import scipy (http://www.scipy.org/)"
+ sys.exit(1)
+
+try:
+ import pylab
+except ImportError:
+ print "Error: could not import pylab (http://matplotlib.sourceforge.net/)"
+ sys.exit(1)
+
+class example_fft_filter_ccc(gr.top_block):
+ def __init__(self, N, fs, bw0, bw1, tw, atten, D):
+ gr.top_block.__init__(self)
+
+ self._nsamps = N
+ self._fs = fs
+ self._bw0 = bw0
+ self._bw1 = bw1
+ self._tw = tw
+ self._at = atten
+ self._decim = D
+ taps = gr.firdes.complex_band_pass_2(1, self._fs,
+ self._bw0, self._bw1,
+ self._tw, self._at)
+ print "Num. Taps: ", len(taps)
+
+ self.src = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+ self.head = gr.head(gr.sizeof_gr_complex, self._nsamps)
+
+ self.filt0 = filter.fft_filter_ccc(self._decim, taps)
+ self.filt1 = gr.fft_filter_ccc(self._decim, taps)
+ #self.filt1 = filter.fft_filter_ccc(self._decim, taps)
+
+ self.vsnk_src = gr.vector_sink_c()
+ self.vsnk_out = gr.vector_sink_c()
+ self.vsnk_gr = gr.vector_sink_c()
+
+ self.connect(self.src, self.head, self.vsnk_src)
+ self.connect(self.head, self.filt0, self.vsnk_out)
+ self.connect(self.head, self.filt1, self.vsnk_gr)
+
+def main():
+ parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+ parser.add_option("-N", "--nsamples", type="int", default=10000,
+ help="Number of samples to process [default=%default]")
+ parser.add_option("-s", "--samplerate", type="eng_float", default=8000,
+ help="System sample rate [default=%default]")
+ parser.add_option("-S", "--start-pass", type="eng_float", default=1000,
+ help="Start of Passband [default=%default]")
+ parser.add_option("-E", "--end-pass", type="eng_float", default=2000,
+ help="End of Passband [default=%default]")
+ parser.add_option("-T", "--transition", type="eng_float", default=100,
+ help="Transition band [default=%default]")
+ parser.add_option("-A", "--attenuation", type="eng_float", default=80,
+ help="Stopband attenuation [default=%default]")
+ parser.add_option("-D", "--decimation", type="int", default=1,
+ help="Decmation factor [default=%default]")
+ (options, args) = parser.parse_args ()
+
+ put = example_fft_filter_ccc(options.nsamples,
+ options.samplerate,
+ options.start_pass,
+ options.end_pass,
+ options.transition,
+ options.attenuation,
+ options.decimation)
+ put.run()
+
+ data_src = scipy.array(put.vsnk_src.data())
+ data_snk = scipy.array(put.vsnk_out.data())
+ data_gr = scipy.array(put.vsnk_gr.data())
+
+ # Plot the signals PSDs
+ nfft = 1024
+ f1 = pylab.figure(1, figsize=(12,10))
+ s1 = f1.add_subplot(1,1,1)
+ s1.psd(data_src, NFFT=nfft, noverlap=nfft/4,
+ Fs=options.samplerate)
+ s1.psd(data_snk, NFFT=nfft, noverlap=nfft/4,
+ Fs=options.samplerate)
+ s1.psd(data_gr, NFFT=nfft, noverlap=nfft/4,
+ Fs=options.samplerate)
+
+
+ f2 = pylab.figure(2, figsize=(12,10))
+ s2 = f2.add_subplot(1,1,1)
+ s2.plot(data_src)
+ s2.plot(data_snk.real, 'g')
+ s2.plot(data_gr.real, 'r--')
+
+ pylab.show()
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-filter/examples/fir_filter_ccc.py b/gr-filter/examples/fir_filter_ccc.py
new file mode 100755
index 000000000..57df868f7
--- /dev/null
+++ b/gr-filter/examples/fir_filter_ccc.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, filter
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+try:
+ import scipy
+except ImportError:
+ print "Error: could not import scipy (http://www.scipy.org/)"
+ sys.exit(1)
+
+try:
+ import pylab
+except ImportError:
+ print "Error: could not import pylab (http://matplotlib.sourceforge.net/)"
+ sys.exit(1)
+
+class example_fir_filter_ccc(gr.top_block):
+ def __init__(self, N, fs, bw, tw, atten, D):
+ gr.top_block.__init__(self)
+
+ self._nsamps = N
+ self._fs = fs
+ self._bw = bw
+ self._tw = tw
+ self._at = atten
+ self._decim = D
+ taps = gr.firdes.low_pass_2(1, self._fs, self._bw, self._tw, self._at)
+ print "Num. Taps: ", len(taps)
+
+ self.src = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
+ self.head = gr.head(gr.sizeof_gr_complex, self._nsamps)
+
+ self.filt0 = filter.fir_filter_ccc(self._decim, taps)
+ self.filt1 = gr.fir_filter_ccc(self._decim, taps)
+ #self.filt1 = filter.fft_filter_ccc(self._decim, taps)
+
+ self.vsnk_src = gr.vector_sink_c()
+ self.vsnk_out = gr.vector_sink_c()
+ self.vsnk_gr = gr.vector_sink_c()
+
+ self.connect(self.src, self.head, self.vsnk_src)
+ self.connect(self.head, self.filt0, self.vsnk_out)
+ self.connect(self.head, self.filt1, self.vsnk_gr)
+
+def main():
+ parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
+ parser.add_option("-N", "--nsamples", type="int", default=10000,
+ help="Number of samples to process [default=%default]")
+ parser.add_option("-s", "--samplerate", type="eng_float", default=8000,
+ help="System sample rate [default=%default]")
+ parser.add_option("-B", "--bandwidth", type="eng_float", default=1000,
+ help="Filter bandwidth [default=%default]")
+ parser.add_option("-T", "--transition", type="eng_float", default=100,
+ help="Transition band [default=%default]")
+ parser.add_option("-A", "--attenuation", type="eng_float", default=80,
+ help="Stopband attenuation [default=%default]")
+ parser.add_option("-D", "--decimation", type="int", default=1,
+ help="Decmation factor [default=%default]")
+ (options, args) = parser.parse_args ()
+
+ put = example_fir_filter_ccc(options.nsamples,
+ options.samplerate,
+ options.bandwidth,
+ options.transition,
+ options.attenuation,
+ options.decimation)
+ put.run()
+
+ data_src = scipy.array(put.vsnk_src.data())
+ data_snk = scipy.array(put.vsnk_out.data())
+ data_gr = scipy.array(put.vsnk_gr.data())
+
+ # Plot the signals PSDs
+ nfft = 1024
+ f1 = pylab.figure(1, figsize=(12,10))
+ s1 = f1.add_subplot(1,1,1)
+ s1.psd(data_src, NFFT=nfft, noverlap=nfft/4,
+ Fs=options.samplerate)
+ s1.psd(data_snk, NFFT=nfft, noverlap=nfft/4,
+ Fs=options.samplerate)
+ s1.psd(data_gr, NFFT=nfft, noverlap=nfft/4,
+ Fs=options.samplerate)
+
+
+ f2 = pylab.figure(2, figsize=(12,10))
+ s2 = f2.add_subplot(1,1,1)
+ s2.plot(data_src)
+ s2.plot(data_snk.real, 'g')
+ s2.plot(data_gr.real, 'r--')
+
+ pylab.show()
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ pass
+
diff --git a/gr-filter/examples/fir_filter_fff.py b/gr-filter/examples/fir_filter_fff.py
index 538aded44..1ed889fcf 100755
--- a/gr-filter/examples/fir_filter_fff.py
+++ b/gr-filter/examples/fir_filter_fff.py
@@ -83,6 +83,13 @@ def main():
s1.psd(data_gr, NFFT=nfft, noverlap=nfft/4,
Fs=options.samplerate)
+
+ f2 = pylab.figure(2, figsize=(12,10))
+ s2 = f2.add_subplot(1,1,1)
+ s2.plot(data_src)
+ s2.plot(data_snk.real, 'g')
+ s2.plot(data_gr.real, 'r--')
+
pylab.show()
if __name__ == "__main__":
diff --git a/gr-filter/include/filter/CMakeLists.txt b/gr-filter/include/filter/CMakeLists.txt
index 4889312da..f96128805 100644
--- a/gr-filter/include/filter/CMakeLists.txt
+++ b/gr-filter/include/filter/CMakeLists.txt
@@ -76,7 +76,9 @@ add_custom_target(filter_generated_includes DEPENDS
install(FILES
api.h
fir_filter.h
+ fft_filter.h
${generated_includes}
+ fft_filter_ccc.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/filter
COMPONENT "fft_devel"
)
diff --git a/gr-filter/include/filter/fft_filter.h b/gr-filter/include/filter/fft_filter.h
new file mode 100644
index 000000000..fccea595f
--- /dev/null
+++ b/gr-filter/include/filter/fft_filter.h
@@ -0,0 +1,105 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010,2012 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_H
+#define INCLUDED_FILTER_FFT_FILTER_H
+
+#include <filter/api.h>
+#include <vector>
+#include <gr_complex.h>
+#include <fft/fft.h>
+
+namespace gr {
+ namespace filter {
+ namespace kernel {
+
+ /*!
+ * \brief Fast FFT filter with gr_complex input, gr_complex output and gr_complex taps
+ * \ingroup filter_blk
+ */
+ class FILTER_API fft_filter_ccc
+ {
+ 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<gr_complex> d_new_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 gr_fft_filter_ccc).
+ *
+ * \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_ccc(int decimation,
+ const std::vector<gr_complex> &taps,
+ int nthreads=1);
+
+ ~fft_filter_ccc();
+
+ /*!
+ * \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<gr_complex> &taps);
+
+ /*!
+ * \brief Set number of threads to use.
+ */
+ void set_nthreads(int n);
+
+ /*!
+ * \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);
+ };
+
+ } /* namespace impl */
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_FILTER_FFT_FILTER_H */
diff --git a/gr-filter/include/filter/fft_filter_ccc.h b/gr-filter/include/filter/fft_filter_ccc.h
new file mode 100644
index 000000000..a309ffc22
--- /dev/null
+++ b/gr-filter/include/filter/fft_filter_ccc.h
@@ -0,0 +1,67 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2012 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_CCC_H
+#define INCLUDED_FILTER_FFT_FILTER_CCC_H
+
+#include <filter/api.h>
+#include <gr_sync_decimator.h>
+
+namespace gr {
+ namespace filter {
+
+ class FILTER_API fft_filter_ccc : virtual public gr_sync_decimator
+ {
+ public:
+ // gr::filter::fft_filter::sptr
+ typedef boost::shared_ptr<fft_filter_ccc> sptr;
+
+ /*!
+ * \brief Fast FFT filter with gr_complex input, gr_complex output and gr_complex taps
+ * \ingroup filter_blk
+ *
+ * \param decimation >= 1
+ * \param taps complex filter taps
+ * \param nthreads number of threads for the FFT to use
+ */
+ static FILTER_API sptr make(int decimation,
+ const std::vector<gr_complex> &taps,
+ int nthreads=1);
+
+ virtual void set_taps(const std::vector<gr_complex> &taps) = 0;
+ virtual std::vector<gr_complex> 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_CCC_H */
diff --git a/gr-filter/include/filter/fft_filter_fff.h b/gr-filter/include/filter/fft_filter_fff.h
new file mode 100644
index 000000000..309a55135
--- /dev/null
+++ b/gr-filter/include/filter/fft_filter_fff.h
@@ -0,0 +1,88 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005 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_GR_FFT_FILTER_FFF_H
+#define INCLUDED_GR_FFT_FILTER_FFF_H
+
+#include <gr_core_api.h>
+#include <gr_sync_decimator.h>
+
+class gr_fft_filter_fff;
+typedef boost::shared_ptr<gr_fft_filter_fff> gr_fft_filter_fff_sptr;
+GR_CORE_API gr_fft_filter_fff_sptr
+gr_make_fft_filter_fff (int decimation, const std::vector<float> &taps,
+ int nthreads=1);
+
+class gri_fft_filter_fff_generic;
+//class gri_fft_filter_fff_sse;
+
+/*!
+ * \brief Fast FFT filter with float input, float output and float taps
+ * \ingroup filter_blk
+ */
+class GR_CORE_API gr_fft_filter_fff : public gr_sync_decimator
+{
+ private:
+ friend GR_CORE_API gr_fft_filter_fff_sptr
+ gr_make_fft_filter_fff (int decimation, const std::vector<float> &taps,
+ int nthreads);
+
+ int d_nsamples;
+ bool d_updated;
+#if 1 // don't enable the sse version until handling it is worked out
+ gri_fft_filter_fff_generic *d_filter;
+#else
+ gri_fft_filter_fff_sse *d_filter;
+#endif
+ std::vector<float> d_new_taps;
+
+ /*!
+ * Construct a FFT filter with the given taps
+ *
+ * \param decimation >= 1
+ * \param taps float filter taps
+ * \param nthreads number of threads for the FFT to use
+ */
+ gr_fft_filter_fff (int decimation, const std::vector<float> &taps,
+ int nthreads=1);
+
+ public:
+ ~gr_fft_filter_fff ();
+
+ void set_taps (const std::vector<float> &taps);
+ std::vector<float> taps () const;
+
+ /*!
+ * \brief Set number of threads to use.
+ */
+ void set_nthreads(int n);
+
+ /*!
+ * \brief Get number of threads being used.
+ */
+ int nthreads() const;
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_GR_FFT_FILTER_FFF_H */
diff --git a/gr-filter/include/filter/fir_filter.h b/gr-filter/include/filter/fir_filter.h
index c307fea46..525532fe6 100644
--- a/gr-filter/include/filter/fir_filter.h
+++ b/gr-filter/include/filter/fir_filter.h
@@ -20,13 +20,16 @@
* Boston, MA 02110-1301, USA.
*/
+#ifndef INCLUDED_FILTER_FIR_FILTER_H
+#define INCLUDED_FILTER_FIR_FILTER_H
+
#include <filter/api.h>
#include <vector>
#include <gr_complex.h>
namespace gr {
namespace filter {
- namespace impl {
+ namespace kernel {
class FILTER_API fir_filter_fff
{
@@ -110,3 +113,5 @@ namespace gr {
} /* namespace impl */
} /* namespace filter */
} /* namespace gr */
+
+#endif /* INCLUDED_FILTER_FIR_FILTER_H */
diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt
index 784a3c109..aa03c4615 100644
--- a/gr-filter/lib/CMakeLists.txt
+++ b/gr-filter/lib/CMakeLists.txt
@@ -106,7 +106,9 @@ link_directories(${FFTW3F_LIBRARY_DIRS})
########################################################################
list(APPEND filter_sources
fir_filter.cc
+ fft_filter.cc
${generated_sources}
+ fft_filter_ccc_impl.cc
)
list(APPEND filter_libs
diff --git a/gr-filter/lib/fft_filter.cc b/gr-filter/lib/fft_filter.cc
new file mode 100644
index 000000000..86b2a2fdb
--- /dev/null
+++ b/gr-filter/lib/fft_filter.cc
@@ -0,0 +1,174 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010,2012 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 <filter/fft_filter.h>
+#include <volk/volk.h>
+#include <iostream>
+
+namespace gr {
+ namespace filter {
+ namespace kernel {
+
+ #define VERBOSE 0
+
+ fft_filter_ccc::fft_filter_ccc(int decimation,
+ const std::vector<gr_complex> &taps,
+ int nthreads)
+ : d_fftsize(-1), d_decimation(decimation), d_fwdfft(0),
+ d_invfft(0), d_nthreads(nthreads)
+ {
+ set_taps(taps);
+ }
+
+ fft_filter_ccc::~fft_filter_ccc()
+ {
+ delete d_fwdfft;
+ delete d_invfft;
+ fft::free(d_xformed_taps);
+ }
+
+ /*
+ * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps
+ */
+ int
+ fft_filter_ccc::set_taps(const std::vector<gr_complex> &taps)
+ {
+ int i = 0;
+ 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)
+ {
+ 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_ccc: 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;
+ 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 = fft::malloc_complex(d_fftsize);
+ }
+ }
+
+ void
+ fft_filter_ccc::set_nthreads(int n)
+ {
+ d_nthreads = n;
+ if(d_fwdfft)
+ d_fwdfft->set_nthreads(n);
+ if(d_invfft)
+ d_invfft->set_nthreads(n);
+ }
+
+ int
+ fft_filter_ccc::nthreads() const
+ {
+ 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;
+
+ 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 impl */
+ } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/fft_filter_ccc_impl.cc b/gr-filter/lib/fft_filter_ccc_impl.cc
new file mode 100644
index 000000000..2721f128e
--- /dev/null
+++ b/gr-filter/lib/fft_filter_ccc_impl.cc
@@ -0,0 +1,119 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2010,2012 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_ccc_impl.h"
+#include <gr_io_signature.h>
+
+#include <math.h>
+#include <assert.h>
+#include <stdexcept>
+#include <gr_firdes.h>
+
+namespace gr {
+ namespace filter {
+
+ fft_filter_ccc::sptr fft_filter_ccc::make(int decimation,
+ const std::vector<gr_complex> &taps,
+ int nthreads)
+ {
+ return gnuradio::get_initial_sptr(new fft_filter_ccc_impl
+ (decimation, taps, nthreads));
+ }
+
+ fft_filter_ccc_impl::fft_filter_ccc_impl(int decimation,
+ const std::vector<gr_complex> &taps,
+ int nthreads)
+ : gr_sync_decimator("fft_filter_ccc",
+ gr_make_io_signature (1, 1, sizeof(gr_complex)),
+ gr_make_io_signature (1, 1, sizeof(gr_complex)),
+ decimation),
+ d_updated(false)
+ {
+ set_history(1);
+
+ d_filter = new kernel::fft_filter_ccc(decimation, taps, nthreads);
+
+ d_new_taps = taps;
+ d_nsamples = d_filter->set_taps(taps);
+ set_output_multiple(d_nsamples);
+ }
+
+ fft_filter_ccc_impl::~fft_filter_ccc_impl()
+ {
+ delete d_filter;
+ }
+
+ void
+ fft_filter_ccc_impl::set_taps(const std::vector<gr_complex> &taps)
+ {
+ d_new_taps = taps;
+ d_updated = true;
+ }
+
+ std::vector<gr_complex>
+ fft_filter_ccc_impl::taps() const
+ {
+ return d_new_taps;
+ }
+
+ void
+ fft_filter_ccc_impl::set_nthreads(int n)
+ {
+ if(d_filter)
+ d_filter->set_nthreads(n);
+ }
+
+ int
+ fft_filter_ccc_impl::nthreads() const
+ {
+ if(d_filter)
+ return d_filter->nthreads();
+ else
+ return 0;
+ }
+
+ int
+ fft_filter_ccc_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_ccc_impl.h b/gr-filter/lib/fft_filter_ccc_impl.h
new file mode 100644
index 000000000..2d8d61c5e
--- /dev/null
+++ b/gr-filter/lib/fft_filter_ccc_impl.h
@@ -0,0 +1,61 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2012 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_CCC_IMPL_H
+#define INCLUDED_FILTER_FFT_FILTER_CCC_IMPL_H
+
+#include <filter/api.h>
+#include <filter/fft_filter.h>
+#include <filter/fft_filter_ccc.h>
+
+namespace gr {
+ namespace filter {
+
+ class FILTER_API fft_filter_ccc_impl : public fft_filter_ccc
+ {
+ private:
+ int d_nsamples;
+ bool d_updated;
+ kernel::fft_filter_ccc *d_filter;
+ std::vector<gr_complex> d_new_taps;
+
+ public:
+ fft_filter_ccc_impl(int decimation,
+ const std::vector<gr_complex> &taps,
+ int nthreads=1);
+
+ ~fft_filter_ccc_impl();
+
+ void set_taps(const std::vector<gr_complex> &taps);
+ std::vector<gr_complex> 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_CCC_IMPL_H */
diff --git a/gr-filter/lib/fft_filter_fff_impl.cc b/gr-filter/lib/fft_filter_fff_impl.cc
new file mode 100644
index 000000000..a09feb7f1
--- /dev/null
+++ b/gr-filter/lib/fft_filter_fff_impl.cc
@@ -0,0 +1,123 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2010 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 <gr_fft_filter_fff.h>
+#include <gri_fft_filter_fff_generic.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <stdexcept>
+
+#include <cstdio>
+#include <iostream>
+#include <string.h>
+
+gr_fft_filter_fff_sptr gr_make_fft_filter_fff (int decimation,
+ const std::vector<float> &taps,
+ int nthreads)
+{
+ return gnuradio::get_initial_sptr(new gr_fft_filter_fff (decimation, taps, nthreads));
+}
+
+
+gr_fft_filter_fff::gr_fft_filter_fff (int decimation,
+ const std::vector<float> &taps,
+ int nthreads)
+ : gr_sync_decimator ("fft_filter_fff",
+ gr_make_io_signature (1, 1, sizeof (float)),
+ gr_make_io_signature (1, 1, sizeof (float)),
+ decimation),
+ d_updated(false)
+{
+ set_history(1);
+
+#if 1 // don't enable the sse version until handling it is worked out
+ d_filter = new gri_fft_filter_fff_generic(decimation, taps, nthreads);
+#else
+ d_filter = new gri_fft_filter_fff_sse(decimation, taps);
+#endif
+
+ d_new_taps = taps;
+ d_nsamples = d_filter->set_taps(taps);
+ set_output_multiple(d_nsamples);
+}
+
+gr_fft_filter_fff::~gr_fft_filter_fff ()
+{
+ delete d_filter;
+}
+
+void
+gr_fft_filter_fff::set_taps (const std::vector<float> &taps)
+{
+ d_new_taps = taps;
+ d_updated = true;
+}
+
+std::vector<float>
+gr_fft_filter_fff::taps () const
+{
+ return d_new_taps;
+}
+
+void
+gr_fft_filter_fff::set_nthreads(int n)
+{
+ if(d_filter)
+ d_filter->set_nthreads(n);
+}
+
+int
+gr_fft_filter_fff::nthreads() const
+{
+ if(d_filter)
+ return d_filter->nthreads();
+ else
+ return 0;
+}
+
+int
+gr_fft_filter_fff::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const float *in = (const float *) input_items[0];
+ float *out = (float *) 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
+ }
+
+ assert(noutput_items % d_nsamples == 0);
+
+ d_filter->filter(noutput_items, in, out);
+
+ //assert((out - (float *) output_items[0]) == noutput_items);
+
+ return noutput_items;
+}
diff --git a/gr-filter/lib/fft_filter_fff_impl.h b/gr-filter/lib/fft_filter_fff_impl.h
new file mode 100644
index 000000000..309a55135
--- /dev/null
+++ b/gr-filter/lib/fft_filter_fff_impl.h
@@ -0,0 +1,88 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005 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_GR_FFT_FILTER_FFF_H
+#define INCLUDED_GR_FFT_FILTER_FFF_H
+
+#include <gr_core_api.h>
+#include <gr_sync_decimator.h>
+
+class gr_fft_filter_fff;
+typedef boost::shared_ptr<gr_fft_filter_fff> gr_fft_filter_fff_sptr;
+GR_CORE_API gr_fft_filter_fff_sptr
+gr_make_fft_filter_fff (int decimation, const std::vector<float> &taps,
+ int nthreads=1);
+
+class gri_fft_filter_fff_generic;
+//class gri_fft_filter_fff_sse;
+
+/*!
+ * \brief Fast FFT filter with float input, float output and float taps
+ * \ingroup filter_blk
+ */
+class GR_CORE_API gr_fft_filter_fff : public gr_sync_decimator
+{
+ private:
+ friend GR_CORE_API gr_fft_filter_fff_sptr
+ gr_make_fft_filter_fff (int decimation, const std::vector<float> &taps,
+ int nthreads);
+
+ int d_nsamples;
+ bool d_updated;
+#if 1 // don't enable the sse version until handling it is worked out
+ gri_fft_filter_fff_generic *d_filter;
+#else
+ gri_fft_filter_fff_sse *d_filter;
+#endif
+ std::vector<float> d_new_taps;
+
+ /*!
+ * Construct a FFT filter with the given taps
+ *
+ * \param decimation >= 1
+ * \param taps float filter taps
+ * \param nthreads number of threads for the FFT to use
+ */
+ gr_fft_filter_fff (int decimation, const std::vector<float> &taps,
+ int nthreads=1);
+
+ public:
+ ~gr_fft_filter_fff ();
+
+ void set_taps (const std::vector<float> &taps);
+ std::vector<float> taps () const;
+
+ /*!
+ * \brief Set number of threads to use.
+ */
+ void set_nthreads(int n);
+
+ /*!
+ * \brief Get number of threads being used.
+ */
+ int nthreads() const;
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_GR_FFT_FILTER_FFF_H */
diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc
index 5f0e0912d..321f6981e 100644
--- a/gr-filter/lib/fir_filter.cc
+++ b/gr-filter/lib/fir_filter.cc
@@ -26,7 +26,7 @@
namespace gr {
namespace filter {
- namespace impl {
+ namespace kernel {
fir_filter_fff::fir_filter_fff(int decimation,
const std::vector<float> &taps)
@@ -55,7 +55,7 @@ namespace gr {
d_ntaps = (int)taps.size();
d_taps = fft::malloc_float(d_ntaps);
for(unsigned int i = 0; i < d_ntaps; i++) {
- d_taps[i] = taps[i];
+ d_taps[d_ntaps-i-1] = taps[i];
}
}
@@ -64,7 +64,7 @@ namespace gr {
{
std::vector<float> t;
for(unsigned int i = 0; i < d_ntaps; i++)
- t.push_back(d_taps[i]);
+ t.push_back(d_taps[d_ntaps-i-1]);
return t;
}
@@ -134,7 +134,7 @@ namespace gr {
d_ntaps = (int)taps.size();
d_taps = fft::malloc_complex(d_ntaps);
for(unsigned int i = 0; i < d_ntaps; i++) {
- d_taps[i] = gr_complex(taps[i],0);
+ d_taps[d_ntaps-i-1] = gr_complex(taps[i],0);
}
}
@@ -143,7 +143,7 @@ namespace gr {
{
std::vector<float> t;
for(unsigned int i = 0; i < d_ntaps; i++)
- t.push_back(d_taps[i].real());
+ t.push_back(d_taps[d_ntaps-i-1].real());
return t;
}
@@ -213,7 +213,7 @@ namespace gr {
d_ntaps = (int)taps.size();
d_taps = fft::malloc_complex(d_ntaps);
for(unsigned int i = 0; i < d_ntaps; i++) {
- d_taps[i] = taps[i];
+ d_taps[d_ntaps-i-1] = taps[i];
}
}
@@ -222,7 +222,7 @@ namespace gr {
{
std::vector<gr_complex> t;
for(unsigned int i = 0; i < d_ntaps; i++)
- t.push_back(d_taps[i]);
+ t.push_back(d_taps[d_ntaps-i-1]);
return t;
}
diff --git a/gr-filter/lib/fir_filter_XXX_impl.cc.t b/gr-filter/lib/fir_filter_XXX_impl.cc.t
index 70c3fba3f..c3637042d 100644
--- a/gr-filter/lib/fir_filter_XXX_impl.cc.t
+++ b/gr-filter/lib/fir_filter_XXX_impl.cc.t
@@ -26,8 +26,6 @@
#include "@IMPL_NAME@.h"
#include <gr_io_signature.h>
-#include <volk/volk.h>
-#include <fft/fft.h>
namespace gr {
namespace filter {
@@ -46,9 +44,9 @@ namespace gr {
gr_make_io_signature(1, 1, sizeof(@O_TYPE@)),
decimation)
{
- d_fir = new impl::@BASE_NAME@(decimation, taps);
+ d_fir = new kernel::@BASE_NAME@(decimation, taps);
d_updated = false;
- set_history(d_fir->ntaps()+1);
+ set_history(d_fir->ntaps());
}
@IMPL_NAME@::~@IMPL_NAME@()
@@ -78,7 +76,7 @@ namespace gr {
@O_TYPE@ *out = (@O_TYPE@*)output_items[0];
if (d_updated) {
- set_history(d_fir->ntaps()+1);
+ set_history(d_fir->ntaps());
d_updated = false;
return 0; // history requirements may have changed.
}
diff --git a/gr-filter/lib/fir_filter_XXX_impl.h.t b/gr-filter/lib/fir_filter_XXX_impl.h.t
index a40c49bf2..d5bf7104d 100644
--- a/gr-filter/lib/fir_filter_XXX_impl.h.t
+++ b/gr-filter/lib/fir_filter_XXX_impl.h.t
@@ -35,7 +35,7 @@ namespace gr {
class FILTER_API @IMPL_NAME@ : public @BASE_NAME@
{
private:
- impl::@BASE_NAME@ *d_fir;
+ kernel::@BASE_NAME@ *d_fir;
bool d_updated;
public:
diff --git a/gr-filter/python/qa_fft_filter.py b/gr-filter/python/qa_fft_filter.py
new file mode 100755
index 000000000..33d3d870b
--- /dev/null
+++ b/gr-filter/python/qa_fft_filter.py
@@ -0,0 +1,380 @@
+#!/usr/bin/env python
+#
+# Copyright 2004,2005,2007,2010,2012 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.
+#
+
+from gnuradio import gr, gr_unittest
+import filter_swig as filter
+import sys
+import random
+
+def make_random_complex_tuple(L):
+ result = []
+ for x in range(L):
+ result.append(complex(random.uniform(-1000,1000),
+ random.uniform(-1000,1000)))
+ return tuple(result)
+
+def make_random_float_tuple(L):
+ result = []
+ for x in range(L):
+ result.append(float(int(random.uniform(-1000,1000))))
+ return tuple(result)
+
+
+def reference_filter_ccc(dec, taps, input):
+ """
+ compute result using conventional fir filter
+ """
+ tb = gr.top_block()
+ #src = gr.vector_source_c(((0,) * (len(taps) - 1)) + input)
+ src = gr.vector_source_c(input)
+ op = filter.fir_filter_ccc(dec, taps)
+ dst = gr.vector_sink_c()
+ tb.connect(src, op, dst)
+ tb.run()
+ return dst.data()
+
+def reference_filter_fff(dec, taps, input):
+ """
+ compute result using conventional fir filter
+ """
+ tb = gr.top_block()
+ #src = gr.vector_source_f(((0,) * (len(taps) - 1)) + input)
+ src = gr.vector_source_f(input)
+ op = filter.fir_filter_fff(dec, taps)
+ dst = gr.vector_sink_f()
+ tb.connect(src, op, dst)
+ tb.run()
+ return dst.data()
+
+
+def print_complex(x):
+ for i in x:
+ i = complex(i)
+ sys.stdout.write("(%6.3f,%6.3fj), " % (i.real, i.imag))
+ sys.stdout.write('\n')
+
+
+class test_fft_filter(gr_unittest.TestCase):
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def assert_fft_ok2(self, expected_result, result_data):
+ expected_result = expected_result[:len(result_data)]
+ self.assertComplexTuplesAlmostEqual2 (expected_result, result_data,
+ abs_eps=1e-9, rel_eps=4e-4)
+
+ def assert_fft_float_ok2(self, expected_result, result_data, abs_eps=1e-9, rel_eps=4e-4):
+ expected_result = expected_result[:len(result_data)]
+ self.assertFloatTuplesAlmostEqual2 (expected_result, result_data,
+ abs_eps, rel_eps)
+
+ def test_ccc_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 = gr.vector_source_c(src_data)
+ op = gr.fft_filter_ccc(1, taps)
+ dst = gr.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_ccc_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 = gr.vector_source_c(src_data)
+ op = gr.fft_filter_ccc(1, taps, nthreads)
+ dst = gr.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_ccc_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 = gr.vector_source_c(src_data)
+ op = gr.fft_filter_ccc(1, taps)
+ dst = gr.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_ccc_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_complex_tuple(ntaps)
+ expected_result = reference_filter_ccc(1, taps, src_data)
+
+ src = gr.vector_source_c(src_data)
+ op = filter.fft_filter_ccc(1, taps)
+ dst = gr.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_ccc_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_complex_tuple(ntaps)
+ expected_result = reference_filter_ccc(dec, taps, src_data)
+
+ src = gr.vector_source_c(src_data)
+ op = gr.fft_filter_ccc(dec, taps)
+ dst = gr.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_ccc_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_complex_tuple(ntaps)
+ expected_result = reference_filter_ccc(dec, taps, src_data)
+
+ src = gr.vector_source_c(src_data)
+ op = filter.fft_filter_ccc(dec, taps, nthreads)
+ dst = gr.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
+ # ----------------------------------------------------------------
+
+ def test_fff_001(self):
+ tb = gr.top_block()
+ src_data = (0,1,2,3,4,5,6,7)
+ taps = (1,)
+ expected_result = tuple([float(x) for x in (0,1,2,3,4,5,6,7)])
+ src = gr.vector_source_f(src_data)
+ op = gr.fft_filter_fff(1, taps)
+ dst = gr.vector_sink_f()
+ tb.connect(src, op, dst)
+ tb.run()
+ result_data = dst.data()
+ #print 'expected:', expected_result
+ #print 'results: ', result_data
+ self.assertFloatTuplesAlmostEqual (expected_result, result_data, 5)
+
+
+ def test_fff_002(self):
+ tb = gr.top_block()
+ src_data = (0,1,2,3,4,5,6,7)
+ taps = (2,)
+ expected_result = tuple([2 * float(x) for x in (0,1,2,3,4,5,6,7)])
+ src = gr.vector_source_f(src_data)
+ op = gr.fft_filter_fff(1, taps)
+ dst = gr.vector_sink_f()
+ tb.connect(src, op, dst)
+ tb.run()
+ result_data = dst.data()
+ #print 'expected:', expected_result
+ #print 'results: ', result_data
+ self.assertFloatTuplesAlmostEqual (expected_result, result_data, 5)
+
+ def test_fff_003(self):
+ # Test 02 with nthreads
+ tb = gr.top_block()
+ src_data = (0,1,2,3,4,5,6,7)
+ taps = (2,)
+ nthreads = 2
+ expected_result = tuple([2 * float(x) for x in (0,1,2,3,4,5,6,7)])
+ src = gr.vector_source_f(src_data)
+ op = gr.fft_filter_fff(1, taps, nthreads)
+ dst = gr.vector_sink_f()
+ tb.connect(src, op, dst)
+ tb.run()
+ result_data = dst.data()
+ self.assertFloatTuplesAlmostEqual (expected_result, result_data, 5)
+
+ def xtest_fff_004(self):
+ random.seed(0)
+ for i in xrange(25):
+ sys.stderr.write("\n>>> Loop = %d\n" % (i,))
+ src_len = 4096
+ src_data = make_random_float_tuple(src_len)
+ ntaps = int(random.uniform(2, 1000))
+ taps = make_random_float_tuple(ntaps)
+ expected_result = reference_filter_fff(1, taps, src_data)
+
+ src = gr.vector_source_f(src_data)
+ op = gr.fft_filter_fff(1, taps)
+ dst = gr.vector_sink_f()
+ tb = gr.top_block()
+ tb.connect(src, op, dst)
+ tb.run()
+ result_data = dst.data()
+
+ #print "src_len =", src_len, " ntaps =", ntaps
+ try:
+ self.assert_fft_float_ok2(expected_result, result_data, abs_eps=1.0)
+ except:
+ expected = open('expected', 'w')
+ for x in expected_result:
+ expected.write(`x` + '\n')
+ actual = open('actual', 'w')
+ for x in result_data:
+ actual.write(`x` + '\n')
+ raise
+
+ def xtest_fff_005(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_float_tuple(src_len)
+ ntaps = int(random.uniform(2, 1000))
+ taps = make_random_float_tuple(ntaps)
+ expected_result = reference_filter_fff(1, taps, src_data)
+
+ src = gr.vector_source_f(src_data)
+ op = gr.fft_filter_fff(1, taps)
+ dst = gr.vector_sink_f()
+ tb = gr.top_block()
+ tb.connect(src, op, dst)
+ tb.run()
+ result_data = dst.data()
+
+ self.assert_fft_float_ok2(expected_result, result_data, abs_eps=2.0)
+
+ def xtest_fff_006(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_float_tuple(src_len)
+ ntaps = int(random.uniform(2, 100))
+ taps = make_random_float_tuple(ntaps)
+ expected_result = reference_filter_fff(dec, taps, src_data)
+
+ src = gr.vector_source_f(src_data)
+ op = gr.fft_filter_fff(dec, taps)
+ dst = gr.vector_sink_f()
+ tb = gr.top_block()
+ tb.connect(src, op, dst)
+ tb.run()
+ result_data = dst.data()
+
+ self.assert_fft_float_ok2(expected_result, result_data)
+
+ def xtest_fff_007(self):
+ # test decimation with nthreads
+ 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_float_tuple(src_len)
+ ntaps = int(random.uniform(2, 100))
+ taps = make_random_float_tuple(ntaps)
+ expected_result = reference_filter_fff(dec, taps, src_data)
+
+ src = gr.vector_source_f(src_data)
+ op = gr.fft_filter_fff(dec, taps, nthreads)
+ dst = gr.vector_sink_f()
+ tb = gr.top_block()
+ tb.connect(src, op, dst)
+ tb.run()
+ result_data = dst.data()
+
+ self.assert_fft_float_ok2(expected_result, result_data)
+
+ def test_fff_get0(self):
+ random.seed(0)
+ for i in xrange(25):
+ ntaps = int(random.uniform(2, 100))
+ taps = make_random_float_tuple(ntaps)
+
+ op = gr.fft_filter_fff(1, taps)
+ result_data = op.taps()
+ #print result_data
+
+ self.assertEqual(taps, result_data)
+
+ def test_ccc_get0(self):
+ random.seed(0)
+ for i in xrange(25):
+ ntaps = int(random.uniform(2, 100))
+ taps = make_random_complex_tuple(ntaps)
+
+ op = gr.fft_filter_ccc(1, taps)
+ result_data = op.taps()
+ #print result_data
+
+ self.assertComplexTuplesAlmostEqual(taps, result_data, 4)
+
+
+if __name__ == '__main__':
+ gr_unittest.run(test_fft_filter, "test_fft_filter.xml")
+
diff --git a/gr-filter/python/qa_fir_filter.py b/gr-filter/python/qa_fir_filter.py
index 2c88e7830..f0f08afca 100755
--- a/gr-filter/python/qa_fir_filter.py
+++ b/gr-filter/python/qa_fir_filter.py
@@ -32,7 +32,7 @@ class test_filter(gr_unittest.TestCase):
def test_fir_filter_fff_001(self):
src_data = [1, 2, 3, 4]
- expected_data = [0, 0.5, 1.5, 2.5]
+ expected_data = [0.5, 1.5, 2.5, 3.5]
src = gr.vector_source_f(src_data)
op = filter.fir_filter_fff(1, [0.5, 0.5])
dst = gr.vector_sink_f()
@@ -43,7 +43,7 @@ class test_filter(gr_unittest.TestCase):
def test_fir_filter_ccf_001(self):
src_data = [1+1j, 2+2j, 3+3j, 4+4j]
- expected_data = [0+0j, 0.5+0.5j, 1.5+1.5j, 2.5+2.5j]
+ expected_data = [0.5+0.5j, 1.5+1.5j, 2.5+2.5j, 3.5+3.5j]
src = gr.vector_source_c(src_data)
op = filter.fir_filter_ccf(1, [0.5, 0.5])
dst = gr.vector_sink_c()
@@ -54,7 +54,7 @@ class test_filter(gr_unittest.TestCase):
def test_fir_filter_ccc_001(self):
src_data = [1+1j, 2+2j, 3+3j, 4+4j]
- expected_data = [0+0j, -0.5+1.5j, -1.5+4.5j, -2.5+7.5j]
+ expected_data = [-0.5+1.5j, -1.5+4.5j, -2.5+7.5j, -3.5+10.5j]
src = gr.vector_source_c(src_data)
op = filter.fir_filter_ccc(1, [0.5+1j, 0.5+1j])
dst = gr.vector_sink_c()
@@ -63,6 +63,22 @@ class test_filter(gr_unittest.TestCase):
result_data = dst.data()
self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5)
+
+ def test_fir_filter_ccc_002(self):
+ src_data = 10*[1+1j, 2+2j, 3+3j, 4+4j]
+
+ # results derived from original gr.fir_filter_ccc
+ expected_data = ((7.537424837948042e-20+7.537424837948042e-20j), (9.131923434324563e-05+9.131923434324563e-05j), (0.0003317668742965907+0.0003317668742965907j), (0.0007230418268591166+0.0007230418268591166j), (0.0012087896466255188+0.0012087896466255188j), (0.0013292605290189385+0.0013292605290189385j), (0.001120875240303576+0.001120875240303576j), (0.000744672492146492+0.000744672492146492j), (0.000429437990533188+0.000429437990533188j), (2.283908543176949e-05+2.283908543176949e-05j), (-0.0002245186478830874-0.0002245186478830874j), (-0.0001157080550910905-0.0001157080550910905j), (0.00041409023106098175+0.00041409023106098175j), (0.0009017843985930085+0.0009017843985930085j), (0.0012520025484263897+0.0012520025484263897j), (0.0014116164529696107+0.0014116164529696107j), (0.001393353333696723+0.001393353333696723j), (0.000912194955162704+0.000912194955162704j), (0.00022649182938039303+0.00022649182938039303j), (-0.00031363096786662936-0.00031363096786662936j), (-0.0003966730728279799-0.0003966730728279799j), (-0.00023757052258588374-0.00023757052258588374j), (0.00021952332463115454+0.00021952332463115454j), (0.0009092430118471384+0.0009092430118471384j), (0.001662317430600524+0.001662317430600524j), (0.0019024648936465383+0.0019024648936465383j), (0.0015955769922584295+0.0015955769922584295j), (0.0009144138311967254+0.0009144138311967254j), (0.0001872836146503687+0.0001872836146503687j), (-0.000581968342885375-0.000581968342885375j), (-0.0009886166080832481-0.0009886166080832481j), (-0.0007480768254026771-0.0007480768254026771j), (0.00018211957649327815+0.00018211957649327815j), (0.0012042406015098095+0.0012042406015098095j), (0.0020200139842927456+0.0020200139842927456j), (0.0023816542234271765+0.0023816542234271765j), (0.002195809967815876+0.002195809967815876j), (0.0012113333214074373+0.0012113333214074373j), (-0.00014088614261709154-0.00014088614261709154j), (-0.0012574587017297745-0.0012574587017297745j))
+
+ taps = gr.firdes.low_pass(1, 1, 0.1, 0.01)
+ src = gr.vector_source_c(src_data)
+ op = filter.fir_filter_ccc(1, taps)
+ dst = gr.vector_sink_c()
+ self.tb.connect(src, op, dst)
+ self.tb.run()
+ result_data = dst.data()
+ self.assertComplexTuplesAlmostEqual(expected_data, result_data, 5)
+
if __name__ == '__main__':
gr_unittest.run(test_filter, "test_filter.xml")
diff --git a/gr-filter/swig/filter_swig.i b/gr-filter/swig/filter_swig.i
index 28268528a..94ad9cd64 100644
--- a/gr-filter/swig/filter_swig.i
+++ b/gr-filter/swig/filter_swig.i
@@ -31,12 +31,15 @@
#include "filter/fir_filter_fff.h"
#include "filter/fir_filter_ccf.h"
#include "filter/fir_filter_ccc.h"
+#include "filter/fft_filter_ccc.h"
%}
%include "filter/fir_filter_fff.h"
%include "filter/fir_filter_ccf.h"
%include "filter/fir_filter_ccc.h"
+%include "filter/fft_filter_ccc.h"
GR_SWIG_BLOCK_MAGIC2(filter, fir_filter_fff);
GR_SWIG_BLOCK_MAGIC2(filter, fir_filter_ccf);
GR_SWIG_BLOCK_MAGIC2(filter, fir_filter_ccc);
+GR_SWIG_BLOCK_MAGIC2(filter, fft_filter_ccc);