diff options
31 files changed, 2058 insertions, 7 deletions
diff --git a/gnuradio-core/src/lib/filter/.gitignore b/gnuradio-core/src/lib/filter/.gitignore index 2d009f154..faaf02cb8 100644 --- a/gnuradio-core/src/lib/filter/.gitignore +++ b/gnuradio-core/src/lib/filter/.gitignore @@ -211,4 +211,16 @@ /gr_rational_resampler_base_scc.cc /gr_rational_resampler_base_scc.h /gr_rational_resampler_base_scc.i +/gri_fir_filter_with_buffer_ccc.cc +/gri_fir_filter_with_buffer_ccc.h +/gri_fir_filter_with_buffer_ccf.cc +/gri_fir_filter_with_buffer_ccf.h +/gri_fir_filter_with_buffer_fcc.cc +/gri_fir_filter_with_buffer_fcc.h +/gri_fir_filter_with_buffer_fff.cc +/gri_fir_filter_with_buffer_fff.h +/gri_fir_filter_with_buffer_fsf.cc +/gri_fir_filter_with_buffer_fsf.h +/gri_fir_filter_with_buffer_scc.cc +/gri_fir_filter_with_buffer_scc.h /stamp-* diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am index 23c1dadc3..6d2ec1c7e 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 # @@ -44,6 +44,7 @@ code_generator = \ generate_gr_fir_sysconfig_generic.py \ generate_gr_fir_util.py \ generate_gr_freq_xlating_fir_filter_XXX.py \ + generate_gri_fir_filter_with_buffer_XXX.py \ generate_utils.py \ gr_fir_XXX.cc.t \ gr_fir_XXX.h.t \ @@ -60,7 +61,10 @@ code_generator = \ gr_rational_resampler_base_XXX.i.t \ gr_freq_xlating_fir_filter_XXX.cc.t \ gr_freq_xlating_fir_filter_XXX.h.t \ - gr_freq_xlating_fir_filter_XXX.i.t + gr_freq_xlating_fir_filter_XXX.i.t \ + gri_fir_filter_with_buffer_XXX.cc.t \ + gri_fir_filter_with_buffer_XXX.h.t + # Source built by Python into $(builddir) BUILT_SOURCES = \ @@ -205,6 +209,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 +225,13 @@ 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 \ + qa_gri_fir_filter_with_buffer_ccc.cc \ + qa_gri_fir_filter_with_buffer_fcc.cc \ + qa_gri_fir_filter_with_buffer_fff.cc \ + qa_gri_fir_filter_with_buffer_fsf.cc \ + qa_gri_fir_filter_with_buffer_scc.cc if MD_CPU_generic libfilter_la_SOURCES = $(libfilter_la_common_SOURCES) $(generic_CODE) @@ -288,6 +299,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 +336,13 @@ 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 \ + qa_gri_fir_filter_with_buffer_ccc.h \ + qa_gri_fir_filter_with_buffer_fcc.h \ + qa_gri_fir_filter_with_buffer_fff.h \ + qa_gri_fir_filter_with_buffer_fsf.h \ + qa_gri_fir_filter_with_buffer_scc.h if PYTHON @@ -344,6 +362,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/Makefile.gen b/gnuradio-core/src/lib/filter/Makefile.gen index 6809274fa..909899c05 100644 --- a/gnuradio-core/src/lib/filter/Makefile.gen +++ b/gnuradio-core/src/lib/filter/Makefile.gen @@ -40,7 +40,14 @@ GENERATED_H = \ gr_rational_resampler_base_fcc.h \ gr_rational_resampler_base_fff.h \ gr_rational_resampler_base_fsf.h \ - gr_rational_resampler_base_scc.h + gr_rational_resampler_base_scc.h \ + gri_fir_filter_with_buffer_ccc.h \ + gri_fir_filter_with_buffer_ccf.h \ + gri_fir_filter_with_buffer_fcc.h \ + gri_fir_filter_with_buffer_fff.h \ + gri_fir_filter_with_buffer_fsf.h \ + gri_fir_filter_with_buffer_scc.h + GENERATED_I = \ gr_fir_filter_ccc.i \ @@ -107,5 +114,11 @@ GENERATED_CC = \ gr_rational_resampler_base_fcc.cc \ gr_rational_resampler_base_fff.cc \ gr_rational_resampler_base_fsf.cc \ - gr_rational_resampler_base_scc.cc + gr_rational_resampler_base_scc.cc \ + gri_fir_filter_with_buffer_ccc.cc \ + gri_fir_filter_with_buffer_ccf.cc \ + gri_fir_filter_with_buffer_fcc.cc \ + gri_fir_filter_with_buffer_fff.cc \ + gri_fir_filter_with_buffer_fsf.cc \ + gri_fir_filter_with_buffer_scc.cc 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/generate_all.py b/gnuradio-core/src/lib/filter/generate_all.py index b34e13c73..ceed2b851 100755 --- a/gnuradio-core/src/lib/filter/generate_all.py +++ b/gnuradio-core/src/lib/filter/generate_all.py @@ -30,6 +30,7 @@ import generate_gr_fir_sysconfig_generic import generate_gr_fir_sysconfig import generate_gr_fir_util import generate_gr_fir_XXX +import generate_gri_fir_filter_with_buffer_XXX def generate_all(): generate_gr_fir_XXX.generate() @@ -40,6 +41,7 @@ def generate_all(): generate_gr_fir_sysconfig_generic.generate() generate_gr_fir_sysconfig.generate() generate_gr_fir_util.generate() + generate_gri_fir_filter_with_buffer_XXX.generate() output_glue('filter') if __name__ == '__main__': diff --git a/gnuradio-core/src/lib/filter/generate_gri_fir_filter_with_buffer_XXX.py b/gnuradio-core/src/lib/filter/generate_gri_fir_filter_with_buffer_XXX.py new file mode 100755 index 000000000..f586b0c27 --- /dev/null +++ b/gnuradio-core/src/lib/filter/generate_gri_fir_filter_with_buffer_XXX.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# -*- python -*- +# +# 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. +# + +import re +from generate_utils import * + +roots = ['gri_fir_filter_with_buffer_XXX',] + +def code3_to_acc_code (code3): + if i_code (code3) == 'c' or o_code (code3) == 'c' or tap_code (code3) == 'c': + return 'c' + if i_code (code3) == 'f' or o_code (code3) == 'f' or tap_code (code3) == 'f': + return 'f' + if i_code (code3) == 'i' or o_code (code3) == 'i' or tap_code (code3) == 'i': + return 'i' + return 'i' # even short short short needs int accumulator + +def code3_to_input_cast (code3): + if i_code (code3) == 's' and o_code (code3) == 'c': + return '(float)' + return '' + +def expand_h_cc (root, code3): + d = init_dict (root, code3) + expand_template (d, root + '.h.t') + expand_template (d, root + '.cc.t') + +def init_dict (root, code3): + name = re.sub ('X+', code3, root) + d = standard_dict (name, code3) + d['INPUT_CAST'] = code3_to_input_cast (code3) + acc_code = code3_to_acc_code (code3) + d['ACC_TYPE'] = char_to_type[acc_code] + return d + + +def generate (): + for r in roots: + for s in fir_signatures: + expand_h_cc (r, s) + + +if __name__ == '__main__': + generate () 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_XXX.cc.t b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_XXX.cc.t new file mode 100644 index 000000000..c0d061c81 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_XXX.cc.t @@ -0,0 +1,88 @@ +/* -*- 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 <@NAME@.h> + +@NAME@::@NAME@(const std::vector<@TAP_TYPE@> &taps) +{ + d_buffer = NULL; + set_taps(taps); +} + +@NAME@::~@NAME@() +{ + if(d_buffer != NULL) + free(d_buffer); +} + +void +@NAME@::set_taps (const std::vector<@TAP_TYPE@> &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(@I_TYPE@) * 2 * d_taps.size(); + d_buffer = (@I_TYPE@*)malloc(t); + memset(d_buffer, 0x00, t); + d_idx = 0; +} + +@O_TYPE@ +@NAME@::filter (@I_TYPE@ 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; + + @ACC_TYPE@ out = 0; + for(i = 0; i < ntaps(); i++) { + out += @INPUT_CAST@ d_buffer[d_idx + i] * d_taps[i]; + } + return (@O_TYPE@)out; +} + +void +@NAME@::filterN (@O_TYPE@ output[], + const @I_TYPE@ 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_XXX.h.t b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_XXX.h.t new file mode 100644 index 000000000..d566b3674 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_XXX.h.t @@ -0,0 +1,119 @@ +/* -*- 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_gri_fir_XXX.py + * Any changes made to this file will be overwritten. + */ + + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include <vector> +#include <gr_types.h> +#include <gr_reverse.h> +#include <string.h> +#include <cstdio> + +/*! + * \brief FIR with internal buffer for @I_TYPE@ input, + @O_TYPE@ output and @TAP_TYPE@ taps + * \ingroup filter + * + */ + +class @NAME@ { + +protected: + std::vector<@TAP_TYPE@> d_taps; // reversed taps + @I_TYPE@ *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. + */ + @NAME@ (const std::vector<@TAP_TYPE@> &taps); + + ~@NAME@ (); + + // 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. + */ + @O_TYPE@ filter (@I_TYPE@ 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 (@O_TYPE@ output[], const @I_TYPE@ 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 (@O_TYPE@ output[], const @I_TYPE@ input[], + unsigned long n, unsigned decimate); + + /*! + * \brief install \p new_taps as the current taps. + */ + void set_taps (const std::vector<@TAP_TYPE@> &taps); + + // ACCESSORS + + /*! + * \return number of taps in filter. + */ + unsigned ntaps () const { return d_taps.size (); } + + /*! + * \return current taps + */ + const std::vector<@TAP_TYPE@> get_taps () const + { + return gr_reverse(d_taps); + } +}; + +#endif /* @GUARD_NAME@ */ 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..2b69f8b03 --- /dev/null +++ b/gnuradio-core/src/lib/filter/gri_fir_filter_with_buffer_ccf.h @@ -0,0 +1,119 @@ +/* -*- 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_gri_fir_XXX.py + * Any changes made to this file will be overwritten. + */ + + +#ifndef INCLUDED_GRI_FIR_FILTER_WITH_BUFFER_CCF_H +#define INCLUDED_GRI_FIR_FILTER_WITH_BUFFER_CCF_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); + + // 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_GRI_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..0d03cb0ee 100644 --- a/gnuradio-core/src/lib/filter/qa_filter.cc +++ b/gnuradio-core/src/lib/filter/qa_filter.cc @@ -36,6 +36,12 @@ #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> +#include <qa_gri_fir_filter_with_buffer_ccc.h> +#include <qa_gri_fir_filter_with_buffer_fcc.h> +#include <qa_gri_fir_filter_with_buffer_fff.h> +#include <qa_gri_fir_filter_with_buffer_fsf.h> +#include <qa_gri_fir_filter_with_buffer_scc.h> CppUnit::TestSuite * qa_filter::suite () @@ -51,6 +57,12 @@ 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 ()); + s->addTest (qa_gri_fir_filter_with_buffer_ccc::suite ()); + s->addTest (qa_gri_fir_filter_with_buffer_fcc::suite ()); + s->addTest (qa_gri_fir_filter_with_buffer_fff::suite ()); + s->addTest (qa_gri_fir_filter_with_buffer_fsf::suite ()); + s->addTest (qa_gri_fir_filter_with_buffer_scc::suite ()); return s; } diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccc.cc b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccc.cc new file mode 100644 index 000000000..cff81ab13 --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccc.cc @@ -0,0 +1,141 @@ +/* -*- 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_ccc.h> +#include <gri_fir_filter_with_buffer_ccc.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 gr_complex 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_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_ccc::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_complex (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_ccc *f1 = new gri_fir_filter_with_buffer_ccc(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_ccc.h b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccc.h new file mode 100644 index 000000000..411a66a9a --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_ccc.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_CCC_H_ +#define _QA_GRI_FIR_FILTER_WITH_BUFFER_CCC_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gri_fir_filter_with_buffer_ccc : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gri_fir_filter_with_buffer_ccc); + CPPUNIT_TEST (t1); + CPPUNIT_TEST_SUITE_END (); + + private: + + void t1 (); + // void t2 (); + // void t3 (); + +}; + + +#endif /* _QA_GR_FIR_FILTER_WITH_BUFFER_CCC_H_ */ 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_ */ diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fcc.cc b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fcc.cc new file mode 100644 index 000000000..de0da9f1c --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fcc.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_fcc.h> +#include <gri_fir_filter_with_buffer_fcc.h> +#include <string.h> +#include <iostream> +#include <cmath> +#include <cppunit/TestAssert.h> +#include <random.h> +#include <malloc16.h> +#include <string.h> + +typedef float i_type; +typedef gr_complex o_type; +typedef gr_complex 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_fcc::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_floats (input, INPUT_LEN); + random_complex (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_fcc *f1 = new gri_fir_filter_with_buffer_fcc(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_fcc.h b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fcc.h new file mode 100644 index 000000000..81b39f488 --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fcc.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_FCC_H_ +#define _QA_GRI_FIR_FILTER_WITH_BUFFER_FCC_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gri_fir_filter_with_buffer_fcc : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gri_fir_filter_with_buffer_fcc); + CPPUNIT_TEST (t1); + CPPUNIT_TEST_SUITE_END (); + + private: + + void t1 (); + // void t2 (); + // void t3 (); + +}; + + +#endif /* _QA_GR_FIR_FILTER_WITH_BUFFER_FCC_H_ */ diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fff.cc b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fff.cc new file mode 100644 index 000000000..ce689a54b --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fff.cc @@ -0,0 +1,137 @@ +/* -*- 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_fff.h> +#include <gri_fir_filter_with_buffer_fff.h> +#include <string.h> +#include <iostream> +#include <cmath> +#include <cppunit/TestAssert.h> +#include <random.h> +#include <malloc16.h> +#include <string.h> + +typedef float i_type; +typedef float o_type; +typedef float tap_type; +typedef float 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 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_fff::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_floats (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_fff *f1 = new gri_fir_filter_with_buffer_fff(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_DOUBLES_EQUAL(expected_output[o], actual_output[o], + fabsf (expected_output[o]) * ERR_DELTA); + } + delete f1; + } + } + free16Align(input); +} diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fff.h b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fff.h new file mode 100644 index 000000000..5bb6c3e93 --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fff.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_FFF_H_ +#define _QA_GRI_FIR_FILTER_WITH_BUFFER_FFF_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gri_fir_filter_with_buffer_fff : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gri_fir_filter_with_buffer_fff); + CPPUNIT_TEST (t1); + CPPUNIT_TEST_SUITE_END (); + + private: + + void t1 (); + // void t2 (); + // void t3 (); + +}; + + +#endif /* _QA_GR_FIR_FILTER_WITH_BUFFER_FFF_H_ */ diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fsf.cc b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fsf.cc new file mode 100644 index 000000000..f09a1d7ac --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fsf.cc @@ -0,0 +1,128 @@ +/* -*- 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_fsf.h> +#include <gri_fir_filter_with_buffer_fsf.h> +#include <string.h> +#include <iostream> +#include <cmath> +#include <cppunit/TestAssert.h> +#include <random.h> +#include <malloc16.h> +#include <string.h> + +typedef float i_type; +typedef short o_type; +typedef float tap_type; +typedef float acc_type; + +using std::vector; + +#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 () * 128); +} + +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 (o_type)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_fsf::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_floats (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_fsf *f1 = new gri_fir_filter_with_buffer_fsf(f1_taps); + + // zero the output, then do the filtering + memset (actual_output, 0, sizeof (actual_output)); + f1->filterN (actual_output, input, ol); + + // check results + for (int o = 0; o < ol; o++){ + CPPUNIT_ASSERT_EQUAL(expected_output[o], actual_output[o]); + } + delete f1; + } + } + free16Align(input); +} diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fsf.h b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fsf.h new file mode 100644 index 000000000..38899b352 --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_fsf.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_FSF_H_ +#define _QA_GRI_FIR_FILTER_WITH_BUFFER_FSF_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gri_fir_filter_with_buffer_fsf : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gri_fir_filter_with_buffer_fsf); + CPPUNIT_TEST (t1); + CPPUNIT_TEST_SUITE_END (); + + private: + + void t1 (); + // void t2 (); + // void t3 (); + +}; + + +#endif /* _QA_GR_FIR_FILTER_WITH_BUFFER_FSF_H_ */ diff --git a/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_scc.cc b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_scc.cc new file mode 100644 index 000000000..4ba433ebf --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_scc.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_scc.h> +#include <gri_fir_filter_with_buffer_scc.h> +#include <string.h> +#include <iostream> +#include <cmath> +#include <cppunit/TestAssert.h> +#include <random.h> +#include <malloc16.h> +#include <string.h> + +typedef short i_type; +typedef gr_complex o_type; +typedef gr_complex 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_shorts (short *buf, unsigned n) +{ + for (unsigned i = 0; i < n; i++) + buf[i] = (short) rint (uniform () * 16384); +} + +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 += (float)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_scc::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_shorts (input, INPUT_LEN); + random_complex (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_scc *f1 = new gri_fir_filter_with_buffer_scc(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_scc.h b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_scc.h new file mode 100644 index 000000000..fd9fe5b76 --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gri_fir_filter_with_buffer_scc.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_SCC_H_ +#define _QA_GRI_FIR_FILTER_WITH_BUFFER_SCC_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gri_fir_filter_with_buffer_scc : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gri_fir_filter_with_buffer_scc); + CPPUNIT_TEST (t1); + CPPUNIT_TEST_SUITE_END (); + + private: + + void t1 (); + // void t2 (); + // void t3 (); + +}; + + +#endif /* _QA_GR_FIR_FILTER_WITH_BUFFER_SCC_H_ */ diff --git a/gnuradio-examples/python/pfb/synth_filter.py b/gnuradio-examples/python/pfb/synth_filter.py new file mode 100755 index 000000000..a1562f9ea --- /dev/null +++ b/gnuradio-examples/python/pfb/synth_filter.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# +# 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. +# + +from gnuradio import gr, blks2 +import scipy, pylab + +def main(): + N = 1000000 + fs = 8000 + + freqs = [100, 200, 300, 400, 500] + nchans = 7 + + sigs = list() + for fi in freqs: + s = gr.sig_source_c(fs, gr.GR_SIN_WAVE, fi, 1) + sigs.append(s) + + taps = gr.firdes.low_pass_2(len(freqs), fs, fs/float(nchans)/2, 100, 100) + print "Num. Taps = %d (taps per filter = %d)" % (len(taps), + len(taps)/nchans) + filtbank = gr.pfb_synthesis_filterbank_ccf(nchans, taps) + + head = gr.head(gr.sizeof_gr_complex, N) + snk = gr.vector_sink_c() + + tb = gr.top_block() + tb.connect(filtbank, head, snk) + + for i,si in enumerate(sigs): + tb.connect(si, (filtbank, i)) + + tb.run() + + if 1: + f1 = pylab.figure(1) + s1 = f1.add_subplot(1,1,1) + s1.plot(snk.data()[1000:]) + + fftlen = 2048 + f2 = pylab.figure(2) + s2 = f2.add_subplot(1,1,1) + winfunc = scipy.blackman + s2.psd(snk.data()[10000:], NFFT=fftlen, + Fs = nchans*fs, + noverlap=fftlen/4, + window = lambda d: d*winfunc(fftlen)) + + pylab.show() + +if __name__ == "__main__": + main() diff --git a/gnuradio-examples/python/pfb/synth_to_chan.py b/gnuradio-examples/python/pfb/synth_to_chan.py new file mode 100755 index 000000000..1beda1a54 --- /dev/null +++ b/gnuradio-examples/python/pfb/synth_to_chan.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# +# 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. +# + +from gnuradio import gr, blks2 +import scipy, pylab + +def main(): + N = 1000000 + fs = 8000 + + freqs = [100, 200, 300, 400, 500] + nchans = 7 + + sigs = list() + fmtx = list() + for fi in freqs: + s = gr.sig_source_f(fs, gr.GR_SIN_WAVE, fi, 1) + fm = blks2.nbfm_tx (fs, 4*fs, max_dev=10000, tau=75e-6) + sigs.append(s) + fmtx.append(fm) + + syntaps = gr.firdes.low_pass_2(len(freqs), fs, fs/float(nchans)/2, 100, 100) + print "Synthesis Num. Taps = %d (taps per filter = %d)" % (len(syntaps), + len(syntaps)/nchans) + chtaps = gr.firdes.low_pass_2(len(freqs), fs, fs/float(nchans)/2, 100, 100) + print "Channelizer Num. Taps = %d (taps per filter = %d)" % (len(chtaps), + len(chtaps)/nchans) + filtbank = gr.pfb_synthesis_filterbank_ccf(nchans, syntaps) + channelizer = blks2.pfb_channelizer_ccf(nchans, chtaps) + + noise_level = 0.01 + head = gr.head(gr.sizeof_gr_complex, N) + noise = gr.noise_source_c(gr.GR_GAUSSIAN, noise_level) + addnoise = gr.add_cc() + snk_synth = gr.vector_sink_c() + + tb = gr.top_block() + + tb.connect(noise, (addnoise,0)) + tb.connect(filtbank, head, (addnoise, 1)) + tb.connect(addnoise, channelizer) + tb.connect(addnoise, snk_synth) + + snk = list() + for i,si in enumerate(sigs): + tb.connect(si, fmtx[i], (filtbank, i)) + + for i in xrange(nchans): + snk.append(gr.vector_sink_c()) + tb.connect((channelizer, i), snk[i]) + + tb.run() + + if 1: + channel = 1 + data = snk[channel].data()[1000:] + + f1 = pylab.figure(1) + s1 = f1.add_subplot(1,1,1) + s1.plot(data[10000:10200] ) + s1.set_title(("Output Signal from Channel %d" % channel)) + + fftlen = 2048 + winfunc = scipy.blackman + #winfunc = scipy.hamming + + f2 = pylab.figure(2) + s2 = f2.add_subplot(1,1,1) + s2.psd(data, NFFT=fftlen, + Fs = nchans*fs, + noverlap=fftlen/4, + window = lambda d: d*winfunc(fftlen)) + s2.set_title(("Output PSD from Channel %d" % channel)) + + f3 = pylab.figure(3) + s3 = f3.add_subplot(1,1,1) + s3.psd(snk_synth.data()[1000:], NFFT=fftlen, + Fs = nchans*fs, + noverlap=fftlen/4, + window = lambda d: d*winfunc(fftlen)) + s3.set_title("Output of Synthesis Filter") + + pylab.show() + +if __name__ == "__main__": + main() diff --git a/gr-wxgui/src/python/constants.py b/gr-wxgui/src/python/constants.py index 9612f36dd..070be0808 100644 --- a/gr-wxgui/src/python/constants.py +++ b/gr-wxgui/src/python/constants.py @@ -66,6 +66,7 @@ X_PER_DIV_KEY = 'x_per_div' Y_DIVS_KEY = 'y_divs' Y_OFF_KEY = 'y_off' Y_PER_DIV_KEY = 'y_per_div' +Y_AXIS_LABEL = 'y_axis_label' MAXIMUM_KEY = 'maximum' MINIMUM_KEY = 'minimum' NUM_BINS_KEY = 'num_bins' diff --git a/gr-wxgui/src/python/scope_window.py b/gr-wxgui/src/python/scope_window.py index a9917782f..89a808cec 100644 --- a/gr-wxgui/src/python/scope_window.py +++ b/gr-wxgui/src/python/scope_window.py @@ -435,6 +435,7 @@ class scope_window(wx.Panel, pubsub.pubsub): use_persistence, persist_alpha, trig_mode, + y_axis_label, ): pubsub.pubsub.__init__(self) #check num inputs @@ -471,6 +472,7 @@ class scope_window(wx.Panel, pubsub.pubsub): self[T_DIVS_KEY] = 8 self[X_DIVS_KEY] = 8 self[Y_DIVS_KEY] = 8 + self[Y_AXIS_LABEL] = y_axis_label self[FRAME_RATE_KEY] = frame_rate self[TRIGGER_LEVEL_KEY] = 0 self[TRIGGER_CHANNEL_KEY] = 0 @@ -676,7 +678,7 @@ class scope_window(wx.Panel, pubsub.pubsub): self.plotter.set_x_label('Time', 's') self.plotter.set_x_grid(self.get_t_min(), self.get_t_max(), self[T_PER_DIV_KEY], True) #update the y axis - self.plotter.set_y_label('Counts') + self.plotter.set_y_label(self[Y_AXIS_LABEL]) self.plotter.set_y_grid(self.get_y_min(), self.get_y_max(), self[Y_PER_DIV_KEY]) #redraw current sample self.handle_samples() diff --git a/gr-wxgui/src/python/scopesink_gl.py b/gr-wxgui/src/python/scopesink_gl.py index 15be23d5a..5ae897400 100644 --- a/gr-wxgui/src/python/scopesink_gl.py +++ b/gr-wxgui/src/python/scopesink_gl.py @@ -77,6 +77,7 @@ class _scope_sink_base(gr.hier_block2, common.wxgui_hb): ac_couple=False, num_inputs=1, trig_mode=scope_window.DEFAULT_TRIG_MODE, + y_axis_label='Counts', frame_rate=scope_window.DEFAULT_FRAME_RATE, use_persistence=False, persist_alpha=None, @@ -134,6 +135,7 @@ class _scope_sink_base(gr.hier_block2, common.wxgui_hb): v_offset=v_offset, xy_mode=xy_mode, trig_mode=trig_mode, + y_axis_label=y_axis_label, ac_couple_key=AC_COUPLE_KEY, trigger_level_key=TRIGGER_LEVEL_KEY, trigger_mode_key=TRIGGER_MODE_KEY, diff --git a/grc/blocks/wxgui_scopesink2.xml b/grc/blocks/wxgui_scopesink2.xml index 50cd977be..ef0377373 100644 --- a/grc/blocks/wxgui_scopesink2.xml +++ b/grc/blocks/wxgui_scopesink2.xml @@ -21,6 +21,7 @@ scopesink2.$(type.fcn)( xy_mode=$xy_mode, num_inputs=$num_inputs, trig_mode=$trig_mode, + y_axis_label=$y_axis_label, #if $win_size() size=$win_size, #end if @@ -156,6 +157,12 @@ $(parent).GridAdd(self.$(id).win, $(', '.join(map(str, $grid_pos())))) <key>gr.gr_TRIG_MODE_STRIPCHART</key> </option> </param> + <param> + <name>Y Axis Label</name> + <key>y_axis_label</key> + <value>Counts</value> + <type>string</type> + </param> <check>not $win_size or len($win_size) == 2</check> <check>not $xy_mode or '$type' == 'complex' or $num_inputs != 1</check> <sink> |