summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/lib
diff options
context:
space:
mode:
authortrondeau2009-08-12 03:39:03 +0000
committertrondeau2009-08-12 03:39:03 +0000
commita0d13b42bfb3fd081d77e9d73cf4db9695a6d88b (patch)
tree1407e44ca9f51399c9ee0a0fe51789fa1f3fcf91 /gnuradio-core/src/lib
parent420f1274bfd7cb40cd6d7851f6541f80ac6616be (diff)
downloadgnuradio-a0d13b42bfb3fd081d77e9d73cf4db9695a6d88b.tar.gz
gnuradio-a0d13b42bfb3fd081d77e9d73cf4db9695a6d88b.tar.bz2
gnuradio-a0d13b42bfb3fd081d77e9d73cf4db9695a6d88b.zip
Merging trondeau/pfb r11249:11581 into trunk. This adds a few polyphase filterbank implementations that do (integer) decimation, (integer) interpolation, arbitrary resampling, and channelizing. gnuradio-example/python/pfb includes a number of different examples of how to use these blocks.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@11583 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gnuradio-core/src/lib')
-rw-r--r--gnuradio-core/src/lib/filter/Makefile.am16
-rw-r--r--gnuradio-core/src/lib/filter/filter.i13
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc196
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h158
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.i41
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc150
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h144
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i38
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc174
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h148
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.i41
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc142
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h129
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.i39
14 files changed, 1426 insertions, 3 deletions
diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am
index e230e88b5..838f69b92 100644
--- a/gnuradio-core/src/lib/filter/Makefile.am
+++ b/gnuradio-core/src/lib/filter/Makefile.am
@@ -201,7 +201,11 @@ libfilter_la_common_SOURCES = \
complex_dotprod_generic.cc \
ccomplex_dotprod_generic.cc \
float_dotprod_generic.c \
- short_dotprod_generic.c
+ short_dotprod_generic.c \
+ gr_pfb_channelizer_ccf.cc \
+ gr_pfb_decimator_ccf.cc \
+ gr_pfb_interpolator_ccf.cc \
+ gr_pfb_arb_resampler_ccf.cc
libfilter_qa_la_common_SOURCES = \
qa_filter.cc \
@@ -276,7 +280,11 @@ grinclude_HEADERS = \
qa_filter.h \
short_dotprod_generic.h \
short_dotprod_x86.h \
- sse_debug.h
+ sse_debug.h \
+ gr_pfb_channelizer_ccf.h \
+ gr_pfb_decimator_ccf.h \
+ gr_pfb_interpolator_ccf.h \
+ gr_pfb_arb_resampler_ccf.h
noinst_HEADERS = \
assembly.h \
@@ -327,6 +335,10 @@ swiginclude_HEADERS = \
gr_iir_filter_ffd.i \
gr_single_pole_iir_filter_ff.i \
gr_single_pole_iir_filter_cc.i \
+ gr_pfb_channelizer_ccf.i \
+ gr_pfb_decimator_ccf.i \
+ gr_pfb_interpolator_ccf.i \
+ gr_pfb_arb_resampler_ccf.i \
$(GENERATED_I)
endif
diff --git a/gnuradio-core/src/lib/filter/filter.i b/gnuradio-core/src/lib/filter/filter.i
index 7931a4d53..16b8005be 100644
--- a/gnuradio-core/src/lib/filter/filter.i
+++ b/gnuradio-core/src/lib/filter/filter.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2004,2005,2006,2007 Free Software Foundation, Inc.
+ * Copyright 2004,2005,2006,2007,2009 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -32,6 +32,10 @@
#include <gr_fractional_interpolator_cc.h>
#include <gr_goertzel_fc.h>
#include <gr_cma_equalizer_cc.h>
+#include <gr_pfb_channelizer_ccf.h>
+#include <gr_pfb_decimator_ccf.h>
+#include <gr_pfb_interpolator_ccf.h>
+#include <gr_pfb_arb_resampler_ccf.h>
%}
%include "gr_iir_filter_ffd.i"
@@ -45,5 +49,12 @@
%include "gr_fractional_interpolator_cc.i"
%include "gr_goertzel_fc.i"
%include "gr_cma_equalizer_cc.i"
+%include "gr_pfb_channelizer_ccf.i"
+%include "gr_pfb_decimator_ccf.i"
+%include "gr_pfb_interpolator_ccf.i"
+%include "gr_pfb_arb_resampler_ccf.i"
+%include "gr_pfb_decimator_ccf.i"
+%include "gr_pfb_interpolator_ccf.i"
+%include "gr_pfb_arb_resampler_ccf.i"
%include "filter_generated.i"
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc
new file mode 100644
index 000000000..bfc4c0467
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc
@@ -0,0 +1,196 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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_pfb_arb_resampler_ccf.h>
+#include <gr_fir_ccf.h>
+#include <gr_fir_util.h>
+#include <gr_io_signature.h>
+
+gr_pfb_arb_resampler_ccf_sptr gr_make_pfb_arb_resampler_ccf (float rate,
+ const std::vector<float> &taps,
+ unsigned int filter_size)
+{
+ return gr_pfb_arb_resampler_ccf_sptr (new gr_pfb_arb_resampler_ccf (rate, taps,
+ filter_size));
+}
+
+
+gr_pfb_arb_resampler_ccf::gr_pfb_arb_resampler_ccf (float rate,
+ const std::vector<float> &taps,
+ unsigned int filter_size)
+ : gr_block ("pfb_arb_resampler_ccf",
+ gr_make_io_signature (1, 1, sizeof(gr_complex)),
+ gr_make_io_signature (1, 1, sizeof(gr_complex))),
+ d_updated (false)
+{
+ /* The number of filters is specified by the user as the filter size;
+ this is also the interpolation rate of the filter. We use it and the
+ rate provided to determine the decimation rate. This acts as a
+ rational resampler. The flt_rate is calculated as the residual
+ between the integer decimation rate and the real decimation rate and
+ will be used to determine to interpolation point of the resampling
+ process.
+ */
+ d_int_rate = filter_size;
+ d_dec_rate = (unsigned int)floor(d_int_rate/rate);
+ d_flt_rate = (d_int_rate/rate) - d_dec_rate;
+
+ // The accumulator keeps track of overflow to increment the stride correctly.
+ d_acc = 0;
+
+ // Store the last filter between calls to work
+ d_last_filter = 0;
+
+ d_filters = std::vector<gr_fir_ccf*>(d_int_rate);
+
+ // Create an FIR filter for each channel and zero out the taps
+ std::vector<float> vtaps(0, d_int_rate);
+ for(unsigned int i = 0; i < d_int_rate; i++) {
+ d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps);
+ }
+
+ // Now, actually set the filters' taps
+ set_taps(taps);
+}
+
+gr_pfb_arb_resampler_ccf::~gr_pfb_arb_resampler_ccf ()
+{
+ for(unsigned int i = 0; i < d_int_rate; i++) {
+ delete d_filters[i];
+ }
+}
+
+void
+gr_pfb_arb_resampler_ccf::set_taps (const std::vector<float> &taps)
+{
+ unsigned int i,j;
+
+ unsigned int ntaps = taps.size();
+ d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate);
+
+ // Create d_numchan vectors to store each channel's taps
+ d_taps.resize(d_int_rate);
+
+ // Make a vector of the taps plus fill it out with 0's to fill
+ // each polyphase filter with exactly d_taps_per_filter
+ std::vector<float> tmp_taps;
+ tmp_taps = taps;
+ while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) {
+ tmp_taps.push_back(0.0);
+ }
+
+ // Partition the filter
+ for(i = 0; i < d_int_rate; i++) {
+ // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
+ d_taps[i] = std::vector<float>(d_taps_per_filter, 0);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ d_taps[i][j] = tmp_taps[i + j*d_int_rate]; // add taps to channels in reverse order
+ }
+
+ // Build a filter for each channel and add it's taps to it
+ d_filters[i]->set_taps(d_taps[i]);
+ }
+
+ // Set the history to ensure enough input items for each filter
+ set_history (d_taps_per_filter);
+
+ d_updated = true;
+}
+
+void
+gr_pfb_arb_resampler_ccf::print_taps()
+{
+ unsigned int i, j;
+ for(i = 0; i < d_int_rate; i++) {
+ printf("filter[%d]: [", i);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ printf(" %.4e", d_taps[i][j]);
+ }
+ printf("]\n");
+ }
+}
+
+int
+gr_pfb_arb_resampler_ccf::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ gr_complex *in = (gr_complex *) input_items[0];
+ gr_complex *out = (gr_complex *) output_items[0];
+
+ if (d_updated) {
+ d_updated = false;
+ return 0; // history requirements may have changed.
+ }
+
+ int i = 0, j, count = 0;
+ gr_complex o0, o1;
+
+ // Restore the last filter position
+ j = d_last_filter;
+
+ // produce output as long as we can and there are enough input samples
+ while((i < noutput_items) && (count < ninput_items[0]-1)) {
+
+ // start j by wrapping around mod the number of channels
+ while((j < d_int_rate) && (i < noutput_items)) {
+ // Take the current filter output
+ o0 = d_filters[j]->filter(&in[count]);
+
+ // Take the next filter output; wrap around to 0 if necessary
+ if(j+1 == d_int_rate)
+ // Use the sample of the next input item through the first filter
+ o1 = d_filters[0]->filter(&in[count+1]);
+ else {
+ // Use the sample from the current input item through the nex filter
+ o1 = d_filters[j+1]->filter(&in[count]);
+ }
+
+ //out[i] = o0; // nearest-neighbor approach
+ out[i] = o0 + (o1 - o0)*d_acc; // linearly interpolate between samples
+ i++;
+
+ // Accumulate the position in the stream for the interpolated point.
+ // If it goes above 1, roll around to zero and increment the stride
+ // length this time by the decimation rate plus 1 for the increment
+ // due to the acculated position.
+ d_acc += d_flt_rate;
+ j += d_dec_rate + (int)floor(d_acc);
+ d_acc = fmodf(d_acc, 1.0);
+ }
+ if(i < noutput_items) { // keep state for next entry
+ count++; // we have fully consumed another input
+ j = j % d_int_rate; // roll filter around
+ }
+ }
+
+ // Store the current filter position
+ d_last_filter = j;
+
+ consume_each(count);
+ return i;
+}
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
new file mode 100644
index 000000000..b79a89fe9
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
@@ -0,0 +1,158 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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_PFB_ARB_RESAMPLER_CCF_H
+#define INCLUDED_GR_PFB_ARB_RESAMPLER_CCF_H
+
+#include <gr_block.h>
+
+class gr_pfb_arb_resampler_ccf;
+typedef boost::shared_ptr<gr_pfb_arb_resampler_ccf> gr_pfb_arb_resampler_ccf_sptr;
+gr_pfb_arb_resampler_ccf_sptr gr_make_pfb_arb_resampler_ccf (float rate,
+ const std::vector<float> &taps,
+ unsigned int filter_size=32);
+
+class gr_fir_ccf;
+
+/*!
+ * \class gr_pfb_arb_resampler_ccf
+ *
+ * \brief Polyphase filterbank arbitrary resampler with
+ * gr_complex input, gr_complex output and float taps
+ *
+ * \ingroup filter_blk
+ *
+ * This block takes in a signal stream and performs arbitrary
+ * resampling. The resampling rate can be any real
+ * number <EM>r</EM>. The resampling is done by constructing
+ * <EM>N</EM> filters where <EM>N</EM> is the interpolation rate. We
+ * then calculate <EM>D</EM> where <EM>D = floor(N/r)</EM>.
+ *
+ * Using <EM>N</EM> and <EM>D</EM>, we can perform rational resampling
+ * where <EM>N/D</EM> is a rational number close to the input rate
+ * <EM>r</EM> where we have <EM>N</EM> filters and we cycle through
+ * them as a polyphase filterbank with a stride of <EM>D</EM> so that
+ * <EM>i+1 = (i + D) % N</EM>.
+ *
+ * To get the arbitrary rate, we want to interpolate between two
+ * points. For each value out, we take an output from the current
+ * filter, <EM>i</EM>, and the next filter <EM>i+1</EM> and then
+ * linearly interpolate between the two based on the real resampling
+ * rate we want.
+ *
+ * The linear interpolation only provides us with an approximation to
+ * the real sampling rate specified. The error is a quantization error
+ * between the two filters we used as our interpolation points. To
+ * this end, the number of filters, <EM>N</EM>, used determines the
+ * quantization error; the larger <EM>N</EM>, the smaller the
+ * noise. You can design for a specified noise floor by setting the
+ * filter size (parameters <EM>filter_size</EM>). The size defaults to
+ * 32 filters, which is about as good as most implementations need.
+ *
+ * The trick with designing this filter is in how to specify the taps
+ * of the prototype filter. Like the PFB interpolator, the taps are
+ * specified using the interpolated filter rate. In this case, that
+ * rate is the input sample rate multiplied by the number of filters
+ * in the filterbank, which is also the interpolation rate. All other
+ * values should be relative to this rate.
+ *
+ * For example, for a 32-filter arbitrary resampler and using the
+ * GNU Radio's firdes utility to build the filter, 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 the
+ * interpolation rate (<EM>32</EM>).
+ *
+ * <B><EM>self._taps = gr.firdes.low_pass_2(32, 32*fs, BW, TB,
+ * attenuation_dB=ATT, window=gr.firdes.WIN_BLACKMAN_hARRIS)</EM></B>
+ *
+ * The theory behind this block can be found in Chapter 7.5 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 gr_pfb_arb_resampler_ccf : public gr_block
+{
+ private:
+ /*!
+ * Build the polyphase filterbank arbitray resampler.
+ * \param rate (float) Specifies the resampling rate to use
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank. The taps
+ * should be generated at the filter_size sampling rate.
+ * \param filter_size (unsigned int) The number of filters in the filter bank. This is directly
+ related to quantization noise introduced during the resampling.
+ Defaults to 32 filters.
+ */
+ friend gr_pfb_arb_resampler_ccf_sptr gr_make_pfb_arb_resampler_ccf (float rate,
+ const std::vector<float> &taps,
+ unsigned int filter_size);
+
+ std::vector<gr_fir_ccf*> d_filters;
+ std::vector< std::vector<float> > d_taps;
+ unsigned int d_int_rate; // the number of filters (interpolation rate)
+ unsigned int d_dec_rate; // the stride through the filters (decimation rate)
+ float d_flt_rate; // residual rate for the linear interpolation
+ float d_acc;
+ unsigned int d_last_filter;
+ unsigned int d_taps_per_filter;
+ bool d_updated;
+
+ /*!
+ * Build the polyphase filterbank arbitray resampler.
+ * \param rate (float) Specifies the resampling rate to use
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank. The taps
+ * should be generated at the filter_size sampling rate.
+ * \param filter_size (unsigned int) The number of filters in the filter bank. This is directly
+ related to quantization noise introduced during the resampling.
+ Defaults to 32 filters.
+ */
+ gr_pfb_arb_resampler_ccf (float rate,
+ const std::vector<float> &taps,
+ unsigned int filter_size);
+
+public:
+ ~gr_pfb_arb_resampler_ccf ();
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank. The taps
+ * should be generated at the interpolated sampling rate.
+ */
+ void set_taps (const std::vector<float> &taps);
+
+ /*!
+ * Print all of the filterbank taps to screen.
+ */
+ void print_taps();
+
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.i
new file mode 100644
index 000000000..e365e0314
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.i
@@ -0,0 +1,41 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,pfb_arb_resampler_ccf);
+
+gr_pfb_arb_resampler_ccf_sptr gr_make_pfb_arb_resampler_ccf (float rate,
+ const std::vector<float> &taps,
+ unsigned int filter_size=32);
+
+class gr_pfb_arb_resampler_ccf : public gr_block
+{
+ private:
+ gr_pfb_arb_resampler_ccf (float rate,
+ const std::vector<float> &taps,
+ unsigned int filter_size);
+
+ public:
+ ~gr_pfb_arb_resampler_ccf ();
+
+ void set_taps (const std::vector<float> &taps);
+ void print_taps();
+};
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc
new file mode 100644
index 000000000..7be611e23
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc
@@ -0,0 +1,150 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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_pfb_channelizer_ccf.h>
+#include <gr_fir_ccf.h>
+#include <gr_fir_util.h>
+#include <gri_fft.h>
+#include <gr_io_signature.h>
+
+gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
+ const std::vector<float> &taps)
+{
+ return gr_pfb_channelizer_ccf_sptr (new gr_pfb_channelizer_ccf (numchans, taps));
+}
+
+
+gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans,
+ const std::vector<float> &taps)
+ : gr_sync_block ("pfb_channelizer_ccf",
+ gr_make_io_signature (numchans, numchans, sizeof(gr_complex)),
+ gr_make_io_signature (1, 1, numchans*sizeof(gr_complex))),
+ d_updated (false)
+{
+ d_numchans = numchans;
+ d_filters = std::vector<gr_fir_ccf*>(d_numchans);
+
+ // Create an FIR filter for each channel and zero out the taps
+ std::vector<float> vtaps(0, d_numchans);
+ for(unsigned int i = 0; i < d_numchans; i++) {
+ d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps);
+ }
+
+ // Now, actually set the filters' taps
+ set_taps(taps);
+
+ // Create the FFT to handle the output de-spinning of the channels
+ d_fft = new gri_fft_complex (d_numchans, false);
+}
+
+gr_pfb_channelizer_ccf::~gr_pfb_channelizer_ccf ()
+{
+ for(unsigned int i = 0; i < d_numchans; i++) {
+ delete d_filters[i];
+ }
+}
+
+void
+gr_pfb_channelizer_ccf::set_taps (const std::vector<float> &taps)
+{
+ unsigned int i,j;
+
+ unsigned int ntaps = taps.size();
+ d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_numchans);
+
+ // Create d_numchan vectors to store each channel's taps
+ d_taps.resize(d_numchans);
+
+ // Make a vector of the taps plus fill it out with 0's to fill
+ // each polyphase filter with exactly d_taps_per_filter
+ std::vector<float> tmp_taps;
+ tmp_taps = taps;
+ while((float)(tmp_taps.size()) < d_numchans*d_taps_per_filter) {
+ tmp_taps.push_back(0.0);
+ }
+
+ // Partition the filter
+ for(i = 0; i < d_numchans; i++) {
+ // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
+ d_taps[i] = std::vector<float>(d_taps_per_filter, 0);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ d_taps[i][j] = tmp_taps[i + j*d_numchans]; // add taps to channels in reverse order
+ }
+
+ // Build a filter for each channel and add it's taps to it
+ d_filters[i]->set_taps(d_taps[i]);
+ }
+
+ // Set the history to ensure enough input items for each filter
+ set_history (d_taps_per_filter);
+
+ d_updated = true;
+}
+
+void
+gr_pfb_channelizer_ccf::print_taps()
+{
+ unsigned int i, j;
+ for(i = 0; i < d_numchans; i++) {
+ printf("filter[%d]: [", i);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ printf(" %.4e", d_taps[i][j]);
+ }
+ printf("]\n\n");
+ }
+}
+
+
+int
+gr_pfb_channelizer_ccf::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ gr_complex *in = (gr_complex *) input_items[0];
+ gr_complex *out = (gr_complex *) output_items[0];
+
+ if (d_updated) {
+ d_updated = false;
+ return 0; // history requirements may have changed.
+ }
+
+ for(int i = 0; i < noutput_items; i++) {
+ // Move through filters from bottom to top
+ for(int j = d_numchans-1; j >= 0; j--) {
+ // Take in the items from the first input stream to d_numchans
+ in = (gr_complex*)input_items[d_numchans - 1 - j];
+
+ // Filter current input stream from bottom filter to top
+ d_fft->get_inbuf()[j] = d_filters[j]->filter(&in[i]);
+ }
+
+ // despin through FFT
+ d_fft->execute();
+ memcpy(&out[d_numchans*i], d_fft->get_outbuf(), d_numchans*sizeof(gr_complex));
+ }
+
+ return noutput_items;
+}
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
new file mode 100644
index 000000000..7d0a31c59
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
@@ -0,0 +1,144 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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_PFB_CHANNELIZER_CCF_H
+#define INCLUDED_GR_PFB_CHANNELIZER_CCF_H
+
+#include <gr_sync_block.h>
+
+class gr_pfb_channelizer_ccf;
+typedef boost::shared_ptr<gr_pfb_channelizer_ccf> gr_pfb_channelizer_ccf_sptr;
+gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
+ const std::vector<float> &taps);
+
+class gr_fir_ccf;
+class gri_fft_complex;
+
+
+/*!
+ * \class gr_pfb_channelizer_ccf
+ *
+ * \brief Polyphase filterbank channelizer with
+ * gr_complex input, gr_complex output and float taps
+ *
+ * \ingroup filter_blk
+ *
+ * This block takes in complex inputs and channelizes it to <EM>M</EM>
+ * channels of equal bandwidth. Each of the resulting channels is
+ * decimated to the new rate that is the input sampling rate
+ * <EM>fs</EM> divided by the number of channels, <EM>M</EM>.
+ *
+ * The PFB channelizer code takes the taps generated above and builds
+ * a set of filters. The set contains <EM>M</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.
+ *
+ * Each filter operates using the gr_fir filter classs of GNU Radio,
+ * which takes the input stream at <EM>i</EM> and performs the inner
+ * product calculation to <EM>i+(n-1)</EM> where <EM>n</EM> is the
+ * number of filter taps. To efficiently handle this in the GNU Radio
+ * structure, each filter input must come from its own input
+ * stream. So the channelizer must be provided with <EM>M</EM> streams
+ * where the input stream has been deinterleaved. This is most easily
+ * done using the gr_stream_to_streams block.
+ *
+ * The output is then produced as a vector, where index <EM>i</EM> in
+ * the vector is the next sample from the <EM>i</EM>th channel. This
+ * is most easily handled by sending the output to a
+ * gr_vector_to_streams block to handle the conversion and passing
+ * <EM>M</EM> streams out.
+ *
+ * The input and output formatting is done using a hier_block2 called
+ * pfb_channelizer_ccf. This can take in a single stream and outputs
+ * <EM>M</EM> streams based on the behavior described above.
+ *
+ * The filter's taps should be based on the input sampling rate.
+ *
+ * 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 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.
+ *
+ */
+
+class gr_pfb_channelizer_ccf : public gr_sync_block
+{
+ private:
+ /*!
+ * Build the polyphase filterbank decimator.
+ * \param numchans (unsigned integer) Specifies the number of channels <EM>M</EM>
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank.
+ */
+ friend gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
+ const std::vector<float> &taps);
+
+ std::vector<gr_fir_ccf*> d_filters;
+ std::vector< std::vector<float> > d_taps;
+ gri_fft_complex *d_fft;
+ unsigned int d_numchans;
+ unsigned int d_taps_per_filter;
+ bool d_updated;
+
+ /*!
+ * Build the polyphase filterbank decimator.
+ * \param numchans (unsigned integer) Specifies the number of channels <EM>M</EM>
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank.
+ */
+ gr_pfb_channelizer_ccf (unsigned int numchans,
+ const std::vector<float> &taps);
+
+public:
+ ~gr_pfb_channelizer_ccf ();
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank.
+ */
+ void set_taps (const std::vector<float> &taps);
+
+ /*!
+ * Print all of the filterbank taps to screen.
+ */
+ void print_taps();
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i
new file mode 100644
index 000000000..4bef90e22
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i
@@ -0,0 +1,38 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,pfb_channelizer_ccf);
+
+gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
+ const std::vector<float> &taps);
+
+class gr_pfb_channelizer_ccf : public gr_sync_block
+{
+ private:
+ gr_pfb_channelizer_ccf (unsigned int numchans,
+ const std::vector<float> &taps);
+
+ public:
+ ~gr_pfb_channelizer_ccf ();
+
+ void set_taps (const std::vector<float> &taps);
+};
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc
new file mode 100644
index 000000000..b334f5878
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.cc
@@ -0,0 +1,174 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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_pfb_decimator_ccf.h>
+#include <gr_fir_ccf.h>
+#include <gr_fir_util.h>
+#include <gri_fft.h>
+#include <gr_io_signature.h>
+#include <gr_expj.h>
+
+gr_pfb_decimator_ccf_sptr gr_make_pfb_decimator_ccf (unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel)
+{
+ return gr_pfb_decimator_ccf_sptr (new gr_pfb_decimator_ccf (decim, taps, channel));
+}
+
+
+gr_pfb_decimator_ccf::gr_pfb_decimator_ccf (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))),
+ d_updated (false)
+{
+ d_rate = decim;
+ d_filters = std::vector<gr_fir_ccf*>(d_rate);
+ d_chan = channel;
+ d_rotator = new gr_complex[d_rate];
+
+ // Create an FIR filter for each channel and zero out the taps
+ std::vector<float> vtaps(0, d_rate);
+ for(unsigned int i = 0; i < d_rate; i++) {
+ d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps);
+ d_rotator[i] = gr_expj(i*2*M_PI*d_chan/d_rate);
+ }
+
+ // Now, actually set the filters' taps
+ set_taps(taps);
+
+ // Create the FFT to handle the output de-spinning of the channels
+ d_fft = new gri_fft_complex (d_rate, false);
+}
+
+gr_pfb_decimator_ccf::~gr_pfb_decimator_ccf ()
+{
+ for(unsigned int i = 0; i < d_rate; i++) {
+ delete d_filters[i];
+ }
+}
+
+void
+gr_pfb_decimator_ccf::set_taps (const std::vector<float> &taps)
+{
+ unsigned int i,j;
+
+ unsigned int ntaps = taps.size();
+ d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_rate);
+
+ // Create d_numchan vectors to store each channel's taps
+ d_taps.resize(d_rate);
+
+ // Make a vector of the taps plus fill it out with 0's to fill
+ // each polyphase filter with exactly d_taps_per_filter
+ std::vector<float> tmp_taps;
+ tmp_taps = taps;
+ while((float)(tmp_taps.size()) < d_rate*d_taps_per_filter) {
+ tmp_taps.push_back(0.0);
+ }
+
+ // Partition the filter
+ for(i = 0; i < d_rate; i++) {
+ // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
+ d_taps[i] = std::vector<float>(d_taps_per_filter, 0);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ d_taps[i][j] = tmp_taps[i + j*d_rate]; // add taps to channels in reverse order
+ }
+
+ // Build a filter for each channel and add it's taps to it
+ d_filters[i]->set_taps(d_taps[i]);
+ }
+
+ // Set the history to ensure enough input items for each filter
+ set_history (d_taps_per_filter);
+
+ d_updated = true;
+}
+
+void
+gr_pfb_decimator_ccf::print_taps()
+{
+ unsigned int i, j;
+ for(i = 0; i < d_rate; i++) {
+ printf("filter[%d]: [", i);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ printf(" %.4e", d_taps[i][j]);
+ }
+ printf("]\n\n");
+ }
+}
+
+#define ROTATEFFT
+
+int
+gr_pfb_decimator_ccf::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ gr_complex *in;
+ gr_complex *out = (gr_complex *) output_items[0];
+
+ 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;
+}
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h
new file mode 100644
index 000000000..83997c0c9
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.h
@@ -0,0 +1,148 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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_PFB_DECIMATOR_CCF_H
+#define INCLUDED_GR_PFB_DECIMATOR_CCF_H
+
+#include <gr_sync_block.h>
+
+class gr_pfb_decimator_ccf;
+typedef boost::shared_ptr<gr_pfb_decimator_ccf> gr_pfb_decimator_ccf_sptr;
+gr_pfb_decimator_ccf_sptr gr_make_pfb_decimator_ccf (unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel=0);
+
+class gr_fir_ccf;
+class gri_fft_complex;
+
+/*!
+ * \class gr_pfb_decimator_ccf
+ * \brief Polyphase filterbank bandpass decimator with gr_complex
+ * input, gr_complex output and float taps
+ *
+ * \ingroup filter_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 gr_pfb_decimator_ccf : public gr_sync_block
+{
+ private:
+ /*!
+ * 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].
+ */
+ friend gr_pfb_decimator_ccf_sptr gr_make_pfb_decimator_ccf (unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel);
+
+ std::vector<gr_fir_ccf*> d_filters;
+ std::vector< std::vector<float> > d_taps;
+ gri_fft_complex *d_fft;
+ unsigned int d_rate;
+ unsigned int d_chan;
+ unsigned int d_taps_per_filter;
+ bool d_updated;
+ gr_complex *d_rotator;
+
+ /*!
+ * 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].
+ */
+ gr_pfb_decimator_ccf (unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel);
+
+public:
+ ~gr_pfb_decimator_ccf ();
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank.
+ */
+ void set_taps (const std::vector<float> &taps);
+
+ /*!
+ * Print all of the filterbank taps to screen.
+ */
+ void print_taps();
+
+ //void set_channel (unsigned int channel);
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.i
new file mode 100644
index 000000000..c4215fce1
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_decimator_ccf.i
@@ -0,0 +1,41 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,pfb_decimator_ccf);
+
+gr_pfb_decimator_ccf_sptr gr_make_pfb_decimator_ccf (unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel);
+
+class gr_pfb_decimator_ccf : public gr_sync_block
+{
+ private:
+ gr_pfb_decimator_ccf (unsigned int decim,
+ const std::vector<float> &taps,
+ unsigned int channel);
+
+ public:
+ ~gr_pfb_decimator_ccf ();
+
+ void set_taps (const std::vector<float> &taps);
+ //void set_channel (unsigned int channel);
+};
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc
new file mode 100644
index 000000000..d5eba885c
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.cc
@@ -0,0 +1,142 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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_pfb_interpolator_ccf.h>
+#include <gr_fir_ccf.h>
+#include <gr_fir_util.h>
+#include <gr_io_signature.h>
+
+gr_pfb_interpolator_ccf_sptr gr_make_pfb_interpolator_ccf (unsigned int interp,
+ const std::vector<float> &taps)
+{
+ return gr_pfb_interpolator_ccf_sptr (new gr_pfb_interpolator_ccf (interp, taps));
+}
+
+
+gr_pfb_interpolator_ccf::gr_pfb_interpolator_ccf (unsigned int interp,
+ const std::vector<float> &taps)
+ : gr_sync_interpolator ("pfb_interpolator_ccf",
+ gr_make_io_signature (1, 1, sizeof(gr_complex)),
+ gr_make_io_signature (1, 1, sizeof(gr_complex)),
+ interp),
+ d_updated (false)
+{
+ d_rate = interp;
+ d_filters = std::vector<gr_fir_ccf*>(d_rate);
+
+ // Create an FIR filter for each channel and zero out the taps
+ std::vector<float> vtaps(0, d_rate);
+ for(unsigned int i = 0; i < d_rate; i++) {
+ d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps);
+ }
+
+ // Now, actually set the filters' taps
+ set_taps(taps);
+}
+
+gr_pfb_interpolator_ccf::~gr_pfb_interpolator_ccf ()
+{
+ for(unsigned int i = 0; i < d_rate; i++) {
+ delete d_filters[i];
+ }
+}
+
+void
+gr_pfb_interpolator_ccf::set_taps (const std::vector<float> &taps)
+{
+ unsigned int i,j;
+
+ unsigned int ntaps = taps.size();
+ d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_rate);
+
+ // Create d_numchan vectors to store each channel's taps
+ //std::vector< std::vector<float> > vtaps(d_rate);
+ d_taps.resize(d_rate);
+
+ // Make a vector of the taps plus fill it out with 0's to fill
+ // each polyphase filter with exactly d_taps_per_filter
+ std::vector<float> tmp_taps;
+ tmp_taps = taps;
+ while((float)(tmp_taps.size()) < d_rate*d_taps_per_filter) {
+ tmp_taps.push_back(0.0);
+ }
+
+ // Partition the filter
+ for(i = 0; i < d_rate; i++) {
+ // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out
+ d_taps[i] = std::vector<float>(d_taps_per_filter, 0);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ d_taps[i][j] = tmp_taps[i + j*d_rate]; // add taps to channels in reverse order
+ }
+
+ // Build a filter for each channel and add it's taps to it
+ d_filters[i]->set_taps(d_taps[i]);
+ }
+
+ // Set the history to ensure enough input items for each filter
+ set_history (d_taps_per_filter);
+
+ d_updated = true;
+}
+
+void
+gr_pfb_interpolator_ccf::print_taps()
+{
+ unsigned int i, j;
+ for(i = 0; i < d_rate; i++) {
+ printf("filter[%d]: [", i);
+ for(j = 0; j < d_taps_per_filter; j++) {
+ printf(" %.4e", d_taps[i][j]);
+ }
+ printf("]\n\n");
+ }
+}
+
+int
+gr_pfb_interpolator_ccf::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ gr_complex *in = (gr_complex *) input_items[0];
+ gr_complex *out = (gr_complex *) output_items[0];
+
+ if (d_updated) {
+ d_updated = false;
+ return 0; // history requirements may have changed.
+ }
+
+ int i = 0, count = 0;
+
+ while(i < noutput_items) {
+ for(int j = 0; j < d_rate; j++) {
+ out[i] = d_filters[j]->filter(&in[count]);
+ i++;
+ }
+ count++;
+ }
+
+ return i;
+}
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h
new file mode 100644
index 000000000..50849d510
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.h
@@ -0,0 +1,129 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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_PFB_INTERPOLATOR_CCF_H
+#define INCLUDED_GR_PFB_INTERPOLATOR_CCF_H
+
+#include <gr_sync_interpolator.h>
+
+class gr_pfb_interpolator_ccf;
+typedef boost::shared_ptr<gr_pfb_interpolator_ccf> gr_pfb_interpolator_ccf_sptr;
+gr_pfb_interpolator_ccf_sptr gr_make_pfb_interpolator_ccf (unsigned int interp,
+ const std::vector<float> &taps);
+
+class gr_fir_ccf;
+
+/*!
+ * \class gr_pfb_interpolator_ccf
+ * \brief Polyphase filterbank interpolator with gr_complex input,
+ * gr_complex output and float taps
+ *
+ * \ingroup filter_blk
+ *
+ * This block takes in a signal stream and performs interger up-
+ * sampling (interpolation) with a polyphase filterbank. The first
+ * input is the integer specifying how much to interpolate by. The
+ * second input is a vector (Python list) of floating-point taps of
+ * the prototype filter.
+ *
+ * The filter's taps should be based on the interpolation rate
+ * specified. That is, the bandwidth specified is relative to the
+ * bandwidth after interpolation.
+ *
+ * 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, ATT, and the filter window function (a
+ * Blackman-harris window in this case). The first input is the gain,
+ * which is also specified as the interpolation rate so that the
+ * output levels are the same as the input (this creates an overall
+ * increase in power).
+ *
+ * <B><EM>self._taps = gr.firdes.low_pass_2(interp, interp*fs, BW, TB,
+ * attenuation_dB=ATT, window=gr.firdes.WIN_BLACKMAN_hARRIS)</EM></B>
+ *
+ * The PFB interpolator code takes the taps generated above and builds
+ * a set of filters. The set contains <EM>interp</EM> number of
+ * filters and each filter contains ceil(taps.size()/interp) 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 7.1 of the
+ * following book.
+ *
+ * <B><EM>f. harris, <EM>Multirate Signal Processing for Communication
+ * Systems</EM>," Upper Saddle River, NJ: Prentice Hall,
+ * Inc. 2004.</EM></B>
+ */
+
+class gr_pfb_interpolator_ccf : public gr_sync_interpolator
+{
+ private:
+ /*!
+ * Build the polyphase filterbank interpolator.
+ * \param interp (unsigned integer) Specifies the interpolation rate to use
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank. The taps
+ * should be generated at the interpolated sampling rate.
+ */
+ friend gr_pfb_interpolator_ccf_sptr gr_make_pfb_interpolator_ccf (unsigned int interp,
+ const std::vector<float> &taps);
+
+ std::vector<gr_fir_ccf*> d_filters;
+ std::vector< std::vector<float> > d_taps;
+ unsigned int d_rate;
+ unsigned int d_taps_per_filter;
+ bool d_updated;
+
+ /*!
+ * Construct a Polyphase filterbank interpolator
+ * \param interp (unsigned integer) Specifies the interpolation rate to use
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank. The taps
+ * should be generated at the interpolated sampling rate.
+ */
+ gr_pfb_interpolator_ccf (unsigned int interp,
+ const std::vector<float> &taps);
+
+public:
+ ~gr_pfb_interpolator_ccf ();
+
+ /*!
+ * Resets the filterbank's filter taps with the new prototype filter
+ * \param taps (vector/list of floats) The prototype filter to populate the filterbank. The taps
+ * should be generated at the interpolated sampling rate.
+ */
+ void set_taps (const std::vector<float> &taps);
+
+ /*!
+ * Print all of the filterbank taps to screen.
+ */
+ void print_taps();
+
+ int work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.i
new file mode 100644
index 000000000..cf4302d45
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gr_pfb_interpolator_ccf.i
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,pfb_interpolator_ccf);
+
+gr_pfb_interpolator_ccf_sptr gr_make_pfb_interpolator_ccf (unsigned int interp,
+ const std::vector<float> &taps);
+
+class gr_pfb_interpolator_ccf : public gr_sync_interpolator
+{
+ private:
+ gr_pfb_interpolator_ccf (unsigned int interp,
+ const std::vector<float> &taps);
+
+ public:
+ ~gr_pfb_interpolator_ccf ();
+
+ void set_taps (const std::vector<float> &taps);
+ void print_taps();
+};