From 06f92ca4200bbebd2ecb77f88b4524711f9292c4 Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Tue, 27 Apr 2010 22:05:15 -0400 Subject: Adding the synthesis filterbank (the opposite of the channelizer). It's ugly right now and uses a lot of memory to handle the buffers for each filter/input stream. --- gnuradio-core/src/lib/filter/Makefile.am | 3 + gnuradio-core/src/lib/filter/filter.i | 2 + .../lib/filter/gr_pfb_synthesis_filterbank_ccf.cc | 164 +++++++++++++++++++++ .../lib/filter/gr_pfb_synthesis_filterbank_ccf.h | 93 ++++++++++++ .../lib/filter/gr_pfb_synthesis_filterbank_ccf.i | 38 +++++ 5 files changed, 300 insertions(+) create mode 100644 gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc create mode 100644 gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h create mode 100644 gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am index 23c1dadc36..6a6532eb0a 100644 --- a/gnuradio-core/src/lib/filter/Makefile.am +++ b/gnuradio-core/src/lib/filter/Makefile.am @@ -205,6 +205,7 @@ libfilter_la_common_SOURCES = \ float_dotprod_generic.c \ short_dotprod_generic.c \ gr_pfb_channelizer_ccf.cc \ + gr_pfb_synthesis_filterbank_ccf.cc\ gr_pfb_decimator_ccf.cc \ gr_pfb_interpolator_ccf.cc \ gr_pfb_arb_resampler_ccf.cc \ @@ -288,6 +289,7 @@ grinclude_HEADERS = \ short_dotprod_x86.h \ sse_debug.h \ gr_pfb_channelizer_ccf.h \ + gr_pfb_synthesis_filterbank_ccf.h\ gr_pfb_decimator_ccf.h \ gr_pfb_interpolator_ccf.h \ gr_pfb_arb_resampler_ccf.h \ @@ -344,6 +346,7 @@ swiginclude_HEADERS = \ gr_single_pole_iir_filter_ff.i \ gr_single_pole_iir_filter_cc.i \ gr_pfb_channelizer_ccf.i \ + gr_pfb_synthesis_filterbank_ccf.i\ gr_pfb_decimator_ccf.i \ gr_pfb_interpolator_ccf.i \ gr_pfb_arb_resampler_ccf.i \ diff --git a/gnuradio-core/src/lib/filter/filter.i b/gnuradio-core/src/lib/filter/filter.i index bdfb8fa8d2..645607cbad 100644 --- a/gnuradio-core/src/lib/filter/filter.i +++ b/gnuradio-core/src/lib/filter/filter.i @@ -33,6 +33,7 @@ #include <gr_goertzel_fc.h> #include <gr_cma_equalizer_cc.h> #include <gr_pfb_channelizer_ccf.h> +#include <gr_pfb_synthesis_filterbank_ccf.h> #include <gr_pfb_decimator_ccf.h> #include <gr_pfb_interpolator_ccf.h> #include <gr_pfb_arb_resampler_ccf.h> @@ -52,6 +53,7 @@ %include "gr_goertzel_fc.i" %include "gr_cma_equalizer_cc.i" %include "gr_pfb_channelizer_ccf.i" +%include "gr_pfb_synthesis_filterbank_ccf.i" %include "gr_pfb_decimator_ccf.i" %include "gr_pfb_interpolator_ccf.i" %include "gr_pfb_arb_resampler_ccf.i" diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc new file mode 100644 index 0000000000..f8b0eae260 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc @@ -0,0 +1,164 @@ +/* -*- c++ -*- */ +/* + * Copyright 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_pfb_synthesis_filterbank_ccf.h> +#include <gr_fir_ccf.h> +#include <gr_fir_util.h> +#include <gri_fft.h> +#include <gr_io_signature.h> +#include <cstdio> +#include <cstring> + +gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf + (unsigned int numchans, const std::vector<float> &taps) +{ + return gr_pfb_synthesis_filterbank_ccf_sptr + (new gr_pfb_synthesis_filterbank_ccf (numchans, taps)); +} + + +gr_pfb_synthesis_filterbank_ccf::gr_pfb_synthesis_filterbank_ccf + (unsigned int numchans, const std::vector<float> &taps) + : gr_sync_interpolator ("pfb_synthesis_filterbank_ccf", + gr_make_io_signature (numchans, numchans, sizeof(gr_complex)), + gr_make_io_signature (1, 1, sizeof(gr_complex)), + numchans), + d_updated (false), d_numchans(numchans) +{ + d_filters = std::vector<gr_fir_ccf*>(d_numchans); + + d_buffer = new gr_complex*[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); + d_buffer[i] = new gr_complex[65535]; + memset(d_buffer[i], 0, 65535*sizeof(gr_complex)); + } + + // Now, actually set the filters' taps + set_taps(taps); + + // Create the IFFT to handle the input channel rotations + d_fft = new gri_fft_complex (d_numchans, true); +} + +gr_pfb_synthesis_filterbank_ccf::~gr_pfb_synthesis_filterbank_ccf () +{ + for(unsigned int i = 0; i < d_numchans; i++) { + delete d_filters[i]; + } +} + +void +gr_pfb_synthesis_filterbank_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+1); + + d_updated = true; +} + +void +gr_pfb_synthesis_filterbank_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_synthesis_filterbank_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. + } + + unsigned int n, i; + for(n = 0; n < noutput_items/d_numchans; n++) { + for(i = 0; i < d_numchans; i++) { + in = (gr_complex*)input_items[i]; + d_fft->get_inbuf()[i] = (in+i)[n]; + } + + // spin through IFFT + d_fft->execute(); + + for(i = 0; i < d_numchans; i++) { + d_buffer[i][n+d_taps_per_filter-1] = d_fft->get_outbuf()[i]; + out[i] = d_filters[i]->filter(&d_buffer[i][n]); + } + out += d_numchans; + } + + for(i = 0; i < d_numchans; i++) { + memcpy(d_buffer[i], &d_buffer[i][n], + (d_taps_per_filter)*sizeof(gr_complex)); + } + + return noutput_items; +} diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h new file mode 100644 index 0000000000..4b6235a8b5 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h @@ -0,0 +1,93 @@ +/* -*- c++ -*- */ +/* + * Copyright 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. + */ + + +#ifndef INCLUDED_GR_PFB_SYNTHESIS_FILTERBANK_CCF_H +#define INCLUDED_GR_PFB_SYNTHESIS_FILTERBANK_CCF_H + +#include <gr_sync_interpolator.h> + +class gr_pfb_synthesis_filterbank_ccf; +typedef boost::shared_ptr<gr_pfb_synthesis_filterbank_ccf> gr_pfb_synthesis_filterbank_ccf_sptr; +gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf + (unsigned int numchans, const std::vector<float> &taps); + +class gr_fir_ccf; +class gri_fft_complex; + + +/*! + * \class gr_pfb_synthesis_filterbank_ccf + * + * \brief Polyphase synthesis filterbank with + * gr_complex input, gr_complex output and float taps + * + * \ingroup filter_blk + */ + +class gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator +{ + private: + /*! + * Build the polyphase synthesis filterbank. + * \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_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf + (unsigned int numchans, const std::vector<float> &taps); + + bool d_updated; + unsigned int d_numchans; + std::vector<gr_fir_ccf*> d_filters; + std::vector< std::vector<float> > d_taps; + unsigned int d_taps_per_filter; + gri_fft_complex *d_fft; + gr_complex **d_buffer; + + /*! + * Build the polyphase synthesis filterbank. + * \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_synthesis_filterbank_ccf (unsigned int numchans, + const std::vector<float> &taps); + +public: + ~gr_pfb_synthesis_filterbank_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_synthesis_filterbank_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i new file mode 100644 index 0000000000..02a9f02556 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.i @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,pfb_synthesis_filterbank_ccf); + +gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf + (unsigned int numchans, const std::vector<float> &taps); + +class gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator +{ + private: + gr_pfb_synthesis_filterbank_ccf (unsigned int numchans, + const std::vector<float> &taps); + + public: + ~gr_pfb_synthesis_filterbank_ccf (); + + void set_taps (const std::vector<float> &taps); +}; -- cgit v1.2.3 From 0c6abf713755e4c7f705bad2e9f982d431b4286d Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Tue, 27 Apr 2010 22:17:44 -0400 Subject: Fixing ordering so that the input channels line up in the output signal properly. --- gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc index f8b0eae260..15ba1ae2e7 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc @@ -150,11 +150,13 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, for(i = 0; i < d_numchans; i++) { d_buffer[i][n+d_taps_per_filter-1] = d_fft->get_outbuf()[i]; - out[i] = d_filters[i]->filter(&d_buffer[i][n]); + out[d_numchans-i-1] = d_filters[d_numchans-i-1]->filter(&d_buffer[i][n]); } out += d_numchans; } + // Move the last chunk of memory to the front for the next entry + // this make sure that the first taps_per_filter values are correct for(i = 0; i < d_numchans; i++) { memcpy(d_buffer[i], &d_buffer[i][n], (d_taps_per_filter)*sizeof(gr_complex)); -- cgit v1.2.3 From 2ee1a94ff42a3d1858805bcce50b6aadb1773f47 Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Sun, 16 May 2010 14:39:53 -0400 Subject: Can now set more channels than input signals. Empty channels are established as the outtermost channels (around fs/2 and -fs/2). --- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.cc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc index 15ba1ae2e7..b1365bcf90 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc @@ -43,7 +43,7 @@ gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf gr_pfb_synthesis_filterbank_ccf::gr_pfb_synthesis_filterbank_ccf (unsigned int numchans, const std::vector<float> &taps) : gr_sync_interpolator ("pfb_synthesis_filterbank_ccf", - gr_make_io_signature (numchans, numchans, sizeof(gr_complex)), + gr_make_io_signature (1, numchans, sizeof(gr_complex)), gr_make_io_signature (1, 1, sizeof(gr_complex)), numchans), d_updated (false), d_numchans(numchans) @@ -132,6 +132,9 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, { gr_complex *in = (gr_complex*) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; + int numsigs = input_items.size(); + int ndiff = d_numchans - numsigs; + int nhalf = (int)ceil((float)numsigs/2.0f); if (d_updated) { d_updated = false; @@ -140,11 +143,24 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, unsigned int n, i; for(n = 0; n < noutput_items/d_numchans; n++) { - for(i = 0; i < d_numchans; i++) { + // fill up the populated channels based on the + // number of real input streams + for(i = 0; i < nhalf; i++) { in = (gr_complex*)input_items[i]; d_fft->get_inbuf()[i] = (in+i)[n]; } + // Make the ndiff channels around N/2 0 + for(; i < nhalf+ndiff; i++) { + d_fft->get_inbuf()[i] = gr_complex(0,0); + } + + // Finish off channels with data + for(; i < d_numchans; i++) { + in = (gr_complex*)input_items[i-ndiff]; + d_fft->get_inbuf()[i] = (in+i)[n]; + } + // spin through IFFT d_fft->execute(); -- cgit v1.2.3 From 2e633fc33dcbc3e1b5c35323ebe24373d57ea459 Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Sat, 16 Oct 2010 11:13:53 -0400 Subject: Adding a FIR filter implemented with its own internal buffer. This one keeps its own delay line and just takes in input samples instead of a pointer to an external buffer. The synthesis filter is being updated to use the new FIR implementation. --- gnuradio-core/src/lib/filter/Makefile.am | 4 +- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.cc | 22 ++-- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.h | 23 ++-- .../lib/filter/gri_fir_filter_with_buffer_ccf.cc | 81 +++++++++++++ .../lib/filter/gri_fir_filter_with_buffer_ccf.h | 130 +++++++++++++++++++++ 5 files changed, 243 insertions(+), 17 deletions(-) create mode 100644 gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc create mode 100644 gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am index 6a6532eb0a..5c7473d06f 100644 --- a/gnuradio-core/src/lib/filter/Makefile.am +++ b/gnuradio-core/src/lib/filter/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2001,2002,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. +# Copyright 2001,2002,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -190,6 +190,7 @@ libfilter_la_common_SOURCES = \ gr_fft_filter_fff.cc \ gr_goertzel_fc.cc \ gr_filter_delay_fc.cc \ + gri_fir_filter_with_buffer_ccf.cc \ gr_fractional_interpolator_ff.cc \ gr_fractional_interpolator_cc.cc \ gr_hilbert_fc.cc \ @@ -267,6 +268,7 @@ grinclude_HEADERS = \ gr_fft_filter_ccc.h \ gr_fft_filter_fff.h \ gr_filter_delay_fc.h \ + gri_fir_filter_with_buffer_ccf.h \ gr_fir_sysconfig_x86.h \ gr_fir_sysconfig_powerpc.h \ gr_fractional_interpolator_ff.h \ diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc index b1365bcf90..0b31bcf72e 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc @@ -48,16 +48,18 @@ gr_pfb_synthesis_filterbank_ccf::gr_pfb_synthesis_filterbank_ccf numchans), d_updated (false), d_numchans(numchans) { - d_filters = std::vector<gr_fir_ccf*>(d_numchans); + //d_filters = std::vector<gr_fir_ccf*>(d_numchans); + d_filters = std::vector<gri_fir_filter_with_buffer_ccf*>(d_numchans); - d_buffer = new gr_complex*[d_numchans]; + //d_buffer = new gr_complex*[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); - d_buffer[i] = new gr_complex[65535]; - memset(d_buffer[i], 0, 65535*sizeof(gr_complex)); + d_filters[i] = new gri_fir_filter_with_buffer_ccf(vtaps); + //d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); + //d_buffer[i] = new gr_complex[65535]; + //memset(d_buffer[i], 0, 65535*sizeof(gr_complex)); } // Now, actually set the filters' taps @@ -134,7 +136,7 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, gr_complex *out = (gr_complex *) output_items[0]; int numsigs = input_items.size(); int ndiff = d_numchans - numsigs; - int nhalf = (int)ceil((float)numsigs/2.0f); + unsigned int nhalf = (unsigned int)ceil((float)numsigs/2.0f); if (d_updated) { d_updated = false; @@ -165,18 +167,22 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, d_fft->execute(); for(i = 0; i < d_numchans; i++) { - d_buffer[i][n+d_taps_per_filter-1] = d_fft->get_outbuf()[i]; - out[d_numchans-i-1] = d_filters[d_numchans-i-1]->filter(&d_buffer[i][n]); + //d_buffer[i][n+d_taps_per_filter-1] = d_fft->get_outbuf()[i]; + //out[d_numchans-i-1] = d_filters[d_numchans-i-1]->filter(&d_buffer[i][n]); + out[d_numchans-i-1] = d_filters[d_numchans-i-1]->filter(d_fft->get_outbuf()[i]); } out += d_numchans; } // Move the last chunk of memory to the front for the next entry // this make sure that the first taps_per_filter values are correct + + /* for(i = 0; i < d_numchans; i++) { memcpy(d_buffer[i], &d_buffer[i][n], (d_taps_per_filter)*sizeof(gr_complex)); } + */ return noutput_items; } diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h index 4b6235a8b5..27c8c2c508 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h @@ -25,6 +25,7 @@ #define INCLUDED_GR_PFB_SYNTHESIS_FILTERBANK_CCF_H #include <gr_sync_interpolator.h> +#include <gri_fir_filter_with_buffer_ccf.h> class gr_pfb_synthesis_filterbank_ccf; typedef boost::shared_ptr<gr_pfb_synthesis_filterbank_ccf> gr_pfb_synthesis_filterbank_ccf_sptr; @@ -49,24 +50,29 @@ class gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator private: /*! * Build the polyphase synthesis filterbank. - * \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. + * \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_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf (unsigned int numchans, const std::vector<float> &taps); bool d_updated; unsigned int d_numchans; - std::vector<gr_fir_ccf*> d_filters; - std::vector< std::vector<float> > d_taps; unsigned int d_taps_per_filter; gri_fft_complex *d_fft; - gr_complex **d_buffer; + //gr_complex **d_buffer; + std::vector< gri_fir_filter_with_buffer_ccf*> d_filters; + std::vector< std::vector<float> > d_taps; + /*! * Build the polyphase synthesis filterbank. - * \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. + * \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_synthesis_filterbank_ccf (unsigned int numchans, const std::vector<float> &taps); @@ -76,7 +82,8 @@ public: /*! * Resets the filterbank's filter taps with the new prototype filter - * \param taps (vector/list of floats) The prototype filter to populate the filterbank. + * \param taps (vector/list of floats) The prototype filter to + populate the filterbank. */ void set_taps (const std::vector<float> &taps); diff --git a/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc new file mode 100644 index 0000000000..e9545549f9 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc @@ -0,0 +1,81 @@ +/* -*- c++ -*- */ +/* + * Copyright 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 <gri_fir_filter_with_buffer_ccf.h> +#include <cstdio> + +gri_fir_filter_with_buffer_ccf::gri_fir_filter_with_buffer_ccf(const std::vector<float> &taps) +{ + d_buffer = NULL; + set_taps(taps); +} + +gri_fir_filter_with_buffer_ccf::~gri_fir_filter_with_buffer_ccf() +{ + free(d_buffer); +} + +gr_complex +gri_fir_filter_with_buffer_ccf::filter (gr_complex input) +{ +#if 0 + unsigned int i; + + for(i = ntaps()-1; i > 0; i--) { + d_buffer[i] = d_buffer[i-1]; + } + d_buffer[0] = input; + + gr_complex out = d_buffer[0]*d_taps[0]; + for(i = 1; i < ntaps(); i++) { + out += d_buffer[i]*d_taps[i]; + } + return out; + +#else + unsigned int i; + + d_buffer[d_idx] = input; + d_buffer[d_idx+ntaps()] = input; + //d_idx = (d_idx + 1) % ntaps(); + d_idx++; + if(d_idx == ntaps()) + d_idx = 0; + + gr_complex out = d_buffer[d_idx]*d_taps[0]; + for(i = 1; i < ntaps(); i++) { + out += d_buffer[d_idx + i]*d_taps[i]; + } + return out; +#endif +} + +void +gri_fir_filter_with_buffer_ccf::filterN (gr_complex output[], + const gr_complex input[], + unsigned long n) +{ + +} diff --git a/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h new file mode 100644 index 0000000000..5adc3e231f --- /dev/null +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h @@ -0,0 +1,130 @@ +/* -*- c++ -*- */ +/* + * Copyright 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. + */ + +/* + * WARNING: This file is automatically generated by generate_gr_fir_XXX.py + * Any changes made to this file will be overwritten. + */ + + +#ifndef INCLUDED_GRI_FIR_FILTER_WITH_BUFFER_H +#define INCLUDED_GRI_FIR_FILTER_WITH_BUFFER_H + +#include <vector> +#include <gr_types.h> +#include <gr_reverse.h> +#include <string.h> + +/*! + * \brief FIR with internal buffer for gr_complex input, + gr_complex output and float taps + * \ingroup filter + * + */ + +class gri_fir_filter_with_buffer_ccf { + +protected: + std::vector<float> d_taps; // reversed taps + gr_complex *d_buffer; + unsigned int d_idx; + +public: + + // CONSTRUCTORS + + /*! + * \brief construct new FIR with given taps. + * + * Note that taps must be in forward order, e.g., coefficient 0 is + * stored in new_taps[0], coefficient 1 is stored in + * new_taps[1], etc. + */ + gri_fir_filter_with_buffer_ccf (const std::vector<float> &taps); + + ~gri_fir_filter_with_buffer_ccf (); + + // MANIPULATORS + + /*! + * \brief compute a single output value. + * + * \p input must have ntaps() valid entries. + * input[0] .. input[ntaps() - 1] are referenced to compute the output value. + * + * \returns the filtered input value. + */ + gr_complex filter (gr_complex input); + + /*! + * \brief compute an array of N output values. + * + * \p input must have (n - 1 + ntaps()) valid entries. + * input[0] .. input[n - 1 + ntaps() - 1] are referenced to compute the output values. + */ + void filterN (gr_complex output[], const gr_complex input[], + unsigned long n); + + /*! + * \brief compute an array of N output values, decimating the input + * + * \p input must have (decimate * (n - 1) + ntaps()) valid entries. + * input[0] .. input[decimate * (n - 1) + ntaps() - 1] are referenced to + * compute the output values. + */ + void filterNdec (gr_complex output[], const gr_complex input[], + unsigned long n, unsigned decimate); + + /*! + * \brief install \p new_taps as the current taps. + */ + void set_taps (const std::vector<float> &taps) + { + d_taps = gr_reverse(taps); + //d_taps = (taps); + + if(d_buffer != NULL) + free(d_buffer); + + // FIXME: memalign this to 16-byte boundaries for SIMD later + d_buffer = (gr_complex*)malloc(sizeof(gr_complex) * 2 * d_taps.size()); + memset(d_buffer, 0x00, sizeof(gr_complex) * 2 * d_taps.size()); + d_idx = 0; + } + + // ACCESSORS + + /*! + * \return number of taps in filter. + */ + unsigned ntaps () const { return d_taps.size (); } + + /*! + * \return current taps + */ + const std::vector<float> get_taps () const + { + return gr_reverse(d_taps); + } +}; + +#endif /* INCLUDED_GR_GR_FIR_FILTER_WITH_BUFFER_CCF_H */ -- cgit v1.2.3 From e037d329ed2b80c655f7d5c0fcdcef8353b6c52f Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Sat, 16 Oct 2010 14:35:03 -0400 Subject: Cleaning up the new FIR filter implementation. Protects against some corner cases and adds filterN. --- .../lib/filter/gri_fir_filter_with_buffer_ccf.cc | 34 ++++++++-------------- .../lib/filter/gri_fir_filter_with_buffer_ccf.h | 11 ++++--- 2 files changed, 19 insertions(+), 26 deletions(-) (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc index e9545549f9..55e316d027 100644 --- a/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc @@ -23,8 +23,8 @@ #ifdef HAVE_CONFIG_H #include <config.h> #endif + #include <gri_fir_filter_with_buffer_ccf.h> -#include <cstdio> gri_fir_filter_with_buffer_ccf::gri_fir_filter_with_buffer_ccf(const std::vector<float> &taps) { @@ -34,42 +34,30 @@ gri_fir_filter_with_buffer_ccf::gri_fir_filter_with_buffer_ccf(const std::vector gri_fir_filter_with_buffer_ccf::~gri_fir_filter_with_buffer_ccf() { - free(d_buffer); + if(d_buffer != NULL) + free(d_buffer); } gr_complex gri_fir_filter_with_buffer_ccf::filter (gr_complex input) { -#if 0 - unsigned int i; - - for(i = ntaps()-1; i > 0; i--) { - d_buffer[i] = d_buffer[i-1]; - } - d_buffer[0] = input; - - gr_complex out = d_buffer[0]*d_taps[0]; - for(i = 1; i < ntaps(); i++) { - out += d_buffer[i]*d_taps[i]; - } - return out; - -#else unsigned int i; d_buffer[d_idx] = input; d_buffer[d_idx+ntaps()] = input; + + // using the later for the case when ntaps=0; + // profiling shows this doesn't make a difference //d_idx = (d_idx + 1) % ntaps(); d_idx++; - if(d_idx == ntaps()) + if(d_idx >= ntaps()) d_idx = 0; - gr_complex out = d_buffer[d_idx]*d_taps[0]; - for(i = 1; i < ntaps(); i++) { + gr_complex out = gr_complex(0,0); + for(i = 0; i < ntaps(); i++) { out += d_buffer[d_idx + i]*d_taps[i]; } return out; -#endif } void @@ -77,5 +65,7 @@ gri_fir_filter_with_buffer_ccf::filterN (gr_complex output[], const gr_complex input[], unsigned long n) { - + for(unsigned long i = 0; i < n; i++) { + output[i] = filter(input[i]); + } } diff --git a/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h index 5adc3e231f..c91d70534e 100644 --- a/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h @@ -33,6 +33,7 @@ #include <gr_types.h> #include <gr_reverse.h> #include <string.h> +#include <cstdio> /*! * \brief FIR with internal buffer for gr_complex input, @@ -100,14 +101,16 @@ public: void set_taps (const std::vector<float> &taps) { d_taps = gr_reverse(taps); - //d_taps = (taps); - if(d_buffer != NULL) + if(d_buffer != NULL) { free(d_buffer); + d_buffer = NULL; + } // FIXME: memalign this to 16-byte boundaries for SIMD later - d_buffer = (gr_complex*)malloc(sizeof(gr_complex) * 2 * d_taps.size()); - memset(d_buffer, 0x00, sizeof(gr_complex) * 2 * d_taps.size()); + size_t t = sizeof(gr_complex) * 2 * d_taps.size(); + d_buffer = (gr_complex*)malloc(t); + memset(d_buffer, 0x00, t); d_idx = 0; } -- cgit v1.2.3 From 72c9a5a158b0b18964c8f2f8f914f16060868146 Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Sat, 16 Oct 2010 14:36:38 -0400 Subject: Cleaning up synthesis filter and using new FIR filter with buffer. --- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.cc | 21 +-------------------- .../lib/filter/gr_pfb_synthesis_filterbank_ccf.h | 2 -- 2 files changed, 1 insertion(+), 22 deletions(-) (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc index 0b31bcf72e..9fad1bd0d8 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc @@ -25,8 +25,6 @@ #endif #include <gr_pfb_synthesis_filterbank_ccf.h> -#include <gr_fir_ccf.h> -#include <gr_fir_util.h> #include <gri_fft.h> #include <gr_io_signature.h> #include <cstdio> @@ -48,18 +46,12 @@ gr_pfb_synthesis_filterbank_ccf::gr_pfb_synthesis_filterbank_ccf numchans), d_updated (false), d_numchans(numchans) { - //d_filters = std::vector<gr_fir_ccf*>(d_numchans); d_filters = std::vector<gri_fir_filter_with_buffer_ccf*>(d_numchans); - //d_buffer = new gr_complex*[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] = new gri_fir_filter_with_buffer_ccf(vtaps); - //d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); - //d_buffer[i] = new gr_complex[65535]; - //memset(d_buffer[i], 0, 65535*sizeof(gr_complex)); } // Now, actually set the filters' taps @@ -167,22 +159,11 @@ gr_pfb_synthesis_filterbank_ccf::work (int noutput_items, d_fft->execute(); for(i = 0; i < d_numchans; i++) { - //d_buffer[i][n+d_taps_per_filter-1] = d_fft->get_outbuf()[i]; - //out[d_numchans-i-1] = d_filters[d_numchans-i-1]->filter(&d_buffer[i][n]); out[d_numchans-i-1] = d_filters[d_numchans-i-1]->filter(d_fft->get_outbuf()[i]); } + out += d_numchans; } - // Move the last chunk of memory to the front for the next entry - // this make sure that the first taps_per_filter values are correct - - /* - for(i = 0; i < d_numchans; i++) { - memcpy(d_buffer[i], &d_buffer[i][n], - (d_taps_per_filter)*sizeof(gr_complex)); - } - */ - return noutput_items; } diff --git a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h index 27c8c2c508..f5b1cbb946 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h @@ -32,7 +32,6 @@ typedef boost::shared_ptr<gr_pfb_synthesis_filterbank_ccf> gr_pfb_synthesis_filt gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf (unsigned int numchans, const std::vector<float> &taps); -class gr_fir_ccf; class gri_fft_complex; @@ -62,7 +61,6 @@ class gr_pfb_synthesis_filterbank_ccf : public gr_sync_interpolator unsigned int d_numchans; unsigned int d_taps_per_filter; gri_fft_complex *d_fft; - //gr_complex **d_buffer; std::vector< gri_fir_filter_with_buffer_ccf*> d_filters; std::vector< std::vector<float> > d_taps; -- cgit v1.2.3 From 62042813aeeffeeb6091e229761c5068b5ed5cde Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Sat, 16 Oct 2010 14:37:55 -0400 Subject: Adding QA code for fir filter with buffer. --- gnuradio-core/src/lib/filter/Makefile.am | 6 +- gnuradio-core/src/lib/filter/qa_filter.cc | 2 + .../filter/qa_gri_fir_filter_with_buffer_ccf.cc | 148 +++++++++++++++++++++ .../lib/filter/qa_gri_fir_filter_with_buffer_ccf.h | 43 ++++++ gnuradio-examples/python/pfb/synth_filter.py | 3 +- 5 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccf.cc create mode 100644 gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccf.h (limited to 'gnuradio-core/src') diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am index 5c7473d06f..ff6c546fdb 100644 --- a/gnuradio-core/src/lib/filter/Makefile.am +++ b/gnuradio-core/src/lib/filter/Makefile.am @@ -222,7 +222,8 @@ libfilter_qa_la_common_SOURCES = \ qa_gr_fir_scc.cc \ qa_gr_rotator.cc \ qa_gri_mmse_fir_interpolator.cc \ - qa_gri_mmse_fir_interpolator_cc.cc + qa_gri_mmse_fir_interpolator_cc.cc \ + qa_gri_fir_filter_with_buffer_ccf.cc if MD_CPU_generic libfilter_la_SOURCES = $(libfilter_la_common_SOURCES) $(generic_CODE) @@ -328,7 +329,8 @@ noinst_HEADERS = \ qa_gr_fir_scc.h \ qa_gr_rotator.h \ qa_gri_mmse_fir_interpolator.h \ - qa_gri_mmse_fir_interpolator_cc.h + qa_gri_mmse_fir_interpolator_cc.h \ + qa_gri_fir_filter_with_buffer_ccf.h if PYTHON diff --git a/gnuradio-core/src/lib/filter/qa_filter.cc b/gnuradio-core/src/lib/filter/qa_filter.cc index 878d48023b..b9a30ba42b 100644 --- a/gnuradio-core/src/lib/filter/qa_filter.cc +++ b/gnuradio-core/src/lib/filter/qa_filter.cc @@ -36,6 +36,7 @@ #include <qa_gri_mmse_fir_interpolator.h> #include <qa_gri_mmse_fir_interpolator_cc.h> #include <qa_gr_rotator.h> +#include <qa_gri_fir_filter_with_buffer_ccf.h> CppUnit::TestSuite * qa_filter::suite () @@ -51,6 +52,7 @@ qa_filter::suite () s->addTest (qa_gri_mmse_fir_interpolator::suite ()); s->addTest (qa_gri_mmse_fir_interpolator_cc::suite ()); s->addTest (qa_gr_rotator::suite ()); + s->addTest (qa_gri_fir_filter_with_buffer_ccf::suite ()); return s; } diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccf.cc b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccf.cc new file mode 100644 index 0000000000..f2e09db1cf --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccf.cc @@ -0,0 +1,148 @@ +/* -*- c++ -*- */ +/* + * Copyright 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_types.h> +#include <qa_gri_fir_filter_with_buffer_ccf.h> +#include <gri_fir_filter_with_buffer_ccf.h> +#include <string.h> +#include <iostream> +#include <cmath> +#include <cppunit/TestAssert.h> +#include <random.h> +#include <malloc16.h> +#include <string.h> + +typedef gr_complex i_type; +typedef gr_complex o_type; +typedef float tap_type; +typedef gr_complex acc_type; + +using std::vector; + +#define ERR_DELTA (1e-5) + +#define NELEM(x) (sizeof (x) / sizeof (x[0])) + +static float +uniform () +{ + return 2.0 * ((float) random () / RANDOM_MAX - 0.5); // uniformly (-1, 1) +} + +static void +random_floats (float *buf, unsigned n) +{ + for (unsigned i = 0; i < n; i++) + buf[i] = (float) rint (uniform () * 32767); +} + +static void +random_complex (gr_complex *buf, unsigned n) +{ + for (unsigned i = 0; i < n; i++){ + float re = rint (uniform () * 32767); + float im = rint (uniform () * 32767); + buf[i] = gr_complex (re, im); + } +} + +static o_type +ref_dotprod (const i_type input[], const tap_type taps[], int ntaps) +{ + acc_type sum = 0; + for (int i = 0; i < ntaps; i++) { + sum += input[i] * taps[i]; + } + + return sum; +} + +// +// Test for ntaps in [0,9], and input lengths in [0,17]. +// This ensures that we are building the shifted taps correctly, +// and exercises all corner cases on input alignment and length. +// + +void +qa_gri_fir_filter_with_buffer_ccf::t1 () +{ + const int MAX_TAPS = 9; + const int OUTPUT_LEN = 17; + const int INPUT_LEN = MAX_TAPS + OUTPUT_LEN; + + // Mem aligned buffer not really necessary, but why not? + i_type *input = (i_type *)malloc16Align(INPUT_LEN * sizeof(i_type)); + i_type *dline = (i_type*)malloc16Align(INPUT_LEN * sizeof(i_type)); + o_type expected_output[OUTPUT_LEN]; + o_type actual_output[OUTPUT_LEN]; + tap_type taps[MAX_TAPS]; + + srandom (0); // we want reproducibility + memset(dline, 0, INPUT_LEN*sizeof(i_type)); + + for (int n = 0; n <= MAX_TAPS; n++){ + for (int ol = 0; ol <= OUTPUT_LEN; ol++){ + + // cerr << "@@@ n:ol " << n << ":" << ol << endl; + + // build random test case + random_complex (input, INPUT_LEN); + random_floats (taps, MAX_TAPS); + + // compute expected output values + memset(dline, 0, INPUT_LEN*sizeof(i_type)); + for (int o = 0; o < ol; o++){ + // use an actual delay line for this test + for(int oo = INPUT_LEN-1; oo > 0; oo--) + dline[oo] = dline[oo-1]; + dline[0] = input[o]; + expected_output[o] = ref_dotprod (dline, taps, n); + } + + // build filter + vector<tap_type> f1_taps(&taps[0], &taps[n]); + gri_fir_filter_with_buffer_ccf *f1 = new gri_fir_filter_with_buffer_ccf(f1_taps); + + // zero the output, then do the filtering + memset (actual_output, 0, sizeof (actual_output)); + f1->filterN (actual_output, input, ol); + + // check results + // + // we use a sloppy error margin because on the x86 architecture, + // our reference implementation is using 80 bit floating point + // arithmetic, while the SSE version is using 32 bit float point + // arithmetic. + + for (int o = 0; o < ol; o++){ + CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected_output[o], actual_output[o], + abs (expected_output[o]) * ERR_DELTA); + } + delete f1; + } + } + free16Align(input); +} diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccf.h b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccf.h new file mode 100644 index 0000000000..b80be70a79 --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccf.h @@ -0,0 +1,43 @@ +/* -*- c++ -*- */ +/* + * Copyright 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. + */ +#ifndef _QA_GRI_FIR_FILTER_WITH_BUFFER_CCF_H_ +#define _QA_GRI_FIR_FILTER_WITH_BUFFER_CCF_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gri_fir_filter_with_buffer_ccf : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gri_fir_filter_with_buffer_ccf); + CPPUNIT_TEST (t1); + CPPUNIT_TEST_SUITE_END (); + + private: + + void t1 (); + // void t2 (); + // void t3 (); + +}; + + +#endif /* _QA_GR_FIR_FILTER_WITH_BUFFER_CCF_H_ */ diff --git a/gnuradio-examples/python/pfb/synth_filter.py b/gnuradio-examples/python/pfb/synth_filter.py index b1708fde5b..015ebd6684 100755 --- a/gnuradio-examples/python/pfb/synth_filter.py +++ b/gnuradio-examples/python/pfb/synth_filter.py @@ -7,8 +7,7 @@ def main(): N = 1000000 fs = 8000 - #freqs = [100, 200, 300, 400, 500] - freqs = [100,] + freqs = [100, 200, 300, 400, 500] nchans = 7 sigs = list() -- cgit v1.2.3