summaryrefslogtreecommitdiff
path: root/gr-filter
diff options
context:
space:
mode:
authorTom Rondeau2012-06-18 14:37:49 -0400
committerTom Rondeau2012-06-18 14:37:49 -0400
commit622464a324abc90f2724d3f846f0b1bdb38b97fc (patch)
treeb38e86cb7a22090d5a6501b37ac2e4d4ef10d5d8 /gr-filter
parentf5449ce2e0a665b725a27855cd94f28a976da792 (diff)
downloadgnuradio-622464a324abc90f2724d3f846f0b1bdb38b97fc.tar.gz
gnuradio-622464a324abc90f2724d3f846f0b1bdb38b97fc.tar.bz2
gnuradio-622464a324abc90f2724d3f846f0b1bdb38b97fc.zip
filter: adding PFB decimator with GRC and QA.
Diffstat (limited to 'gr-filter')
-rw-r--r--gr-filter/grc/CMakeLists.txt1
-rw-r--r--gr-filter/grc/filter_block_tree.xml1
-rw-r--r--gr-filter/grc/pfb_decimator.xml43
-rw-r--r--gr-filter/include/filter/CMakeLists.txt1
-rw-r--r--gr-filter/include/filter/pfb_channelizer_ccf.h3
-rw-r--r--gr-filter/include/filter/pfb_decimator_ccf.h132
-rw-r--r--gr-filter/lib/CMakeLists.txt1
-rw-r--r--gr-filter/lib/pfb_channelizer_ccf_impl.h1
-rw-r--r--gr-filter/lib/pfb_decimator_ccf_impl.cc137
-rw-r--r--gr-filter/lib/pfb_decimator_ccf_impl.h65
-rwxr-xr-x[-rw-r--r--]gr-filter/python/qa_freq_xlating_fir_filter.py0
-rwxr-xr-x[-rw-r--r--]gr-filter/python/qa_pfb_channelizer.py0
-rwxr-xr-xgr-filter/python/qa_pfb_decimator.py125
-rw-r--r--gr-filter/swig/filter_swig.i3
14 files changed, 511 insertions, 2 deletions
diff --git a/gr-filter/grc/CMakeLists.txt b/gr-filter/grc/CMakeLists.txt
index a269c2b25..a160b00bb 100644
--- a/gr-filter/grc/CMakeLists.txt
+++ b/gr-filter/grc/CMakeLists.txt
@@ -29,6 +29,7 @@ install(FILES
iir_filter_ffd.xml
interp_fir_filter_xxx.xml
pfb_channelizer.xml
+ pfb_decimator.xml
single_pole_iir_filter_xx.xml
DESTINATION ${GRC_BLOCKS_DIR}
COMPONENT "filter_python"
diff --git a/gr-filter/grc/filter_block_tree.xml b/gr-filter/grc/filter_block_tree.xml
index a5630bc88..2a0d02346 100644
--- a/gr-filter/grc/filter_block_tree.xml
+++ b/gr-filter/grc/filter_block_tree.xml
@@ -40,6 +40,7 @@
<block>iir_filter_ffd</block>
<block>interp_fir_filter_xxx</block>
<block>pfb_channelizer_ccf</block>
+ <block>pfb_decimator_ccf</block>
<block>single_pole_iir_filter_xx</block>
</cat>
</cat>
diff --git a/gr-filter/grc/pfb_decimator.xml b/gr-filter/grc/pfb_decimator.xml
new file mode 100644
index 000000000..dea5bdb43
--- /dev/null
+++ b/gr-filter/grc/pfb_decimator.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##Polyphase Channelizer
+###################################################
+ -->
+<block>
+ <name>Polyphase Decimator</name>
+ <key>pfb_decimator_ccf</key>
+ <import>from gnuradio import filter</import>
+ <import>from gnuradio.filter import firdes</import>
+ <make>filter.pfb.decimator_ccf(
+ $decim,
+ $taps,
+ $channel)
+ </make>
+ <callback>set_taps($taps)</callback>
+ <param>
+ <name>Decimation</name>
+ <key>decim</key>
+ <type>int</type>
+ </param>
+ <param>
+ <name>Taps</name>
+ <key>taps</key>
+ <value>None</value>
+ <type>real_vector</type>
+ </param>
+ <param>
+ <name>Output Channel</name>
+ <key>channel</key>
+ <value>0</value>
+ <type>int</type>
+ </param>
+ <sink>
+ <name>in</name>
+ <type>complex</type>
+ </sink>
+ <source>
+ <name>out</name>
+ <type>complex</type>
+ </source>
+</block>
diff --git a/gr-filter/include/filter/CMakeLists.txt b/gr-filter/include/filter/CMakeLists.txt
index e9ba8c246..77ae78e35 100644
--- a/gr-filter/include/filter/CMakeLists.txt
+++ b/gr-filter/include/filter/CMakeLists.txt
@@ -101,6 +101,7 @@ install(FILES
hilbert_fc.h
iir_filter_ffd.h
pfb_channelizer_ccf.h
+ pfb_decimator_ccf.h
single_pole_iir_filter_cc.h
single_pole_iir_filter_ff.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/filter
diff --git a/gr-filter/include/filter/pfb_channelizer_ccf.h b/gr-filter/include/filter/pfb_channelizer_ccf.h
index ab79f7036..ba55782b4 100644
--- a/gr-filter/include/filter/pfb_channelizer_ccf.h
+++ b/gr-filter/include/filter/pfb_channelizer_ccf.h
@@ -26,13 +26,12 @@
#include <filter/api.h>
#include <gr_block.h>
-#include <gruel/thread.h>
namespace gr {
namespace filter {
/*!
- * \class gr_pfb_channelizer_ccf
+ * \class pfb_channelizer_ccf
*
* \brief Polyphase filterbank channelizer with
* gr_complex input, gr_complex output and float taps
diff --git a/gr-filter/include/filter/pfb_decimator_ccf.h b/gr-filter/include/filter/pfb_decimator_ccf.h
new file mode 100644
index 000000000..a933fbb5b
--- /dev/null
+++ b/gr-filter/include/filter/pfb_decimator_ccf.h
@@ -0,0 +1,132 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009,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_PFB_DECIMATOR_CCF_H
+#define INCLUDED_PFB_DECIMATOR_CCF_H
+
+#include <filter/api.h>
+#include <gr_sync_block.h>
+#include <gruel/thread.h>
+
+namespace gr {
+ namespace filter {
+
+ /*!
+ * \class pfb_decimator_ccf
+ * \brief Polyphase filterbank bandpass decimator with gr_complex
+ * input, gr_complex output and float taps
+ *
+ * \ingroup filter_blk
+ * \ingroup pfb_blk
+ *
+ * This block takes in a signal stream and performs interger down-
+ * sampling (decimation) with a polyphase filterbank. The first
+ * input is the integer specifying how much to decimate by. The
+ * second input is a vector (Python list) of floating-point taps
+ * of the prototype filter. The third input specifies the channel
+ * to extract. By default, the zeroth channel is used, which is
+ * the baseband channel (first Nyquist zone).
+ *
+ * The <EM>channel</EM> parameter specifies which channel to use
+ * since this class is capable of bandpass decimation. Given a
+ * complex input stream at a sampling rate of <EM>fs</EM> and a
+ * decimation rate of <EM>decim</EM>, the input frequency domain
+ * is split into <EM>decim</EM> channels that represent the
+ * Nyquist zones. Using the polyphase filterbank, we can select
+ * any one of these channels to decimate.
+ *
+ * The output signal will be the basebanded and decimated signal
+ * from that channel. This concept is very similar to the PFB
+ * channelizer (see #gr_pfb_channelizer_ccf) where only a single
+ * channel is extracted at a time.
+ *
+ * The filter's taps should be based on the sampling rate before
+ * decimation.
+ *
+ * For example, using the GNU Radio's firdes utility to building
+ * filters, we build a low-pass filter with a sampling rate of
+ * <EM>fs</EM>, a 3-dB bandwidth of <EM>BW</EM> and a transition
+ * bandwidth of <EM>TB</EM>. We can also specify the out-of-band
+ * attenuation to use, <EM>ATT</EM>, and the filter window
+ * function (a Blackman-harris window in this case). The first
+ * input is the gain of the filter, which we specify here as
+ * unity.
+ *
+ * <B><EM>self._taps = gr.firdes.low_pass_2(1, fs, BW, TB,
+ * attenuation_dB=ATT, window=gr.firdes.WIN_BLACKMAN_hARRIS)</EM></B>
+ *
+ * The PFB decimator code takes the taps generated above and
+ * builds a set of filters. The set contains <EM>decim</EM> number
+ * of filters and each filter contains ceil(taps.size()/decim)
+ * number of taps. Each tap from the filter prototype is
+ * sequentially inserted into the next filter. When all of the
+ * input taps are used, the remaining filters in the filterbank
+ * are filled out with 0's to make sure each filter has the same
+ * number of taps.
+ *
+ * The theory behind this block can be found in Chapter 6 of
+ * the following book.
+ *
+ * <B><EM>f. harris, "Multirate Signal Processing for Communication
+ * Systems," Upper Saddle River, NJ: Prentice Hall, Inc. 2004.</EM></B>
+ */
+
+ class FILTER_API pfb_decimator_ccf : virtual public gr_sync_block
+ {
+ public:
+ // gr::filter::pfb_decimator_ccf::sptr
+ typedef boost::shared_ptr<pfb_decimator_ccf> sptr;
+
+ /*!
+ * Build the polyphase filterbank decimator.
+ * \param decim (unsigned integer) Specifies the decimation rate to use
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank.
+ * \param channel (unsigned integer) Selects the channel to return [default=0].
+ */
+ static FILTER_API sptr make(unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel);
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank.
+ */
+ virtual void set_taps(const std::vector<float> &taps) = 0;
+
+ /*!
+ * Return a vector<vector<>> of the filterbank taps
+ */
+ virtual std::vector<std::vector<float> > taps() const = 0;
+
+ /*!
+ * Print all of the filterbank taps to screen.
+ */
+ virtual void print_taps() = 0;
+
+ //virtual void set_channel(unsigned int channel) = 0;
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_FILTER_PFB_DECIMATOR_CCF_H */
diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt
index 11135b864..40faa8f0e 100644
--- a/gr-filter/lib/CMakeLists.txt
+++ b/gr-filter/lib/CMakeLists.txt
@@ -128,6 +128,7 @@ list(APPEND filter_sources
hilbert_fc_impl.cc
iir_filter_ffd_impl.cc
pfb_channelizer_ccf_impl.cc
+ pfb_decimator_ccf_impl.cc
single_pole_iir_filter_cc_impl.cc
single_pole_iir_filter_ff_impl.cc
)
diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.h b/gr-filter/lib/pfb_channelizer_ccf_impl.h
index 8cabc4e34..16b112b9a 100644
--- a/gr-filter/lib/pfb_channelizer_ccf_impl.h
+++ b/gr-filter/lib/pfb_channelizer_ccf_impl.h
@@ -27,6 +27,7 @@
#include <filter/polyphase_filterbank.h>
#include <filter/fir_filter.h>
#include <fft/fft.h>
+#include <gruel/thread.h>
namespace gr {
namespace filter {
diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.cc b/gr-filter/lib/pfb_decimator_ccf_impl.cc
new file mode 100644
index 000000000..139cd9bec
--- /dev/null
+++ b/gr-filter/lib/pfb_decimator_ccf_impl.cc
@@ -0,0 +1,137 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009,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 "pfb_decimator_ccf_impl.h"
+#include <gr_io_signature.h>
+
+namespace gr {
+ namespace filter {
+
+ pfb_decimator_ccf::sptr
+ pfb_decimator_ccf::make(unsigned int nfilts,
+ const std::vector<float> &taps,
+ unsigned int channel)
+ {
+ return gnuradio::get_initial_sptr
+ (new pfb_decimator_ccf_impl(nfilts, taps, channel));
+ }
+
+
+ pfb_decimator_ccf_impl::pfb_decimator_ccf_impl(unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel)
+ : gr_sync_block("pfb_decimator_ccf",
+ gr_make_io_signature(decim, decim, sizeof(gr_complex)),
+ gr_make_io_signature(1, 1, sizeof(gr_complex))),
+ polyphase_filterbank(decim, taps),
+ d_updated(false), d_chan(channel)
+ {
+ d_rate = decim;
+ d_rotator = new gr_complex[d_rate];
+
+ set_relative_rate(1.0/(float)decim);
+ set_history(d_taps_per_filter+1);
+ }
+
+ pfb_decimator_ccf_impl::~pfb_decimator_ccf_impl()
+ {
+ }
+
+ void
+ pfb_decimator_ccf_impl::set_taps(const std::vector<float> &taps)
+ {
+ gruel::scoped_lock guard(d_mutex);
+
+ polyphase_filterbank::set_taps(taps);
+ set_history(d_taps_per_filter+1);
+ d_updated = true;
+ }
+
+ void
+ pfb_decimator_ccf_impl::print_taps()
+ {
+ polyphase_filterbank::print_taps();
+ }
+
+ std::vector<std::vector<float> >
+ pfb_decimator_ccf_impl::taps() const
+ {
+ return polyphase_filterbank::taps();
+ }
+
+#define ROTATEFFT
+
+ int
+ pfb_decimator_ccf_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ gruel::scoped_lock guard(d_mutex);
+
+ gr_complex *in;
+ gr_complex *out = (gr_complex *)output_items[0];
+
+ if(d_updated) {
+ d_updated = false;
+ return 0; // history requirements may have changed.
+ }
+
+ int i;
+ for(i = 0; i < noutput_items; i++) {
+ // Move through filters from bottom to top
+ out[i] = 0;
+ for(int j = d_rate-1; j >= 0; j--) {
+ // Take in the items from the first input stream to d_rate
+ in = (gr_complex*)input_items[d_rate - 1 - j];
+
+ // Filter current input stream from bottom filter to top
+ // The rotate them by expj(j*k*2pi/M) where M is the number of filters
+ // (the decimation rate) and k is the channel number to extract
+
+ // This is the real math that goes on; we abuse the FFT to do this quickly
+ // for decimation rates > N where N is a small number (~5):
+ // out[i] += d_filters[j]->filter(&in[i])*gr_expj(j*d_chan*2*M_PI/d_rate);
+#ifdef ROTATEFFT
+ d_fft->get_inbuf()[j] = d_filters[j]->filter(&in[i]);
+#else
+ out[i] += d_filters[j]->filter(&in[i])*d_rotator[i];
+#endif
+ }
+
+#ifdef ROTATEFFT
+ // Perform the FFT to do the complex multiply despinning for all channels
+ d_fft->execute();
+
+ // Select only the desired channel out
+ out[i] = d_fft->get_outbuf()[d_chan];
+#endif
+ }
+
+ return noutput_items;
+ }
+
+ } /* namespace filter */
+} /* namespace gr */
diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.h b/gr-filter/lib/pfb_decimator_ccf_impl.h
new file mode 100644
index 000000000..c4338a5ec
--- /dev/null
+++ b/gr-filter/lib/pfb_decimator_ccf_impl.h
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009,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_PFB_DECIMATOR_CCF_IMPL_H
+#define INCLUDED_PFB_DECIMATOR_CCF_IMPL_H
+
+#include <filter/pfb_decimator_ccf.h>
+#include <filter/polyphase_filterbank.h>
+#include <filter/fir_filter.h>
+#include <fft/fft.h>
+#include <gruel/thread.h>
+
+namespace gr {
+ namespace filter {
+
+ class FILTER_API pfb_decimator_ccf_impl : public pfb_decimator_ccf, kernel::polyphase_filterbank
+ {
+ private:
+ bool d_updated;
+ unsigned int d_rate;
+ unsigned int d_chan;
+ gr_complex *d_rotator;
+ gruel::mutex d_mutex; // mutex to protect set/work access
+
+ public:
+ pfb_decimator_ccf_impl(unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel);
+
+ ~pfb_decimator_ccf_impl();
+
+ void set_taps(const std::vector<float> &taps);
+ void print_taps();
+ std::vector<std::vector<float> > taps() const;
+ //void set_channel(unsigned int channel);
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* INCLUDED_PFB_DECIMATOR_CCF_IMPL_H */
diff --git a/gr-filter/python/qa_freq_xlating_fir_filter.py b/gr-filter/python/qa_freq_xlating_fir_filter.py
index ee38eb7df..ee38eb7df 100644..100755
--- a/gr-filter/python/qa_freq_xlating_fir_filter.py
+++ b/gr-filter/python/qa_freq_xlating_fir_filter.py
diff --git a/gr-filter/python/qa_pfb_channelizer.py b/gr-filter/python/qa_pfb_channelizer.py
index b52c80e8b..b52c80e8b 100644..100755
--- a/gr-filter/python/qa_pfb_channelizer.py
+++ b/gr-filter/python/qa_pfb_channelizer.py
diff --git a/gr-filter/python/qa_pfb_decimator.py b/gr-filter/python/qa_pfb_decimator.py
new file mode 100755
index 000000000..c8fd408be
--- /dev/null
+++ b/gr-filter/python/qa_pfb_decimator.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+#
+# Copyright 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 math
+
+class test_pfb_decimator(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb = gr.top_block()
+
+ def tearDown(self):
+ self.tb = None
+
+ def test_000(self):
+ N = 1000 # number of samples to use
+ M = 5 # Number of channels
+ fs = 1000 # baseband sampling rate
+ ifs = M*fs # input samp rate to decimator
+ channel = 0 # Extract channel 0
+
+ taps = gr.firdes.low_pass_2(1, ifs, fs/2, fs/10,
+ attenuation_dB=80,
+ window=gr.firdes.WIN_BLACKMAN_hARRIS)
+
+ signals = list()
+ add = gr.add_cc()
+ freqs = [-200, -100, 0, 100, 200]
+ for i in xrange(len(freqs)):
+ f = freqs[i] + (M/2-M+i+1)*fs
+ signals.append(gr.sig_source_c(ifs, gr.GR_SIN_WAVE, f, 1))
+ self.tb.connect(signals[i], (add,i))
+
+ head = gr.head(gr.sizeof_gr_complex, N)
+ s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, M)
+ pfb = filter.pfb_decimator_ccf(M, taps, channel)
+ snk = gr.vector_sink_c()
+
+ self.tb.connect(add, head, s2ss)
+ for i in xrange(M):
+ self.tb.connect((s2ss,i), (pfb,i))
+ self.tb.connect(pfb, snk)
+
+ self.tb.run()
+
+ Ntest = 50
+ L = len(snk.data())
+ t = map(lambda x: float(x)/fs, xrange(L))
+
+ # Create known data as complex sinusoids for the baseband freq
+ # of the extracted channel is due to decimator output order.
+ phase = 0
+ expected_data = map(lambda x: math.cos(2.*math.pi*freqs[2]*x+phase) + \
+ 1j*math.sin(2.*math.pi*freqs[2]*x+phase), t)
+
+ dst_data = snk.data()
+
+ self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 4)
+
+ def test_001(self):
+ N = 1000 # number of samples to use
+ M = 5 # Number of channels
+ fs = 1000 # baseband sampling rate
+ ifs = M*fs # input samp rate to decimator
+ channel = 1 # Extract channel 0
+
+ taps = gr.firdes.low_pass_2(1, ifs, fs/2, fs/10,
+ attenuation_dB=80,
+ window=gr.firdes.WIN_BLACKMAN_hARRIS)
+
+ signals = list()
+ add = gr.add_cc()
+ freqs = [-200, -100, 0, 100, 200]
+ for i in xrange(len(freqs)):
+ f = freqs[i] + (M/2-M+i+1)*fs
+ signals.append(gr.sig_source_c(ifs, gr.GR_SIN_WAVE, f, 1))
+ self.tb.connect(signals[i], (add,i))
+
+ head = gr.head(gr.sizeof_gr_complex, N)
+ s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, M)
+ pfb = filter.pfb_decimator_ccf(M, taps, channel)
+ snk = gr.vector_sink_c()
+
+ self.tb.connect(add, head, s2ss)
+ for i in xrange(M):
+ self.tb.connect((s2ss,i), (pfb,i))
+ self.tb.connect(pfb, snk)
+
+ self.tb.run()
+
+ Ntest = 50
+ L = len(snk.data())
+ t = map(lambda x: float(x)/fs, xrange(L))
+
+ # Create known data as complex sinusoids for the baseband freq
+ # of the extracted channel is due to decimator output order.
+ phase = 6.15746
+ expected_data = map(lambda x: math.cos(2.*math.pi*freqs[3]*x+phase) + \
+ 1j*math.sin(2.*math.pi*freqs[3]*x+phase), t)
+ dst_data = snk.data()
+
+ self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 4)
+
+if __name__ == '__main__':
+ gr_unittest.run(test_pfb_decimator, "test_pfb_decimator.xml")
diff --git a/gr-filter/swig/filter_swig.i b/gr-filter/swig/filter_swig.i
index 7a7f548a9..0f814f955 100644
--- a/gr-filter/swig/filter_swig.i
+++ b/gr-filter/swig/filter_swig.i
@@ -60,6 +60,7 @@
#include "filter/interp_fir_filter_fsf.h"
#include "filter/interp_fir_filter_scc.h"
#include "filter/pfb_channelizer_ccf.h"
+#include "filter/pfb_decimator_ccf.h"
#include "filter/single_pole_iir_filter_cc.h"
#include "filter/single_pole_iir_filter_ff.h"
%}
@@ -96,6 +97,7 @@
%include "filter/interp_fir_filter_fsf.h"
%include "filter/interp_fir_filter_scc.h"
%include "filter/pfb_channelizer_ccf.h"
+%include "filter/pfb_decimator_ccf.h"
%include "filter/single_pole_iir_filter_cc.h"
%include "filter/single_pole_iir_filter_ff.h"
@@ -129,5 +131,6 @@ GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_fff);
GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_fsf);
GR_SWIG_BLOCK_MAGIC2(filter, interp_fir_filter_scc);
GR_SWIG_BLOCK_MAGIC2(filter, pfb_channelizer_ccf);
+GR_SWIG_BLOCK_MAGIC2(filter, pfb_decimator_ccf);
GR_SWIG_BLOCK_MAGIC2(filter, single_pole_iir_filter_cc);
GR_SWIG_BLOCK_MAGIC2(filter, single_pole_iir_filter_ff);