diff options
author | Tom Rondeau | 2010-10-16 17:03:59 -0400 |
---|---|---|
committer | Tom Rondeau | 2010-10-16 17:03:59 -0400 |
commit | 07343791e5aecb6fb1f7b997b5d2aa98d96e4b97 (patch) | |
tree | 7eae5baaaf1d3f9e08765e032499b7ec9ed544dc /gnuradio-core/src | |
parent | d74b45e2b4b5ad5ed772fd452541c2ad7429c0db (diff) | |
parent | 80b84262f6fba7da08d888e73e8cb0e981a3a065 (diff) | |
download | gnuradio-07343791e5aecb6fb1f7b997b5d2aa98d96e4b97.tar.gz gnuradio-07343791e5aecb6fb1f7b997b5d2aa98d96e4b97.tar.bz2 gnuradio-07343791e5aecb6fb1f7b997b5d2aa98d96e4b97.zip |
Merge branch 'synfilt'
Diffstat (limited to 'gnuradio-core/src')
10 files changed, 714 insertions, 3 deletions
diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am index 23c1dadc3..ff6c546fd 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 \ @@ -205,6 +206,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 \ @@ -220,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) @@ -266,6 +269,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 \ @@ -288,6 +292,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 \ @@ -324,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 @@ -344,6 +350,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 bdfb8fa8d..645607cba 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 000000000..9fad1bd0d --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.cc @@ -0,0 +1,169 @@ +/* -*- 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 <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 (1, numchans, sizeof(gr_complex)), + gr_make_io_signature (1, 1, sizeof(gr_complex)), + numchans), + d_updated (false), d_numchans(numchans) +{ + d_filters = std::vector<gri_fir_filter_with_buffer_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] = new gri_fir_filter_with_buffer_ccf(vtaps); + } + + // 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]; + int numsigs = input_items.size(); + int ndiff = d_numchans - numsigs; + unsigned int nhalf = (unsigned int)ceil((float)numsigs/2.0f); + + 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++) { + // 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(); + + for(i = 0; i < d_numchans; i++) { + out[d_numchans-i-1] = d_filters[d_numchans-i-1]->filter(d_fft->get_outbuf()[i]); + } + + out += d_numchans; + } + + 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 000000000..f5b1cbb94 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gr_pfb_synthesis_filterbank_ccf.h @@ -0,0 +1,98 @@ +/* -*- 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> +#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; +gr_pfb_synthesis_filterbank_ccf_sptr gr_make_pfb_synthesis_filterbank_ccf + (unsigned int numchans, const std::vector<float> &taps); + +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; + unsigned int d_taps_per_filter; + gri_fft_complex *d_fft; + 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. + */ + 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 000000000..02a9f0255 --- /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); +}; 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 000000000..55e316d02 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.cc @@ -0,0 +1,71 @@ +/* -*- 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> + +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() +{ + if(d_buffer != NULL) + free(d_buffer); +} + +gr_complex +gri_fir_filter_with_buffer_ccf::filter (gr_complex input) +{ + 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()) + d_idx = 0; + + gr_complex out = gr_complex(0,0); + for(i = 0; i < ntaps(); i++) { + out += d_buffer[d_idx + i]*d_taps[i]; + } + return out; +} + +void +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 new file mode 100644 index 000000000..c91d70534 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h @@ -0,0 +1,133 @@ +/* -*- 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> +#include <cstdio> + +/*! + * \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); + + if(d_buffer != NULL) { + free(d_buffer); + d_buffer = NULL; + } + + // FIXME: memalign this to 16-byte boundaries for SIMD later + size_t t = sizeof(gr_complex) * 2 * d_taps.size(); + d_buffer = (gr_complex*)malloc(t); + memset(d_buffer, 0x00, t); + 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 */ diff --git a/gnuradio-core/src/lib/filter/qa_filter.cc b/gnuradio-core/src/lib/filter/qa_filter.cc index 878d48023..b9a30ba42 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 000000000..f2e09db1c --- /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 000000000..b80be70a7 --- /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_ */ |