From f64b971f34ab813f70b0680ec7ae02744343ef3c Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 1 May 2012 22:10:17 -0400 Subject: filter: work on creating gr-filter top-level component. Builds but does not bring in libgnuradio-fft.so symbols. --- gr-filter/lib/CMakeLists.txt | 60 +++++++++++++++++++ gr-filter/lib/fir_filter_fff_impl.cc | 110 +++++++++++++++++++++++++++++++++++ gr-filter/lib/fir_filter_fff_impl.h | 56 ++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 gr-filter/lib/CMakeLists.txt create mode 100644 gr-filter/lib/fir_filter_fff_impl.cc create mode 100644 gr-filter/lib/fir_filter_fff_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt new file mode 100644 index 000000000..0ffdb75fc --- /dev/null +++ b/gr-filter/lib/CMakeLists.txt @@ -0,0 +1,60 @@ +# Copyright 2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +######################################################################## +# Setup the include and linker paths +######################################################################## +include_directories( + ${GNURADIO_CORE_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +include_directories(${FILTER_INCLUDE_DIRS}) +link_directories(${FILTER_LIBRARY_DIRS}) + +include_directories(${FFT_INCLUDE_DIRS}) +link_directories(${FFT_LIBRARY_DIRS}) + +include_directories(${Boost_INCLUDE_DIRS}) +link_directories(${Boost_LIBRARY_DIRS}) + +include_directories(${FFTW3F_INCLUDE_DIRS}) +link_directories(${FFTW3F_LIBRARY_DIRS}) + +######################################################################## +# Setup library +######################################################################## +list(APPEND filter_sources + fir_filter_fff_impl.cc +) + +list(APPEND filter_libs + gnuradio-core + gnuradio-fft + ${Boost_LIBRARIES} + ${FFTW3F_LIBRARIES} + ${VOLK_LIBRARIES} +) + +add_library(gnuradio-filter SHARED ${filter_sources}) +target_link_libraries(gnuradio-filter ${filter_libs}) +GR_LIBRARY_FOO(gnuradio-filter RUNTIME_COMPONENT "filter_runtime" DEVEL_COMPONENT "filter_devel") +add_dependencies(gnuradio-filter gnuradio-fft filter_generated_includes filter_generated_swigs) diff --git a/gr-filter/lib/fir_filter_fff_impl.cc b/gr-filter/lib/fir_filter_fff_impl.cc new file mode 100644 index 000000000..4a1233a24 --- /dev/null +++ b/gr-filter/lib/fir_filter_fff_impl.cc @@ -0,0 +1,110 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "fir_filter_fff_impl.h" +#include +#include +#include +#include + +namespace gr { + namespace filter { + + fir_filter_fff::sptr + fir_filter_fff::make(int decimation, const std::vector &taps) + { + return gnuradio::get_initial_sptr(new fir_filter_fff_impl + (decimation, taps)); + } + + + fir_filter_fff_impl::fir_filter_fff_impl(int decimation, + const std::vector &taps) + : gr_sync_decimator("fir_filter_fff", + gr_make_io_signature (1, 1, sizeof(float)), + gr_make_io_signature (1, 1, sizeof(float)), + decimation) + { + set_taps(taps); + d_updated = false; + set_history(d_ntaps+1); + } + + fir_filter_fff_impl::~fir_filter_fff_impl() + { + } + + void + fir_filter_fff_impl::set_taps(const std::vector &taps) + { + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_float(d_ntaps); + for(int i = 0; i < d_ntaps; i++) { + d_taps[i] = taps[i]; + } + d_updated = true; + } + + std::vector + fir_filter_fff_impl::taps() const + { + std::vector t; + for(int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[i]); + return t; + } + + int + fir_filter_fff_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float*)input_items[0]; + float *out = (float*)output_items[0]; + + if (d_updated) { + set_history((unsigned int)d_ntaps+1); + d_updated = false; + return 0; // history requirements may have changed. + } + + if (decimation() == 1) { + for(int i = 0; i < noutput_items; i++) { + volk_32f_x2_dot_prod_32f_u(&out[i], &in[i], d_taps, d_ntaps); + } + + //d_fir->filterN(out, in, noutput_items); + } + else { + //d_fir->filterNdec(out, in, noutput_items, decimation()); + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ + diff --git a/gr-filter/lib/fir_filter_fff_impl.h b/gr-filter/lib/fir_filter_fff_impl.h new file mode 100644 index 000000000..962781466 --- /dev/null +++ b/gr-filter/lib/fir_filter_fff_impl.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef FILTER_FIR_FILTER_FFF_IMPL_H +#define FILTER_FIR_FILTER_FFF_IMPL_H + +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API fir_filter_fff_impl : public fir_filter_fff + { + private: + float *d_taps; + int d_ntaps; + bool d_updated; + + public: + fir_filter_fff_impl(int decimation, + const std::vector &taps); + + ~fir_filter_fff_impl(); + + void set_taps(const std::vector &taps); + std::vector taps() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* FILTER_FIR_FILTER_FFF_IMPL_H */ -- cgit From 7f8331808f99a9747bed39e55bbee98bc58c6038 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 2 May 2012 11:45:29 -0400 Subject: build: reworking cmake structure for include and lib directories. I think this is cleaner. We also probably don't need the link_directories (according to the cmake guys, this is no longer necessary). --- gr-filter/lib/CMakeLists.txt | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 0ffdb75fc..2850b6925 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -21,22 +21,18 @@ # Setup the include and linker paths ######################################################################## include_directories( - ${GNURADIO_CORE_INCLUDE_DIRS} - ${VOLK_INCLUDE_DIRS} + ${GR_FILTER_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} + ${VOLK_INCLUDE_DIRS} + ${GNURADIO_CORE_INCLUDE_DIRS} + ${GR_FFT_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${FFTW3F_INCLUDE_DIRS} ) -include_directories(${FILTER_INCLUDE_DIRS}) -link_directories(${FILTER_LIBRARY_DIRS}) - -include_directories(${FFT_INCLUDE_DIRS}) link_directories(${FFT_LIBRARY_DIRS}) - -include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) - -include_directories(${FFTW3F_INCLUDE_DIRS}) link_directories(${FFTW3F_LIBRARY_DIRS}) ######################################################################## -- cgit From 417337cd4a6cef95bbec7c5d04bbacdab0eb9f47 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 2 May 2012 12:43:18 -0400 Subject: filter: fixing up fir_filter_fff to handle taps appropriately, also does decimation. --- gr-filter/lib/fir_filter_fff_impl.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter_fff_impl.cc b/gr-filter/lib/fir_filter_fff_impl.cc index 4a1233a24..15ccb4d07 100644 --- a/gr-filter/lib/fir_filter_fff_impl.cc +++ b/gr-filter/lib/fir_filter_fff_impl.cc @@ -48,6 +48,7 @@ namespace gr { gr_make_io_signature (1, 1, sizeof(float)), decimation) { + d_taps = NULL; set_taps(taps); d_updated = false; set_history(d_ntaps+1); @@ -55,11 +56,21 @@ namespace gr { fir_filter_fff_impl::~fir_filter_fff_impl() { + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } } void fir_filter_fff_impl::set_taps(const std::vector &taps) { + // Free the taps if already allocated + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + d_ntaps = (int)taps.size(); d_taps = fft::malloc_float(d_ntaps); for(int i = 0; i < d_ntaps; i++) { @@ -95,11 +106,13 @@ namespace gr { for(int i = 0; i < noutput_items; i++) { volk_32f_x2_dot_prod_32f_u(&out[i], &in[i], d_taps, d_ntaps); } - - //d_fir->filterN(out, in, noutput_items); } else { - //d_fir->filterNdec(out, in, noutput_items, decimation()); + int j = 0; + for(int i = 0; i < noutput_items; i++) { + volk_32f_x2_dot_prod_32f_u(&out[i], &in[j], d_taps, d_ntaps); + j += decimation(); + } } return noutput_items; -- cgit From 32f807a8c8f1bcadfd8f8ad4c5a46c1b099f8c8f Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 2 May 2012 16:14:09 -0400 Subject: filter: Reworking filter to have a set of basic implementation classes for filters of different kinds. The GR blocks are templated now and call from fir_filters for the volk-specific implemenation. Note the modification to build_utils.py to accomodate these changes. --- gr-filter/lib/CMakeLists.txt | 69 ++++++++- gr-filter/lib/fir_filter.cc | 268 +++++++++++++++++++++++++++++++++ gr-filter/lib/fir_filter_XXX_impl.cc.t | 98 ++++++++++++ gr-filter/lib/fir_filter_XXX_impl.h.t | 57 +++++++ gr-filter/lib/fir_filter_fff_impl.cc | 123 --------------- gr-filter/lib/fir_filter_fff_impl.h | 56 ------- 6 files changed, 491 insertions(+), 180 deletions(-) create mode 100644 gr-filter/lib/fir_filter.cc create mode 100644 gr-filter/lib/fir_filter_XXX_impl.cc.t create mode 100644 gr-filter/lib/fir_filter_XXX_impl.h.t delete mode 100644 gr-filter/lib/fir_filter_fff_impl.cc delete mode 100644 gr-filter/lib/fir_filter_fff_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 2850b6925..784a3c109 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -17,6 +17,72 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. +######################################################################## +# generate helper scripts to expand templated files +######################################################################## +include(GrPython) + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py " +#!${PYTHON_EXECUTABLE} + +import sys, os, re +sys.path.append('${GR_CORE_PYTHONPATH}') +os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}' +os.chdir('${CMAKE_CURRENT_BINARY_DIR}') + +if __name__ == '__main__': + import build_utils + root, inp = sys.argv[1:3] + for sig in sys.argv[3:]: + name = re.sub ('X+', sig, root) + d = build_utils.standard_impl_dict2(name, sig, 'filter') + build_utils.expand_template(d, inp) +") + +macro(expand_cc root) + #make a list of all the generated files + unset(expanded_files_cc) + unset(expanded_files_h) + foreach(sig ${ARGN}) + string(REGEX REPLACE "X+" ${sig} name ${root}) + list(APPEND expanded_files_cc ${CMAKE_CURRENT_BINARY_DIR}/${name}.cc) + list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h) + endforeach(sig) + + #create a command to generate the source files + add_custom_command( + OUTPUT ${expanded_files_cc} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.cc.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}.cc.t ${ARGN} + ) + + #create a command to generate the header file + add_custom_command( + OUTPUT ${expanded_files_h} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}.h.t ${ARGN} + ) + + #make source files depends on headers to force generation + set_source_files_properties(${expanded_files_cc} + PROPERTIES OBJECT_DEPENDS "${expanded_files_h}" + ) + + #install rules for the generated cc files + list(APPEND generated_sources ${expanded_files_cc}) + list(APPEND generated_headers ${expanded_files_h}) +endmacro(expand_cc) + +######################################################################## +# Invoke macro to generate various sources +######################################################################## +expand_cc(fir_filter_XXX_impl fff ccf ccc) + + ######################################################################## # Setup the include and linker paths ######################################################################## @@ -39,7 +105,8 @@ link_directories(${FFTW3F_LIBRARY_DIRS}) # Setup library ######################################################################## list(APPEND filter_sources - fir_filter_fff_impl.cc + fir_filter.cc + ${generated_sources} ) list(APPEND filter_libs diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc new file mode 100644 index 000000000..5f0e0912d --- /dev/null +++ b/gr-filter/lib/fir_filter.cc @@ -0,0 +1,268 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +namespace gr { + namespace filter { + namespace impl { + + fir_filter_fff::fir_filter_fff(int decimation, + const std::vector &taps) + { + d_taps = NULL; + set_taps(taps); + } + + fir_filter_fff::~fir_filter_fff() + { + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + } + + void + fir_filter_fff::set_taps(const std::vector &taps) + { + // Free the taps if already allocated + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_float(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[i] = taps[i]; + } + } + + std::vector + fir_filter_fff::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[i]); + return t; + } + + unsigned int + fir_filter_fff::ntaps() const + { + return d_ntaps; + } + + float + fir_filter_fff::filter(const float input[]) + { + float output; + volk_32f_x2_dot_prod_32f_u(&output, input, d_taps, d_ntaps); + return output; + } + + void + fir_filter_fff::filterN(float output[], + const float input[], + unsigned long n) + { + for(unsigned long i = 0; i < n; i++) + output[i] = filter(&input[i]); + } + + + void + fir_filter_fff::filterNdec(float output[], + const float input[], + unsigned long n, + unsigned int decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++){ + output[i] = filter(&input[j]); + j += decimate; + } + } + + /**************************************************************/ + + fir_filter_ccf::fir_filter_ccf(int decimation, + const std::vector &taps) + { + d_taps = NULL; + set_taps(taps); + } + + fir_filter_ccf::~fir_filter_ccf() + { + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + } + + void + fir_filter_ccf::set_taps(const std::vector &taps) + { + // Free the taps if already allocated + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_complex(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[i] = gr_complex(taps[i],0); + } + } + + std::vector + fir_filter_ccf::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[i].real()); + return t; + } + + unsigned int + fir_filter_ccf::ntaps() const + { + return d_ntaps; + } + + gr_complex + fir_filter_ccf::filter(const gr_complex input[]) + { + gr_complex output; + volk_32fc_x2_dot_prod_32fc_u(&output, input, d_taps, d_ntaps); + return output; + } + + void + fir_filter_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]); + } + + + void + fir_filter_ccf::filterNdec(gr_complex output[], + const gr_complex input[], + unsigned long n, + unsigned int decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++){ + output[i] = filter(&input[j]); + j += decimate; + } + } + + /**************************************************************/ + + fir_filter_ccc::fir_filter_ccc(int decimation, + const std::vector &taps) + { + d_taps = NULL; + set_taps(taps); + } + + fir_filter_ccc::~fir_filter_ccc() + { + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + } + + void + fir_filter_ccc::set_taps(const std::vector &taps) + { + // Free the taps if already allocated + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_complex(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[i] = taps[i]; + } + } + + std::vector + fir_filter_ccc::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[i]); + return t; + } + + unsigned int + fir_filter_ccc::ntaps() const + { + return d_ntaps; + } + + gr_complex + fir_filter_ccc::filter(const gr_complex input[]) + { + gr_complex output; + volk_32fc_x2_dot_prod_32fc_u(&output, input, d_taps, d_ntaps); + return output; + } + + void + fir_filter_ccc::filterN(gr_complex output[], + const gr_complex input[], + unsigned long n) + { + for(unsigned long i = 0; i < n; i++) + output[i] = filter(&input[i]); + } + + + void + fir_filter_ccc::filterNdec(gr_complex output[], + const gr_complex input[], + unsigned long n, + unsigned int decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++){ + output[i] = filter(&input[j]); + j += decimate; + } + } + + } /* namespace impl */ + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/fir_filter_XXX_impl.cc.t b/gr-filter/lib/fir_filter_XXX_impl.cc.t new file mode 100644 index 000000000..70c3fba3f --- /dev/null +++ b/gr-filter/lib/fir_filter_XXX_impl.cc.t @@ -0,0 +1,98 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "@IMPL_NAME@.h" +#include +#include +#include + +namespace gr { + namespace filter { + + @BASE_NAME@::sptr + @BASE_NAME@::make(int decimation, const std::vector<@TAP_TYPE@> &taps) + { + return gnuradio::get_initial_sptr(new @IMPL_NAME@ + (decimation, taps)); + } + + + @IMPL_NAME@::@IMPL_NAME@(int decimation, const std::vector<@TAP_TYPE@> &taps) + : gr_sync_decimator("fir_filter_fff", + gr_make_io_signature(1, 1, sizeof(@I_TYPE@)), + gr_make_io_signature(1, 1, sizeof(@O_TYPE@)), + decimation) + { + d_fir = new impl::@BASE_NAME@(decimation, taps); + d_updated = false; + set_history(d_fir->ntaps()+1); + } + + @IMPL_NAME@::~@IMPL_NAME@() + { + delete d_fir; + } + + void + @IMPL_NAME@::set_taps(const std::vector<@TAP_TYPE@> &taps) + { + d_fir->set_taps(taps); + d_updated = true; + } + + std::vector<@TAP_TYPE@> + @IMPL_NAME@::taps() const + { + return d_fir->taps(); + } + + int + @IMPL_NAME@::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const @I_TYPE@ *in = (const @I_TYPE@*)input_items[0]; + @O_TYPE@ *out = (@O_TYPE@*)output_items[0]; + + if (d_updated) { + set_history(d_fir->ntaps()+1); + d_updated = false; + return 0; // history requirements may have changed. + } + + if (decimation() == 1) { + d_fir->filterN(out, in, noutput_items); + } + else { + d_fir->filterNdec(out, in, noutput_items, decimation()); + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ + diff --git a/gr-filter/lib/fir_filter_XXX_impl.h.t b/gr-filter/lib/fir_filter_XXX_impl.h.t new file mode 100644 index 000000000..a40c49bf2 --- /dev/null +++ b/gr-filter/lib/fir_filter_XXX_impl.h.t @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* @WARNING@ */ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API @IMPL_NAME@ : public @BASE_NAME@ + { + private: + impl::@BASE_NAME@ *d_fir; + bool d_updated; + + public: + @IMPL_NAME@(int decimation, const std::vector<@TAP_TYPE@> &taps); + + ~@IMPL_NAME@(); + + void set_taps(const std::vector<@TAP_TYPE@> &taps); + std::vector<@TAP_TYPE@> taps() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* @GUARD_NAME@ */ diff --git a/gr-filter/lib/fir_filter_fff_impl.cc b/gr-filter/lib/fir_filter_fff_impl.cc deleted file mode 100644 index 15ccb4d07..000000000 --- a/gr-filter/lib/fir_filter_fff_impl.cc +++ /dev/null @@ -1,123 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2010,2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "fir_filter_fff_impl.h" -#include -#include -#include -#include - -namespace gr { - namespace filter { - - fir_filter_fff::sptr - fir_filter_fff::make(int decimation, const std::vector &taps) - { - return gnuradio::get_initial_sptr(new fir_filter_fff_impl - (decimation, taps)); - } - - - fir_filter_fff_impl::fir_filter_fff_impl(int decimation, - const std::vector &taps) - : gr_sync_decimator("fir_filter_fff", - gr_make_io_signature (1, 1, sizeof(float)), - gr_make_io_signature (1, 1, sizeof(float)), - decimation) - { - d_taps = NULL; - set_taps(taps); - d_updated = false; - set_history(d_ntaps+1); - } - - fir_filter_fff_impl::~fir_filter_fff_impl() - { - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - } - } - - void - fir_filter_fff_impl::set_taps(const std::vector &taps) - { - // Free the taps if already allocated - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - } - - d_ntaps = (int)taps.size(); - d_taps = fft::malloc_float(d_ntaps); - for(int i = 0; i < d_ntaps; i++) { - d_taps[i] = taps[i]; - } - d_updated = true; - } - - std::vector - fir_filter_fff_impl::taps() const - { - std::vector t; - for(int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[i]); - return t; - } - - int - fir_filter_fff_impl::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - const float *in = (const float*)input_items[0]; - float *out = (float*)output_items[0]; - - if (d_updated) { - set_history((unsigned int)d_ntaps+1); - d_updated = false; - return 0; // history requirements may have changed. - } - - if (decimation() == 1) { - for(int i = 0; i < noutput_items; i++) { - volk_32f_x2_dot_prod_32f_u(&out[i], &in[i], d_taps, d_ntaps); - } - } - else { - int j = 0; - for(int i = 0; i < noutput_items; i++) { - volk_32f_x2_dot_prod_32f_u(&out[i], &in[j], d_taps, d_ntaps); - j += decimation(); - } - } - - return noutput_items; - } - - } /* namespace filter */ -} /* namespace gr */ - diff --git a/gr-filter/lib/fir_filter_fff_impl.h b/gr-filter/lib/fir_filter_fff_impl.h deleted file mode 100644 index 962781466..000000000 --- a/gr-filter/lib/fir_filter_fff_impl.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef FILTER_FIR_FILTER_FFF_IMPL_H -#define FILTER_FIR_FILTER_FFF_IMPL_H - -#include -#include - -namespace gr { - namespace filter { - - class FILTER_API fir_filter_fff_impl : public fir_filter_fff - { - private: - float *d_taps; - int d_ntaps; - bool d_updated; - - public: - fir_filter_fff_impl(int decimation, - const std::vector &taps); - - ~fir_filter_fff_impl(); - - void set_taps(const std::vector &taps); - std::vector taps() const; - - int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - }; - - } /* namespace filter */ -} /* namespace gr */ - -#endif /* FILTER_FIR_FILTER_FFF_IMPL_H */ -- cgit From 26531c2da601a1c21c50e3644350c604c27f8658 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 2 May 2012 18:59:23 -0400 Subject: filter: fixed FIR filter taps and added complex FFT filter. --- gr-filter/lib/CMakeLists.txt | 2 + gr-filter/lib/fft_filter.cc | 174 +++++++++++++++++++++++++++++++++ gr-filter/lib/fft_filter_ccc_impl.cc | 119 ++++++++++++++++++++++ gr-filter/lib/fft_filter_ccc_impl.h | 61 ++++++++++++ gr-filter/lib/fft_filter_fff_impl.cc | 123 +++++++++++++++++++++++ gr-filter/lib/fft_filter_fff_impl.h | 88 +++++++++++++++++ gr-filter/lib/fir_filter.cc | 14 +-- gr-filter/lib/fir_filter_XXX_impl.cc.t | 8 +- gr-filter/lib/fir_filter_XXX_impl.h.t | 2 +- 9 files changed, 578 insertions(+), 13 deletions(-) create mode 100644 gr-filter/lib/fft_filter.cc create mode 100644 gr-filter/lib/fft_filter_ccc_impl.cc create mode 100644 gr-filter/lib/fft_filter_ccc_impl.h create mode 100644 gr-filter/lib/fft_filter_fff_impl.cc create mode 100644 gr-filter/lib/fft_filter_fff_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 784a3c109..aa03c4615 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -106,7 +106,9 @@ link_directories(${FFTW3F_LIBRARY_DIRS}) ######################################################################## list(APPEND filter_sources fir_filter.cc + fft_filter.cc ${generated_sources} + fft_filter_ccc_impl.cc ) list(APPEND filter_libs diff --git a/gr-filter/lib/fft_filter.cc b/gr-filter/lib/fft_filter.cc new file mode 100644 index 000000000..86b2a2fdb --- /dev/null +++ b/gr-filter/lib/fft_filter.cc @@ -0,0 +1,174 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +namespace gr { + namespace filter { + namespace kernel { + + #define VERBOSE 0 + + fft_filter_ccc::fft_filter_ccc(int decimation, + const std::vector &taps, + int nthreads) + : d_fftsize(-1), d_decimation(decimation), d_fwdfft(0), + d_invfft(0), d_nthreads(nthreads) + { + set_taps(taps); + } + + fft_filter_ccc::~fft_filter_ccc() + { + delete d_fwdfft; + delete d_invfft; + fft::free(d_xformed_taps); + } + + /* + * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps + */ + int + fft_filter_ccc::set_taps(const std::vector &taps) + { + int i = 0; + compute_sizes(taps.size()); + + d_tail.resize(tailsize()); + for(i = 0; i < tailsize(); i++) + d_tail[i] = 0; + + gr_complex *in = d_fwdfft->get_inbuf(); + gr_complex *out = d_fwdfft->get_outbuf(); + + float scale = 1.0 / d_fftsize; + + // Compute forward xform of taps. + // Copy taps into first ntaps slots, then pad with zeros + for(i = 0; i < d_ntaps; i++) + in[i] = taps[i] * scale; + + for(; i < d_fftsize; i++) + in[i] = 0; + + d_fwdfft->execute(); // do the xform + + // now copy output to d_xformed_taps + for(i = 0; i < d_fftsize; i++) + d_xformed_taps[i] = out[i]; + + return d_nsamples; + } + + // determine and set d_ntaps, d_nsamples, d_fftsize + void + fft_filter_ccc::compute_sizes(int ntaps) + { + int old_fftsize = d_fftsize; + d_ntaps = ntaps; + d_fftsize = (int) (2 * pow(2.0, ceil(log(double(ntaps)) / log(2.0)))); + d_nsamples = d_fftsize - d_ntaps + 1; + + if(VERBOSE) { + std::cerr << "fft_filter_ccc: ntaps = " << d_ntaps + << " fftsize = " << d_fftsize + << " nsamples = " << d_nsamples << std::endl; + } + + // compute new plans + if(d_fftsize != old_fftsize) { + delete d_fwdfft; + delete d_invfft; + d_fwdfft = new fft::fft_complex(d_fftsize, true, d_nthreads); + d_invfft = new fft::fft_complex(d_fftsize, false, d_nthreads); + d_xformed_taps = fft::malloc_complex(d_fftsize); + } + } + + void + fft_filter_ccc::set_nthreads(int n) + { + d_nthreads = n; + if(d_fwdfft) + d_fwdfft->set_nthreads(n); + if(d_invfft) + d_invfft->set_nthreads(n); + } + + int + fft_filter_ccc::nthreads() const + { + return d_nthreads; + } + + int + fft_filter_ccc::filter (int nitems, const gr_complex *input, gr_complex *output) + { + int dec_ctr = 0; + int j = 0; + int ninput_items = nitems * d_decimation; + + for(int i = 0; i < ninput_items; i += d_nsamples) { + memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * sizeof(gr_complex)); + + for(j = d_nsamples; j < d_fftsize; j++) + d_fwdfft->get_inbuf()[j] = 0; + + d_fwdfft->execute(); // compute fwd xform + + gr_complex *a = d_fwdfft->get_outbuf(); + gr_complex *b = d_xformed_taps; + gr_complex *c = d_invfft->get_inbuf(); + + volk_32fc_x2_multiply_32fc_a(c, a, b, d_fftsize); + + d_invfft->execute(); // compute inv xform + + // add in the overlapping tail + + for(j = 0; j < tailsize(); j++) + d_invfft->get_outbuf()[j] += d_tail[j]; + + // copy nsamples to output + j = dec_ctr; + while(j < d_nsamples) { + *output++ = d_invfft->get_outbuf()[j]; + j += d_decimation; + } + dec_ctr = (j - d_nsamples); + + // stash the tail + memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples, + tailsize() * sizeof(gr_complex)); + } + + return nitems; + } + } /* namespace impl */ + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/fft_filter_ccc_impl.cc b/gr-filter/lib/fft_filter_ccc_impl.cc new file mode 100644 index 000000000..2721f128e --- /dev/null +++ b/gr-filter/lib/fft_filter_ccc_impl.cc @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "fft_filter_ccc_impl.h" +#include + +#include +#include +#include +#include + +namespace gr { + namespace filter { + + fft_filter_ccc::sptr fft_filter_ccc::make(int decimation, + const std::vector &taps, + int nthreads) + { + return gnuradio::get_initial_sptr(new fft_filter_ccc_impl + (decimation, taps, nthreads)); + } + + fft_filter_ccc_impl::fft_filter_ccc_impl(int decimation, + const std::vector &taps, + int nthreads) + : gr_sync_decimator("fft_filter_ccc", + gr_make_io_signature (1, 1, sizeof(gr_complex)), + gr_make_io_signature (1, 1, sizeof(gr_complex)), + decimation), + d_updated(false) + { + set_history(1); + + d_filter = new kernel::fft_filter_ccc(decimation, taps, nthreads); + + d_new_taps = taps; + d_nsamples = d_filter->set_taps(taps); + set_output_multiple(d_nsamples); + } + + fft_filter_ccc_impl::~fft_filter_ccc_impl() + { + delete d_filter; + } + + void + fft_filter_ccc_impl::set_taps(const std::vector &taps) + { + d_new_taps = taps; + d_updated = true; + } + + std::vector + fft_filter_ccc_impl::taps() const + { + return d_new_taps; + } + + void + fft_filter_ccc_impl::set_nthreads(int n) + { + if(d_filter) + d_filter->set_nthreads(n); + } + + int + fft_filter_ccc_impl::nthreads() const + { + if(d_filter) + return d_filter->nthreads(); + else + return 0; + } + + int + fft_filter_ccc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + if (d_updated){ + d_nsamples = d_filter->set_taps(d_new_taps); + d_updated = false; + set_output_multiple(d_nsamples); + return 0; // output multiple may have changed + } + + d_filter->filter(noutput_items, in, out); + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/fft_filter_ccc_impl.h b/gr-filter/lib/fft_filter_ccc_impl.h new file mode 100644 index 000000000..2d8d61c5e --- /dev/null +++ b/gr-filter/lib/fft_filter_ccc_impl.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_FILTER_FFT_FILTER_CCC_IMPL_H +#define INCLUDED_FILTER_FFT_FILTER_CCC_IMPL_H + +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API fft_filter_ccc_impl : public fft_filter_ccc + { + private: + int d_nsamples; + bool d_updated; + kernel::fft_filter_ccc *d_filter; + std::vector d_new_taps; + + public: + fft_filter_ccc_impl(int decimation, + const std::vector &taps, + int nthreads=1); + + ~fft_filter_ccc_impl(); + + void set_taps(const std::vector &taps); + std::vector taps() const; + + void set_nthreads(int n); + int nthreads() const; + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_FFT_FILTER_CCC_IMPL_H */ diff --git a/gr-filter/lib/fft_filter_fff_impl.cc b/gr-filter/lib/fft_filter_fff_impl.cc new file mode 100644 index 000000000..a09feb7f1 --- /dev/null +++ b/gr-filter/lib/fft_filter_fff_impl.cc @@ -0,0 +1,123 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,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 +#include +#include +#include +#include + +#include +#include +#include + +gr_fft_filter_fff_sptr gr_make_fft_filter_fff (int decimation, + const std::vector &taps, + int nthreads) +{ + return gnuradio::get_initial_sptr(new gr_fft_filter_fff (decimation, taps, nthreads)); +} + + +gr_fft_filter_fff::gr_fft_filter_fff (int decimation, + const std::vector &taps, + int nthreads) + : gr_sync_decimator ("fft_filter_fff", + gr_make_io_signature (1, 1, sizeof (float)), + gr_make_io_signature (1, 1, sizeof (float)), + decimation), + d_updated(false) +{ + set_history(1); + +#if 1 // don't enable the sse version until handling it is worked out + d_filter = new gri_fft_filter_fff_generic(decimation, taps, nthreads); +#else + d_filter = new gri_fft_filter_fff_sse(decimation, taps); +#endif + + d_new_taps = taps; + d_nsamples = d_filter->set_taps(taps); + set_output_multiple(d_nsamples); +} + +gr_fft_filter_fff::~gr_fft_filter_fff () +{ + delete d_filter; +} + +void +gr_fft_filter_fff::set_taps (const std::vector &taps) +{ + d_new_taps = taps; + d_updated = true; +} + +std::vector +gr_fft_filter_fff::taps () const +{ + return d_new_taps; +} + +void +gr_fft_filter_fff::set_nthreads(int n) +{ + if(d_filter) + d_filter->set_nthreads(n); +} + +int +gr_fft_filter_fff::nthreads() const +{ + if(d_filter) + return d_filter->nthreads(); + else + return 0; +} + +int +gr_fft_filter_fff::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const float *in = (const float *) input_items[0]; + float *out = (float *) output_items[0]; + + if (d_updated){ + d_nsamples = d_filter->set_taps(d_new_taps); + d_updated = false; + set_output_multiple(d_nsamples); + return 0; // output multiple may have changed + } + + assert(noutput_items % d_nsamples == 0); + + d_filter->filter(noutput_items, in, out); + + //assert((out - (float *) output_items[0]) == noutput_items); + + return noutput_items; +} diff --git a/gr-filter/lib/fft_filter_fff_impl.h b/gr-filter/lib/fft_filter_fff_impl.h new file mode 100644 index 000000000..309a55135 --- /dev/null +++ b/gr-filter/lib/fft_filter_fff_impl.h @@ -0,0 +1,88 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 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_FFT_FILTER_FFF_H +#define INCLUDED_GR_FFT_FILTER_FFF_H + +#include +#include + +class gr_fft_filter_fff; +typedef boost::shared_ptr gr_fft_filter_fff_sptr; +GR_CORE_API gr_fft_filter_fff_sptr +gr_make_fft_filter_fff (int decimation, const std::vector &taps, + int nthreads=1); + +class gri_fft_filter_fff_generic; +//class gri_fft_filter_fff_sse; + +/*! + * \brief Fast FFT filter with float input, float output and float taps + * \ingroup filter_blk + */ +class GR_CORE_API gr_fft_filter_fff : public gr_sync_decimator +{ + private: + friend GR_CORE_API gr_fft_filter_fff_sptr + gr_make_fft_filter_fff (int decimation, const std::vector &taps, + int nthreads); + + int d_nsamples; + bool d_updated; +#if 1 // don't enable the sse version until handling it is worked out + gri_fft_filter_fff_generic *d_filter; +#else + gri_fft_filter_fff_sse *d_filter; +#endif + std::vector d_new_taps; + + /*! + * Construct a FFT filter with the given taps + * + * \param decimation >= 1 + * \param taps float filter taps + * \param nthreads number of threads for the FFT to use + */ + gr_fft_filter_fff (int decimation, const std::vector &taps, + int nthreads=1); + + public: + ~gr_fft_filter_fff (); + + void set_taps (const std::vector &taps); + std::vector taps () const; + + /*! + * \brief Set number of threads to use. + */ + void set_nthreads(int n); + + /*! + * \brief Get number of threads being used. + */ + int nthreads() const; + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_GR_FFT_FILTER_FFF_H */ diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 5f0e0912d..321f6981e 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -26,7 +26,7 @@ namespace gr { namespace filter { - namespace impl { + namespace kernel { fir_filter_fff::fir_filter_fff(int decimation, const std::vector &taps) @@ -55,7 +55,7 @@ namespace gr { d_ntaps = (int)taps.size(); d_taps = fft::malloc_float(d_ntaps); for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[i] = taps[i]; + d_taps[d_ntaps-i-1] = taps[i]; } } @@ -64,7 +64,7 @@ namespace gr { { std::vector t; for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[i]); + t.push_back(d_taps[d_ntaps-i-1]); return t; } @@ -134,7 +134,7 @@ namespace gr { d_ntaps = (int)taps.size(); d_taps = fft::malloc_complex(d_ntaps); for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[i] = gr_complex(taps[i],0); + d_taps[d_ntaps-i-1] = gr_complex(taps[i],0); } } @@ -143,7 +143,7 @@ namespace gr { { std::vector t; for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[i].real()); + t.push_back(d_taps[d_ntaps-i-1].real()); return t; } @@ -213,7 +213,7 @@ namespace gr { d_ntaps = (int)taps.size(); d_taps = fft::malloc_complex(d_ntaps); for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[i] = taps[i]; + d_taps[d_ntaps-i-1] = taps[i]; } } @@ -222,7 +222,7 @@ namespace gr { { std::vector t; for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[i]); + t.push_back(d_taps[d_ntaps-i-1]); return t; } diff --git a/gr-filter/lib/fir_filter_XXX_impl.cc.t b/gr-filter/lib/fir_filter_XXX_impl.cc.t index 70c3fba3f..c3637042d 100644 --- a/gr-filter/lib/fir_filter_XXX_impl.cc.t +++ b/gr-filter/lib/fir_filter_XXX_impl.cc.t @@ -26,8 +26,6 @@ #include "@IMPL_NAME@.h" #include -#include -#include namespace gr { namespace filter { @@ -46,9 +44,9 @@ namespace gr { gr_make_io_signature(1, 1, sizeof(@O_TYPE@)), decimation) { - d_fir = new impl::@BASE_NAME@(decimation, taps); + d_fir = new kernel::@BASE_NAME@(decimation, taps); d_updated = false; - set_history(d_fir->ntaps()+1); + set_history(d_fir->ntaps()); } @IMPL_NAME@::~@IMPL_NAME@() @@ -78,7 +76,7 @@ namespace gr { @O_TYPE@ *out = (@O_TYPE@*)output_items[0]; if (d_updated) { - set_history(d_fir->ntaps()+1); + set_history(d_fir->ntaps()); d_updated = false; return 0; // history requirements may have changed. } diff --git a/gr-filter/lib/fir_filter_XXX_impl.h.t b/gr-filter/lib/fir_filter_XXX_impl.h.t index a40c49bf2..d5bf7104d 100644 --- a/gr-filter/lib/fir_filter_XXX_impl.h.t +++ b/gr-filter/lib/fir_filter_XXX_impl.h.t @@ -35,7 +35,7 @@ namespace gr { class FILTER_API @IMPL_NAME@ : public @BASE_NAME@ { private: - impl::@BASE_NAME@ *d_fir; + kernel::@BASE_NAME@ *d_fir; bool d_updated; public: -- cgit From b63e3b8a6923cf358d42064dca16d262a33c2918 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 2 May 2012 19:59:43 -0400 Subject: filter: adding fff version of FFT filter. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/fft_filter.cc | 145 ++++++++++++++++++++++++++- gr-filter/lib/fft_filter_ccc_impl.h | 10 +- gr-filter/lib/fft_filter_fff_impl.cc | 187 +++++++++++++++++------------------ gr-filter/lib/fft_filter_fff_impl.h | 109 ++++++++------------ gr-filter/lib/fir_filter.cc | 2 +- 6 files changed, 283 insertions(+), 171 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index aa03c4615..e0af76700 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -109,6 +109,7 @@ list(APPEND filter_sources fft_filter.cc ${generated_sources} fft_filter_ccc_impl.cc + fft_filter_fff_impl.cc ) list(APPEND filter_libs diff --git a/gr-filter/lib/fft_filter.cc b/gr-filter/lib/fft_filter.cc index 86b2a2fdb..130886d7f 100644 --- a/gr-filter/lib/fft_filter.cc +++ b/gr-filter/lib/fft_filter.cc @@ -33,6 +33,146 @@ namespace gr { namespace kernel { #define VERBOSE 0 + + fft_filter_fff::fft_filter_fff(int decimation, + const std::vector &taps, + int nthreads) + : d_fftsize(-1), d_decimation(decimation), d_fwdfft(0), + d_invfft(0), d_nthreads(nthreads) + { + set_taps(taps); + } + + fft_filter_fff::~fft_filter_fff() + { + delete d_fwdfft; + delete d_invfft; + fft::free(d_xformed_taps); + } + + /* + * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps + */ + int + fft_filter_fff::set_taps(const std::vector &taps) + { + int i = 0; + compute_sizes(taps.size()); + + d_tail.resize(tailsize()); + for(i = 0; i < tailsize(); i++) + d_tail[i] = 0; + + float *in = d_fwdfft->get_inbuf(); + gr_complex *out = d_fwdfft->get_outbuf(); + + float scale = 1.0 / d_fftsize; + + // Compute forward xform of taps. + // Copy taps into first ntaps slots, then pad with zeros + for (i = 0; i < d_ntaps; i++) + in[i] = taps[i] * scale; + + for (; i < d_fftsize; i++) + in[i] = 0; + + d_fwdfft->execute(); // do the xform + + // now copy output to d_xformed_taps + for (i = 0; i < d_fftsize/2+1; i++) + d_xformed_taps[i] = out[i]; + + return d_nsamples; + } + + // determine and set d_ntaps, d_nsamples, d_fftsize + void + fft_filter_fff::compute_sizes(int ntaps) + { + int old_fftsize = d_fftsize; + d_ntaps = ntaps; + d_fftsize = (int) (2 * pow(2.0, ceil(log(double(ntaps)) / log(2.0)))); + d_nsamples = d_fftsize - d_ntaps + 1; + + if(VERBOSE) { + std::cerr << "fft_filter_fff: ntaps = " << d_ntaps + << " fftsize = " << d_fftsize + << " nsamples = " << d_nsamples << std::endl; + } + + // compute new plans + if(d_fftsize != old_fftsize) { + delete d_fwdfft; + delete d_invfft; + d_fwdfft = new fft::fft_real_fwd(d_fftsize); + d_invfft = new fft::fft_real_rev(d_fftsize); + d_xformed_taps = fft::malloc_complex(d_fftsize/2+1); + } + } + + void + fft_filter_fff::set_nthreads(int n) + { + d_nthreads = n; + if(d_fwdfft) + d_fwdfft->set_nthreads(n); + if(d_invfft) + d_invfft->set_nthreads(n); + } + + int + fft_filter_fff::nthreads() const + { + return d_nthreads; + } + + int + fft_filter_fff::filter(int nitems, const float *input, float *output) + { + int dec_ctr = 0; + int j = 0; + int ninput_items = nitems * d_decimation; + + for (int i = 0; i < ninput_items; i += d_nsamples){ + + memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * sizeof(float)); + + for (j = d_nsamples; j < d_fftsize; j++) + d_fwdfft->get_inbuf()[j] = 0; + + d_fwdfft->execute(); // compute fwd xform + + gr_complex *a = d_fwdfft->get_outbuf(); + gr_complex *b = d_xformed_taps; + gr_complex *c = d_invfft->get_inbuf(); + + volk_32fc_x2_multiply_32fc_a(c, a, b, d_fftsize/2+1); + + d_invfft->execute(); // compute inv xform + + // add in the overlapping tail + for (j = 0; j < tailsize(); j++) + d_invfft->get_outbuf()[j] += d_tail[j]; + + // copy nsamples to output + j = dec_ctr; + while (j < d_nsamples) { + *output++ = d_invfft->get_outbuf()[j]; + j += d_decimation; + } + dec_ctr = (j - d_nsamples); + + // stash the tail + memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples, + tailsize() * sizeof(float)); + } + + return nitems; + } + + + /**************************************************************/ + fft_filter_ccc::fft_filter_ccc(int decimation, const std::vector &taps, @@ -127,7 +267,7 @@ namespace gr { } int - fft_filter_ccc::filter (int nitems, const gr_complex *input, gr_complex *output) + fft_filter_ccc::filter(int nitems, const gr_complex *input, gr_complex *output) { int dec_ctr = 0; int j = 0; @@ -169,6 +309,7 @@ namespace gr { return nitems; } - } /* namespace impl */ + + } /* namespace kernel */ } /* namespace filter */ } /* namespace gr */ diff --git a/gr-filter/lib/fft_filter_ccc_impl.h b/gr-filter/lib/fft_filter_ccc_impl.h index 2d8d61c5e..82be00915 100644 --- a/gr-filter/lib/fft_filter_ccc_impl.h +++ b/gr-filter/lib/fft_filter_ccc_impl.h @@ -39,8 +39,8 @@ namespace gr { public: fft_filter_ccc_impl(int decimation, - const std::vector &taps, - int nthreads=1); + const std::vector &taps, + int nthreads=1); ~fft_filter_ccc_impl(); @@ -50,9 +50,9 @@ namespace gr { void set_nthreads(int n); int nthreads() const; - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; } /* namespace filter */ diff --git a/gr-filter/lib/fft_filter_fff_impl.cc b/gr-filter/lib/fft_filter_fff_impl.cc index a09feb7f1..95b82aae5 100644 --- a/gr-filter/lib/fft_filter_fff_impl.cc +++ b/gr-filter/lib/fft_filter_fff_impl.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005,2010 Free Software Foundation, Inc. + * Copyright 2005,2010,2012 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,100 +24,97 @@ #include "config.h" #endif -#include -#include +#include "fft_filter_fff_impl.h" #include + +#include #include #include - -#include -#include -#include - -gr_fft_filter_fff_sptr gr_make_fft_filter_fff (int decimation, - const std::vector &taps, - int nthreads) -{ - return gnuradio::get_initial_sptr(new gr_fft_filter_fff (decimation, taps, nthreads)); -} - - -gr_fft_filter_fff::gr_fft_filter_fff (int decimation, - const std::vector &taps, - int nthreads) - : gr_sync_decimator ("fft_filter_fff", - gr_make_io_signature (1, 1, sizeof (float)), - gr_make_io_signature (1, 1, sizeof (float)), - decimation), - d_updated(false) -{ - set_history(1); - -#if 1 // don't enable the sse version until handling it is worked out - d_filter = new gri_fft_filter_fff_generic(decimation, taps, nthreads); -#else - d_filter = new gri_fft_filter_fff_sse(decimation, taps); -#endif - - d_new_taps = taps; - d_nsamples = d_filter->set_taps(taps); - set_output_multiple(d_nsamples); -} - -gr_fft_filter_fff::~gr_fft_filter_fff () -{ - delete d_filter; -} - -void -gr_fft_filter_fff::set_taps (const std::vector &taps) -{ - d_new_taps = taps; - d_updated = true; -} - -std::vector -gr_fft_filter_fff::taps () const -{ - return d_new_taps; -} - -void -gr_fft_filter_fff::set_nthreads(int n) -{ - if(d_filter) - d_filter->set_nthreads(n); -} - -int -gr_fft_filter_fff::nthreads() const -{ - if(d_filter) - return d_filter->nthreads(); - else - return 0; -} - -int -gr_fft_filter_fff::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const float *in = (const float *) input_items[0]; - float *out = (float *) output_items[0]; - - if (d_updated){ - d_nsamples = d_filter->set_taps(d_new_taps); - d_updated = false; - set_output_multiple(d_nsamples); - return 0; // output multiple may have changed - } - - assert(noutput_items % d_nsamples == 0); - - d_filter->filter(noutput_items, in, out); - - //assert((out - (float *) output_items[0]) == noutput_items); - - return noutput_items; -} +#include + +namespace gr { + namespace filter { + + fft_filter_fff::sptr fft_filter_fff::make(int decimation, + const std::vector &taps, + int nthreads) + { + return gnuradio::get_initial_sptr(new fft_filter_fff_impl + (decimation, taps, nthreads)); + } + + + fft_filter_fff_impl::fft_filter_fff_impl(int decimation, + const std::vector &taps, + int nthreads) + : gr_sync_decimator("fft_filter_fff", + gr_make_io_signature (1, 1, sizeof(float)), + gr_make_io_signature (1, 1, sizeof(float)), + decimation), + d_updated(false) + { + set_history(1); + + d_filter = new kernel::fft_filter_fff(decimation, taps, nthreads); + + d_new_taps = taps; + d_nsamples = d_filter->set_taps(taps); + set_output_multiple(d_nsamples); + } + + fft_filter_fff_impl::~fft_filter_fff_impl() + { + delete d_filter; + } + + void + fft_filter_fff_impl::set_taps(const std::vector &taps) + { + d_new_taps = taps; + d_updated = true; + } + + std::vector + fft_filter_fff_impl::taps() const + { + return d_new_taps; + } + + void + fft_filter_fff_impl::set_nthreads(int n) + { + if(d_filter) + d_filter->set_nthreads(n); + } + + int + fft_filter_fff_impl::nthreads() const + { + if(d_filter) + return d_filter->nthreads(); + else + return 0; + } + + int + fft_filter_fff_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float *)input_items[0]; + float *out = (float *)output_items[0]; + + if (d_updated){ + d_nsamples = d_filter->set_taps(d_new_taps); + d_updated = false; + set_output_multiple(d_nsamples); + return 0; // output multiple may have changed + } + + d_filter->filter(noutput_items, in, out); + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/fft_filter_fff_impl.h b/gr-filter/lib/fft_filter_fff_impl.h index 309a55135..df35d3df7 100644 --- a/gr-filter/lib/fft_filter_fff_impl.h +++ b/gr-filter/lib/fft_filter_fff_impl.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005 Free Software Foundation, Inc. + * Copyright 2005,2012 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,70 +19,43 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_GR_FFT_FILTER_FFF_H -#define INCLUDED_GR_FFT_FILTER_FFF_H - -#include -#include - -class gr_fft_filter_fff; -typedef boost::shared_ptr gr_fft_filter_fff_sptr; -GR_CORE_API gr_fft_filter_fff_sptr -gr_make_fft_filter_fff (int decimation, const std::vector &taps, - int nthreads=1); - -class gri_fft_filter_fff_generic; -//class gri_fft_filter_fff_sse; - -/*! - * \brief Fast FFT filter with float input, float output and float taps - * \ingroup filter_blk - */ -class GR_CORE_API gr_fft_filter_fff : public gr_sync_decimator -{ - private: - friend GR_CORE_API gr_fft_filter_fff_sptr - gr_make_fft_filter_fff (int decimation, const std::vector &taps, - int nthreads); - - int d_nsamples; - bool d_updated; -#if 1 // don't enable the sse version until handling it is worked out - gri_fft_filter_fff_generic *d_filter; -#else - gri_fft_filter_fff_sse *d_filter; -#endif - std::vector d_new_taps; - - /*! - * Construct a FFT filter with the given taps - * - * \param decimation >= 1 - * \param taps float filter taps - * \param nthreads number of threads for the FFT to use - */ - gr_fft_filter_fff (int decimation, const std::vector &taps, - int nthreads=1); - - public: - ~gr_fft_filter_fff (); - - void set_taps (const std::vector &taps); - std::vector taps () const; - - /*! - * \brief Set number of threads to use. - */ - void set_nthreads(int n); - - /*! - * \brief Get number of threads being used. - */ - int nthreads() const; - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_GR_FFT_FILTER_FFF_H */ +#ifndef INCLUDED_FILTER_FFT_FILTER_FFF_IMPL_H +#define INCLUDED_FILTER_FFT_FILTER_FFF_IMPL_H + +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API fft_filter_fff_impl : public fft_filter_fff + { + private: + int d_nsamples; + bool d_updated; + kernel::fft_filter_fff *d_filter; + std::vector d_new_taps; + + public: + fft_filter_fff_impl(int decimation, + const std::vector &taps, + int nthreads=1); + + ~fft_filter_fff_impl(); + + void set_taps(const std::vector &taps); + std::vector taps() const; + + void set_nthreads(int n); + int nthreads() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_FFT_FILTER_FFF_IMPL_H */ diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 321f6981e..b45209aa7 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -263,6 +263,6 @@ namespace gr { } } - } /* namespace impl */ + } /* namespace kernel */ } /* namespace filter */ } /* namespace gr */ -- cgit From 9968eb116b89f2a38602d590207fbe0ea514c018 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 3 May 2012 12:17:35 -0400 Subject: filter: preparing to handle alignment better in FIR filters. --- gr-filter/lib/fir_filter.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index b45209aa7..3abcda53e 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -57,6 +57,12 @@ namespace gr { for(unsigned int i = 0; i < d_ntaps; i++) { d_taps[d_ntaps-i-1] = taps[i]; } + + for(int i = 0; i < 4; i++) { + d_aligned_taps[i] = fft::malloc_float(d_ntaps+3); + memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+3)); + memcpy(&d_aligned_taps[i][i], d_taps, sizeof(float)*(d_ntaps)); + } } std::vector @@ -78,6 +84,9 @@ namespace gr { fir_filter_fff::filter(const float input[]) { float output; + + //const float *ar = (float*)((unsigned long)input & ~15); + volk_32f_x2_dot_prod_32f_u(&output, input, d_taps, d_ntaps); return output; } -- cgit From 906fe742d1c6a6ca93b47261b0ee615d4779081b Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 5 May 2012 13:34:56 -0400 Subject: filter: added firdes for generating FIR filters to gr-filter. Addes QA code in both Python and C++. --- gr-filter/lib/CMakeLists.txt | 22 ++ gr-filter/lib/firdes.cc | 855 ++++++++++++++++++++++++++++++++++++++++ gr-filter/lib/qa_filter.cc | 39 ++ gr-filter/lib/qa_filter.h | 38 ++ gr-filter/lib/qa_firdes.cc | 621 +++++++++++++++++++++++++++++ gr-filter/lib/qa_firdes.h | 56 +++ gr-filter/lib/test_gr_filter.cc | 42 ++ 7 files changed, 1673 insertions(+) create mode 100644 gr-filter/lib/firdes.cc create mode 100644 gr-filter/lib/qa_filter.cc create mode 100644 gr-filter/lib/qa_filter.h create mode 100644 gr-filter/lib/qa_firdes.cc create mode 100644 gr-filter/lib/qa_firdes.h create mode 100644 gr-filter/lib/test_gr_filter.cc (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index e0af76700..f085987de 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -107,6 +107,7 @@ link_directories(${FFTW3F_LIBRARY_DIRS}) list(APPEND filter_sources fir_filter.cc fft_filter.cc + firdes_impl.cc ${generated_sources} fft_filter_ccc_impl.cc fft_filter_fff_impl.cc @@ -124,3 +125,24 @@ add_library(gnuradio-filter SHARED ${filter_sources}) target_link_libraries(gnuradio-filter ${filter_libs}) GR_LIBRARY_FOO(gnuradio-filter RUNTIME_COMPONENT "filter_runtime" DEVEL_COMPONENT "filter_devel") add_dependencies(gnuradio-filter gnuradio-fft filter_generated_includes filter_generated_swigs) + + +######################################################################## +# QA C++ Code for gr-filter +######################################################################## +list(APPEND test_gr_filter_sources + ${CMAKE_CURRENT_SOURCE_DIR}/test_gr_filter.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_filter.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_firdes.cc +) + +add_executable(test-gr-filter ${test_gr_filter_sources}) +target_link_libraries( + test-gr-filter + gnuradio-core + gnuradio-filter + ${CPPUNIT_LIBRARIES} + ${Boost_LIBRARIES} +) + +GR_ADD_TEST(test_gr_filter) diff --git a/gr-filter/lib/firdes.cc b/gr-filter/lib/firdes.cc new file mode 100644 index 000000000..5c3320d71 --- /dev/null +++ b/gr-filter/lib/firdes.cc @@ -0,0 +1,855 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2007,2008,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +using std::vector; + +namespace gr { + namespace filter { + +#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */ + + static double Izero(double x) + { + double sum, u, halfx, temp; + int n; + + sum = u = n = 1; + halfx = x/2.0; + do { + temp = halfx/(double)n; + n += 1; + temp *= temp; + u *= temp; + sum += u; + } while (u >= IzeroEPSILON*sum); + return(sum); + } + + + // + // === Low Pass === + // + + vector + firdes::low_pass_2(double gain, + double sampling_freq, // Hz + double cutoff_freq, // Hz BEGINNING of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_1f(sampling_freq, cutoff_freq, transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + // construct the truncated ideal impulse response + // [sin(x)/x for the low pass case] + + vector taps(ntaps); + vector w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = fwT0 / M_PI * w[n + M]; + else { + // a little algebra gets this into the more familiar sin(x)/x form + taps[n + M] = sin(n * fwT0) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For low-pass, gain @ zero freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M]; + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + vector + firdes::low_pass(double gain, + double sampling_freq, + double cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_1f(sampling_freq, cutoff_freq, transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response + // [sin(x)/x for the low pass case] + + vector taps(ntaps); + vector w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if(n == 0) + taps[n + M] = fwT0 / M_PI * w[n + M]; + else { + // a little algebra gets this into the more familiar sin(x)/x form + taps[n + M] = sin(n * fwT0) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For low-pass, gain @ zero freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M]; + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + + // + // === High Pass === + // + + vector + firdes::high_pass_2(double gain, + double sampling_freq, + double cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_1f(sampling_freq, cutoff_freq, transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + // construct the truncated ideal impulse response times the window function + + vector taps(ntaps); + vector w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if(n == 0) + taps[n + M] = (1 - (fwT0 / M_PI)) * w[n + M]; + else { + // a little algebra gets this into the more familiar sin(x)/x form + taps[n + M] = -sin(n * fwT0) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For high-pass, gain @ fs/2 freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M] * cos(n * M_PI); + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + + vector + firdes::high_pass(double gain, + double sampling_freq, + double cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_1f(sampling_freq, cutoff_freq, transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response times the window function + + vector taps(ntaps); + vector w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if(n == 0) + taps[n + M] = (1 - (fwT0 / M_PI)) * w[n + M]; + else { + // a little algebra gets this into the more familiar sin(x)/x form + taps[n + M] = -sin(n * fwT0) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For high-pass, gain @ fs/2 freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M] * cos(n * M_PI); + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + // + // === Band Pass === + // + + vector + firdes::band_pass_2(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + vector taps(ntaps); + vector w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * low_cutoff_freq / sampling_freq; + double fwT1 = 2 * M_PI * high_cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = (fwT1 - fwT0) / M_PI * w[n + M]; + else { + taps[n + M] = (sin(n * fwT1) - sin(n * fwT0)) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For band-pass, gain @ center freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M] * cos(n * (fwT0 + fwT1) * 0.5); + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + + vector + firdes::band_pass(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response times the window function + + vector taps(ntaps); + vector w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * low_cutoff_freq / sampling_freq; + double fwT1 = 2 * M_PI * high_cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = (fwT1 - fwT0) / M_PI * w[n + M]; + else { + taps[n + M] = (sin(n * fwT1) - sin(n * fwT0)) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For band-pass, gain @ center freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M] * cos(n * (fwT0 + fwT1) * 0.5); + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + // + // === Complex Band Pass === + // + + vector + firdes::complex_band_pass_2(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f_c(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + vector taps(ntaps); + vector lptaps(ntaps); + vector w = window(window_type, ntaps, beta); + + lptaps = low_pass_2(gain, sampling_freq, + (high_cutoff_freq - low_cutoff_freq)/2, + transition_width, attenuation_dB, + window_type, beta); + + gr_complex *optr = &taps[0]; + float *iptr = &lptaps[0]; + float freq = M_PI * (high_cutoff_freq + low_cutoff_freq)/sampling_freq; + float phase = 0; + if (lptaps.size() & 01) { + phase = - freq * ( lptaps.size() >> 1 ); + } + else + phase = - freq/2.0 * ((1 + 2*lptaps.size()) >> 1); + + for(unsigned int i = 0; i < lptaps.size(); i++) { + *optr++ = gr_complex(*iptr * cos(phase), *iptr * sin(phase)); + iptr++, phase += freq; + } + + return taps; + } + + + vector + firdes::complex_band_pass(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f_c (sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response times the window function + + vector taps(ntaps); + vector lptaps(ntaps); + vector w = window(window_type, ntaps, beta); + + lptaps = low_pass(gain, sampling_freq, + (high_cutoff_freq - low_cutoff_freq)/2, + transition_width, window_type, beta); + + gr_complex *optr = &taps[0]; + float *iptr = &lptaps[0]; + float freq = M_PI * (high_cutoff_freq + low_cutoff_freq)/sampling_freq; + float phase = 0; + if(lptaps.size() & 01) { + phase = - freq * ( lptaps.size() >> 1 ); + } + else + phase = - freq/2.0 * ((1 + 2*lptaps.size()) >> 1); + + for(unsigned int i=0;i + firdes::band_reject_2(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + double attenuation_dB, // attenuation dB + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps_windes(sampling_freq, + transition_width, + attenuation_dB); + + // construct the truncated ideal impulse response times the window function + + vector taps(ntaps); + vector w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * low_cutoff_freq / sampling_freq; + double fwT1 = 2 * M_PI * high_cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = 1.0 + ((fwT0 - fwT1) / M_PI * w[n + M]); + else { + taps[n + M] = (sin(n * fwT0) - sin(n * fwT1)) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For band-reject, gain @ zero freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M]; + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + vector + firdes::band_reject(double gain, + double sampling_freq, + double low_cutoff_freq, // Hz center of transition band + double high_cutoff_freq, // Hz center of transition band + double transition_width, // Hz width of transition band + win_type window_type, + double beta) // used only with Kaiser + { + sanity_check_2f(sampling_freq, + low_cutoff_freq, + high_cutoff_freq, + transition_width); + + int ntaps = compute_ntaps(sampling_freq, + transition_width, + window_type, beta); + + // construct the truncated ideal impulse response times the window function + + vector taps(ntaps); + vector w = window(window_type, ntaps, beta); + + int M = (ntaps - 1) / 2; + double fwT0 = 2 * M_PI * low_cutoff_freq / sampling_freq; + double fwT1 = 2 * M_PI * high_cutoff_freq / sampling_freq; + + for(int n = -M; n <= M; n++) { + if (n == 0) + taps[n + M] = 1.0 + ((fwT0 - fwT1) / M_PI * w[n + M]); + else { + taps[n + M] = (sin(n * fwT0) - sin(n * fwT1)) / (n * M_PI) * w[n + M]; + } + } + + // find the factor to normalize the gain, fmax. + // For band-reject, gain @ zero freq = 1.0 + + double fmax = taps[0 + M]; + for(int n = 1; n <= M; n++) + fmax += 2 * taps[n + M]; + + gain /= fmax; // normalize + + for(int i = 0; i < ntaps; i++) + taps[i] *= gain; + + return taps; + } + + // + // Hilbert Transform + // + + vector + firdes::hilbert(unsigned int ntaps, + win_type windowtype, + double beta) + { + if(!(ntaps & 1)) + throw std::out_of_range("Hilbert: Must have odd number of taps"); + + vector taps(ntaps); + vector w = window (windowtype, ntaps, beta); + unsigned int h = (ntaps-1)/2; + float gain=0; + for(unsigned int i = 1; i <= h; i++) { + if(i & 1) { + float x = 1/(float)i; + taps[h+i] = x * w[h+i]; + taps[h-i] = -x * w[h-i]; + gain = taps[h+i] - gain; + } + else + taps[h+i] = taps[h-i] = 0; + } + + gain = 2 * fabs(gain); + for(unsigned int i = 0; i < ntaps; i++) + taps[i] /= gain; + return taps; + } + + // + // Gaussian + // + + vector + firdes::gaussian(double gain, + double spb, + double bt, + int ntaps) + { + vector taps(ntaps); + double scale = 0; + double dt = 1.0/spb; + double s = 1.0/(sqrt(log(2.0)) / (2*M_PI*bt)); + double t0 = -0.5 * ntaps; + double ts; + for(int i=0;i + firdes::root_raised_cosine(double gain, + double sampling_freq, + double symbol_rate, + double alpha, + int ntaps) + { + ntaps |= 1; // ensure that ntaps is odd + + double spb = sampling_freq/symbol_rate; // samples per bit/symbol + vector taps(ntaps); + double scale = 0; + for(int i = 0; i < ntaps; i++) { + double x1,x2,x3,num,den; + double xindx = i - ntaps/2; + x1 = M_PI * xindx/spb; + x2 = 4 * alpha * xindx / spb; + x3 = x2*x2 - 1; + + if(fabs(x3) >= 0.000001) { // Avoid Rounding errors... + if(i != ntaps/2) + num = cos((1+alpha)*x1) + sin((1-alpha)*x1)/(4*alpha*xindx/spb); + else + num = cos((1+alpha)*x1) + (1-alpha) * M_PI / (4*alpha); + den = x3 * M_PI; + } + else { + if(alpha==1) { + taps[i] = -1; + continue; + } + x3 = (1-alpha)*x1; + x2 = (1+alpha)*x1; + num = (sin(x2)*(1+alpha)*M_PI + - cos(x3)*((1-alpha)*M_PI*spb)/(4*alpha*xindx) + + sin(x3)*spb*spb/(4*alpha*xindx*xindx)); + den = -32 * M_PI * alpha * alpha * xindx/spb; + } + taps[i] = 4 * alpha * num / den; + scale += taps[i]; + } + + for(int i = 0; i < ntaps; i++) + taps[i] = taps[i] * gain / scale; + + return taps; + } + + // + // === Utilities === + // + + // delta_f / width_factor gives number of taps required. + static const float width_factor[5] = { // indexed by win_type + 3.3, // WIN_HAMMING + 3.1, // WIN_HANN + 5.5, // WIN_BLACKMAN + 2.0, // WIN_RECTANGULAR + //5.0 // WIN_KAISER (guesstimate compromise) + //2.0 // WIN_KAISER (guesstimate compromise) + 10.0 // WIN_KAISER + }; + + int + firdes::compute_ntaps_windes(double sampling_freq, + double transition_width, // this is frequency, not relative frequency + double attenuation_dB) + { + // Based on formula from Multirate Signal Processing for + // Communications Systems, fredric j harris + int ntaps = (int)(attenuation_dB*sampling_freq/(22.0*transition_width)); + if ((ntaps & 1) == 0) // if even... + ntaps++; // ...make odd + return ntaps; + } + + int + firdes::compute_ntaps(double sampling_freq, + double transition_width, + win_type window_type, + double beta) + { + // normalized transition width + double delta_f = transition_width / sampling_freq; + + // compute number of taps required for given transition width + int ntaps = (int)(width_factor[window_type] / delta_f + 0.5); + if((ntaps & 1) == 0) // if even... + ntaps++; // ...make odd + + return ntaps; + } + + double + firdes::bessi0(double x) + { + double ax,ans; + double y; + + ax=fabs(x); + if (ax < 3.75) { + y=x/3.75; + y*=y; + ans=1.0+y*(3.5156229+y*(3.0899424+y*(1.2067492 + +y*(0.2659732+y*(0.360768e-1+y*0.45813e-2))))); + } + else { + y=3.75/ax; + ans=(exp(ax)/sqrt(ax))*(0.39894228+y*(0.1328592e-1 + +y*(0.225319e-2+y*(-0.157565e-2+y*(0.916281e-2 + +y*(-0.2057706e-1+y*(0.2635537e-1+y*(-0.1647633e-1 + +y*0.392377e-2)))))))); + } + return ans; + } + + vector + firdes::window (win_type type, int ntaps, double beta) + { + vector taps(ntaps); + int M = ntaps - 1; // filter order + + switch (type) { + case WIN_RECTANGULAR: + for(int n = 0; n < ntaps; n++) + taps[n] = 1; + + case WIN_HAMMING: + for(int n = 0; n < ntaps; n++) + taps[n] = 0.54 - 0.46 * cos((2 * M_PI * n) / M); + break; + + case WIN_HANN: + for(int n = 0; n < ntaps; n++) + taps[n] = 0.5 - 0.5 * cos((2 * M_PI * n) / M); + break; + + case WIN_BLACKMAN: + for(int n = 0; n < ntaps; n++) + taps[n] = 0.42 - 0.50 * cos((2*M_PI * n) / (M-1)) + - 0.08 * cos((4*M_PI * n) / (M-1)); + break; + + case WIN_BLACKMAN_hARRIS: + for(int n = -ntaps/2; n < ntaps/2; n++) + taps[n+ntaps/2] = 0.35875 + 0.48829*cos((2*M_PI * n) / (float)M) + + 0.14128*cos((4*M_PI * n) / (float)M) + 0.01168*cos((6*M_PI * n) / (float)M); + break; + + case WIN_KAISER: + { + double IBeta = 1.0/Izero(beta); + double inm1 = 1.0/((double)(ntaps)); + double temp; + //fprintf(stderr, "IBeta = %g; inm1 = %g\n", IBeta, inm1); + + for(int i=0; i 0"); + + if(fa <= 0.0 || fa > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fa <= sampling_freq / 2"); + + if(transition_width <= 0) + throw std::out_of_range("gr_dirdes check failed: transition_width > 0"); + } + + void + firdes::sanity_check_2f(double sampling_freq, + double fa, // first cutoff freq + double fb, // second cutoff freq + double transition_width) + { + if (sampling_freq <= 0.0) + throw std::out_of_range("firdes check failed: sampling_freq > 0"); + + if (fa <= 0.0 || fa > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fa <= sampling_freq / 2"); + + if (fb <= 0.0 || fb > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fb <= sampling_freq / 2"); + + if (fa > fb) + throw std::out_of_range("firdes check failed: fa <= fb"); + + if (transition_width <= 0) + throw std::out_of_range("firdes check failed: transition_width > 0"); + } + + void + firdes::sanity_check_2f_c(double sampling_freq, + double fa, // first cutoff freq + double fb, // second cutoff freq + double transition_width) + { + if(sampling_freq <= 0.0) + throw std::out_of_range("firdes check failed: sampling_freq > 0"); + + if(fa < -sampling_freq / 2 || fa > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fa <= sampling_freq / 2"); + + if(fb < -sampling_freq / 2 || fb > sampling_freq / 2) + throw std::out_of_range("firdes check failed: 0 < fb <= sampling_freq / 2"); + + if(fa > fb) + throw std::out_of_range("firdes check failed: fa <= fb"); + + if(transition_width <= 0) + throw std::out_of_range("firdes check failed: transition_width > 0"); + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/qa_filter.cc b/gr-filter/lib/qa_filter.cc new file mode 100644 index 000000000..86d4860de --- /dev/null +++ b/gr-filter/lib/qa_filter.cc @@ -0,0 +1,39 @@ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * This class gathers together all the test cases for the gr-filter + * directory into a single test suite. As you create new test cases, + * add them here. + */ + +#include +#include + +CppUnit::TestSuite * +qa_gr_filter::suite () +{ + CppUnit::TestSuite *s = new CppUnit::TestSuite ("gr-filter"); + + s->addTest(gr::filter::qa_firdes::suite ()); + + return s; +} diff --git a/gr-filter/lib/qa_filter.h b/gr-filter/lib/qa_filter.h new file mode 100644 index 000000000..427e7f9f6 --- /dev/null +++ b/gr-filter/lib/qa_filter.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _QA_GR_FILTER_H_ +#define _QA_GR_FILTER_H_ + +#include +#include + +//! collect all the tests for the gr-filter directory + +class __GR_ATTR_EXPORT qa_gr_filter { + public: + //! return suite of tests for all of gr-filter directory + static CppUnit::TestSuite *suite (); +}; + + +#endif /* _QA_GR_FILTER_H_ */ diff --git a/gr-filter/lib/qa_firdes.cc b/gr-filter/lib/qa_firdes.cc new file mode 100644 index 000000000..c2fe399d5 --- /dev/null +++ b/gr-filter/lib/qa_firdes.cc @@ -0,0 +1,621 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace gr { + namespace filter { + +#define NELEM(x) (sizeof(x) / sizeof(x[0])) + + using std::vector; + +#if 0 + static void + print_taps(std::ostream &s, vector &v) + { + + for(unsigned int i = 0; i < v.size(); i++) { + printf("tap[%2d] = %16.7e\n", i, v[i]); + } + } +#endif + + static void + check_symmetry(vector &v) + { + int n = v.size(); + int m = n / 2; + + for(int i = 0; i < m; i++) + CPPUNIT_ASSERT_DOUBLES_EQUAL(v[i], v[n - i - 1], 1e-9); + } + + const static float t1_exp[53] = { + -9.0525491e-04, + 2.0713841e-04, + 1.2388536e-03, + 2.9683491e-04, + -1.7744775e-03, + -1.3599906e-03, + 2.2031884e-03, + 3.2744040e-03, + -1.8868084e-03, + -5.9935520e-03, + 6.4301129e-18, + 8.9516686e-03, + 4.2178580e-03, + -1.0998557e-02, + -1.1173409e-02, + 1.0455756e-02, + 2.0686293e-02, + -5.2032238e-03, + -3.1896964e-02, + -7.4998410e-03, + 4.3362070e-02, + 3.2502845e-02, + -5.3328082e-02, + -8.5621715e-02, + 6.0117975e-02, + 3.1128189e-01, + 4.3769023e-01, + 3.1128189e-01, + 6.0117975e-02, + -8.5621715e-02, + -5.3328082e-02, + 3.2502845e-02, + 4.3362070e-02, + -7.4998410e-03, + -3.1896964e-02, + -5.2032238e-03, + 2.0686293e-02, + 1.0455756e-02, + -1.1173409e-02, + -1.0998557e-02, + 4.2178580e-03, + 8.9516686e-03, + 6.4301129e-18, + -5.9935520e-03, + -1.8868084e-03, + 3.2744040e-03, + 2.2031884e-03, + -1.3599906e-03, + -1.7744775e-03, + 2.9683491e-04, + 1.2388536e-03, + 2.0713841e-04, + -9.0525491e-04 + }; + + const static float t2_exp[53] = { + 9.0380036e-04, + -2.0680559e-04, + -1.2368630e-03, + -2.9635796e-04, + 1.7716263e-03, + 1.3578053e-03, + -2.1996482e-03, + -3.2691427e-03, + 1.8837767e-03, + 5.9839217e-03, + -6.4197810e-18, + -8.9372853e-03, + -4.2110807e-03, + 1.0980885e-02, + 1.1155456e-02, + -1.0438956e-02, + -2.0653054e-02, + 5.1948633e-03, + 3.1845711e-02, + 7.4877902e-03, + -4.3292396e-02, + -3.2450620e-02, + 5.3242393e-02, + 8.5484132e-02, + -6.0021374e-02, + -3.1078172e-01, + 5.6184036e-01, + -3.1078172e-01, + -6.0021374e-02, + 8.5484132e-02, + 5.3242393e-02, + -3.2450620e-02, + -4.3292396e-02, + 7.4877902e-03, + 3.1845711e-02, + 5.1948633e-03, + -2.0653054e-02, + -1.0438956e-02, + 1.1155456e-02, + 1.0980885e-02, + -4.2110807e-03, + -8.9372853e-03, + -6.4197810e-18, + 5.9839217e-03, + 1.8837767e-03, + -3.2691427e-03, + -2.1996482e-03, + 1.3578053e-03, + 1.7716263e-03, + -2.9635796e-04, + -1.2368630e-03, + -2.0680559e-04, + 9.0380036e-04 + }; + + const static float t3_exp[107] = { + -1.8970841e-06, + -7.1057165e-04, + 5.4005696e-04, + 4.6233178e-04, + 2.0572044e-04, + 3.5209916e-04, + -1.4098573e-03, + 1.1279077e-04, + -6.2994129e-04, + 1.1450432e-03, + 1.3637283e-03, + -6.4360141e-04, + 3.6509900e-04, + -3.2864159e-03, + 7.0192874e-04, + 3.7524730e-04, + 2.0256115e-03, + 3.0641893e-03, + -3.6618244e-03, + 7.5592739e-05, + -5.5586505e-03, + 2.3849572e-03, + 4.0114378e-03, + 1.6636450e-03, + 4.7835698e-03, + -1.0191196e-02, + -3.8158931e-04, + -5.5551580e-03, + 5.3901658e-03, + 1.1366769e-02, + -3.0000482e-03, + 4.9341680e-03, + -2.0093076e-02, + 5.5752542e-17, + 1.2093617e-03, + 8.6089745e-03, + 2.2382140e-02, + -1.6854567e-02, + 1.6913920e-03, + -3.1222520e-02, + 3.2711059e-03, + 2.2604836e-02, + 8.1451107e-03, + 3.7583180e-02, + -5.2293688e-02, + -8.0551542e-03, + -4.0092729e-02, + 1.5582236e-02, + 9.7452506e-02, + -1.6183170e-02, + 8.3281815e-02, + -2.8196752e-01, + -1.0965768e-01, + 5.2867508e-01, + -1.0965768e-01, + -2.8196752e-01, + 8.3281815e-02, + -1.6183170e-02, + 9.7452506e-02, + 1.5582236e-02, + -4.0092729e-02, + -8.0551542e-03, + -5.2293688e-02, + 3.7583180e-02, + 8.1451107e-03, + 2.2604836e-02, + 3.2711059e-03, + -3.1222520e-02, + 1.6913920e-03, + -1.6854567e-02, + 2.2382140e-02, + 8.6089745e-03, + 1.2093617e-03, + 5.5752542e-17, + -2.0093076e-02, + 4.9341680e-03, + -3.0000482e-03, + 1.1366769e-02, + 5.3901658e-03, + -5.5551580e-03, + -3.8158931e-04, + -1.0191196e-02, + 4.7835698e-03, + 1.6636450e-03, + 4.0114378e-03, + 2.3849572e-03, + -5.5586505e-03, + 7.5592739e-05, + -3.6618244e-03, + 3.0641893e-03, + 2.0256115e-03, + 3.7524730e-04, + 7.0192874e-04, + -3.2864159e-03, + 3.6509900e-04, + -6.4360141e-04, + 1.3637283e-03, + 1.1450432e-03, + -6.2994129e-04, + 1.1279077e-04, + -1.4098573e-03, + 3.5209916e-04, + 2.0572044e-04, + 4.6233178e-04, + 5.4005696e-04, + -7.1057165e-04, + -1.8970841e-06 + }; + + const static float t4_exp[] = { // low pass + 0.001059958362, + 0.0002263929928, + -0.001277606934, + -0.0009675776237, + 0.001592264394, + 0.00243603508, + -0.001451682881, + -0.004769335967, + 5.281541594e-18, + 0.007567512803, + 0.003658855334, + -0.009761494584, + -0.01011830103, + 0.009636915289, + 0.0193619132, + -0.004935568199, + -0.03060629964, + -0.007267376408, + 0.04236677289, + 0.03197422624, + -0.05274848267, + -0.0850463286, + 0.05989059806, + 0.31065014, + 0.4370569289, + 0.31065014, + 0.05989059806, + -0.0850463286, + -0.05274848267, + 0.03197422624, + 0.04236677289, + -0.007267376408, + -0.03060629964, + -0.004935568199, + 0.0193619132, + 0.009636915289, + -0.01011830103, + -0.009761494584, + 0.003658855334, + 0.007567512803, + 5.281541594e-18, + -0.004769335967, + -0.001451682881, + 0.00243603508, + 0.001592264394, + -0.0009675776237, + -0.001277606934, + 0.0002263929928, + 0.001059958362, + }; + + const static float t5_exp[] = { //high pass + -0.001062123571, + -0.0002268554381, + 0.001280216733, + 0.000969554123, + -0.001595516922, + -0.002441011136, + 0.001454648213, + 0.004779078532, + -5.292330097e-18, + -0.007582970895, + -0.00366632943, + 0.009781434201, + 0.01013896987, + -0.009656600654, + -0.01940146461, + 0.004945650231, + 0.03066881932, + 0.00728222169, + -0.04245331511, + -0.03203954175, + 0.05285623297, + 0.08522006124, + -0.06001294032, + -0.3112847209, + 0.5630782247, + -0.3112847209, + -0.06001294032, + 0.08522006124, + 0.05285623297, + -0.03203954175, + -0.04245331511, + 0.00728222169, + 0.03066881932, + 0.004945650231, + -0.01940146461, + -0.009656600654, + 0.01013896987, + 0.009781434201, + -0.00366632943, + -0.007582970895, + -5.292330097e-18, + 0.004779078532, + 0.001454648213, + -0.002441011136, + -0.001595516922, + 0.000969554123, + 0.001280216733, + -0.0002268554381, + -0.001062123571, + }; + + const static float t6_exp[] = { // bandpass + 0.0002809273137, + -0.001047327649, + 7.936541806e-05, + -0.0004270860809, + 0.0007595835486, + 0.0008966081077, + -0.0004236323002, + 0.0002423936094, + -0.002212299034, + 0.0004807534278, + 0.0002620361629, + 0.001443728455, + 0.002229931997, + -0.002720607212, + 5.731141573e-05, + -0.004297634587, + 0.001878833398, + 0.003217151389, + 0.001357055153, + 0.003965090029, + -0.008576190099, + -0.0003257228818, + -0.004805727862, + 0.004721920472, + 0.01007549558, + -0.002688719891, + 0.004467967432, + -0.01837076992, + 5.119658377e-17, + 0.001125075156, + 0.008071650751, + 0.02113764361, + -0.01602453552, + 0.001618095324, + -0.03004053794, + 0.003163811285, + 0.0219683405, + 0.007950295694, + 0.03682873398, + -0.05142467469, + -0.00794606097, + -0.03965795785, + 0.01544955093, + 0.09681399167, + -0.01610304788, + 0.08297294378, + -0.2811714709, + -0.1094062924, + 0.5275565982, + -0.1094062924, + -0.2811714709, + 0.08297294378, + -0.01610304788, + 0.09681399167, + 0.01544955093, + -0.03965795785, + -0.00794606097, + -0.05142467469, + 0.03682873398, + 0.007950295694, + 0.0219683405, + 0.003163811285, + -0.03004053794, + 0.001618095324, + -0.01602453552, + 0.02113764361, + 0.008071650751, + 0.001125075156, + 5.119658377e-17, + -0.01837076992, + 0.004467967432, + -0.002688719891, + 0.01007549558, + 0.004721920472, + -0.004805727862, + -0.0003257228818, + -0.008576190099, + 0.003965090029, + 0.001357055153, + 0.003217151389, + 0.001878833398, + -0.004297634587, + 5.731141573e-05, + -0.002720607212, + 0.002229931997, + 0.001443728455, + 0.0002620361629, + 0.0004807534278, + -0.002212299034, + 0.0002423936094, + -0.0004236323002, + 0.0008966081077, + 0.0007595835486, + -0.0004270860809, + 7.936541806e-05, + -0.001047327649, + 0.0002809273137, + }; + + void + qa_firdes::t1() + { + vector taps = + firdes::low_pass(1.0, + 8000, + 1750, + 500, + firdes::WIN_HAMMING); + + // cout << "ntaps: " << taps.size() << endl; + // print_taps(cout, taps); + + CPPUNIT_ASSERT_EQUAL(NELEM(t1_exp), taps.size()); + for(unsigned int i = 0; i < taps.size(); i++) + CPPUNIT_ASSERT_DOUBLES_EQUAL(t1_exp[i], taps[i], 1e-9); + + check_symmetry(taps); +} + + void + qa_firdes::t2() + { + vector taps = + firdes::high_pass(1.0, + 8000, + 1750, + 500, + firdes::WIN_HAMMING); + + // cout << "ntaps: " << taps.size() << endl; + // print_taps(cout, taps); + + CPPUNIT_ASSERT_EQUAL(NELEM(t2_exp), taps.size()); + + for(unsigned int i = 0; i < taps.size(); i++) + CPPUNIT_ASSERT_DOUBLES_EQUAL(t2_exp[i], taps[i], 1e-9); + + check_symmetry(taps); + } + + void + qa_firdes::t3() + { + vector taps = + firdes::band_pass(1.0, + 20e6, + 5.75e6 - (5.28e6/2), + 5.75e6 + (5.28e6/2), + 0.62e6, + firdes::WIN_HAMMING); + + // cout << "ntaps: " << taps.size() << endl; + // print_taps(cout, taps); + + CPPUNIT_ASSERT_EQUAL(NELEM(t3_exp), taps.size()); + + for(unsigned int i = 0; i < taps.size(); i++) + CPPUNIT_ASSERT_DOUBLES_EQUAL(t3_exp[i], taps[i], 1e-7); + + check_symmetry(taps); + } + + void + qa_firdes::t4() + { + vector taps = + firdes::low_pass_2(1.0, + 8000, + 1750, + 500, + 66, + firdes::WIN_HAMMING); + + // std::cout << "ntaps: " << taps.size() << std::endl; + // print_taps(std::cout, taps); + + CPPUNIT_ASSERT_EQUAL(NELEM(t4_exp), taps.size()); + for(unsigned int i = 0; i < taps.size(); i++) + CPPUNIT_ASSERT_DOUBLES_EQUAL(t4_exp[i], taps[i], 1e-9); + + check_symmetry(taps); + } + + void + qa_firdes::t5() + { + vector taps = + firdes::high_pass_2(1.0, + 8000, + 1750, + 500, + 66, + firdes::WIN_HAMMING); + + // std::cout << "ntaps: " << taps.size() << std::endl; + // print_taps(std::cout, taps); + + CPPUNIT_ASSERT_EQUAL(NELEM(t5_exp), taps.size()); + + for(unsigned int i = 0; i < taps.size(); i++) + CPPUNIT_ASSERT_DOUBLES_EQUAL(t5_exp[i], taps[i], 1e-9); + + check_symmetry(taps); +} + + void + qa_firdes::t6() + { + vector taps = + firdes::band_pass_2(1.0, + 20e6, + 5.75e6 - (5.28e6/2), + 5.75e6 + (5.28e6/2), + 0.62e6, + 66, + firdes::WIN_HAMMING); + + // std::cout << "ntaps: " << taps.size() << std::endl; + // print_taps(std::cout, taps); + + CPPUNIT_ASSERT_EQUAL(NELEM(t6_exp), taps.size()); + + for(unsigned int i = 0; i < taps.size(); i++) + CPPUNIT_ASSERT_DOUBLES_EQUAL(t6_exp[i], taps[i], 1e-7); + + check_symmetry(taps); + } + + void + qa_firdes::t7() + { + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/qa_firdes.h b/gr-filter/lib/qa_firdes.h new file mode 100644 index 000000000..b27cf78b9 --- /dev/null +++ b/gr-filter/lib/qa_firdes.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef _QA_FILTER_FIRDES_H_ +#define _QA_FILTER_FIRDES_H_ + +#include +#include + +namespace gr { + namespace filter { + + class qa_firdes : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE(qa_firdes); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST(t4); + CPPUNIT_TEST(t5); + CPPUNIT_TEST(t6); + CPPUNIT_TEST(t7); + CPPUNIT_TEST_SUITE_END(); + + private: + void t1(); + void t2(); + void t3(); + void t4(); + void t5(); + void t6(); + void t7(); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* _QA_FILTER_FIRDES_H_ */ diff --git a/gr-filter/lib/test_gr_filter.cc b/gr-filter/lib/test_gr_filter.cc new file mode 100644 index 000000000..9027b7a99 --- /dev/null +++ b/gr-filter/lib/test_gr_filter.cc @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include +#include + +int +main (int argc, char **argv) +{ + CppUnit::TextTestRunner runner; + std::ofstream xmlfile(get_unittest_path("gr_filter.xml").c_str()); + CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile); + + runner.addTest(qa_gr_filter::suite()); + runner.setOutputter(xmlout); + + bool was_successful = runner.run("", false); + + return was_successful ? 0 : 1; +} -- cgit From 77d5097c7df9494ee7e215d9dbf29d185ffbe5ed Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 5 May 2012 13:35:40 -0400 Subject: filter: cleanup and moving calls from gr.firdes to filter.firdes. --- gr-filter/lib/fft_filter_ccc_impl.cc | 1 - gr-filter/lib/fft_filter_fff_impl.cc | 1 - 2 files changed, 2 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fft_filter_ccc_impl.cc b/gr-filter/lib/fft_filter_ccc_impl.cc index 2721f128e..0a2002991 100644 --- a/gr-filter/lib/fft_filter_ccc_impl.cc +++ b/gr-filter/lib/fft_filter_ccc_impl.cc @@ -30,7 +30,6 @@ #include #include #include -#include namespace gr { namespace filter { diff --git a/gr-filter/lib/fft_filter_fff_impl.cc b/gr-filter/lib/fft_filter_fff_impl.cc index 95b82aae5..1d6eb02db 100644 --- a/gr-filter/lib/fft_filter_fff_impl.cc +++ b/gr-filter/lib/fft_filter_fff_impl.cc @@ -30,7 +30,6 @@ #include #include #include -#include namespace gr { namespace filter { -- cgit From e832b09166547e380972f48b2317d96a25d3d0e5 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 5 May 2012 14:41:03 -0400 Subject: filter: added Parks-McClellen algorithm. Renamed gr_remez to pm_remez here. Added QA code and fixed coding style. --- gr-filter/lib/CMakeLists.txt | 3 +- gr-filter/lib/pm_remez.cc | 834 ++++++++++++++++++++++++++++++++++++++++ gr-filter/lib/test_gr_filter.cc | 1 + 3 files changed, 837 insertions(+), 1 deletion(-) create mode 100644 gr-filter/lib/pm_remez.cc (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index f085987de..247d0604c 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -107,7 +107,8 @@ link_directories(${FFTW3F_LIBRARY_DIRS}) list(APPEND filter_sources fir_filter.cc fft_filter.cc - firdes_impl.cc + firdes.cc + pm_remez.cc ${generated_sources} fft_filter_ccc_impl.cc fft_filter_fff_impl.cc diff --git a/gr-filter/lib/pm_remez.cc b/gr-filter/lib/pm_remez.cc new file mode 100644 index 000000000..e7136bd83 --- /dev/null +++ b/gr-filter/lib/pm_remez.cc @@ -0,0 +1,834 @@ +/************************************************************************** + * Parks-McClellan algorithm for FIR filter design (C version) + *------------------------------------------------- + * Copyright (c) 1995,1998 Jake Janovetz (janovetz@uiuc.edu) + * Copyright (c) 2004 Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA + * + * + * Sep 1999 - Paul Kienzle (pkienzle@cs.indiana.edu) + * Modified for use in octave as a replacement for the matlab function + * remez.mex. In particular, magnitude responses are required for all + * band edges rather than one per band, griddensity is a parameter, + * and errors are returned rather than printed directly. + * Mar 2000 - Kai Habel (kahacjde@linux.zrz.tu-berlin.de) + * Change: ColumnVector x=arg(i).vector_value(); + * to: ColumnVector x(arg(i).vector_value()); + * There appear to be some problems with the routine search. See comments + * therein [search for PAK:]. I haven't looked closely at the rest + * of the code---it may also have some problems. + *************************************************************************/ + +/* + * This code was extracted from octave.sf.net, and wrapped with + * GNU Radio glue. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#ifndef LOCAL_BUFFER +#include +#define LOCAL_BUFFER(T, buf, size) \ + std::vector buf ## _vector (size); \ + T *buf = &(buf ## _vector[0]) +#endif + +namespace gr { + namespace filter { + +#define CONST const +#define BANDPASS 1 +#define DIFFERENTIATOR 2 +#define HILBERT 3 + +#define NEGATIVE 0 +#define POSITIVE 1 + +#define Pi 3.14159265358979323846 +#define Pi2 (2*Pi) + +#define GRIDDENSITY 16 +#define MAXITERATIONS 40 + + /******************* + * create_dense_grid + *================= + * + * Creates the dense grid of frequencies from the specified bands. + * Also creates the Desired Frequency Response function (D[]) and + * the Weight function (W[]) on that dense grid + * + * + * INPUT: + * ------ + * int r - 1/2 the number of filter coefficients + * int numtaps - Number of taps in the resulting filter + * int numband - Number of bands in user specification + * double bands[] - User-specified band edges [2*numband] + * double des[] - Desired response per band [2*numband] + * double weight[] - Weight per band [numband] + * int symmetry - Symmetry of filter - used for grid check + * int griddensity + * + * OUTPUT: + * ------- + * int gridsize - Number of elements in the dense frequency grid + * double Grid[] - Frequencies (0 to 0.5) on the dense grid [gridsize] + * double D[] - Desired response on the dense grid [gridsize] + * double W[] - Weight function on the dense grid [gridsize] + *******************/ + + static void + create_dense_grid(int r, int numtaps, int numband, const double bands[], + const double des[], const double weight[], int gridsize, + double Grid[], double D[], double W[], + int symmetry, int griddensity) + { + int i, j, k, band; + double delf, lowf, highf, grid0; + + delf = 0.5/(griddensity*r); + + /* + * For differentiator, hilbert, + * symmetry is odd and Grid[0] = max(delf, bands[0]) + */ + grid0 = (symmetry == NEGATIVE) && (delf > bands[0]) ? delf : bands[0]; + + j=0; + for(band=0; band < numband; band++) { + lowf = (band==0 ? grid0 : bands[2*band]); + highf = bands[2*band + 1]; + k = (int)((highf - lowf)/delf + 0.5); /* .5 for rounding */ + for(i=0; i (0.5 - delf)) && + (numtaps % 2)) + { + Grid[gridsize-1] = 0.5-delf; + } + } + + + /******************** + * initial_guess + *============== + * Places Extremal Frequencies evenly throughout the dense grid. + * + * + * INPUT: + * ------ + * int r - 1/2 the number of filter coefficients + * int gridsize - Number of elements in the dense frequency grid + * + * OUTPUT: + * ------- + * int ext[] - Extremal indexes to dense frequency grid [r+1] + ********************/ + + static void + initial_guess(int r, int Ext[], int gridsize) + { + int i; + + for(i=0; i<=r; i++) + Ext[i] = i * (gridsize-1) / r; + } + + + /*********************** + * calc_parms + *=========== + * + * + * INPUT: + * ------ + * int r - 1/2 the number of filter coefficients + * int Ext[] - Extremal indexes to dense frequency grid [r+1] + * double Grid[] - Frequencies (0 to 0.5) on the dense grid [gridsize] + * double D[] - Desired response on the dense grid [gridsize] + * double W[] - Weight function on the dense grid [gridsize] + * + * OUTPUT: + * ------- + * double ad[] - 'b' in Oppenheim & Schafer [r+1] + * double x[] - [r+1] + * double y[] - 'C' in Oppenheim & Schafer [r+1] + ***********************/ + + static void + calc_parms(int r, int Ext[], double Grid[], double D[], double W[], + double ad[], double x[], double y[]) + { + int i, j, k, ld; + double sign, xi, delta, denom, numer; + + /* + * Find x[] + */ + for(i = 0; i <= r; i++) + x[i] = cos(Pi2 * Grid[Ext[i]]); + + /* + * Calculate ad[] - Oppenheim & Schafer eq 7.132 + */ + ld = (r-1)/15 + 1; /* Skips around to avoid round errors */ + for(i = 0; i <= r; i++) { + denom = 1.0; + xi = x[i]; + for(j = 0; j < ld; j++) { + for(k = j; k <= r; k += ld) + if(k != i) + denom *= 2.0*(xi - x[k]); + } + if(fabs(denom) < 0.00001) + denom = 0.00001; + ad[i] = 1.0/denom; + } + + /* + * Calculate delta - Oppenheim & Schafer eq 7.131 + */ + numer = denom = 0; + sign = 1; + for(i = 0; i <= r; i++) { + numer += ad[i] * D[Ext[i]]; + denom += sign * ad[i]/W[Ext[i]]; + sign = -sign; + } + delta = numer/denom; + sign = 1; + + /* + * Calculate y[] - Oppenheim & Schafer eq 7.133b + */ + for(i = 0; i <= r; i++) { + y[i] = D[Ext[i]] - sign * delta/W[Ext[i]]; + sign = -sign; + } + } + + + /********************* + * compute_A + *========== + * Using values calculated in calc_parms, compute_A calculates the + * actual filter response at a given frequency (freq). Uses + * eq 7.133a from Oppenheim & Schafer. + * + * + * INPUT: + * ------ + * double freq - Frequency (0 to 0.5) at which to calculate A + * int r - 1/2 the number of filter coefficients + * double ad[] - 'b' in Oppenheim & Schafer [r+1] + * double x[] - [r+1] + * double y[] - 'C' in Oppenheim & Schafer [r+1] + * + * OUTPUT: + * ------- + * Returns double value of A[freq] + *********************/ + + static double + compute_A(double freq, int r, double ad[], double x[], double y[]) + { + int i; + double xc, c, denom, numer; + + denom = numer = 0; + xc = cos(Pi2 * freq); + for(i = 0; i <= r; i++) { + c = xc - x[i]; + if(fabs(c) < 1.0e-7) { + numer = y[i]; + denom = 1; + break; + } + c = ad[i]/c; + denom += c; + numer += c*y[i]; + } + return numer/denom; + } + + + /************************ + * calc_error + *=========== + * Calculates the Error function from the desired frequency response + * on the dense grid (D[]), the weight function on the dense grid (W[]), + * and the present response calculation (A[]) + * + * + * INPUT: + * ------ + * int r - 1/2 the number of filter coefficients + * double ad[] - [r+1] + * double x[] - [r+1] + * double y[] - [r+1] + * int gridsize - Number of elements in the dense frequency grid + * double Grid[] - Frequencies on the dense grid [gridsize] + * double D[] - Desired response on the dense grid [gridsize] + * double W[] - Weight function on the desnse grid [gridsize] + * + * OUTPUT: + * ------- + * double E[] - Error function on dense grid [gridsize] + ************************/ + + static void + calc_error(int r, double ad[], double x[], double y[], + int gridsize, double Grid[], + double D[], double W[], double E[]) + { + int i; + double A; + + for(i = 0; i < gridsize; i++) { + A = compute_A(Grid[i], r, ad, x, y); + E[i] = W[i] * (D[i] - A); + } + } + + /************************ + * search + *======== + * Searches for the maxima/minima of the error curve. If more than + * r+1 extrema are found, it uses the following heuristic (thanks + * Chris Hanson): + * 1) Adjacent non-alternating extrema deleted first. + * 2) If there are more than one excess extrema, delete the + * one with the smallest error. This will create a non-alternation + * condition that is fixed by 1). + * 3) If there is exactly one excess extremum, delete the smaller + * of the first/last extremum + * + * + * INPUT: + * ------ + * int r - 1/2 the number of filter coefficients + * int Ext[] - Indexes to Grid[] of extremal frequencies [r+1] + * int gridsize - Number of elements in the dense frequency grid + * double E[] - Array of error values. [gridsize] + * OUTPUT: + * ------- + * int Ext[] - New indexes to extremal frequencies [r+1] + ************************/ + static int + search(int r, int Ext[], + int gridsize, double E[]) + { + int i, j, k, l, extra; /* Counters */ + int up, alt; + int *foundExt; /* Array of found extremals */ + + /* + * Allocate enough space for found extremals. + */ + foundExt = (int *)malloc((2*r) * sizeof(int)); + k = 0; + + /* + * Check for extremum at 0. + */ + if(((E[0] > 0.0) && (E[0] > E[1])) || + ((E[0] < 0.0) && (E[0] < E[1]))) + foundExt[k++] = 0; + + /* + * Check for extrema inside dense grid + */ + for(i = 1; i < gridsize-1; i++) { + if(((E[i] >= E[i-1]) && (E[i] > E[i+1]) && (E[i] > 0.0)) || + ((E[i] <= E[i-1]) && (E[i] < E[i+1]) && (E[i] < 0.0))) { + // PAK: we sometimes get too many extremal frequencies + if(k >= 2*r) + return -3; + foundExt[k++] = i; + } + } + + /* + * Check for extremum at 0.5 + */ + j = gridsize-1; + if(((E[j] > 0.0) && (E[j] > E[j-1])) || + ((E[j] < 0.0) && (E[j] < E[j-1]))) { + if(k >= 2*r) + return -3; + foundExt[k++] = j; + } + + // PAK: we sometimes get not enough extremal frequencies + if(k < r+1) + return -2; + + /* + * Remove extra extremals + */ + extra = k - (r+1); + assert(extra >= 0); + + while(extra > 0) { + if(E[foundExt[0]] > 0.0) + up = 1; /* first one is a maxima */ + else + up = 0; /* first one is a minima */ + + l=0; + alt = 1; + for(j = 1; j < k; j++) { + if(fabs(E[foundExt[j]]) < fabs(E[foundExt[l]])) + l = j; /* new smallest error. */ + if((up) && (E[foundExt[j]] < 0.0)) + up = 0; /* switch to a minima */ + else if((!up) && (E[foundExt[j]] > 0.0)) + up = 1; /* switch to a maxima */ + else { + alt = 0; + // PAK: break now and you will delete the smallest overall + // extremal. If you want to delete the smallest of the + // pair of non-alternating extremals, then you must do: + // + // if(fabs(E[foundExt[j]]) < fabs(E[foundExt[j-1]])) l=j; + // else l=j-1; + break; /* Ooops, found two non-alternating */ + } /* extrema. Delete smallest of them */ + } /* if the loop finishes, all extrema are alternating */ + + /* + * If there's only one extremal and all are alternating, + * delete the smallest of the first/last extremals. + */ + if((alt) && (extra == 1)) { + if(fabs(E[foundExt[k-1]]) < fabs(E[foundExt[0]])) + /* Delete last extremal */ + l = k-1; + // PAK: changed from l = foundExt[k-1]; + else + /* Delete first extremal */ + l = 0; + // PAK: changed from l = foundExt[0]; + } + + for(j = l; j < k-1; j++) { /* Loop that does the deletion */ + foundExt[j] = foundExt[j+1]; + assert(foundExt[j] max) + max = current; + } + return(((max-min)/max) < 0.0001); + } + + /******************** + * remez + *======= + * Calculates the optimal (in the Chebyshev/minimax sense) + * FIR filter impulse response given a set of band edges, + * the desired reponse on those bands, and the weight given to + * the error in those bands. + * + * INPUT: + * ------ + * int numtaps - Number of filter coefficients + * int numband - Number of bands in filter specification + * double bands[] - User-specified band edges [2 * numband] + * double des[] - User-specified band responses [2 * numband] + * double weight[] - User-specified error weights [numband] + * int type - Type of filter + * + * OUTPUT: + * ------- + * double h[] - Impulse response of final filter [numtaps] + * returns - true on success, false on failure to converge + ********************/ + + static int + remez(double h[], int numtaps, + int numband, const double bands[], + const double des[], const double weight[], + int type, int griddensity) + { + double *Grid, *W, *D, *E; + int i, iter, gridsize, r, *Ext; + double *taps, c; + double *x, *y, *ad; + int symmetry; + + if(type == BANDPASS) + symmetry = POSITIVE; + else + symmetry = NEGATIVE; + + r = numtaps/2; /* number of extrema */ + if((numtaps % 2) && (symmetry == POSITIVE)) + r++; + + /* + * Predict dense grid size in advance for memory allocation + * .5 is so we round up, not truncate + */ + gridsize = 0; + for(i = 0; i < numband; i++) { + gridsize +=(int)(2*r*griddensity*(bands[2*i+1] - bands[2*i]) + .5); + } + if(symmetry == NEGATIVE) { + gridsize--; + } + + /* + * Dynamically allocate memory for arrays with proper sizes + */ + Grid = (double *)malloc(gridsize * sizeof(double)); + D = (double *)malloc(gridsize * sizeof(double)); + W = (double *)malloc(gridsize * sizeof(double)); + E = (double *)malloc(gridsize * sizeof(double)); + Ext = (int *)malloc((r+1) * sizeof(int)); + taps = (double *)malloc((r+1) * sizeof(double)); + x = (double *)malloc((r+1) * sizeof(double)); + y = (double *)malloc((r+1) * sizeof(double)); + ad = (double *)malloc((r+1) * sizeof(double)); + + /* + * Create dense frequency grid + */ + create_dense_grid(r, numtaps, numband, bands, des, weight, + gridsize, Grid, D, W, symmetry, griddensity); + initial_guess(r, Ext, gridsize); + + /* + * For Differentiator: (fix grid) + */ + if(type == DIFFERENTIATOR) { + for(i = 0; i < gridsize; i++) { + /* D[i] = D[i]*Grid[i]; */ + if(D[i] > 0.0001) + W[i] = W[i]/Grid[i]; + } + } + + /* + * For odd or Negative symmetry filters, alter the + * D[] and W[] according to Parks McClellan + */ + if(symmetry == POSITIVE) { + if(numtaps % 2 == 0) { + for(i = 0; i < gridsize; i++) { + c = cos(Pi * Grid[i]); + D[i] /= c; + W[i] *= c; + } + } + } + else { + if(numtaps % 2) { + for(i = 0; i < gridsize; i++) { + c = sin(Pi2 * Grid[i]); + D[i] /= c; + W[i] *= c; + } + } + else { + for(i = 0; i < gridsize; i++) { + c = sin(Pi * Grid[i]); + D[i] /= c; + W[i] *= c; + } + } + } + + /* + * Perform the Remez Exchange algorithm + */ + for(iter = 0; iter < MAXITERATIONS; iter++) { + calc_parms(r, Ext, Grid, D, W, ad, x, y); + calc_error(r, ad, x, y, gridsize, Grid, D, W, E); + int err = search(r, Ext, gridsize, E); + if(err) + return err; + for(int i = 0; i <= r; i++) + assert(Ext[i] < gridsize); + if(is_done(r, Ext, E)) + break; + } + + calc_parms(r, Ext, Grid, D, W, ad, x, y); + + /* + * Find the 'taps' of the filter for use with Frequency + * Sampling. If odd or Negative symmetry, fix the taps + * according to Parks McClellan + */ + for(i = 0; i <= numtaps/2; i++) { + if(symmetry == POSITIVE) { + if(numtaps % 2) + c = 1; + else + c = cos(Pi * (double)i/numtaps); + } + else { + if(numtaps % 2) + c = sin(Pi2 * (double)i/numtaps); + else + c = sin(Pi * (double)i/numtaps); + } + taps[i] = compute_A((double)i/numtaps, r, ad, x, y)*c; + } + + /* + * Frequency sampling design with calculated taps + */ + freq_sample(numtaps, taps, h, symmetry); + + /* + * Delete allocated memory + */ + free(Grid); + free(W); + free(D); + free(E); + free(Ext); + free(x); + free(y); + free(ad); + + return iter + pm_remez(int order, + const std::vector &arg_bands, + const std::vector &arg_response, + const std::vector &arg_weight, + const std::string filter_type, + int grid_density + ) throw (std::runtime_error) + { + int numtaps = order + 1; + if(numtaps < 4) + punt("gr_remez: number of taps must be >= 3"); + + int numbands = arg_bands.size() / 2; + LOCAL_BUFFER(double, bands, numbands * 2); + if(numbands < 1 || arg_bands.size() % 2 == 1) + punt("gr_remez: must have an even number of band edges"); + + for(unsigned int i = 1; i < arg_bands.size(); i++){ + if(arg_bands[i] < arg_bands[i-1]) + punt("gr_remez: band edges must be nondecreasing"); + } + + if(arg_bands[0] < 0 || arg_bands[arg_bands.size() - 1] > 1) + punt("gr_remez: band edges must be in the range [0,1]"); + + // Divide by 2 to fit with the implementation that uses a + // sample rate of [0, 0.5] instead of [0, 1.0] + for(int i = 0; i < 2 * numbands; i++) + bands[i] = arg_bands[i] / 2; + + LOCAL_BUFFER(double, response, numbands * 2); + if(arg_response.size() != arg_bands.size()) + punt("gr_remez: must have one response magnitude for each band edge"); + + for(int i = 0; i < 2 * numbands; i++) + response[i] = arg_response[i]; + + LOCAL_BUFFER(double, weight, numbands); + for(int i = 0; i < numbands; i++) + weight[i] = 1.0; + + if(arg_weight.size() != 0) { + if((int) arg_weight.size() != numbands) + punt("gr_remez: need one weight for each band [=length(band)/2]"); + for(int i = 0; i < numbands; i++) + weight[i] = arg_weight [i]; + } + + int itype = 0; + if(filter_type == "bandpass") + itype = BANDPASS; + else if(filter_type == "differentiator") + itype = DIFFERENTIATOR; + else if(filter_type == "hilbert") + itype = HILBERT; + else + punt("gr_remez: unknown ftype '" + filter_type + "'"); + + if(grid_density < 16) + punt("gr_remez: grid_density is too low; must be >= 16"); + + LOCAL_BUFFER(double, coeff, numtaps + 5); // FIXME why + 5? + int err = remez(coeff, numtaps, numbands, + bands, response, weight, itype, grid_density); + + if(err == -1) + punt("gr_remez: failed to converge"); + + if(err == -2) + punt("gr_remez: insufficient extremals -- cannot continue"); + + if(err == -3) + punt("gr_remez: too many extremals -- cannot continue"); + + return std::vector(&coeff[0], &coeff[numtaps]); + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/test_gr_filter.cc b/gr-filter/lib/test_gr_filter.cc index 9027b7a99..915b6286b 100644 --- a/gr-filter/lib/test_gr_filter.cc +++ b/gr-filter/lib/test_gr_filter.cc @@ -25,6 +25,7 @@ #include #include +#include int main (int argc, char **argv) -- cgit From 53f57b6730fa7579d34bf6387d50f894a46030d4 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 5 May 2012 14:42:18 -0400 Subject: filter: actually run the C++ unit tests. --- gr-filter/lib/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 247d0604c..e8a2a04a7 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -146,4 +146,4 @@ target_link_libraries( ${Boost_LIBRARIES} ) -GR_ADD_TEST(test_gr_filter) +GR_ADD_TEST(test_gr_filter test-gr-filter) -- cgit From 897a60220a29fc509802e5e30e645e7ee154e184 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 5 May 2012 17:52:28 -0400 Subject: filter: added hilbert xform block with QA and GRC block. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/hilbert_fc_impl.cc | 70 ++++++++++++++++++++++++++++++++++++++++ gr-filter/lib/hilbert_fc_impl.h | 53 ++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 gr-filter/lib/hilbert_fc_impl.cc create mode 100644 gr-filter/lib/hilbert_fc_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index e8a2a04a7..6b33d547b 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -112,6 +112,7 @@ list(APPEND filter_sources ${generated_sources} fft_filter_ccc_impl.cc fft_filter_fff_impl.cc + hilbert_fc_impl.cc ) list(APPEND filter_libs diff --git a/gr-filter/lib/hilbert_fc_impl.cc b/gr-filter/lib/hilbert_fc_impl.cc new file mode 100644 index 000000000..946b47e4a --- /dev/null +++ b/gr-filter/lib/hilbert_fc_impl.cc @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,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 "hilbert_fc_impl.h" +#include +#include + +namespace gr { + namespace filter { + + hilbert_fc::sptr hilbert_fc::make(unsigned int ntaps) + { + return gnuradio::get_initial_sptr(new hilbert_fc_impl(ntaps)); + } + + hilbert_fc_impl::hilbert_fc_impl(unsigned int ntaps) + : gr_sync_block ("hilbert_fc", + gr_make_io_signature (1, 1, sizeof(float)), + gr_make_io_signature (1, 1, sizeof(gr_complex))), + d_ntaps(ntaps | 0x1) // ensure ntaps is odd + { + d_hilb = new kernel::fir_filter_fff(1, firdes::hilbert(d_ntaps)); + set_history (d_ntaps); + } + + hilbert_fc_impl::~hilbert_fc_impl() + { + delete d_hilb; + } + + int + hilbert_fc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + float *in = (float *)input_items[0]; + gr_complex *out = (gr_complex *)output_items[0]; + + for(int i = 0; i < noutput_items; i++) + out[i] = gr_complex (in[i + d_ntaps/2], + d_hilb->filter (&in[i])); + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/hilbert_fc_impl.h b/gr-filter/lib/hilbert_fc_impl.h new file mode 100644 index 000000000..de4d754b4 --- /dev/null +++ b/gr-filter/lib/hilbert_fc_impl.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FILTER_HILBERT_FC_IMPL_H +#define INCLUDED_FILTER_HILBERT_FC_IMPL_H + +#include +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API hilbert_fc_impl : public hilbert_fc + { + private: + unsigned int d_ntaps; + kernel::fir_filter_fff *d_hilb; + + public: + hilbert_fc_impl(unsigned int ntaps); + + ~hilbert_fc_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_HILBERT_FC_IMPL_H */ -- cgit From 137cd17199b62409591acff84476605f64e15ff8 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 6 May 2012 16:24:43 -0400 Subject: filter: moved dc_blocker to gr-filter with QA and GRC blocks. --- gr-filter/lib/CMakeLists.txt | 2 + gr-filter/lib/dc_blocker_cc_impl.cc | 144 ++++++++++++++++++++++++++++++++++++ gr-filter/lib/dc_blocker_cc_impl.h | 76 +++++++++++++++++++ gr-filter/lib/dc_blocker_ff_impl.cc | 142 +++++++++++++++++++++++++++++++++++ gr-filter/lib/dc_blocker_ff_impl.h | 76 +++++++++++++++++++ 5 files changed, 440 insertions(+) create mode 100644 gr-filter/lib/dc_blocker_cc_impl.cc create mode 100644 gr-filter/lib/dc_blocker_cc_impl.h create mode 100644 gr-filter/lib/dc_blocker_ff_impl.cc create mode 100644 gr-filter/lib/dc_blocker_ff_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 6b33d547b..ab49cf7ae 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -110,6 +110,8 @@ list(APPEND filter_sources firdes.cc pm_remez.cc ${generated_sources} + dc_blocker_cc_impl.cc + dc_blocker_ff_impl.cc fft_filter_ccc_impl.cc fft_filter_fff_impl.cc hilbert_fc_impl.cc diff --git a/gr-filter/lib/dc_blocker_cc_impl.cc b/gr-filter/lib/dc_blocker_cc_impl.cc new file mode 100644 index 000000000..11974e5ae --- /dev/null +++ b/gr-filter/lib/dc_blocker_cc_impl.cc @@ -0,0 +1,144 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dc_blocker_cc_impl.h" +#include +#include + +namespace gr { + namespace filter { + + moving_averager_c::moving_averager_c(int D) + : d_length(D), d_out(0), d_out_d1(0), d_out_d2(0) + { + d_delay_line = std::deque(d_length-1, gr_complex(0,0)); + } + + moving_averager_c::~moving_averager_c() + { + } + + gr_complex + moving_averager_c::filter(gr_complex x) + { + d_out_d1 = d_out; + d_delay_line.push_back(x); + d_out = d_delay_line[0]; + d_delay_line.pop_front(); + + gr_complex y = x - d_out_d1 + d_out_d2; + d_out_d2 = y; + + return (y / (float)(d_length)); + } + + + + dc_blocker_cc::sptr dc_blocker_cc::make(int D, bool long_form) + { + return gnuradio::get_initial_sptr(new dc_blocker_cc_impl(D, long_form)); + } + + + dc_blocker_cc_impl::dc_blocker_cc_impl(int D, bool long_form) + : gr_sync_block ("dc_blocker_cc", + gr_make_io_signature (1, 1, sizeof(gr_complex)), + gr_make_io_signature (1, 1, sizeof(gr_complex))), + d_length(D), d_long_form(long_form) + { + if(d_long_form) { + d_ma_0 = new moving_averager_c(D); + d_ma_1 = new moving_averager_c(D); + d_ma_2 = new moving_averager_c(D); + d_ma_3 = new moving_averager_c(D); + d_delay_line = std::deque(d_length-1, gr_complex(0,0)); + } + else { + d_ma_0 = new moving_averager_c(D); + d_ma_1 = new moving_averager_c(D); + } + } + + dc_blocker_cc_impl::~dc_blocker_cc_impl() + { + if(d_long_form) { + delete d_ma_0; + delete d_ma_1; + delete d_ma_2; + delete d_ma_3; + } + else { + delete d_ma_0; + delete d_ma_1; + } + } + + int + dc_blocker_cc_impl::get_group_delay() + { + if(d_long_form) + return (2*d_length-2); + else + return d_length - 1; + } + + int + dc_blocker_cc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + if(d_long_form) { + gr_complex y1, y2, y3, y4, d; + for(int i = 0; i < noutput_items; i++) { + y1 = d_ma_0->filter(in[i]); + y2 = d_ma_1->filter(y1); + y3 = d_ma_2->filter(y2); + y4 = d_ma_3->filter(y3); + + d_delay_line.push_back(d_ma_0->delayed_sig()); + d = d_delay_line[0]; + d_delay_line.pop_front(); + + out[i] = d - y4; + } + } + else { + gr_complex y1, y2; + for(int i = 0; i < noutput_items; i++) { + y1 = d_ma_0->filter(in[i]); + y2 = d_ma_1->filter(y1); + out[i] = d_ma_0->delayed_sig() - y2; + } + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/dc_blocker_cc_impl.h b/gr-filter/lib/dc_blocker_cc_impl.h new file mode 100644 index 000000000..7c8d1d93d --- /dev/null +++ b/gr-filter/lib/dc_blocker_cc_impl.h @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_FILTER_DC_BLOCKER_CC_IMPL_H +#define INCLUDED_FILTER_DC_BLOCKER_CC_IMPL_H + +#include +#include + +namespace gr { + namespace filter { + + class moving_averager_c + { + public: + moving_averager_c(int D); + ~moving_averager_c(); + + gr_complex filter(gr_complex x); + gr_complex delayed_sig() { return d_out; } + + private: + int d_length; + gr_complex d_out, d_out_d1, d_out_d2; + std::deque d_delay_line; + }; + + class FILTER_API dc_blocker_cc_impl : public dc_blocker_cc + { + private: + int d_length; + bool d_long_form; + moving_averager_c *d_ma_0; + moving_averager_c *d_ma_1; + moving_averager_c *d_ma_2; + moving_averager_c *d_ma_3; + std::deque d_delay_line; + + public: + dc_blocker_cc_impl(int D, bool long_form); + + ~dc_blocker_cc_impl(); + + int get_group_delay(); + + //int set_length(int D); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_DC_BLOCKER_CC_IMPL_H */ diff --git a/gr-filter/lib/dc_blocker_ff_impl.cc b/gr-filter/lib/dc_blocker_ff_impl.cc new file mode 100644 index 000000000..86d2f2f7a --- /dev/null +++ b/gr-filter/lib/dc_blocker_ff_impl.cc @@ -0,0 +1,142 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "dc_blocker_ff_impl.h" +#include +#include + +namespace gr { + namespace filter { + + moving_averager_f::moving_averager_f(int D) + : d_length(D), d_out(0), d_out_d1(0), d_out_d2(0) + { + d_delay_line = std::deque(d_length-1, 0); + } + + moving_averager_f::~moving_averager_f() + { + } + + float + moving_averager_f::filter(float x) + { + d_out_d1 = d_out; + d_delay_line.push_back(x); + d_out = d_delay_line[0]; + d_delay_line.pop_front(); + + float y = x - d_out_d1 + d_out_d2; + d_out_d2 = y; + + return (y / (float)(d_length)); + } + + + dc_blocker_ff::sptr dc_blocker_ff::make(int D, bool long_form) + { + return gnuradio::get_initial_sptr(new dc_blocker_ff_impl(D, long_form)); + } + + dc_blocker_ff_impl::dc_blocker_ff_impl (int D, bool long_form) + : gr_sync_block ("dc_blocker_ff", + gr_make_io_signature (1, 1, sizeof(float)), + gr_make_io_signature (1, 1, sizeof(float))), + d_length(D), d_long_form(long_form) + { + if(d_long_form) { + d_ma_0 = new moving_averager_f(D); + d_ma_1 = new moving_averager_f(D); + d_ma_2 = new moving_averager_f(D); + d_ma_3 = new moving_averager_f(D); + d_delay_line = std::deque(d_length-1, 0); + } + else { + d_ma_0 = new moving_averager_f(D); + d_ma_1 = new moving_averager_f(D); + } + } + + dc_blocker_ff_impl::~dc_blocker_ff_impl() + { + if(d_long_form) { + delete d_ma_0; + delete d_ma_1; + delete d_ma_2; + delete d_ma_3; + } + else { + delete d_ma_0; + delete d_ma_1; + } + } + + int + dc_blocker_ff_impl::get_group_delay() + { + if(d_long_form) + return (2*d_length-2); + else + return d_length - 1; + } + + int + dc_blocker_ff_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float*)input_items[0]; + float *out = (float*)output_items[0]; + + if(d_long_form) { + float y1, y2, y3, y4, d; + for(int i = 0; i < noutput_items; i++) { + y1 = d_ma_0->filter(in[i]); + y2 = d_ma_1->filter(y1); + y3 = d_ma_2->filter(y2); + y4 = d_ma_3->filter(y3); + + d_delay_line.push_back(d_ma_0->delayed_sig()); + d = d_delay_line[0]; + d_delay_line.pop_front(); + + out[i] = d - y4; + } + } + else { + float y1, y2; + for(int i = 0; i < noutput_items; i++) { + y1 = d_ma_0->filter(in[i]); + y2 = d_ma_1->filter(y1); + out[i] = d_ma_0->delayed_sig() - y2; + } + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/dc_blocker_ff_impl.h b/gr-filter/lib/dc_blocker_ff_impl.h new file mode 100644 index 000000000..868e1d433 --- /dev/null +++ b/gr-filter/lib/dc_blocker_ff_impl.h @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_FILTER_DC_BLOCKER_FF_IMPL_H +#define INCLUDED_FILTER_DC_BLOCKER_FF_IMPL_H + +#include +#include + +namespace gr { + namespace filter { + + class moving_averager_f + { + public: + moving_averager_f(int D); + ~moving_averager_f(); + + float filter(float x); + float delayed_sig() { return d_out; } + + private: + int d_length; + float d_out, d_out_d1, d_out_d2; + std::deque d_delay_line; + }; + + class FILTER_API dc_blocker_ff_impl : public dc_blocker_ff + { + private: + int d_length; + bool d_long_form; + moving_averager_f *d_ma_0; + moving_averager_f *d_ma_1; + moving_averager_f *d_ma_2; + moving_averager_f *d_ma_3; + std::deque d_delay_line; + + public: + dc_blocker_ff_impl(int D, bool long_form); + + ~dc_blocker_ff_impl(); + + int get_group_delay(); + + //int set_length(int D); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_DC_BLOCKER_FF_IMPL_H */ -- cgit From b3987add5662344ed88be910afdb55de1097ed15 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 6 May 2012 17:11:05 -0400 Subject: filter: some cleanup with the dc_blocker code. --- gr-filter/lib/dc_blocker_cc_impl.cc | 8 ++++---- gr-filter/lib/dc_blocker_cc_impl.h | 2 +- gr-filter/lib/dc_blocker_ff_impl.cc | 10 +++++----- gr-filter/lib/dc_blocker_ff_impl.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/dc_blocker_cc_impl.cc b/gr-filter/lib/dc_blocker_cc_impl.cc index 11974e5ae..663ba94f1 100644 --- a/gr-filter/lib/dc_blocker_cc_impl.cc +++ b/gr-filter/lib/dc_blocker_cc_impl.cc @@ -64,9 +64,9 @@ namespace gr { dc_blocker_cc_impl::dc_blocker_cc_impl(int D, bool long_form) - : gr_sync_block ("dc_blocker_cc", - gr_make_io_signature (1, 1, sizeof(gr_complex)), - gr_make_io_signature (1, 1, sizeof(gr_complex))), + : gr_sync_block("dc_blocker_cc", + gr_make_io_signature (1, 1, sizeof(gr_complex)), + gr_make_io_signature (1, 1, sizeof(gr_complex))), d_length(D), d_long_form(long_form) { if(d_long_form) { @@ -97,7 +97,7 @@ namespace gr { } int - dc_blocker_cc_impl::get_group_delay() + dc_blocker_cc_impl::group_delay() { if(d_long_form) return (2*d_length-2); diff --git a/gr-filter/lib/dc_blocker_cc_impl.h b/gr-filter/lib/dc_blocker_cc_impl.h index 7c8d1d93d..6f8bc16c7 100644 --- a/gr-filter/lib/dc_blocker_cc_impl.h +++ b/gr-filter/lib/dc_blocker_cc_impl.h @@ -61,7 +61,7 @@ namespace gr { ~dc_blocker_cc_impl(); - int get_group_delay(); + int group_delay(); //int set_length(int D); diff --git a/gr-filter/lib/dc_blocker_ff_impl.cc b/gr-filter/lib/dc_blocker_ff_impl.cc index 86d2f2f7a..22822d147 100644 --- a/gr-filter/lib/dc_blocker_ff_impl.cc +++ b/gr-filter/lib/dc_blocker_ff_impl.cc @@ -61,10 +61,10 @@ namespace gr { return gnuradio::get_initial_sptr(new dc_blocker_ff_impl(D, long_form)); } - dc_blocker_ff_impl::dc_blocker_ff_impl (int D, bool long_form) - : gr_sync_block ("dc_blocker_ff", - gr_make_io_signature (1, 1, sizeof(float)), - gr_make_io_signature (1, 1, sizeof(float))), + dc_blocker_ff_impl::dc_blocker_ff_impl(int D, bool long_form) + : gr_sync_block("dc_blocker_ff", + gr_make_io_signature (1, 1, sizeof(float)), + gr_make_io_signature (1, 1, sizeof(float))), d_length(D), d_long_form(long_form) { if(d_long_form) { @@ -95,7 +95,7 @@ namespace gr { } int - dc_blocker_ff_impl::get_group_delay() + dc_blocker_ff_impl::group_delay() { if(d_long_form) return (2*d_length-2); diff --git a/gr-filter/lib/dc_blocker_ff_impl.h b/gr-filter/lib/dc_blocker_ff_impl.h index 868e1d433..5ae60e2e4 100644 --- a/gr-filter/lib/dc_blocker_ff_impl.h +++ b/gr-filter/lib/dc_blocker_ff_impl.h @@ -61,7 +61,7 @@ namespace gr { ~dc_blocker_ff_impl(); - int get_group_delay(); + int group_delay(); //int set_length(int D); -- cgit From fc98a2a9775ab8e091413a195ce2584e5b76de99 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 6 May 2012 19:36:03 -0400 Subject: filter: added filter_delay_fc to gr-filter with QA and GRC files. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/filter_delay_fc_impl.cc | 107 ++++++++++++++++++++++++++++++++++ gr-filter/lib/filter_delay_fc_impl.h | 56 ++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 gr-filter/lib/filter_delay_fc_impl.cc create mode 100644 gr-filter/lib/filter_delay_fc_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index ab49cf7ae..c8e7b7e18 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -112,6 +112,7 @@ list(APPEND filter_sources ${generated_sources} dc_blocker_cc_impl.cc dc_blocker_ff_impl.cc + filter_delay_fc_impl.cc fft_filter_ccc_impl.cc fft_filter_fff_impl.cc hilbert_fc_impl.cc diff --git a/gr-filter/lib/filter_delay_fc_impl.cc b/gr-filter/lib/filter_delay_fc_impl.cc new file mode 100644 index 000000000..ce320c557 --- /dev/null +++ b/gr-filter/lib/filter_delay_fc_impl.cc @@ -0,0 +1,107 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "filter_delay_fc_impl.h" + +namespace gr { + namespace filter { + + filter_delay_fc::sptr filter_delay_fc::make(const std::vector &taps) + { + return gnuradio::get_initial_sptr(new filter_delay_fc_impl(taps)); + } + + filter_delay_fc_impl::filter_delay_fc_impl(const std::vector &taps) + : gr_sync_block("filter_delay_fc", + gr_make_io_signature(1, 2, sizeof(float)), + gr_make_io_signature(1, 1, sizeof(gr_complex))), + d_update(false) + { + d_taps = taps; + d_fir = new kernel::fir_filter_fff(1, taps); + d_delay = d_fir->ntaps() / 2; + set_history(d_fir->ntaps()); + } + + filter_delay_fc_impl::~filter_delay_fc_impl() + { + delete d_fir; + } + + std::vector + filter_delay_fc_impl::taps() + { + return d_fir->taps(); + } + + void + filter_delay_fc_impl::set_taps(const std::vector &taps) + { + // don't reset taps in case history changes + d_taps = taps; + d_update = true; + } + + int + filter_delay_fc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + float *in0 = (float *)input_items[0]; + float *in1 = (float *)input_items[1]; + gr_complex *out = (gr_complex *)output_items[0]; + + if(d_update) { + d_fir->set_taps(d_taps); + d_delay = d_fir->ntaps() / 2; + set_history(d_fir->ntaps()); + return 0; + } + + switch(input_items.size ()) { + case 1: + for(int i = 0; i < noutput_items; i++) { + out[i] = gr_complex (in0[i + d_delay], + d_fir->filter (&in0[i])); + } + break; + + case 2: + for(int j = 0; j < noutput_items; j++) { + out[j] = gr_complex (in0[j + d_delay], + d_fir->filter (&in1[j])); + } + break; + + default: + assert(0); + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/filter_delay_fc_impl.h b/gr-filter/lib/filter_delay_fc_impl.h new file mode 100644 index 000000000..5157d6e02 --- /dev/null +++ b/gr-filter/lib/filter_delay_fc_impl.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FILTER_FILTER_DELAY_FC_IMPL_H +#define INCLUDED_FILTER_FILTER_DELAY_FC_IMPL_H + +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API filter_delay_fc_impl : public filter_delay_fc + { + private: + unsigned int d_delay; + kernel::fir_filter_fff *d_fir; + std::vector d_taps; + bool d_update; + + public: + filter_delay_fc_impl(const std::vector &taps); + ~filter_delay_fc_impl(); + + std::vector taps(); + void set_taps(const std::vector &taps); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_FILTER_DELAY_FC_IMPL_H */ -- cgit From 0f6af7cf0ed1cad636a185fb951f026b85b49064 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 6 May 2012 22:42:22 -0400 Subject: filter: added fir_filter_with_buffer to gr-filter. Only fff and ccc versions so far. Needs work on Volk to be followed from fir_filter. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/fir_filter_with_buffer.cc | 236 ++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 gr-filter/lib/fir_filter_with_buffer.cc (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index c8e7b7e18..e1fae56a3 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -106,6 +106,7 @@ link_directories(${FFTW3F_LIBRARY_DIRS}) ######################################################################## list(APPEND filter_sources fir_filter.cc + fir_filter_with_buffer.cc fft_filter.cc firdes.cc pm_remez.cc diff --git a/gr-filter/lib/fir_filter_with_buffer.cc b/gr-filter/lib/fir_filter_with_buffer.cc new file mode 100644 index 000000000..a2b804a08 --- /dev/null +++ b/gr-filter/lib/fir_filter_with_buffer.cc @@ -0,0 +1,236 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +namespace gr { + namespace filter { + namespace kernel { + + fir_filter_with_buffer_fff::fir_filter_with_buffer_fff(const std::vector &taps) + { + d_buffer = NULL; + set_taps(taps); + } + + fir_filter_with_buffer_fff::~fir_filter_with_buffer_fff() + { + if(d_buffer != NULL) + fft::free(d_buffer); + } + + void + fir_filter_with_buffer_fff::set_taps(const std::vector &taps) + { + if(d_buffer != NULL) { + fft::free(d_buffer); + d_buffer = NULL; + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_float(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[d_ntaps-i-1] = taps[i]; + } + d_idx = 0; + } + + std::vector + fir_filter_with_buffer_fff::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[d_ntaps-i-1]); + return t; + } + + float + fir_filter_with_buffer_fff::filter(float input) + { + d_buffer[d_idx] = input; + d_buffer[d_idx+ntaps()] = input; + + d_idx++; + if(d_idx >= ntaps()) + d_idx = 0; + + float output = 0; + volk_32f_x2_dot_prod_32f_u(&output, &d_buffer[d_idx], + d_taps, d_ntaps); + + return output; + } + + float + fir_filter_with_buffer_fff::filter(const float input[], + unsigned long dec) + { + unsigned int i; + + for(i = 0; i < dec; i++) { + d_buffer[d_idx] = input[i]; + d_buffer[d_idx+ntaps()] = input[i]; + d_idx++; + if(d_idx >= ntaps()) + d_idx = 0; + } + + float output = 0; + volk_32f_x2_dot_prod_32f_u(&output, &d_buffer[d_idx], + d_taps, d_ntaps); + return output; + } + + void + fir_filter_with_buffer_fff::filterN(float output[], + const float input[], + unsigned long n) + { + for(unsigned long i = 0; i < n; i++) { + output[i] = filter(input[i]); + } + } + + void + fir_filter_with_buffer_fff::filterNdec(float output[], + const float input[], + unsigned long n, + unsigned long decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++) { + output[i] = filter(&input[j], decimate); + j += decimate; + } + } + + + /**************************************************************/ + + + fir_filter_with_buffer_ccc::fir_filter_with_buffer_ccc(const std::vector &taps) + { + d_buffer = NULL; + set_taps(taps); + } + + fir_filter_with_buffer_ccc::~fir_filter_with_buffer_ccc() + { + if(d_buffer != NULL) + fft::free(d_buffer); + } + + void + fir_filter_with_buffer_ccc::set_taps(const std::vector &taps) + { + if(d_buffer != NULL) { + fft::free(d_buffer); + d_buffer = NULL; + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_complex(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[d_ntaps-i-1] = taps[i]; + } + d_idx = 0; + } + + std::vector + fir_filter_with_buffer_ccc::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[d_ntaps-i-1]); + return t; + } + + gr_complex + fir_filter_with_buffer_ccc::filter(gr_complex input) + { + d_buffer[d_idx] = input; + d_buffer[d_idx+ntaps()] = input; + + d_idx++; + if(d_idx >= ntaps()) + d_idx = 0; + + gr_complex output = 0; + volk_32fc_x2_dot_prod_32fc_u(&output, &d_buffer[d_idx], + d_taps, d_ntaps); + + return output; + } + + gr_complex + fir_filter_with_buffer_ccc::filter(const gr_complex input[], + unsigned long dec) + { + unsigned int i; + + for(i = 0; i < dec; i++) { + d_buffer[d_idx] = input[i]; + d_buffer[d_idx+ntaps()] = input[i]; + d_idx++; + if(d_idx >= ntaps()) + d_idx = 0; + } + + gr_complex output = 0; + volk_32fc_x2_dot_prod_32fc_u(&output, &d_buffer[d_idx], + d_taps, d_ntaps); + return output; + } + + void + fir_filter_with_buffer_ccc::filterN(gr_complex output[], + const gr_complex input[], + unsigned long n) + { + for(unsigned long i = 0; i < n; i++) { + output[i] = filter(input[i]); + } + } + + void + fir_filter_with_buffer_ccc::filterNdec(gr_complex output[], + const gr_complex input[], + unsigned long n, + unsigned long decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++) { + output[i] = filter(&input[j], decimate); + j += decimate; + } + } + + + } /* namespace kernel */ + } /* namespace filter */ +} /* namespace gr */ -- cgit From 4f08cb7eb6e3ac4b7315b4b78dbc7d812b6c3dd1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 8 May 2012 22:07:05 -0400 Subject: filter: copied over pfb_channelizer to gr-filter with QA and GRC. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/hilbert_fc_impl.h | 1 - gr-filter/lib/pfb_channelizer_ccf_impl.cc | 240 ++++++++++++++++++++++++++++++ gr-filter/lib/pfb_channelizer_ccf_impl.h | 72 +++++++++ 4 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 gr-filter/lib/pfb_channelizer_ccf_impl.cc create mode 100644 gr-filter/lib/pfb_channelizer_ccf_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index e1fae56a3..5930ec9bb 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -117,6 +117,7 @@ list(APPEND filter_sources fft_filter_ccc_impl.cc fft_filter_fff_impl.cc hilbert_fc_impl.cc + pfb_channelizer_ccf_impl.cc ) list(APPEND filter_libs diff --git a/gr-filter/lib/hilbert_fc_impl.h b/gr-filter/lib/hilbert_fc_impl.h index de4d754b4..d2b41b573 100644 --- a/gr-filter/lib/hilbert_fc_impl.h +++ b/gr-filter/lib/hilbert_fc_impl.h @@ -25,7 +25,6 @@ #include #include -#include #include namespace gr { diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.cc b/gr-filter/lib/pfb_channelizer_ccf_impl.cc new file mode 100644 index 000000000..4006db789 --- /dev/null +++ b/gr-filter/lib/pfb_channelizer_ccf_impl.cc @@ -0,0 +1,240 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pfb_channelizer_ccf_impl.h" +#include +#include + +namespace gr { + namespace filter { + + pfb_channelizer_ccf::sptr pfb_channelizer_ccf::make(unsigned int numchans, + const std::vector &taps, + float oversample_rate) + { + return gnuradio::get_initial_sptr(new pfb_channelizer_ccf_impl(numchans, taps, + oversample_rate)); + } + + pfb_channelizer_ccf_impl::pfb_channelizer_ccf_impl(unsigned int numchans, + const std::vector &taps, + float oversample_rate) + : gr_block("pfb_channelizer_ccf", + gr_make_io_signature(numchans, numchans, sizeof(gr_complex)), + gr_make_io_signature(1, numchans, sizeof(gr_complex))), + d_updated(false), d_numchans(numchans), d_oversample_rate(oversample_rate) + { + // The over sampling rate must be rationally related to the number of channels + // in that it must be N/i for i in [1,N], which gives an outputsample rate + // of [fs/N, fs] where fs is the input sample rate. + // This tests the specified input sample rate to see if it conforms to this + // requirement within a few significant figures. + double intp = 0; + double fltp = modf(numchans / oversample_rate, &intp); + if(fltp != 0.0) + throw std::invalid_argument("pfb_channelizer: oversample rate must be N/i for i in [1, N]"); + + set_relative_rate(1.0/intp); + + d_filters = std::vector(d_numchans); + d_channel_map.resize(d_numchans); + + // Create an FIR filter for each channel and zero out the taps + std::vector vtaps(0, d_numchans); + for(unsigned int i = 0; i < d_numchans; i++) { + d_filters[i] = new kernel::fir_filter_ccf(1, vtaps); + d_channel_map[i] = i; + } + + // Now, actually set the filters' taps + set_taps(taps); + + // Create the FFT to handle the output de-spinning of the channels + d_fft = new fft::fft_complex(d_numchans, false); + + // Although the filters change, we use this look up table + // to set the index of the FFT input buffer, which equivalently + // performs the FFT shift operation on every other turn. + d_rate_ratio = (int)rintf(d_numchans / d_oversample_rate); + d_idxlut = new int[d_numchans]; + for(unsigned int i = 0; i < d_numchans; i++) { + d_idxlut[i] = d_numchans - ((i + d_rate_ratio) % d_numchans) - 1; + } + + // Calculate the number of filtering rounds to do to evenly + // align the input vectors with the output channels + d_output_multiple = 1; + while((d_output_multiple * d_rate_ratio) % d_numchans != 0) + d_output_multiple++; + set_output_multiple(d_output_multiple); + } + + pfb_channelizer_ccf_impl::~pfb_channelizer_ccf_impl() + { + delete [] d_idxlut; + delete d_fft; + + for(unsigned int i = 0; i < d_numchans; i++) { + delete d_filters[i]; + } + } + + void + pfb_channelizer_ccf_impl::set_taps (const std::vector &taps) + { + gruel::scoped_lock guard(d_mutex); + 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 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(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 + pfb_channelizer_ccf_impl::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"); + } + } + + std::vector< std::vector > + pfb_channelizer_ccf_impl::taps() const + { + return d_taps; + } + + void + pfb_channelizer_ccf_impl::set_channel_map(const std::vector &map) + { + gruel::scoped_lock guard(d_mutex); + + if(map.size() > 0) { + unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); + unsigned int min = (unsigned int)*std::min_element(map.begin(), map.end()); + if((max >= d_numchans) || (min < 0)) { + throw std::invalid_argument("pfb_channelizer_ccf_impl::set_channel_map: map range out of bounds.\n"); + } + d_channel_map = map; + } + } + + std::vector + pfb_channelizer_ccf_impl::channel_map() const + { + return d_channel_map; + } + + int + pfb_channelizer_ccf_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gruel::scoped_lock guard(d_mutex); + + gr_complex *in = (gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + if (d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + size_t noutputs = output_items.size(); + + int n=1, i=-1, j=0, oo=0, last; + int toconsume = (int)rintf(noutput_items/d_oversample_rate); + while(n <= toconsume) { + j = 0; + i = (i + d_rate_ratio) % d_numchans; + last = i; + while(i >= 0) { + in = (gr_complex*)input_items[j]; + d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n]); + j++; + i--; + } + + i = d_numchans-1; + while(i > last) { + in = (gr_complex*)input_items[j]; + d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n-1]); + j++; + i--; + } + + n += (i+d_rate_ratio) >= (int)d_numchans; + + // despin through FFT + d_fft->execute(); + + // Send to output channels + for(unsigned int nn = 0; nn < noutputs; nn++) { + out = (gr_complex*)output_items[nn]; + out[oo] = d_fft->get_outbuf()[d_channel_map[nn]]; + } + oo++; + } + + consume_each(toconsume); + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.h b/gr-filter/lib/pfb_channelizer_ccf_impl.h new file mode 100644 index 000000000..ee9327663 --- /dev/null +++ b/gr-filter/lib/pfb_channelizer_ccf_impl.h @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FILTER_PFB_CHANNELIZER_CCF_IMPL_H +#define INCLUDED_FILTER_PFB_CHANNELIZER_CCF_IMPL_H + +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API pfb_channelizer_ccf_impl : public pfb_channelizer_ccf + { + private: + bool d_updated; + unsigned int d_numchans; + float d_oversample_rate; + std::vector d_filters; + std::vector< std::vector > d_taps; + unsigned int d_taps_per_filter; + fft::fft_complex *d_fft; + int *d_idxlut; + int d_rate_ratio; + int d_output_multiple; + std::vector d_channel_map; + gruel::mutex d_mutex; // mutex to protect set/work access + + public: + pfb_channelizer_ccf_impl(unsigned int numchans, + const std::vector &taps, + float oversample_rate); + + ~pfb_channelizer_ccf_impl(); + + void set_taps(const std::vector &taps); + void print_taps(); + std::vector > taps() const; + + void set_channel_map(const std::vector &map); + std::vector channel_map() const; + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif -- cgit From 274bc141208ac8209c6b3342ff5ddc3755b321de Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 8 May 2012 22:43:48 -0400 Subject: filter: created polyphase_filterbank parent class to handle some initialization and setting taps of PFB blocks. Converted pfb_channelizer_ccf over to new parent class. Passes QA. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/pfb_channelizer_ccf_impl.cc | 102 +++++++------------------- gr-filter/lib/pfb_channelizer_ccf_impl.h | 24 +++---- gr-filter/lib/polyphase_filterbank.cc | 114 ++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 89 deletions(-) create mode 100644 gr-filter/lib/polyphase_filterbank.cc (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 5930ec9bb..b7577ad5e 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -110,6 +110,7 @@ list(APPEND filter_sources fft_filter.cc firdes.cc pm_remez.cc + polyphase_filterbank.cc ${generated_sources} dc_blocker_cc_impl.cc dc_blocker_ff_impl.cc diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.cc b/gr-filter/lib/pfb_channelizer_ccf_impl.cc index 4006db789..4e06cbc5f 100644 --- a/gr-filter/lib/pfb_channelizer_ccf_impl.cc +++ b/gr-filter/lib/pfb_channelizer_ccf_impl.cc @@ -26,26 +26,26 @@ #include "pfb_channelizer_ccf_impl.h" #include -#include namespace gr { namespace filter { - pfb_channelizer_ccf::sptr pfb_channelizer_ccf::make(unsigned int numchans, + pfb_channelizer_ccf::sptr pfb_channelizer_ccf::make(unsigned int nfilts, const std::vector &taps, float oversample_rate) { - return gnuradio::get_initial_sptr(new pfb_channelizer_ccf_impl(numchans, taps, + return gnuradio::get_initial_sptr(new pfb_channelizer_ccf_impl(nfilts, taps, oversample_rate)); } - pfb_channelizer_ccf_impl::pfb_channelizer_ccf_impl(unsigned int numchans, + pfb_channelizer_ccf_impl::pfb_channelizer_ccf_impl(unsigned int nfilts, const std::vector &taps, float oversample_rate) : gr_block("pfb_channelizer_ccf", - gr_make_io_signature(numchans, numchans, sizeof(gr_complex)), - gr_make_io_signature(1, numchans, sizeof(gr_complex))), - d_updated(false), d_numchans(numchans), d_oversample_rate(oversample_rate) + gr_make_io_signature(nfilts, nfilts, sizeof(gr_complex)), + gr_make_io_signature(1, nfilts, sizeof(gr_complex))), + polyphase_filterbank(nfilts, taps), + d_updated(false), d_oversample_rate(oversample_rate) { // The over sampling rate must be rationally related to the number of channels // in that it must be N/i for i in [1,N], which gives an outputsample rate @@ -53,110 +53,62 @@ namespace gr { // This tests the specified input sample rate to see if it conforms to this // requirement within a few significant figures. double intp = 0; - double fltp = modf(numchans / oversample_rate, &intp); + double fltp = modf(nfilts / oversample_rate, &intp); if(fltp != 0.0) throw std::invalid_argument("pfb_channelizer: oversample rate must be N/i for i in [1, N]"); set_relative_rate(1.0/intp); - d_filters = std::vector(d_numchans); - d_channel_map.resize(d_numchans); - - // Create an FIR filter for each channel and zero out the taps - std::vector vtaps(0, d_numchans); - for(unsigned int i = 0; i < d_numchans; i++) { - d_filters[i] = new kernel::fir_filter_ccf(1, vtaps); + // Default channel map + d_channel_map.resize(d_nfilts); + for(unsigned int i = 0; i < d_nfilts; i++) { d_channel_map[i] = i; } - // Now, actually set the filters' taps - set_taps(taps); - - // Create the FFT to handle the output de-spinning of the channels - d_fft = new fft::fft_complex(d_numchans, false); - // Although the filters change, we use this look up table // to set the index of the FFT input buffer, which equivalently // performs the FFT shift operation on every other turn. - d_rate_ratio = (int)rintf(d_numchans / d_oversample_rate); - d_idxlut = new int[d_numchans]; - for(unsigned int i = 0; i < d_numchans; i++) { - d_idxlut[i] = d_numchans - ((i + d_rate_ratio) % d_numchans) - 1; + d_rate_ratio = (int)rintf(d_nfilts / d_oversample_rate); + d_idxlut = new int[d_nfilts]; + for(unsigned int i = 0; i < d_nfilts; i++) { + d_idxlut[i] = d_nfilts - ((i + d_rate_ratio) % d_nfilts) - 1; } // Calculate the number of filtering rounds to do to evenly // align the input vectors with the output channels d_output_multiple = 1; - while((d_output_multiple * d_rate_ratio) % d_numchans != 0) + while((d_output_multiple * d_rate_ratio) % d_nfilts != 0) d_output_multiple++; set_output_multiple(d_output_multiple); + + set_history (d_taps_per_filter+1); } pfb_channelizer_ccf_impl::~pfb_channelizer_ccf_impl() { delete [] d_idxlut; - delete d_fft; - - for(unsigned int i = 0; i < d_numchans; i++) { - delete d_filters[i]; - } } void - pfb_channelizer_ccf_impl::set_taps (const std::vector &taps) + pfb_channelizer_ccf_impl::set_taps(const std::vector &taps) { gruel::scoped_lock guard(d_mutex); - 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 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(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 + polyphase_filterbank::set_taps(taps); set_history (d_taps_per_filter+1); - d_updated = true; } void pfb_channelizer_ccf_impl::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"); - } + polyphase_filterbank::print_taps(); } - std::vector< std::vector > + std::vector > pfb_channelizer_ccf_impl::taps() const { - return d_taps; + return polyphase_filterbank::taps(); } void @@ -167,7 +119,7 @@ namespace gr { if(map.size() > 0) { unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); unsigned int min = (unsigned int)*std::min_element(map.begin(), map.end()); - if((max >= d_numchans) || (min < 0)) { + if((max >= d_nfilts) || (min < 0)) { throw std::invalid_argument("pfb_channelizer_ccf_impl::set_channel_map: map range out of bounds.\n"); } d_channel_map = map; @@ -202,7 +154,7 @@ namespace gr { int toconsume = (int)rintf(noutput_items/d_oversample_rate); while(n <= toconsume) { j = 0; - i = (i + d_rate_ratio) % d_numchans; + i = (i + d_rate_ratio) % d_nfilts; last = i; while(i >= 0) { in = (gr_complex*)input_items[j]; @@ -211,7 +163,7 @@ namespace gr { i--; } - i = d_numchans-1; + i = d_nfilts-1; while(i > last) { in = (gr_complex*)input_items[j]; d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n-1]); @@ -219,7 +171,7 @@ namespace gr { i--; } - n += (i+d_rate_ratio) >= (int)d_numchans; + n += (i+d_rate_ratio) >= (int)d_nfilts; // despin through FFT d_fft->execute(); diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.h b/gr-filter/lib/pfb_channelizer_ccf_impl.h index ee9327663..8cabc4e34 100644 --- a/gr-filter/lib/pfb_channelizer_ccf_impl.h +++ b/gr-filter/lib/pfb_channelizer_ccf_impl.h @@ -24,30 +24,26 @@ #define INCLUDED_FILTER_PFB_CHANNELIZER_CCF_IMPL_H #include +#include #include #include namespace gr { namespace filter { - class FILTER_API pfb_channelizer_ccf_impl : public pfb_channelizer_ccf + class FILTER_API pfb_channelizer_ccf_impl : public pfb_channelizer_ccf, kernel::polyphase_filterbank { private: - bool d_updated; - unsigned int d_numchans; - float d_oversample_rate; - std::vector d_filters; - std::vector< std::vector > d_taps; - unsigned int d_taps_per_filter; - fft::fft_complex *d_fft; - int *d_idxlut; - int d_rate_ratio; - int d_output_multiple; - std::vector d_channel_map; - gruel::mutex d_mutex; // mutex to protect set/work access + bool d_updated; + float d_oversample_rate; + int *d_idxlut; + int d_rate_ratio; + int d_output_multiple; + std::vector d_channel_map; + gruel::mutex d_mutex; // mutex to protect set/work access public: - pfb_channelizer_ccf_impl(unsigned int numchans, + pfb_channelizer_ccf_impl(unsigned int nfilts, const std::vector &taps, float oversample_rate); diff --git a/gr-filter/lib/polyphase_filterbank.cc b/gr-filter/lib/polyphase_filterbank.cc new file mode 100644 index 000000000..9d881d76e --- /dev/null +++ b/gr-filter/lib/polyphase_filterbank.cc @@ -0,0 +1,114 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +namespace gr { + namespace filter { + namespace kernel { + + polyphase_filterbank::polyphase_filterbank(unsigned int nfilts, + const std::vector &taps) + : d_nfilts(nfilts) + { + d_filters = std::vector(d_nfilts); + + // Create an FIR filter for each channel and zero out the taps + std::vector vtaps(0, d_nfilts); + for(unsigned int i = 0; i < d_nfilts; i++) { + d_filters[i] = new kernel::fir_filter_ccf(1, vtaps); + } + + // Now, actually set the filters' taps + set_taps(taps); + + // Create the FFT to handle the output de-spinning of the channels + d_fft = new fft::fft_complex(d_nfilts, false); + } + + polyphase_filterbank::~polyphase_filterbank() + { + delete d_fft; + for(unsigned int i = 0; i < d_nfilts; i++) { + delete d_filters[i]; + } + } + + void + polyphase_filterbank::set_taps (const std::vector &taps) + { + unsigned int i,j; + + unsigned int ntaps = taps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilts); + + // Create d_numchan vectors to store each channel's taps + d_taps.resize(d_nfilts); + + // 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 tmp_taps; + tmp_taps = taps; + while((float)(tmp_taps.size()) < d_nfilts*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(i = 0; i < d_nfilts; i++) { + // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out + d_taps[i] = std::vector(d_taps_per_filter, 0); + for(j = 0; j < d_taps_per_filter; j++) { + d_taps[i][j] = tmp_taps[i + j*d_nfilts]; // 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]); + } + } + + void + polyphase_filterbank::print_taps() + { + unsigned int i, j; + for(i = 0; i < d_nfilts; i++) { + printf("filter[%d]: [", i); + for(j = 0; j < d_taps_per_filter; j++) { + printf(" %.4e", d_taps[i][j]); + } + printf("]\n\n"); + } + } + + std::vector< std::vector > + polyphase_filterbank::taps() const + { + return d_taps; + } + + } /* namespace kernel */ + } /* namespace filter */ +} /* namespace gr */ -- cgit From 511f351466e77fb49cc26d21fca3396f2213a44c Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 9 May 2012 20:17:39 -0400 Subject: filter: wip: working on adaptive FIR filter. Moved ccc and created parent class that is not a gr_block. --- gr-filter/lib/CMakeLists.txt | 2 + gr-filter/lib/adaptive_fir.cc | 109 +++++++++++++++++++++++++++++++++ gr-filter/lib/adaptive_fir_ccc_impl.cc | 94 ++++++++++++++++++++++++++++ gr-filter/lib/adaptive_fir_ccc_impl.h | 58 ++++++++++++++++++ 4 files changed, 263 insertions(+) create mode 100644 gr-filter/lib/adaptive_fir.cc create mode 100644 gr-filter/lib/adaptive_fir_ccc_impl.cc create mode 100644 gr-filter/lib/adaptive_fir_ccc_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index b7577ad5e..6f3e80d82 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -105,6 +105,7 @@ link_directories(${FFTW3F_LIBRARY_DIRS}) # Setup library ######################################################################## list(APPEND filter_sources + adaptive_fir.cc fir_filter.cc fir_filter_with_buffer.cc fft_filter.cc @@ -112,6 +113,7 @@ list(APPEND filter_sources pm_remez.cc polyphase_filterbank.cc ${generated_sources} + adaptive_fir_ccc_impl.cc dc_blocker_cc_impl.cc dc_blocker_ff_impl.cc filter_delay_fc_impl.cc diff --git a/gr-filter/lib/adaptive_fir.cc b/gr-filter/lib/adaptive_fir.cc new file mode 100644 index 000000000..413133941 --- /dev/null +++ b/gr-filter/lib/adaptive_fir.cc @@ -0,0 +1,109 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +namespace gr { + namespace filter { + namespace kernel { + + adaptive_fir_ccc::adaptive_fir_ccc(int decimation, + const std::vector &taps) + { + d_taps = NULL; + d_decim = decimation; + set_taps(taps); + } + + void + adaptive_fir_ccc::set_taps(const std::vector &taps) + { + // Free the taps if already allocated + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_complex(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[d_ntaps-i-1] = taps[i]; + } + } + + std::vector + adaptive_fir_ccc::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[d_ntaps-i-1]); + return t; + } + + int + adaptive_fir_ccc::decimation() const + { + return d_decim; + } + + unsigned int + adaptive_fir_ccc::ntaps() const + { + return d_ntaps; + } + + gr_complex + adaptive_fir_ccc::filter(gr_complex *input) + { + gr_complex output; + volk_32fc_x2_dot_prod_32fc_u(&output, input, d_taps, d_ntaps); + return output; + } + + void + adaptive_fir_ccc::filterN(gr_complex *out, gr_complex *in, + int nitems) + { + int j = 0; + unsigned int k; + for(int i = 0; i < nitems; i++) { + out[i] = filter(&in[j]); + + // Adjust taps + d_error = error(out[i]); + for(k = 0; k < d_ntaps; k++) { + update_tap(d_taps[d_ntaps-k-1], in[j+k]); + } + + j += decimation(); + } + } + + } /* namespace kernel */ + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/adaptive_fir_ccc_impl.cc b/gr-filter/lib/adaptive_fir_ccc_impl.cc new file mode 100644 index 000000000..06736ae6f --- /dev/null +++ b/gr-filter/lib/adaptive_fir_ccc_impl.cc @@ -0,0 +1,94 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "adaptive_fir_ccc_impl.h" +#include + +namespace gr { + namespace filter { + + adaptive_fir_ccc::sptr adaptive_fir_ccc::make(const char *name, int decimation, + const std::vector &taps) + { + return gnuradio::get_initial_sptr(new adaptive_fir_ccc_impl + (name, decimation, taps)); + } + + adaptive_fir_ccc_impl::adaptive_fir_ccc_impl(const char *name, int decimation, + const std::vector &taps) + : gr_sync_decimator(name, + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + decimation), + kernel::adaptive_fir_ccc(decimation, taps), + d_updated(false) + { + set_history(d_ntaps); + } + + void + adaptive_fir_ccc_impl::set_taps(const std::vector &taps) + { + d_new_taps = taps; + d_updated = true; + } + + gr_complex + adaptive_fir_ccc_impl::error(const gr_complex &out) + { + return 0; + } + + void + adaptive_fir_ccc_impl::update_tap(gr_complex &tap, const gr_complex &in) + { + tap = tap; + } + + int + adaptive_fir_ccc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr_complex *in = (gr_complex *)input_items[0]; + gr_complex *out = (gr_complex *)output_items[0]; + + if (d_updated) { + kernel::adaptive_fir_ccc::set_taps(d_new_taps); + set_history(d_ntaps); + d_updated = false; + return 0; // history requirements may have changed. + } + + // Call base class filtering function that uses + // overloaded error and update_tap functions. + filterN(out, in, noutput_items); + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/adaptive_fir_ccc_impl.h b/gr-filter/lib/adaptive_fir_ccc_impl.h new file mode 100644 index 000000000..f145ceeaa --- /dev/null +++ b/gr-filter/lib/adaptive_fir_ccc_impl.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FILTER_ADAPTIVE_FIR_CCC_IMPL_H +#define INCLUDED_FILTER_ADAPTIVE_FIR_CCC_IMPL_H + +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API adaptive_fir_ccc_impl : public adaptive_fir_ccc, public kernel::adaptive_fir_ccc + { + private: + std::vector d_new_taps; + bool d_updated; + + // Override to calculate error signal per output + gr_complex error(const gr_complex &out); + + // Override to calculate new weight from old, corresponding input + void update_tap(gr_complex &tap, const gr_complex &in); + + public: + void set_taps(const std::vector &taps); + + adaptive_fir_ccc_impl(const char *name, int decimation, + const std::vector &taps); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_ADAPTIVE_FIR_CCC_IMPL_H */ -- cgit From 14532d8da0f40f2b58595bd7e217004bdbfc90e3 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 10 Jun 2012 19:33:52 -0400 Subject: filter: adding ccf version for adaptive filter. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/adaptive_fir.cc | 76 +++++++++++++++++++++++++++ gr-filter/lib/adaptive_fir_ccf_impl.cc | 94 ++++++++++++++++++++++++++++++++++ gr-filter/lib/adaptive_fir_ccf_impl.h | 58 +++++++++++++++++++++ 4 files changed, 229 insertions(+) create mode 100644 gr-filter/lib/adaptive_fir_ccf_impl.cc create mode 100644 gr-filter/lib/adaptive_fir_ccf_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 6f3e80d82..b51a23bab 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -114,6 +114,7 @@ list(APPEND filter_sources polyphase_filterbank.cc ${generated_sources} adaptive_fir_ccc_impl.cc + adaptive_fir_ccf_impl.cc dc_blocker_cc_impl.cc dc_blocker_ff_impl.cc filter_delay_fc_impl.cc diff --git a/gr-filter/lib/adaptive_fir.cc b/gr-filter/lib/adaptive_fir.cc index 413133941..9098e86ca 100644 --- a/gr-filter/lib/adaptive_fir.cc +++ b/gr-filter/lib/adaptive_fir.cc @@ -104,6 +104,82 @@ namespace gr { } } + + /**************************************************************/ + + + adaptive_fir_ccf::adaptive_fir_ccf(int decimation, + const std::vector &taps) + { + d_taps = NULL; + d_decim = decimation; + set_taps(taps); + } + + void + adaptive_fir_ccf::set_taps(const std::vector &taps) + { + // Free the taps if already allocated + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_complex(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[d_ntaps-i-1] = taps[i]; + } + } + + std::vector + adaptive_fir_ccf::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[d_ntaps-i-1].real()); + return t; + } + + int + adaptive_fir_ccf::decimation() const + { + return d_decim; + } + + unsigned int + adaptive_fir_ccf::ntaps() const + { + return d_ntaps; + } + + gr_complex + adaptive_fir_ccf::filter(gr_complex *input) + { + gr_complex output; + volk_32fc_x2_dot_prod_32fc_u(&output, input, d_taps, d_ntaps); + return output; + } + + void + adaptive_fir_ccf::filterN(gr_complex *out, gr_complex *in, + int nitems) + { + int j = 0; + unsigned int k; + for(int i = 0; i < nitems; i++) { + out[i] = filter(&in[j]); + + // Adjust taps + d_error = error(out[i]); + for(k = 0; k < d_ntaps; k++) { + update_tap(d_taps[d_ntaps-k-1], in[j+k]); + } + + j += decimation(); + } + } + } /* namespace kernel */ } /* namespace filter */ } /* namespace gr */ diff --git a/gr-filter/lib/adaptive_fir_ccf_impl.cc b/gr-filter/lib/adaptive_fir_ccf_impl.cc new file mode 100644 index 000000000..053facdc2 --- /dev/null +++ b/gr-filter/lib/adaptive_fir_ccf_impl.cc @@ -0,0 +1,94 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "adaptive_fir_ccf_impl.h" +#include + +namespace gr { + namespace filter { + + adaptive_fir_ccf::sptr adaptive_fir_ccf::make(const char *name, int decimation, + const std::vector &taps) + { + return gnuradio::get_initial_sptr(new adaptive_fir_ccf_impl + (name, decimation, taps)); + } + + adaptive_fir_ccf_impl::adaptive_fir_ccf_impl(const char *name, int decimation, + const std::vector &taps) + : gr_sync_decimator(name, + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + decimation), + kernel::adaptive_fir_ccf(decimation, taps), + d_updated(false) + { + set_history(d_ntaps); + } + + void + adaptive_fir_ccf_impl::set_taps(const std::vector &taps) + { + d_new_taps = taps; + d_updated = true; + } + + float + adaptive_fir_ccf_impl::error(const gr_complex &out) + { + return 0; + } + + void + adaptive_fir_ccf_impl::update_tap(gr_complex &tap, const gr_complex &in) + { + tap = tap; + } + + int + adaptive_fir_ccf_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr_complex *in = (gr_complex *)input_items[0]; + gr_complex *out = (gr_complex *)output_items[0]; + + if (d_updated) { + kernel::adaptive_fir_ccf::set_taps(d_new_taps); + set_history(d_ntaps); + d_updated = false; + return 0; // history requirements may have changed. + } + + // Call base class filtering function that uses + // overloaded error and update_tap functions. + filterN(out, in, noutput_items); + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/adaptive_fir_ccf_impl.h b/gr-filter/lib/adaptive_fir_ccf_impl.h new file mode 100644 index 000000000..fa9a42189 --- /dev/null +++ b/gr-filter/lib/adaptive_fir_ccf_impl.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FILTER_ADAPTIVE_FIR_CCF_IMPL_H +#define INCLUDED_FILTER_ADAPTIVE_FIR_CCF_IMPL_H + +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API adaptive_fir_ccf_impl : public adaptive_fir_ccf, public kernel::adaptive_fir_ccf + { + private: + std::vector d_new_taps; + bool d_updated; + + // Override to calculate error signal per output + float error(const gr_complex &out); + + // Override to calculate new weight from old, corresponding input + void update_tap(gr_complex &tap, const gr_complex &in); + + public: + void set_taps(const std::vector &taps); + + adaptive_fir_ccf_impl(const char *name, int decimation, + const std::vector &taps); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_ADAPTIVE_FIR_CCF_IMPL_H */ -- cgit From 227448e247ba720b87b99e1b9382cd3737241ab3 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 10 Jun 2012 19:35:55 -0400 Subject: filter: working aligned taps loads for regular and decimating filter. Has working QA code but needs significant performance improvements. --- gr-filter/lib/fir_filter.cc | 49 ++++++++++++++++++++++++++-------- gr-filter/lib/fir_filter_XXX_impl.cc.t | 8 +++++- 2 files changed, 45 insertions(+), 12 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 3abcda53e..098dd8d36 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -23,6 +23,7 @@ #include #include #include +#include namespace gr { namespace filter { @@ -33,15 +34,29 @@ namespace gr { { d_taps = NULL; set_taps(taps); + d_offset = 0; + + // Make sure the output sample is always aligned, too. + d_output = fft::malloc_float(1); } fir_filter_fff::~fir_filter_fff() { + // Free taps if(d_taps != NULL) { fft::free(d_taps); d_taps = NULL; } - } + + // Free all aligned taps + for(int i = 0; i < 4; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + + // Free output sample + fft::free(d_output); + } void fir_filter_fff::set_taps(const std::vector &taps) @@ -50,6 +65,11 @@ namespace gr { if(d_taps != NULL) { fft::free(d_taps); d_taps = NULL; + + for(int i = 0; i < 4; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); } d_ntaps = (int)taps.size(); @@ -58,6 +78,8 @@ namespace gr { d_taps[d_ntaps-i-1] = taps[i]; } + // Make a set of taps at all possible arch alignments + d_aligned_taps = (float**)malloc(4*sizeof(float**)); for(int i = 0; i < 4; i++) { d_aligned_taps[i] = fft::malloc_float(d_ntaps+3); memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+3)); @@ -83,12 +105,9 @@ namespace gr { float fir_filter_fff::filter(const float input[]) { - float output; - - //const float *ar = (float*)((unsigned long)input & ~15); - - volk_32f_x2_dot_prod_32f_u(&output, input, d_taps, d_ntaps); - return output; + volk_32f_x2_dot_prod_32f_a(d_output, input, + d_aligned_taps[d_offset], d_ntaps+3); + return *d_output; } void @@ -96,8 +115,16 @@ namespace gr { const float input[], unsigned long n) { - for(unsigned long i = 0; i < n; i++) - output[i] = filter(&input[i]); + unsigned long ar = ((unsigned long) input); + int off = (ar - (ar & ~15))/4; + + int j = -off; + d_offset = off; + for(unsigned long i = 0; i < n; i++) { + output[i] = filter(&input[j]); + d_offset= (d_offset+1) & 0x03; + j += (d_offset == 0 ? 4 : 0); + } } @@ -108,8 +135,8 @@ namespace gr { unsigned int decimate) { unsigned long j = 0; - for(unsigned long i = 0; i < n; i++){ - output[i] = filter(&input[j]); + for(unsigned long i = 0; i < n; i++) { + filterN(&output[i], &input[j], 1); j += decimate; } } diff --git a/gr-filter/lib/fir_filter_XXX_impl.cc.t b/gr-filter/lib/fir_filter_XXX_impl.cc.t index c3637042d..18bec38be 100644 --- a/gr-filter/lib/fir_filter_XXX_impl.cc.t +++ b/gr-filter/lib/fir_filter_XXX_impl.cc.t @@ -26,6 +26,7 @@ #include "@IMPL_NAME@.h" #include +#include namespace gr { namespace filter { @@ -47,6 +48,10 @@ namespace gr { d_fir = new kernel::@BASE_NAME@(decimation, taps); d_updated = false; set_history(d_fir->ntaps()); + + const int alignment_multiple = + volk_get_alignment() / sizeof(float); + set_alignment(std::max(1, alignment_multiple)); } @IMPL_NAME@::~@IMPL_NAME@() @@ -85,7 +90,8 @@ namespace gr { d_fir->filterN(out, in, noutput_items); } else { - d_fir->filterNdec(out, in, noutput_items, decimation()); + d_fir->filterNdec(out, in, noutput_items, + decimation()); } return noutput_items; -- cgit From 46bd64dc8231402535bad742a74250599e595148 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 10 Jun 2012 19:21:51 -0400 Subject: filter: Fixed filter_delay and hilbert filter to work with aligned filter loads. --- gr-filter/lib/filter_delay_fc_impl.cc | 16 ++++++++++++---- gr-filter/lib/hilbert_fc_impl.cc | 14 +++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/filter_delay_fc_impl.cc b/gr-filter/lib/filter_delay_fc_impl.cc index ce320c557..279368664 100644 --- a/gr-filter/lib/filter_delay_fc_impl.cc +++ b/gr-filter/lib/filter_delay_fc_impl.cc @@ -25,6 +25,7 @@ #endif #include "filter_delay_fc_impl.h" +#include namespace gr { namespace filter { @@ -44,6 +45,10 @@ namespace gr { d_fir = new kernel::fir_filter_fff(1, taps); d_delay = d_fir->ntaps() / 2; set_history(d_fir->ntaps()); + + const int alignment_multiple = + volk_get_alignment() / sizeof(float); + set_alignment(std::max(1, alignment_multiple)); } filter_delay_fc_impl::~filter_delay_fc_impl() @@ -73,6 +78,7 @@ namespace gr { float *in0 = (float *)input_items[0]; float *in1 = (float *)input_items[1]; gr_complex *out = (gr_complex *)output_items[0]; + float d_out; if(d_update) { d_fir->set_taps(d_taps); @@ -84,15 +90,17 @@ namespace gr { switch(input_items.size ()) { case 1: for(int i = 0; i < noutput_items; i++) { - out[i] = gr_complex (in0[i + d_delay], - d_fir->filter (&in0[i])); + d_fir->filterN(&d_out, &in0[i], 1); + out[i] = gr_complex(in0[i + d_delay], + d_out); } break; case 2: for(int j = 0; j < noutput_items; j++) { - out[j] = gr_complex (in0[j + d_delay], - d_fir->filter (&in1[j])); + d_fir->filterN(&d_out, &in1[j], 1); + out[j] = gr_complex(in0[j + d_delay], + d_out); } break; diff --git a/gr-filter/lib/hilbert_fc_impl.cc b/gr-filter/lib/hilbert_fc_impl.cc index 946b47e4a..7aaa23a62 100644 --- a/gr-filter/lib/hilbert_fc_impl.cc +++ b/gr-filter/lib/hilbert_fc_impl.cc @@ -27,6 +27,7 @@ #include "hilbert_fc_impl.h" #include #include +#include namespace gr { namespace filter { @@ -44,6 +45,10 @@ namespace gr { { d_hilb = new kernel::fir_filter_fff(1, firdes::hilbert(d_ntaps)); set_history (d_ntaps); + + const int alignment_multiple = + volk_get_alignment() / sizeof(float); + set_alignment(std::max(1, alignment_multiple)); } hilbert_fc_impl::~hilbert_fc_impl() @@ -58,10 +63,13 @@ namespace gr { { float *in = (float *)input_items[0]; gr_complex *out = (gr_complex *)output_items[0]; + float h_out; - for(int i = 0; i < noutput_items; i++) - out[i] = gr_complex (in[i + d_ntaps/2], - d_hilb->filter (&in[i])); + for(int i = 0; i < noutput_items; i++) { + d_hilb->filterN(&h_out, &in[i], 1); + out[i] = gr_complex(in[i + d_ntaps/2], + h_out); + } return noutput_items; } -- cgit From 9e2e896e9d4dbc4627702cde82a48e9ee5136f26 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 13 Jun 2012 14:53:41 -0400 Subject: filter: process 4 vectors each time in volk dot_prod to speed up fir filters. This makes the volk version of the SSE FIR filter the same speed as using the hand-crafted float_dotprod from before. --- gr-filter/lib/fir_filter.cc | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 098dd8d36..c6e179246 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -24,6 +24,7 @@ #include #include #include +#include namespace gr { namespace filter { @@ -101,12 +102,16 @@ namespace gr { { return d_ntaps; } - + + /* float fir_filter_fff::filter(const float input[]) { volk_32f_x2_dot_prod_32f_a(d_output, input, - d_aligned_taps[d_offset], d_ntaps+3); + d_aligned_taps[d_offset], + (d_ntaps + d_offset - 1) / 4 + 1); + //*d_output = float_dotprod_sse(input, d_aligned_taps[d_offset], + // (d_ntaps + d_offset - 1) / 4 + 1); return *d_output; } @@ -126,7 +131,34 @@ namespace gr { j += (d_offset == 0 ? 4 : 0); } } + */ + + float + fir_filter_fff::filter(const float input[]) + { + //unsigned long ar = ((unsigned long) input); + //int off = (ar - (ar & ~15))/4; + + const float *ar = (float *)((unsigned long) input & ~15); + unsigned al = input - ar; + + volk_32f_x2_dot_prod_32f_a(d_output, ar, + d_aligned_taps[al], + (d_ntaps + al - 1) / 4 + 1); + //*d_output = float_dotprod_sse(input, d_aligned_taps[d_offset], + // (d_ntaps + d_offset - 1) / 4 + 1); + return *d_output; + } + void + fir_filter_fff::filterN(float output[], + const float input[], + unsigned long n) + { + for(unsigned long i = 0; i < n; i++) { + output[i] = filter(&input[i]); + } + } void fir_filter_fff::filterNdec(float output[], @@ -136,7 +168,7 @@ namespace gr { { unsigned long j = 0; for(unsigned long i = 0; i < n; i++) { - filterN(&output[i], &input[j], 1); + output[i] = filter(&input[j]); j += decimate; } } -- cgit From 1b93bb39731517e6d7bb8a78ea9569995e8a371a Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 13 Jun 2012 14:55:16 -0400 Subject: filter wip and probably squash with last. Removing unecessary d_offset counter from fir_filter. --- gr-filter/lib/fir_filter.cc | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index c6e179246..30c8325f7 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -35,7 +35,6 @@ namespace gr { { d_taps = NULL; set_taps(taps); - d_offset = 0; // Make sure the output sample is always aligned, too. d_output = fft::malloc_float(1); @@ -103,50 +102,15 @@ namespace gr { return d_ntaps; } - /* float fir_filter_fff::filter(const float input[]) { - volk_32f_x2_dot_prod_32f_a(d_output, input, - d_aligned_taps[d_offset], - (d_ntaps + d_offset - 1) / 4 + 1); - //*d_output = float_dotprod_sse(input, d_aligned_taps[d_offset], - // (d_ntaps + d_offset - 1) / 4 + 1); - return *d_output; - } - - void - fir_filter_fff::filterN(float output[], - const float input[], - unsigned long n) - { - unsigned long ar = ((unsigned long) input); - int off = (ar - (ar & ~15))/4; - - int j = -off; - d_offset = off; - for(unsigned long i = 0; i < n; i++) { - output[i] = filter(&input[j]); - d_offset= (d_offset+1) & 0x03; - j += (d_offset == 0 ? 4 : 0); - } - } - */ - - float - fir_filter_fff::filter(const float input[]) - { - //unsigned long ar = ((unsigned long) input); - //int off = (ar - (ar & ~15))/4; - const float *ar = (float *)((unsigned long) input & ~15); unsigned al = input - ar; volk_32f_x2_dot_prod_32f_a(d_output, ar, d_aligned_taps[al], (d_ntaps + al - 1) / 4 + 1); - //*d_output = float_dotprod_sse(input, d_aligned_taps[d_offset], - // (d_ntaps + d_offset - 1) / 4 + 1); return *d_output; } -- cgit From dae3b39098c16573f9c70e77f1a9a6b09ecfd041 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 14 Jun 2012 12:26:45 -0400 Subject: filter: fff FIR filters use VOLK machine information to set alignment. Works with SSE and AVX machines. SSE results comparable to float_dotprod still. AVX slightly faster. --- gr-filter/lib/fir_filter.cc | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 30c8325f7..1e5990294 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -33,6 +33,9 @@ namespace gr { fir_filter_fff::fir_filter_fff(int decimation, const std::vector &taps) { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(float); + d_taps = NULL; set_taps(taps); @@ -49,7 +52,7 @@ namespace gr { } // Free all aligned taps - for(int i = 0; i < 4; i++) { + for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } fft::free(d_aligned_taps); @@ -66,7 +69,7 @@ namespace gr { fft::free(d_taps); d_taps = NULL; - for(int i = 0; i < 4; i++) { + for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } fft::free(d_aligned_taps); @@ -79,10 +82,10 @@ namespace gr { } // Make a set of taps at all possible arch alignments - d_aligned_taps = (float**)malloc(4*sizeof(float**)); - for(int i = 0; i < 4; i++) { - d_aligned_taps[i] = fft::malloc_float(d_ntaps+3); - memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+3)); + d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_float(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+d_naligned-1)); memcpy(&d_aligned_taps[i][i], d_taps, sizeof(float)*(d_ntaps)); } } @@ -105,12 +108,12 @@ namespace gr { float fir_filter_fff::filter(const float input[]) { - const float *ar = (float *)((unsigned long) input & ~15); + const float *ar = (float *)((unsigned long) input & ~(d_align-1)); unsigned al = input - ar; volk_32f_x2_dot_prod_32f_a(d_output, ar, d_aligned_taps[al], - (d_ntaps + al - 1) / 4 + 1); + d_ntaps+al); return *d_output; } -- cgit From 4e2f38528e90ee4a05644d48d015b098a8651405 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 14 Jun 2012 12:44:41 -0400 Subject: filter: switched ccc FIR filter to use aligned VOLK calls. --- gr-filter/lib/fir_filter.cc | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 1e5990294..973be45d4 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -224,16 +224,32 @@ namespace gr { fir_filter_ccc::fir_filter_ccc(int decimation, const std::vector &taps) { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(gr_complex); + d_taps = NULL; set_taps(taps); + + // Make sure the output sample is always aligned, too. + d_output = fft::malloc_complex(1); } fir_filter_ccc::~fir_filter_ccc() { + // Free taps if(d_taps != NULL) { fft::free(d_taps); d_taps = NULL; } + + // Free all aligned taps + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + + // Free output sample + fft::free(d_output); } void @@ -243,6 +259,11 @@ namespace gr { if(d_taps != NULL) { fft::free(d_taps); d_taps = NULL; + + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); } d_ntaps = (int)taps.size(); @@ -250,6 +271,14 @@ namespace gr { for(unsigned int i = 0; i < d_ntaps; i++) { d_taps[d_ntaps-i-1] = taps[i]; } + + // Make a set of taps at all possible arch alignments + d_aligned_taps = (gr_complex**)malloc(d_naligned*sizeof(gr_complex**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_complex(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(gr_complex)*(d_ntaps+d_naligned-1)); + memcpy(&d_aligned_taps[i][i], d_taps, sizeof(gr_complex)*(d_ntaps)); + } } std::vector @@ -270,9 +299,13 @@ namespace gr { gr_complex fir_filter_ccc::filter(const gr_complex input[]) { - gr_complex output; - volk_32fc_x2_dot_prod_32fc_u(&output, input, d_taps, d_ntaps); - return output; + const gr_complex *ar = (gr_complex *)((unsigned long) input & ~(d_align-1)); + unsigned al = input - ar; + + volk_32fc_x2_dot_prod_32fc_a(d_output, ar, + d_aligned_taps[al], + (d_ntaps+al)*sizeof(gr_complex)); + return *d_output; } void -- cgit From 1a5a1d4e2e0374f73cef5fbc9a01bf82d8b7d892 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 14 Jun 2012 16:12:00 -0400 Subject: filter: added a ccf Volk dot product to use with ccf filters and used it in fir_filter_ccf. Produces improved results to previous version. --- gr-filter/lib/fir_filter.cc | 30 ++++++++++++++++++++++++------ gr-filter/lib/fir_filter_XXX_impl.cc.t | 2 +- 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 973be45d4..18568da9d 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -145,8 +145,14 @@ namespace gr { fir_filter_ccf::fir_filter_ccf(int decimation, const std::vector &taps) { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(gr_complex); + d_taps = NULL; set_taps(taps); + + // Make sure the output sample is always aligned, too. + d_output = fft::malloc_complex(1); } fir_filter_ccf::~fir_filter_ccf() @@ -167,9 +173,17 @@ namespace gr { } d_ntaps = (int)taps.size(); - d_taps = fft::malloc_complex(d_ntaps); + d_taps = fft::malloc_float(d_ntaps); for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = gr_complex(taps[i],0); + d_taps[d_ntaps-i-1] = taps[i]; + } + + // Make a set of taps at all possible arch alignments + d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_float(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+d_naligned-1)); + memcpy(&d_aligned_taps[i][i], d_taps, sizeof(float)*(d_ntaps)); } } @@ -178,7 +192,7 @@ namespace gr { { std::vector t; for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1].real()); + t.push_back(d_taps[d_ntaps-i-1]); return t; } @@ -191,9 +205,13 @@ namespace gr { gr_complex fir_filter_ccf::filter(const gr_complex input[]) { - gr_complex output; - volk_32fc_x2_dot_prod_32fc_u(&output, input, d_taps, d_ntaps); - return output; + const gr_complex *ar = (gr_complex *)((unsigned long) input & ~(d_align-1)); + unsigned al = input - ar; + + volk_32fc_32f_dot_prod_32fc_a(d_output, ar, + d_aligned_taps[al], + (d_ntaps+al)); + return *d_output; } void diff --git a/gr-filter/lib/fir_filter_XXX_impl.cc.t b/gr-filter/lib/fir_filter_XXX_impl.cc.t index 18bec38be..8ea8151f8 100644 --- a/gr-filter/lib/fir_filter_XXX_impl.cc.t +++ b/gr-filter/lib/fir_filter_XXX_impl.cc.t @@ -40,7 +40,7 @@ namespace gr { @IMPL_NAME@::@IMPL_NAME@(int decimation, const std::vector<@TAP_TYPE@> &taps) - : gr_sync_decimator("fir_filter_fff", + : gr_sync_decimator("@BASE_NAME@", gr_make_io_signature(1, 1, sizeof(@I_TYPE@)), gr_make_io_signature(1, 1, sizeof(@O_TYPE@)), decimation) -- cgit From 5585c71229cfa7886e0bd090828cd1f5104f6b27 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 15 Jun 2012 08:43:20 -0400 Subject: filter: adding ssc and fsf versions of filter with associated new Volk kernels. These routines work and pass QA. They could use some performance work. the FSF is just slightly slower than before; the SCC version is more noticably slower. Both could benefit, probably, by using SSE2 intrinsics to handle the shorts. --- gr-filter/lib/CMakeLists.txt | 2 +- gr-filter/lib/fir_filter.cc | 232 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+), 1 deletion(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index b51a23bab..f5dbd1bb3 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -80,7 +80,7 @@ endmacro(expand_cc) ######################################################################## # Invoke macro to generate various sources ######################################################################## -expand_cc(fir_filter_XXX_impl fff ccf ccc) +expand_cc(fir_filter_XXX_impl fff ccf ccc scc fsf) ######################################################################## diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 18568da9d..be8017400 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -349,6 +349,238 @@ namespace gr { } } + /**************************************************************/ + + fir_filter_scc::fir_filter_scc(int decimation, + const std::vector &taps) + { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(short); + + d_taps = NULL; + set_taps(taps); + + // Make sure the output sample is always aligned, too. + d_output = fft::malloc_complex(1); + } + + fir_filter_scc::~fir_filter_scc() + { + // Free taps + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + + // Free all aligned taps + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + + // Free output sample + fft::free(d_output); + } + + void + fir_filter_scc::set_taps(const std::vector &taps) + { + // Free the taps if already allocated + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_complex(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[d_ntaps-i-1] = taps[i]; + } + + // Make a set of taps at all possible arch alignments + d_aligned_taps = (gr_complex**)malloc(d_naligned*sizeof(gr_complex**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_complex(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(gr_complex)*(d_ntaps+d_naligned-1)); + memcpy(&d_aligned_taps[i][i], d_taps, sizeof(gr_complex)*(d_ntaps)); + } + + } + + std::vector + fir_filter_scc::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[d_ntaps-i-1]); + return t; + } + + unsigned int + fir_filter_scc::ntaps() const + { + return d_ntaps; + } + + gr_complex + fir_filter_scc::filter(const short input[]) + { + const short *ar = (short *)((unsigned long) input & ~(d_align-1)); + unsigned al = input - ar; + + volk_16i_32fc_dot_prod_32fc_a(d_output, ar, + d_aligned_taps[al], + (d_ntaps+al)); + + return *d_output; + } + + void + fir_filter_scc::filterN(gr_complex output[], + const short input[], + unsigned long n) + { + for(unsigned long i = 0; i < n; i++) + output[i] = filter(&input[i]); + } + + + void + fir_filter_scc::filterNdec(gr_complex output[], + const short input[], + unsigned long n, + unsigned int decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++){ + output[i] = filter(&input[j]); + j += decimate; + } + } + + /**************************************************************/ + + fir_filter_fsf::fir_filter_fsf(int decimation, + const std::vector &taps) + { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(float); + + d_taps = NULL; + set_taps(taps); + + // Make sure the output sample is always aligned, too. + d_output = (short*)fft::malloc_float(1); + } + + fir_filter_fsf::~fir_filter_fsf() + { + // Free taps + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + } + + // Free all aligned taps + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + + // Free output sample + fft::free(d_output); + } + + void + fir_filter_fsf::set_taps(const std::vector &taps) + { + // Free the taps if already allocated + if(d_taps != NULL) { + fft::free(d_taps); + d_taps = NULL; + + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + } + + d_ntaps = (int)taps.size(); + d_taps = fft::malloc_float(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_taps[d_ntaps-i-1] = taps[i]; + } + + // Make a set of taps at all possible arch alignments + d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_float(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+d_naligned-1)); + memcpy(&d_aligned_taps[i][i], d_taps, sizeof(float)*(d_ntaps)); + } + } + + std::vector + fir_filter_fsf::taps() const + { + std::vector t; + for(unsigned int i = 0; i < d_ntaps; i++) + t.push_back(d_taps[d_ntaps-i-1]); + return t; + } + + unsigned int + fir_filter_fsf::ntaps() const + { + return d_ntaps; + } + + short + fir_filter_fsf::filter(const float input[]) + { + const float *ar = (float *)((unsigned long) input & ~(d_align-1)); + unsigned al = input - ar; + + volk_32f_x2_dot_prod_16i_a(d_output, ar, + d_aligned_taps[al], + (d_ntaps+al)); + + //float out = 0; + //for(unsigned int i = 0; i < d_ntaps; i++) { + // out += d_taps[i] * input[i]; + //} + //*d_output = (short)out; + + return *d_output; + } + + void + fir_filter_fsf::filterN(short output[], + const float input[], + unsigned long n) + { + for(unsigned long i = 0; i < n; i++) + output[i] = filter(&input[i]); + } + + void + fir_filter_fsf::filterNdec(short output[], + const float input[], + unsigned long n, + unsigned int decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++){ + output[i] = filter(&input[j]); + j += decimate; + } + } + } /* namespace kernel */ } /* namespace filter */ } /* namespace gr */ -- cgit From 408f44a735ff8e90b3206500b8154b37eb3e65b2 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 15 Jun 2012 11:52:51 -0400 Subject: filter: mods to fir filter bases to make consistent and simpler. --- gr-filter/lib/fir_filter.cc | 203 ++++++++++++-------------- gr-filter/lib/fir_filter_with_buffer.cc | 243 ++++++++++++++++++++++++++++---- 2 files changed, 301 insertions(+), 145 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index be8017400..6c82dda5e 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -36,7 +36,7 @@ namespace gr { d_align = volk_get_alignment(); d_naligned = d_align / sizeof(float); - d_taps = NULL; + d_aligned_taps = NULL; set_taps(taps); // Make sure the output sample is always aligned, too. @@ -45,17 +45,14 @@ namespace gr { fir_filter_fff::~fir_filter_fff() { - // Free taps - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - } - // Free all aligned taps - for(int i = 0; i < d_naligned; i++) { - fft::free(d_aligned_taps[i]); + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; } - fft::free(d_aligned_taps); // Free output sample fft::free(d_output); @@ -65,37 +62,33 @@ namespace gr { fir_filter_fff::set_taps(const std::vector &taps) { // Free the taps if already allocated - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - + if(d_aligned_taps!= NULL) { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } fft::free(d_aligned_taps); + d_aligned_taps = NULL; } d_ntaps = (int)taps.size(); - d_taps = fft::malloc_float(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; - } + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); // Make a set of taps at all possible arch alignments d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); for(int i = 0; i < d_naligned; i++) { d_aligned_taps[i] = fft::malloc_float(d_ntaps+d_naligned-1); memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+d_naligned-1)); - memcpy(&d_aligned_taps[i][i], d_taps, sizeof(float)*(d_ntaps)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; } } std::vector fir_filter_fff::taps() const { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1]); + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); return t; } @@ -148,7 +141,7 @@ namespace gr { d_align = volk_get_alignment(); d_naligned = d_align / sizeof(gr_complex); - d_taps = NULL; + d_aligned_taps = NULL; set_taps(taps); // Make sure the output sample is always aligned, too. @@ -157,42 +150,50 @@ namespace gr { fir_filter_ccf::~fir_filter_ccf() { - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; + // Free all aligned taps + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; } - } + + // Free output sample + fft::free(d_output); + } void fir_filter_ccf::set_taps(const std::vector &taps) { // Free the taps if already allocated - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; } d_ntaps = (int)taps.size(); - d_taps = fft::malloc_float(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; - } + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); // Make a set of taps at all possible arch alignments d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); for(int i = 0; i < d_naligned; i++) { d_aligned_taps[i] = fft::malloc_float(d_ntaps+d_naligned-1); memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+d_naligned-1)); - memcpy(&d_aligned_taps[i][i], d_taps, sizeof(float)*(d_ntaps)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; } } std::vector fir_filter_ccf::taps() const { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1]); + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); return t; } @@ -245,7 +246,7 @@ namespace gr { d_align = volk_get_alignment(); d_naligned = d_align / sizeof(gr_complex); - d_taps = NULL; + d_aligned_taps = NULL; set_taps(taps); // Make sure the output sample is always aligned, too. @@ -254,57 +255,50 @@ namespace gr { fir_filter_ccc::~fir_filter_ccc() { - // Free taps - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - } - // Free all aligned taps - for(int i = 0; i < d_naligned; i++) { - fft::free(d_aligned_taps[i]); + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; } - fft::free(d_aligned_taps); // Free output sample fft::free(d_output); - } + } void fir_filter_ccc::set_taps(const std::vector &taps) { // Free the taps if already allocated - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - + if(d_aligned_taps != NULL) { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } fft::free(d_aligned_taps); + d_aligned_taps = NULL; } d_ntaps = (int)taps.size(); - d_taps = fft::malloc_complex(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; - } + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); // Make a set of taps at all possible arch alignments d_aligned_taps = (gr_complex**)malloc(d_naligned*sizeof(gr_complex**)); for(int i = 0; i < d_naligned; i++) { d_aligned_taps[i] = fft::malloc_complex(d_ntaps+d_naligned-1); memset(d_aligned_taps[i], 0, sizeof(gr_complex)*(d_ntaps+d_naligned-1)); - memcpy(&d_aligned_taps[i][i], d_taps, sizeof(gr_complex)*(d_ntaps)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; } } std::vector fir_filter_ccc::taps() const { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1]); + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); return t; } @@ -357,7 +351,7 @@ namespace gr { d_align = volk_get_alignment(); d_naligned = d_align / sizeof(short); - d_taps = NULL; + d_aligned_taps = NULL; set_taps(taps); // Make sure the output sample is always aligned, too. @@ -366,58 +360,50 @@ namespace gr { fir_filter_scc::~fir_filter_scc() { - // Free taps - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - } - // Free all aligned taps - for(int i = 0; i < d_naligned; i++) { - fft::free(d_aligned_taps[i]); + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; } - fft::free(d_aligned_taps); // Free output sample fft::free(d_output); - } + } void fir_filter_scc::set_taps(const std::vector &taps) { // Free the taps if already allocated - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - + if(d_aligned_taps != NULL) { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } fft::free(d_aligned_taps); + d_aligned_taps = NULL; } d_ntaps = (int)taps.size(); - d_taps = fft::malloc_complex(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; - } + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); // Make a set of taps at all possible arch alignments d_aligned_taps = (gr_complex**)malloc(d_naligned*sizeof(gr_complex**)); for(int i = 0; i < d_naligned; i++) { d_aligned_taps[i] = fft::malloc_complex(d_ntaps+d_naligned-1); memset(d_aligned_taps[i], 0, sizeof(gr_complex)*(d_ntaps+d_naligned-1)); - memcpy(&d_aligned_taps[i][i], d_taps, sizeof(gr_complex)*(d_ntaps)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; } - } std::vector fir_filter_scc::taps() const { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1]); + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); return t; } @@ -471,7 +457,7 @@ namespace gr { d_align = volk_get_alignment(); d_naligned = d_align / sizeof(float); - d_taps = NULL; + d_aligned_taps = NULL; set_taps(taps); // Make sure the output sample is always aligned, too. @@ -480,57 +466,50 @@ namespace gr { fir_filter_fsf::~fir_filter_fsf() { - // Free taps - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - } - - // Free all aligned taps - for(int i = 0; i < d_naligned; i++) { - fft::free(d_aligned_taps[i]); + // Free all aligned taps + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; } - fft::free(d_aligned_taps); // Free output sample fft::free(d_output); - } + } void fir_filter_fsf::set_taps(const std::vector &taps) { // Free the taps if already allocated - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - + if(d_aligned_taps != NULL) { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } fft::free(d_aligned_taps); + d_aligned_taps = NULL; } d_ntaps = (int)taps.size(); - d_taps = fft::malloc_float(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; - } + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); // Make a set of taps at all possible arch alignments d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); for(int i = 0; i < d_naligned; i++) { d_aligned_taps[i] = fft::malloc_float(d_ntaps+d_naligned-1); memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+d_naligned-1)); - memcpy(&d_aligned_taps[i][i], d_taps, sizeof(float)*(d_ntaps)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; } } std::vector fir_filter_fsf::taps() const { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1]); + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); return t; } @@ -550,12 +529,6 @@ namespace gr { d_aligned_taps[al], (d_ntaps+al)); - //float out = 0; - //for(unsigned int i = 0; i < d_ntaps; i++) { - // out += d_taps[i] * input[i]; - //} - //*d_output = (short)out; - return *d_output; } diff --git a/gr-filter/lib/fir_filter_with_buffer.cc b/gr-filter/lib/fir_filter_with_buffer.cc index a2b804a08..b1cc589a5 100644 --- a/gr-filter/lib/fir_filter_with_buffer.cc +++ b/gr-filter/lib/fir_filter_with_buffer.cc @@ -27,6 +27,7 @@ #include #include #include +#include namespace gr { namespace filter { @@ -34,14 +35,30 @@ namespace gr { fir_filter_with_buffer_fff::fir_filter_with_buffer_fff(const std::vector &taps) { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(float); + d_buffer = NULL; + d_aligned_taps = NULL; set_taps(taps); + + // Make sure the output sample is always aligned, too. + d_output = fft::malloc_float(1); } fir_filter_with_buffer_fff::~fir_filter_with_buffer_fff() { - if(d_buffer != NULL) + if(d_buffer != NULL) { fft::free(d_buffer); + d_buffer = NULL; + } + + // Free aligned taps + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + + // Free output sample + fft::free(d_output); } void @@ -52,20 +69,32 @@ namespace gr { d_buffer = NULL; } + // Free the taps if already allocated + if(d_aligned_taps != NULL) { + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + } + + d_buffer = fft::malloc_float(d_ntaps); + d_ntaps = (int)taps.size(); - d_taps = fft::malloc_float(d_ntaps); + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); + + // Allocate aligned taps + d_aligned_taps = fft::malloc_float(d_ntaps); for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; + d_aligned_taps[i] = d_taps[i]; } + d_idx = 0; } std::vector fir_filter_with_buffer_fff::taps() const { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1]); + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); return t; } @@ -79,11 +108,10 @@ namespace gr { if(d_idx >= ntaps()) d_idx = 0; - float output = 0; - volk_32f_x2_dot_prod_32f_u(&output, &d_buffer[d_idx], - d_taps, d_ntaps); - - return output; + volk_32f_x2_dot_prod_32f_a(d_output, d_buffer, + d_aligned_taps, + ntaps()); + return *d_output; } float @@ -100,10 +128,10 @@ namespace gr { d_idx = 0; } - float output = 0; - volk_32f_x2_dot_prod_32f_u(&output, &d_buffer[d_idx], - d_taps, d_ntaps); - return output; + volk_32f_x2_dot_prod_32f_a(d_output, d_buffer, + d_aligned_taps, + ntaps()); + return *d_output; } void @@ -135,14 +163,30 @@ namespace gr { fir_filter_with_buffer_ccc::fir_filter_with_buffer_ccc(const std::vector &taps) { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(gr_complex); + d_buffer = NULL; + d_aligned_taps = NULL; set_taps(taps); + + // Make sure the output sample is always aligned, too. + d_output = fft::malloc_complex(1); } fir_filter_with_buffer_ccc::~fir_filter_with_buffer_ccc() { - if(d_buffer != NULL) + if(d_buffer != NULL) { fft::free(d_buffer); + d_buffer = NULL; + } + + // Free aligned taps + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + + // Free output sample + fft::free(d_output); } void @@ -153,20 +197,32 @@ namespace gr { d_buffer = NULL; } + // Free the taps if already allocated + if(d_aligned_taps != NULL) { + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + } + + d_buffer = fft::malloc_complex(d_ntaps); + d_ntaps = (int)taps.size(); - d_taps = fft::malloc_complex(d_ntaps); + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); + + // Allocate aligned taps + d_aligned_taps = fft::malloc_complex(d_ntaps); for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; + d_aligned_taps[i] = d_taps[i]; } + d_idx = 0; } std::vector fir_filter_with_buffer_ccc::taps() const { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1]); + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); return t; } @@ -180,11 +236,10 @@ namespace gr { if(d_idx >= ntaps()) d_idx = 0; - gr_complex output = 0; - volk_32fc_x2_dot_prod_32fc_u(&output, &d_buffer[d_idx], - d_taps, d_ntaps); - - return output; + volk_32fc_x2_dot_prod_32fc_a(d_output, d_buffer, + d_aligned_taps, + ntaps()); + return *d_output; } gr_complex @@ -201,10 +256,10 @@ namespace gr { d_idx = 0; } - gr_complex output = 0; - volk_32fc_x2_dot_prod_32fc_u(&output, &d_buffer[d_idx], - d_taps, d_ntaps); - return output; + volk_32fc_x2_dot_prod_32fc_a(d_output, d_buffer, + d_aligned_taps, + ntaps()); + return *d_output; } void @@ -230,6 +285,134 @@ namespace gr { } } + + /**************************************************************/ + + + fir_filter_with_buffer_ccf::fir_filter_with_buffer_ccf(const std::vector &taps) + { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(gr_complex); + + d_buffer = NULL; + d_aligned_taps = NULL; + set_taps(taps); + + // Make sure the output sample is always aligned, too. + d_output = fft::malloc_complex(1); + } + + fir_filter_with_buffer_ccf::~fir_filter_with_buffer_ccf() + { + if(d_buffer != NULL) { + fft::free(d_buffer); + d_buffer = NULL; + } + + // Free aligned taps + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + + // Free output sample + fft::free(d_output); + } + + void + fir_filter_with_buffer_ccf::set_taps(const std::vector &taps) + { + if(d_buffer != NULL) { + fft::free(d_buffer); + d_buffer = NULL; + } + + // Free the taps if already allocated + if(d_aligned_taps != NULL) { + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + } + + d_buffer = fft::malloc_complex(d_ntaps); + + d_ntaps = (int)taps.size(); + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); + + // Allocate aligned taps + d_aligned_taps = fft::malloc_float(d_ntaps); + for(unsigned int i = 0; i < d_ntaps; i++) { + d_aligned_taps[i] = d_taps[i]; + } + + d_idx = 0; + } + + std::vector + fir_filter_with_buffer_ccf::taps() const + { + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); + return t; + } + + gr_complex + fir_filter_with_buffer_ccf::filter(gr_complex input) + { + d_buffer[d_idx] = input; + d_buffer[d_idx+ntaps()] = input; + + d_idx++; + if(d_idx >= ntaps()) + d_idx = 0; + + volk_32fc_32f_dot_prod_32fc_a(d_output, d_buffer, + d_aligned_taps, + ntaps()); + return *d_output; + } + + gr_complex + fir_filter_with_buffer_ccf::filter(const gr_complex input[], + unsigned long dec) + { + unsigned int i; + + for(i = 0; i < dec; i++) { + d_buffer[d_idx] = input[i]; + d_buffer[d_idx+ntaps()] = input[i]; + d_idx++; + if(d_idx >= ntaps()) + d_idx = 0; + } + + volk_32fc_32f_dot_prod_32fc_a(d_output, d_buffer, + d_aligned_taps, + ntaps()); + return *d_output; + } + + void + 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]); + } + } + + void + fir_filter_with_buffer_ccf::filterNdec(gr_complex output[], + const gr_complex input[], + unsigned long n, + unsigned long decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++) { + output[i] = filter(&input[j], decimate); + j += decimate; + } + } + } /* namespace kernel */ } /* namespace filter */ -- cgit From 1e7aae3678b0ce08e71b444225aca794f490ffaf Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 15 Jun 2012 11:53:46 -0400 Subject: filter: minor coding things. --- gr-filter/lib/pfb_channelizer_ccf_impl.cc | 6 +++--- gr-filter/lib/polyphase_filterbank.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.cc b/gr-filter/lib/pfb_channelizer_ccf_impl.cc index 4e06cbc5f..ca92066f5 100644 --- a/gr-filter/lib/pfb_channelizer_ccf_impl.cc +++ b/gr-filter/lib/pfb_channelizer_ccf_impl.cc @@ -81,7 +81,7 @@ namespace gr { d_output_multiple++; set_output_multiple(d_output_multiple); - set_history (d_taps_per_filter+1); + set_history(d_taps_per_filter+1); } pfb_channelizer_ccf_impl::~pfb_channelizer_ccf_impl() @@ -95,7 +95,7 @@ namespace gr { gruel::scoped_lock guard(d_mutex); polyphase_filterbank::set_taps(taps); - set_history (d_taps_per_filter+1); + set_history(d_taps_per_filter+1); d_updated = true; } @@ -143,7 +143,7 @@ namespace gr { gr_complex *in = (gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; - if (d_updated) { + if(d_updated) { d_updated = false; return 0; // history requirements may have changed. } diff --git a/gr-filter/lib/polyphase_filterbank.cc b/gr-filter/lib/polyphase_filterbank.cc index 9d881d76e..046c23fc0 100644 --- a/gr-filter/lib/polyphase_filterbank.cc +++ b/gr-filter/lib/polyphase_filterbank.cc @@ -59,7 +59,7 @@ namespace gr { } void - polyphase_filterbank::set_taps (const std::vector &taps) + polyphase_filterbank::set_taps(const std::vector &taps) { unsigned int i,j; -- cgit From 05c117f359b831513bbf6c4f43dca9cb181e5920 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 15 Jun 2012 11:53:58 -0400 Subject: filter: updating adaptive FIR filters. No need for our own adaptive_fir class; can do everything with fir_filter. With QA code. --- gr-filter/lib/CMakeLists.txt | 1 - gr-filter/lib/adaptive_fir.cc | 185 --------------------------------- gr-filter/lib/adaptive_fir_ccc_impl.cc | 18 +++- gr-filter/lib/adaptive_fir_ccc_impl.h | 5 +- gr-filter/lib/adaptive_fir_ccf_impl.cc | 18 +++- gr-filter/lib/adaptive_fir_ccf_impl.h | 5 +- 6 files changed, 38 insertions(+), 194 deletions(-) delete mode 100644 gr-filter/lib/adaptive_fir.cc (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index f5dbd1bb3..7a6394b57 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -105,7 +105,6 @@ link_directories(${FFTW3F_LIBRARY_DIRS}) # Setup library ######################################################################## list(APPEND filter_sources - adaptive_fir.cc fir_filter.cc fir_filter_with_buffer.cc fft_filter.cc diff --git a/gr-filter/lib/adaptive_fir.cc b/gr-filter/lib/adaptive_fir.cc deleted file mode 100644 index 9098e86ca..000000000 --- a/gr-filter/lib/adaptive_fir.cc +++ /dev/null @@ -1,185 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -namespace gr { - namespace filter { - namespace kernel { - - adaptive_fir_ccc::adaptive_fir_ccc(int decimation, - const std::vector &taps) - { - d_taps = NULL; - d_decim = decimation; - set_taps(taps); - } - - void - adaptive_fir_ccc::set_taps(const std::vector &taps) - { - // Free the taps if already allocated - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - } - - d_ntaps = (int)taps.size(); - d_taps = fft::malloc_complex(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; - } - } - - std::vector - adaptive_fir_ccc::taps() const - { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1]); - return t; - } - - int - adaptive_fir_ccc::decimation() const - { - return d_decim; - } - - unsigned int - adaptive_fir_ccc::ntaps() const - { - return d_ntaps; - } - - gr_complex - adaptive_fir_ccc::filter(gr_complex *input) - { - gr_complex output; - volk_32fc_x2_dot_prod_32fc_u(&output, input, d_taps, d_ntaps); - return output; - } - - void - adaptive_fir_ccc::filterN(gr_complex *out, gr_complex *in, - int nitems) - { - int j = 0; - unsigned int k; - for(int i = 0; i < nitems; i++) { - out[i] = filter(&in[j]); - - // Adjust taps - d_error = error(out[i]); - for(k = 0; k < d_ntaps; k++) { - update_tap(d_taps[d_ntaps-k-1], in[j+k]); - } - - j += decimation(); - } - } - - - /**************************************************************/ - - - adaptive_fir_ccf::adaptive_fir_ccf(int decimation, - const std::vector &taps) - { - d_taps = NULL; - d_decim = decimation; - set_taps(taps); - } - - void - adaptive_fir_ccf::set_taps(const std::vector &taps) - { - // Free the taps if already allocated - if(d_taps != NULL) { - fft::free(d_taps); - d_taps = NULL; - } - - d_ntaps = (int)taps.size(); - d_taps = fft::malloc_complex(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_taps[d_ntaps-i-1] = taps[i]; - } - } - - std::vector - adaptive_fir_ccf::taps() const - { - std::vector t; - for(unsigned int i = 0; i < d_ntaps; i++) - t.push_back(d_taps[d_ntaps-i-1].real()); - return t; - } - - int - adaptive_fir_ccf::decimation() const - { - return d_decim; - } - - unsigned int - adaptive_fir_ccf::ntaps() const - { - return d_ntaps; - } - - gr_complex - adaptive_fir_ccf::filter(gr_complex *input) - { - gr_complex output; - volk_32fc_x2_dot_prod_32fc_u(&output, input, d_taps, d_ntaps); - return output; - } - - void - adaptive_fir_ccf::filterN(gr_complex *out, gr_complex *in, - int nitems) - { - int j = 0; - unsigned int k; - for(int i = 0; i < nitems; i++) { - out[i] = filter(&in[j]); - - // Adjust taps - d_error = error(out[i]); - for(k = 0; k < d_ntaps; k++) { - update_tap(d_taps[d_ntaps-k-1], in[j+k]); - } - - j += decimation(); - } - } - - } /* namespace kernel */ - } /* namespace filter */ -} /* namespace gr */ diff --git a/gr-filter/lib/adaptive_fir_ccc_impl.cc b/gr-filter/lib/adaptive_fir_ccc_impl.cc index 06736ae6f..515ef90cd 100644 --- a/gr-filter/lib/adaptive_fir_ccc_impl.cc +++ b/gr-filter/lib/adaptive_fir_ccc_impl.cc @@ -43,7 +43,7 @@ namespace gr { gr_make_io_signature(1, 1, sizeof(gr_complex)), gr_make_io_signature(1, 1, sizeof(gr_complex)), decimation), - kernel::adaptive_fir_ccc(decimation, taps), + kernel::fir_filter_ccc(decimation, taps), d_updated(false) { set_history(d_ntaps); @@ -56,6 +56,12 @@ namespace gr { d_updated = true; } + std::vector + adaptive_fir_ccc_impl::taps() const + { + return kernel::fir_filter_ccc::taps(); + } + gr_complex adaptive_fir_ccc_impl::error(const gr_complex &out) { @@ -77,7 +83,7 @@ namespace gr { gr_complex *out = (gr_complex *)output_items[0]; if (d_updated) { - kernel::adaptive_fir_ccc::set_taps(d_new_taps); + kernel::fir_filter_ccc::set_taps(d_new_taps); set_history(d_ntaps); d_updated = false; return 0; // history requirements may have changed. @@ -85,7 +91,13 @@ namespace gr { // Call base class filtering function that uses // overloaded error and update_tap functions. - filterN(out, in, noutput_items); + if (decimation() == 1) { + filterN(out, in, noutput_items); + } + else { + filterNdec(out, in, noutput_items, + decimation()); + } return noutput_items; } diff --git a/gr-filter/lib/adaptive_fir_ccc_impl.h b/gr-filter/lib/adaptive_fir_ccc_impl.h index f145ceeaa..fd6274a1d 100644 --- a/gr-filter/lib/adaptive_fir_ccc_impl.h +++ b/gr-filter/lib/adaptive_fir_ccc_impl.h @@ -24,17 +24,19 @@ #define INCLUDED_FILTER_ADAPTIVE_FIR_CCC_IMPL_H #include +#include #include namespace gr { namespace filter { - class FILTER_API adaptive_fir_ccc_impl : public adaptive_fir_ccc, public kernel::adaptive_fir_ccc + class FILTER_API adaptive_fir_ccc_impl : public adaptive_fir_ccc, public kernel::fir_filter_ccc { private: std::vector d_new_taps; bool d_updated; + protected: // Override to calculate error signal per output gr_complex error(const gr_complex &out); @@ -43,6 +45,7 @@ namespace gr { public: void set_taps(const std::vector &taps); + std::vector taps() const; adaptive_fir_ccc_impl(const char *name, int decimation, const std::vector &taps); diff --git a/gr-filter/lib/adaptive_fir_ccf_impl.cc b/gr-filter/lib/adaptive_fir_ccf_impl.cc index 053facdc2..62d7e5337 100644 --- a/gr-filter/lib/adaptive_fir_ccf_impl.cc +++ b/gr-filter/lib/adaptive_fir_ccf_impl.cc @@ -43,7 +43,7 @@ namespace gr { gr_make_io_signature(1, 1, sizeof(gr_complex)), gr_make_io_signature(1, 1, sizeof(gr_complex)), decimation), - kernel::adaptive_fir_ccf(decimation, taps), + kernel::fir_filter_ccf(decimation, taps), d_updated(false) { set_history(d_ntaps); @@ -56,6 +56,12 @@ namespace gr { d_updated = true; } + std::vector + adaptive_fir_ccf_impl::taps() + { + return kernel::fir_filter_ccf::taps(); + } + float adaptive_fir_ccf_impl::error(const gr_complex &out) { @@ -77,7 +83,7 @@ namespace gr { gr_complex *out = (gr_complex *)output_items[0]; if (d_updated) { - kernel::adaptive_fir_ccf::set_taps(d_new_taps); + kernel::fir_filter_ccf::set_taps(d_new_taps); set_history(d_ntaps); d_updated = false; return 0; // history requirements may have changed. @@ -85,7 +91,13 @@ namespace gr { // Call base class filtering function that uses // overloaded error and update_tap functions. - filterN(out, in, noutput_items); + if (decimation() == 1) { + filterN(out, in, noutput_items); + } + else { + filterNdec(out, in, noutput_items, + decimation()); + } return noutput_items; } diff --git a/gr-filter/lib/adaptive_fir_ccf_impl.h b/gr-filter/lib/adaptive_fir_ccf_impl.h index fa9a42189..2a1c7e5e9 100644 --- a/gr-filter/lib/adaptive_fir_ccf_impl.h +++ b/gr-filter/lib/adaptive_fir_ccf_impl.h @@ -24,17 +24,19 @@ #define INCLUDED_FILTER_ADAPTIVE_FIR_CCF_IMPL_H #include +#include #include namespace gr { namespace filter { - class FILTER_API adaptive_fir_ccf_impl : public adaptive_fir_ccf, public kernel::adaptive_fir_ccf + class FILTER_API adaptive_fir_ccf_impl : public adaptive_fir_ccf, public kernel::fir_filter_ccf { private: std::vector d_new_taps; bool d_updated; + protected: // Override to calculate error signal per output float error(const gr_complex &out); @@ -43,6 +45,7 @@ namespace gr { public: void set_taps(const std::vector &taps); + std::vector taps(); adaptive_fir_ccf_impl(const char *name, int decimation, const std::vector &taps); -- cgit From 76a6a4c668579ff2e17f8fa44ceb0db381b9053f Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 15 Jun 2012 15:58:28 -0400 Subject: filter: adding single_pole_iir_filter blocks. QA, docs, and GRC. --- gr-filter/lib/CMakeLists.txt | 2 + gr-filter/lib/single_pole_iir_filter_cc_impl.cc | 89 +++++++++++++++++++++++++ gr-filter/lib/single_pole_iir_filter_cc_impl.h | 55 +++++++++++++++ gr-filter/lib/single_pole_iir_filter_ff_impl.cc | 87 ++++++++++++++++++++++++ gr-filter/lib/single_pole_iir_filter_ff_impl.h | 54 +++++++++++++++ 5 files changed, 287 insertions(+) create mode 100644 gr-filter/lib/single_pole_iir_filter_cc_impl.cc create mode 100644 gr-filter/lib/single_pole_iir_filter_cc_impl.h create mode 100644 gr-filter/lib/single_pole_iir_filter_ff_impl.cc create mode 100644 gr-filter/lib/single_pole_iir_filter_ff_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 7a6394b57..d661d01b6 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -121,6 +121,8 @@ list(APPEND filter_sources fft_filter_fff_impl.cc hilbert_fc_impl.cc pfb_channelizer_ccf_impl.cc + single_pole_iir_filter_cc_impl.cc + single_pole_iir_filter_ff_impl.cc ) list(APPEND filter_libs diff --git a/gr-filter/lib/single_pole_iir_filter_cc_impl.cc b/gr-filter/lib/single_pole_iir_filter_cc_impl.cc new file mode 100644 index 000000000..9406f2c98 --- /dev/null +++ b/gr-filter/lib/single_pole_iir_filter_cc_impl.cc @@ -0,0 +1,89 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "single_pole_iir_filter_cc_impl.h" +#include + + +namespace gr { + namespace filter { + + single_pole_iir_filter_cc::sptr + single_pole_iir_filter_cc::make(double alpha, unsigned int vlen) + { + return gnuradio::get_initial_sptr + (new single_pole_iir_filter_cc_impl(alpha, vlen)); + } + + single_pole_iir_filter_cc_impl::single_pole_iir_filter_cc_impl + (double alpha, unsigned int vlen) + : gr_sync_block("single_pole_iir_filter_cc", + gr_make_io_signature(1, 1, sizeof (gr_complex) * vlen), + gr_make_io_signature(1, 1, sizeof (gr_complex) * vlen)), + d_vlen(vlen), d_iir(vlen) + { + set_taps(alpha); + } + + single_pole_iir_filter_cc_impl::~single_pole_iir_filter_cc_impl() + { + } + + void + single_pole_iir_filter_cc_impl::set_taps(double alpha) + { + for(unsigned int i = 0; i < d_vlen; i++) { + d_iir[i].set_taps(alpha); + } + } + + int + single_pole_iir_filter_cc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + unsigned int vlen = d_vlen; + + if(d_vlen == 1) { + for(int i = 0; i < noutput_items; i++) { + out[i] = d_iir[0].filter(in[i]); + } + } + else { + for(int i = 0; i < noutput_items; i++) { + for(unsigned int j = 0; j < vlen; j++) { + *out++ = d_iir[j].filter(*in++); + } + } + } + + return noutput_items; + }; + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/single_pole_iir_filter_cc_impl.h b/gr-filter/lib/single_pole_iir_filter_cc_impl.h new file mode 100644 index 000000000..fa627881e --- /dev/null +++ b/gr-filter/lib/single_pole_iir_filter_cc_impl.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004-2006,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_SINGLE_POLE_IIR_FILTER_CC_IMPL_H +#define INCLUDED_SINGLE_POLE_IIR_FILTER_CC_IMPL_H + +#include +#include +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API single_pole_iir_filter_cc_impl : public single_pole_iir_filter_cc + { + private: + unsigned int d_vlen; + std::vector > d_iir; + + public: + single_pole_iir_filter_cc_impl(double alpha, unsigned int vlen); + ~single_pole_iir_filter_cc_impl(); + + void set_taps(double alpha); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_SINGLE_POLE_IIR_FILTER_CC_IMPL_H */ diff --git a/gr-filter/lib/single_pole_iir_filter_ff_impl.cc b/gr-filter/lib/single_pole_iir_filter_ff_impl.cc new file mode 100644 index 000000000..7e2bae5db --- /dev/null +++ b/gr-filter/lib/single_pole_iir_filter_ff_impl.cc @@ -0,0 +1,87 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "single_pole_iir_filter_ff_impl.h" +#include + +namespace gr { + namespace filter { + + single_pole_iir_filter_ff::sptr + single_pole_iir_filter_ff::make(double alpha, unsigned int vlen) + { + return gnuradio::get_initial_sptr + (new single_pole_iir_filter_ff_impl(alpha, vlen)); + } + + single_pole_iir_filter_ff_impl::single_pole_iir_filter_ff_impl + (double alpha, unsigned int vlen) + : gr_sync_block("single_pole_iir_filter_ff", + gr_make_io_signature(1, 1, sizeof(float)*vlen), + gr_make_io_signature(1, 1, sizeof(float)*vlen)), + d_vlen(vlen), d_iir(vlen) + { + set_taps(alpha); + } + + single_pole_iir_filter_ff_impl::~single_pole_iir_filter_ff_impl() + { + } + + void + single_pole_iir_filter_ff_impl::set_taps(double alpha) + { + for(unsigned int i = 0; i < d_vlen; i++) { + d_iir[i].set_taps(alpha); + } + } + + int + single_pole_iir_filter_ff_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float*)input_items[0]; + float *out = (float*)output_items[0]; + unsigned int vlen = d_vlen; + + if(d_vlen == 1) { + for(int i = 0; i < noutput_items; i++) { + out[i] = d_iir[0].filter (in[i]); + } + } + else { + for(int i = 0; i < noutput_items; i++) { + for(unsigned int j = 0; j < vlen; j++) { + *out++ = d_iir[j].filter(*in++); + } + } + } + return noutput_items; + }; + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/single_pole_iir_filter_ff_impl.h b/gr-filter/lib/single_pole_iir_filter_ff_impl.h new file mode 100644 index 000000000..cba9c188c --- /dev/null +++ b/gr-filter/lib/single_pole_iir_filter_ff_impl.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004-2006,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_SINGLE_POLE_IIR_FILTER_FF_IMPL_H +#define INCLUDED_SINGLE_POLE_IIR_FILTER_FF_IMPL_H + +#include +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API single_pole_iir_filter_ff_impl : public single_pole_iir_filter_ff + { + private: + unsigned int d_vlen; + std::vector > d_iir; + + public: + single_pole_iir_filter_ff_impl(double alpha, unsigned int vlen); + ~single_pole_iir_filter_ff_impl(); + + void set_taps(double alpha); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_SINGLE_POLE_IIR_FILTER_FF_IMPL_H */ -- cgit From 3cd0ea45255e2ca43931b2f067ec82fc92f4293e Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 15 Jun 2012 17:56:33 -0400 Subject: filter: adding IIR filter. Include QA and GRC. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/iir_filter_ffd_impl.cc | 85 ++++++++++++++++++++++++++++++++++++ gr-filter/lib/iir_filter_ffd_impl.h | 56 ++++++++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 gr-filter/lib/iir_filter_ffd_impl.cc create mode 100644 gr-filter/lib/iir_filter_ffd_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index d661d01b6..7a8b5aa0b 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -120,6 +120,7 @@ list(APPEND filter_sources fft_filter_ccc_impl.cc fft_filter_fff_impl.cc hilbert_fc_impl.cc + iir_filter_ffd_impl.cc pfb_channelizer_ccf_impl.cc single_pole_iir_filter_cc_impl.cc single_pole_iir_filter_ff_impl.cc diff --git a/gr-filter/lib/iir_filter_ffd_impl.cc b/gr-filter/lib/iir_filter_ffd_impl.cc new file mode 100644 index 000000000..24bfad190 --- /dev/null +++ b/gr-filter/lib/iir_filter_ffd_impl.cc @@ -0,0 +1,85 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "iir_filter_ffd_impl.h" +#include + +namespace gr { + namespace filter { + + iir_filter_ffd::sptr + iir_filter_ffd::make(const std::vector &fftaps, + const std::vector &fbtaps) + { + return gnuradio::get_initial_sptr(new iir_filter_ffd_impl(fftaps, fbtaps)); + } + + iir_filter_ffd_impl::iir_filter_ffd_impl(const std::vector &fftaps, + const std::vector &fbtaps) + + : gr_sync_block("iir_filter_ffd", + gr_make_io_signature(1, 1, sizeof (float)), + gr_make_io_signature(1, 1, sizeof (float))), + d_updated(false) + { + d_iir = new kernel::iir_filter(fftaps, fbtaps); + //d_iir = new gri_iir(fftaps, fbtaps); + } + + iir_filter_ffd_impl::~iir_filter_ffd_impl() + { + delete d_iir; + } + + void + iir_filter_ffd_impl::set_taps(const std::vector &fftaps, + const std::vector &fbtaps) + { + d_new_fftaps = fftaps; + d_new_fbtaps = fbtaps; + d_updated = true; + } + + int + iir_filter_ffd_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float*)input_items[0]; + float *out = (float*)output_items[0]; + + if(d_updated) { + d_iir->set_taps(d_new_fftaps, d_new_fbtaps); + d_updated = false; + } + + d_iir->filter_n(out, in, noutput_items); + return noutput_items; + }; + + } /* namespace filter */ +} /* namespace gr */ + diff --git a/gr-filter/lib/iir_filter_ffd_impl.h b/gr-filter/lib/iir_filter_ffd_impl.h new file mode 100644 index 000000000..45aab6c22 --- /dev/null +++ b/gr-filter/lib/iir_filter_ffd_impl.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_IIR_FILTER_FFD_IMPL_H +#define INCLUDED_IIR_FILTER_FFD_IMPL_H + +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API iir_filter_ffd_impl : public iir_filter_ffd + { + private: + bool d_updated; + kernel::iir_filter *d_iir; + std::vector d_new_fftaps; + std::vector d_new_fbtaps; + + public: + iir_filter_ffd_impl(const std::vector &fftaps, + const std::vector &fbtaps); + ~iir_filter_ffd_impl(); + + void set_taps(const std::vector &fftaps, + const std::vector &fbtaps); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_IIR_FILTER_FFD_IMPL_H */ -- cgit From d647fbbaa07554ad314c9eb2b5c1735b6265d13a Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sat, 16 Jun 2012 10:55:36 -0400 Subject: filter: adding freq_xlating_filter. Includes QA and GRC. Update to build_utils adds a FIR_TYPE for the type of filter and CFIR_TYPE for the type of filter where the taps are always complex (needed for freq_xlating_filter). --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/fir_filter.cc | 108 ++++++++++++++++ .../lib/freq_xlating_fir_filter_XXX_impl.cc.t | 143 +++++++++++++++++++++ gr-filter/lib/freq_xlating_fir_filter_XXX_impl.h.t | 71 ++++++++++ 4 files changed, 323 insertions(+) create mode 100644 gr-filter/lib/freq_xlating_fir_filter_XXX_impl.cc.t create mode 100644 gr-filter/lib/freq_xlating_fir_filter_XXX_impl.h.t (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 7a8b5aa0b..055e3da90 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -81,6 +81,7 @@ endmacro(expand_cc) # Invoke macro to generate various sources ######################################################################## expand_cc(fir_filter_XXX_impl fff ccf ccc scc fsf) +expand_cc(freq_xlating_fir_filter_XXX_impl ccc ccf fcc fcf scc scf) ######################################################################## diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 6c82dda5e..7ca1fae19 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -238,6 +238,114 @@ namespace gr { } } + + /**************************************************************/ + + + fir_filter_fcc::fir_filter_fcc(int decimation, + const std::vector &taps) + { + d_align = volk_get_alignment(); + d_naligned = d_align / sizeof(float); + + d_aligned_taps = NULL; + set_taps(taps); + + // Make sure the output sample is always aligned, too. + d_output = fft::malloc_complex(1); + } + + fir_filter_fcc::~fir_filter_fcc() + { + // Free all aligned taps + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + } + + // Free output sample + fft::free(d_output); + } + + void + fir_filter_fcc::set_taps(const std::vector &taps) + { + // Free the taps if already allocated + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + } + + d_ntaps = (int)taps.size(); + d_taps = taps; + std::reverse(d_taps.begin(), d_taps.end()); + + // Make a set of taps at all possible arch alignments + d_aligned_taps = (gr_complex**)malloc(d_naligned*sizeof(gr_complex**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_complex(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(gr_complex)*(d_ntaps+d_naligned-1)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; + } + } + + std::vector + fir_filter_fcc::taps() const + { + std::vector t = d_taps; + std::reverse(t.begin(), t.end()); + return t; + } + + unsigned int + fir_filter_fcc::ntaps() const + { + return d_ntaps; + } + + gr_complex + fir_filter_fcc::filter(const float input[]) + { + const float *ar = (float *)((unsigned long) input & ~(d_align-1)); + unsigned al = input - ar; + + volk_32fc_32f_dot_prod_32fc_a(d_output, + d_aligned_taps[al], + ar, + (d_ntaps+al)); + return *d_output; + } + + void + fir_filter_fcc::filterN(gr_complex output[], + const float input[], + unsigned long n) + { + for(unsigned long i = 0; i < n; i++) + output[i] = filter(&input[i]); + } + + + void + fir_filter_fcc::filterNdec(gr_complex output[], + const float input[], + unsigned long n, + unsigned int decimate) + { + unsigned long j = 0; + for(unsigned long i = 0; i < n; i++){ + output[i] = filter(&input[j]); + j += decimate; + } + } + /**************************************************************/ fir_filter_ccc::fir_filter_ccc(int decimation, diff --git a/gr-filter/lib/freq_xlating_fir_filter_XXX_impl.cc.t b/gr-filter/lib/freq_xlating_fir_filter_XXX_impl.cc.t new file mode 100644 index 000000000..a59fa12b3 --- /dev/null +++ b/gr-filter/lib/freq_xlating_fir_filter_XXX_impl.cc.t @@ -0,0 +1,143 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * WARNING: This file is automatically generated by cmake. + * Any changes made to this file will be overwritten. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "@IMPL_NAME@.h" +#include +#include + +namespace gr { + namespace filter { + + @BASE_NAME@::sptr + @BASE_NAME@::make(int decimation, + const std::vector<@TAP_TYPE@> &taps, + double center_freq, + double sampling_freq) + { + return gnuradio::get_initial_sptr(new @IMPL_NAME@ + (decimation, taps, + center_freq, + sampling_freq)); + } + + @IMPL_NAME@::@IMPL_NAME@(int decimation, + const std::vector<@TAP_TYPE@> &taps, + double center_freq, + double sampling_freq) + : gr_sync_decimator("@BASE_NAME@", + gr_make_io_signature(1, 1, sizeof(@I_TYPE@)), + gr_make_io_signature(1, 1, sizeof(@O_TYPE@)), + decimation), + d_proto_taps(taps), d_center_freq(center_freq), + d_sampling_freq(sampling_freq), + d_updated(false) + { + std::vector dummy_taps; + d_composite_fir = new kernel::@CFIR_TYPE@(decimation, dummy_taps); + + set_history(d_proto_taps.size()); + build_composite_fir(); + } + + @IMPL_NAME@::~@IMPL_NAME@() + { + delete d_composite_fir; + } + + void + @IMPL_NAME@::build_composite_fir() + { + std::vector ctaps(d_proto_taps.size()); + + float fwT0 = -2 * M_PI * d_center_freq / d_sampling_freq; + for(unsigned int i = 0; i < d_proto_taps.size(); i++) { + ctaps[i] = d_proto_taps[i] * exp(gr_complex(0, i * fwT0)); + } + + std::reverse(ctaps.begin(), ctaps.end()); + d_composite_fir->set_taps(ctaps); + d_r.set_phase_incr(exp(gr_complex(0, fwT0 * decimation()))); + } + + void + @IMPL_NAME@::set_center_freq(double center_freq) + { + d_center_freq = center_freq; + d_updated = true; + } + + double + @IMPL_NAME@::center_freq() const + { + return d_center_freq; + } + + void + @IMPL_NAME@::set_taps(const std::vector<@TAP_TYPE@> &taps) + { + d_proto_taps = taps; + d_updated = true; + } + + std::vector<@TAP_TYPE@> + @IMPL_NAME@::taps() const + { + return d_proto_taps; + } + + int + @IMPL_NAME@::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + @I_TYPE@ *in = (@I_TYPE@ *)input_items[0]; + @O_TYPE@ *out = (@O_TYPE@ *)output_items[0]; + + // rebuild composite FIR if the center freq has changed + if(d_updated) { + set_history(d_proto_taps.size()); + build_composite_fir(); + d_updated = false; + return 0; // history requirements may have changed. + } + + unsigned j = 0; + for (int i = 0; i < noutput_items; i++){ + out[i] = d_r.rotate(d_composite_fir->filter(&in[j])); + j += decimation(); + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ + diff --git a/gr-filter/lib/freq_xlating_fir_filter_XXX_impl.h.t b/gr-filter/lib/freq_xlating_fir_filter_XXX_impl.h.t new file mode 100644 index 000000000..0cf976d58 --- /dev/null +++ b/gr-filter/lib/freq_xlating_fir_filter_XXX_impl.h.t @@ -0,0 +1,71 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2004,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * WARNING: This file is automatically generated by cmake. + * Any changes made to this file will be overwritten. + */ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API @IMPL_NAME@ : public @BASE_NAME@ + { + protected: + std::vector<@TAP_TYPE@> d_proto_taps; + kernel::@CFIR_TYPE@ *d_composite_fir; + gr_rotator d_r; + double d_center_freq; + double d_sampling_freq; + bool d_updated; + + virtual void build_composite_fir(); + public: + + @IMPL_NAME@(int decimation, + const std::vector<@TAP_TYPE@> &taps, + double center_freq, + double sampling_freq); + virtual ~@IMPL_NAME@(); + + void set_center_freq(double center_freq); + double center_freq() const; + + void set_taps(const std::vector<@TAP_TYPE@> &taps); + std::vector<@TAP_TYPE@> taps() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* @GUARD_NAME@ */ -- cgit From ce3d887a47b47cb2d5351e14066ceb56b2b3c892 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 17 Jun 2012 16:44:04 -0400 Subject: filter: added mmse_fir_interpolator with QA code. --- gr-filter/lib/CMakeLists.txt | 4 + gr-filter/lib/mmse_fir_interpolator_cc.cc | 77 +++++++++++++++++ gr-filter/lib/mmse_fir_interpolator_ff.cc | 77 +++++++++++++++++ gr-filter/lib/qa_filter.cc | 6 +- gr-filter/lib/qa_mmse_fir_interpolator_cc.cc | 125 +++++++++++++++++++++++++++ gr-filter/lib/qa_mmse_fir_interpolator_cc.h | 48 ++++++++++ gr-filter/lib/qa_mmse_fir_interpolator_ff.cc | 69 +++++++++++++++ gr-filter/lib/qa_mmse_fir_interpolator_ff.h | 45 ++++++++++ 8 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 gr-filter/lib/mmse_fir_interpolator_cc.cc create mode 100644 gr-filter/lib/mmse_fir_interpolator_ff.cc create mode 100644 gr-filter/lib/qa_mmse_fir_interpolator_cc.cc create mode 100644 gr-filter/lib/qa_mmse_fir_interpolator_cc.h create mode 100644 gr-filter/lib/qa_mmse_fir_interpolator_ff.cc create mode 100644 gr-filter/lib/qa_mmse_fir_interpolator_ff.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 055e3da90..4d950230a 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -110,6 +110,8 @@ list(APPEND filter_sources fir_filter_with_buffer.cc fft_filter.cc firdes.cc + mmse_fir_interpolator_cc.cc + mmse_fir_interpolator_ff.cc pm_remez.cc polyphase_filterbank.cc ${generated_sources} @@ -148,6 +150,8 @@ list(APPEND test_gr_filter_sources ${CMAKE_CURRENT_SOURCE_DIR}/test_gr_filter.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_filter.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_firdes.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_fir_interpolator_cc.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_fir_interpolator_ff.cc ) add_executable(test-gr-filter ${test_gr_filter_sources}) diff --git a/gr-filter/lib/mmse_fir_interpolator_cc.cc b/gr-filter/lib/mmse_fir_interpolator_cc.cc new file mode 100644 index 000000000..8af1fb39a --- /dev/null +++ b/gr-filter/lib/mmse_fir_interpolator_cc.cc @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +namespace gr { + namespace filter { + + mmse_fir_interpolator_cc::mmse_fir_interpolator_cc() + { + filters.resize (NSTEPS + 1); + + for(int i = 0; i < NSTEPS + 1; i++) { + std::vector t (&taps[i][0], &taps[i][NTAPS]); + filters[i] = new kernel::fir_filter_ccf(1, t); + } + } + + mmse_fir_interpolator_cc::~mmse_fir_interpolator_cc() + { + for(int i = 0; i < NSTEPS + 1; i++) + delete filters[i]; + } + + unsigned + mmse_fir_interpolator_cc::ntaps() const + { + return NTAPS; + } + + unsigned + mmse_fir_interpolator_cc::nsteps() const + { + return NSTEPS; + } + + gr_complex + mmse_fir_interpolator_cc::interpolate(const gr_complex input[], + float mu) const + { + int imu = (int)rint(mu * NSTEPS); + + if((imu < 0) || (imu > NSTEPS)) { + throw std::runtime_error("mmse_fir_interpolator_cc: imu out of bounds.\n"); + } + + gr_complex r = filters[imu]->filter(input); + return r; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/mmse_fir_interpolator_ff.cc b/gr-filter/lib/mmse_fir_interpolator_ff.cc new file mode 100644 index 000000000..ff2c4dd87 --- /dev/null +++ b/gr-filter/lib/mmse_fir_interpolator_ff.cc @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +namespace gr { + namespace filter { + + mmse_fir_interpolator_ff::mmse_fir_interpolator_ff() + { + filters.resize(NSTEPS + 1); + + for(int i = 0; i < NSTEPS + 1; i++) { + std::vector t(&taps[i][0], &taps[i][NTAPS]); + filters[i] = new kernel::fir_filter_fff(1, t); + } + } + + mmse_fir_interpolator_ff::~mmse_fir_interpolator_ff() + { + for(int i = 0; i < NSTEPS + 1; i++) + delete filters[i]; + } + + unsigned + mmse_fir_interpolator_ff::ntaps() const + { + return NTAPS; + } + + unsigned + mmse_fir_interpolator_ff::nsteps() const + { + return NSTEPS; + } + + float + mmse_fir_interpolator_ff::interpolate(const float input[], + float mu) const + { + int imu = (int)rint(mu * NSTEPS); + + if((imu < 0) || (imu > NSTEPS)) { + throw std::runtime_error("mmse_fir_interpolator_ff: imu out of bounds.\n"); + } + + float r = filters[imu]->filter(input); + return r; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/qa_filter.cc b/gr-filter/lib/qa_filter.cc index 86d4860de..8aa24651c 100644 --- a/gr-filter/lib/qa_filter.cc +++ b/gr-filter/lib/qa_filter.cc @@ -27,13 +27,17 @@ #include #include +#include +#include CppUnit::TestSuite * qa_gr_filter::suite () { CppUnit::TestSuite *s = new CppUnit::TestSuite ("gr-filter"); - s->addTest(gr::filter::qa_firdes::suite ()); + s->addTest(gr::filter::qa_firdes::suite()); + s->addTest(gr::filter::qa_mmse_fir_interpolator_cc::suite()); + s->addTest(gr::filter::qa_mmse_fir_interpolator_ff::suite()); return s; } diff --git a/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc b/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc new file mode 100644 index 000000000..5850cb86c --- /dev/null +++ b/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc @@ -0,0 +1,125 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2007,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +namespace gr { + namespace filter { + +#define NELEM(x) (sizeof(x) / sizeof(x[0])) + + static float + test_fcn_sin(double index) + { + return (2 * sin (index * 0.25 * 2 * M_PI + 0.125 * M_PI) + + 3 * sin (index * 0.077 * 2 * M_PI + 0.3 * M_PI)); + } + + static float + test_fcn_cos(double index) + { + return (2 * cos (index * 0.25 * 2 * M_PI + 0.125 * M_PI) + + 3 * cos (index * 0.077 * 2 * M_PI + 0.3 * M_PI)); + } + + static gr_complex + test_fcn(double index) + { + return gr_complex(test_fcn_cos(index), test_fcn_sin(index)); + } + + + void + qa_mmse_fir_interpolator_cc::t1() + { + static const unsigned N = 100; + __GR_ATTR_ALIGNED(8) gr_complex input[N + 10]; + + for(unsigned i = 0; i < NELEM(input); i++) + input[i] = test_fcn((double) i); + + mmse_fir_interpolator_cc intr; + float inv_nsteps = 1.0 / intr.nsteps(); + + for(unsigned i = 0; i < N; i++) { + for(unsigned imu = 0; imu <= intr.nsteps (); imu += 1) { + gr_complex expected = test_fcn((i + 3) + imu * inv_nsteps); + gr_complex actual = intr.interpolate(&input[i], imu * inv_nsteps); + + CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected, actual, 0.004); + // printf ("%9.6f %9.6f %9.6f\n", expected, actual, expected - actual); + } + } + } + + /* + * Force bad alignment and confirm that it raises an exception + */ + void + qa_mmse_fir_interpolator_cc::t2_body() + { + static const unsigned N = 100; + float float_input[2*(N+10) + 1]; + gr_complex *input; + + // We require that gr_complex be aligned on an 8-byte boundary. + // Ensure that we ARE NOT ;) + + if(((intptr_t) float_input & 0x7) == 0) + input = reinterpret_cast(&float_input[1]); + else + input = reinterpret_cast(&float_input[0]); + + for(unsigned i = 0; i < (N+10); i++) + input[i] = test_fcn((double) i); + + mmse_fir_interpolator_cc intr; + float inv_nsteps = 1.0 / intr.nsteps(); + + for(unsigned i = 0; i < N; i++) { + for(unsigned imu = 0; imu <= intr.nsteps (); imu += 1) { + gr_complex expected = test_fcn((i + 3) + imu * inv_nsteps); + gr_complex actual = intr.interpolate(&input[i], imu * inv_nsteps); + + CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected, actual, 0.004); + // printf ("%9.6f %9.6f %9.6f\n", expected, actual, expected - actual); + } + } + } + + void + qa_mmse_fir_interpolator_cc::t2() + { + CPPUNIT_ASSERT_THROW(t2_body(), std::invalid_argument); + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/qa_mmse_fir_interpolator_cc.h b/gr-filter/lib/qa_mmse_fir_interpolator_cc.h new file mode 100644 index 000000000..a45965ca2 --- /dev/null +++ b/gr-filter/lib/qa_mmse_fir_interpolator_cc.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2007,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _QA_MMSE_FIR_INTERPOLATOR_CC_H_ +#define _QA_MMSE_FIR_INTERPOLATOR_CC_H_ + +#include +#include + +namespace gr { + namespace filter { + + class qa_mmse_fir_interpolator_cc : public CppUnit::TestCase + { + CPPUNIT_TEST_SUITE(qa_mmse_fir_interpolator_cc); + CPPUNIT_TEST(t1); + // CPPUNIT_TEST(t2); + CPPUNIT_TEST_SUITE_END(); + + private: + void t1(); + void t2(); + void t2_body(); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* _QA_MMSE_FIR_INTERPOLATOR_CC_H_ */ diff --git a/gr-filter/lib/qa_mmse_fir_interpolator_ff.cc b/gr-filter/lib/qa_mmse_fir_interpolator_ff.cc new file mode 100644 index 000000000..128b638b9 --- /dev/null +++ b/gr-filter/lib/qa_mmse_fir_interpolator_ff.cc @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +namespace gr { + namespace filter { + +#define NELEM(x) (sizeof(x) / sizeof(x[0])) + + static float + test_fcn(double index) + { + return (2 * sin(index * 0.25 * 2 * M_PI + 0.125 * M_PI) + + 3 * sin(index * 0.077 * 2 * M_PI + 0.3 * M_PI)); + } + + void + qa_mmse_fir_interpolator_ff::t1() + { + static const unsigned N = 100; + float input[N + 10]; + + for(unsigned i = 0; i < NELEM(input); i++) + input[i] = test_fcn((double) i); + + mmse_fir_interpolator_ff intr; + float inv_nsteps = 1.0 / intr.nsteps(); + + for(unsigned i = 0; i < N; i++) { + for(unsigned imu = 0; imu <= intr.nsteps (); imu += 1) { + float expected = test_fcn((i + 3) + imu * inv_nsteps); + float actual = intr.interpolate(&input[i], imu * inv_nsteps); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, 0.004); + // printf ("%9.6f %9.6f %9.6f\n", expected, actual, expected - actual); + } + } + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/qa_mmse_fir_interpolator_ff.h b/gr-filter/lib/qa_mmse_fir_interpolator_ff.h new file mode 100644 index 000000000..833ec173a --- /dev/null +++ b/gr-filter/lib/qa_mmse_fir_interpolator_ff.h @@ -0,0 +1,45 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _QA_MMSE_FIR_INTERPOLATOR_FF_H_ +#define _QA_MMSE_FIR_INTERPOLATOR_FF_H_ + +#include +#include + +namespace gr { + namespace filter { + + class qa_mmse_fir_interpolator_ff : public CppUnit::TestCase + { + CPPUNIT_TEST_SUITE(qa_mmse_fir_interpolator_ff); + CPPUNIT_TEST(t1); + CPPUNIT_TEST_SUITE_END(); + + private: + void t1(); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* _QA_MMSE_FIR_INTERPOLATOR_FF_H_ */ -- cgit From 765d82d839e1773c77556e5d73ab229cbe6b96dc Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 17 Jun 2012 16:48:35 -0400 Subject: filter: redoing hilbert and fir_delay to use normal filter calls since alignment is properly handled. --- gr-filter/lib/filter_delay_fc_impl.cc | 7 ++----- gr-filter/lib/hilbert_fc_impl.cc | 4 +--- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/filter_delay_fc_impl.cc b/gr-filter/lib/filter_delay_fc_impl.cc index 279368664..3bb550864 100644 --- a/gr-filter/lib/filter_delay_fc_impl.cc +++ b/gr-filter/lib/filter_delay_fc_impl.cc @@ -78,7 +78,6 @@ namespace gr { float *in0 = (float *)input_items[0]; float *in1 = (float *)input_items[1]; gr_complex *out = (gr_complex *)output_items[0]; - float d_out; if(d_update) { d_fir->set_taps(d_taps); @@ -90,17 +89,15 @@ namespace gr { switch(input_items.size ()) { case 1: for(int i = 0; i < noutput_items; i++) { - d_fir->filterN(&d_out, &in0[i], 1); out[i] = gr_complex(in0[i + d_delay], - d_out); + d_fir->filter(&in0[i])); } break; case 2: for(int j = 0; j < noutput_items; j++) { - d_fir->filterN(&d_out, &in1[j], 1); out[j] = gr_complex(in0[j + d_delay], - d_out); + d_fir->filter(&in1[j])); } break; diff --git a/gr-filter/lib/hilbert_fc_impl.cc b/gr-filter/lib/hilbert_fc_impl.cc index 7aaa23a62..52b2dabae 100644 --- a/gr-filter/lib/hilbert_fc_impl.cc +++ b/gr-filter/lib/hilbert_fc_impl.cc @@ -63,12 +63,10 @@ namespace gr { { float *in = (float *)input_items[0]; gr_complex *out = (gr_complex *)output_items[0]; - float h_out; for(int i = 0; i < noutput_items; i++) { - d_hilb->filterN(&h_out, &in[i], 1); out[i] = gr_complex(in[i + d_ntaps/2], - h_out); + d_hilb->filter(&in[i])); } return noutput_items; -- cgit From 6b2dbab570adceb3a7fa29f298da24a5e53cbf64 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 17 Jun 2012 20:35:53 -0400 Subject: filter: fixed fir_filter_with_buffer and added QA code to check. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/fir_filter.cc | 1 - gr-filter/lib/fir_filter_with_buffer.cc | 133 +++++++--- gr-filter/lib/qa_filter.cc | 4 + gr-filter/lib/qa_fir_filter_with_buffer.cc | 408 +++++++++++++++++++++++++++++ gr-filter/lib/qa_fir_filter_with_buffer.h | 94 +++++++ 6 files changed, 601 insertions(+), 40 deletions(-) create mode 100644 gr-filter/lib/qa_fir_filter_with_buffer.cc create mode 100644 gr-filter/lib/qa_fir_filter_with_buffer.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 4d950230a..97afe7139 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -150,6 +150,7 @@ list(APPEND test_gr_filter_sources ${CMAKE_CURRENT_SOURCE_DIR}/test_gr_filter.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_filter.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_firdes.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_fir_filter_with_buffer.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_fir_interpolator_cc.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_fir_interpolator_ff.cc ) diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 7ca1fae19..8e585f245 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -24,7 +24,6 @@ #include #include #include -#include namespace gr { namespace filter { diff --git a/gr-filter/lib/fir_filter_with_buffer.cc b/gr-filter/lib/fir_filter_with_buffer.cc index b1cc589a5..58ef67fb7 100644 --- a/gr-filter/lib/fir_filter_with_buffer.cc +++ b/gr-filter/lib/fir_filter_with_buffer.cc @@ -28,6 +28,7 @@ #include #include #include +#include namespace gr { namespace filter { @@ -54,8 +55,13 @@ namespace gr { } // Free aligned taps - fft::free(d_aligned_taps); - d_aligned_taps = NULL; + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + } // Free output sample fft::free(d_output); @@ -71,20 +77,27 @@ namespace gr { // Free the taps if already allocated if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } fft::free(d_aligned_taps); d_aligned_taps = NULL; } - d_buffer = fft::malloc_float(d_ntaps); - d_ntaps = (int)taps.size(); d_taps = taps; std::reverse(d_taps.begin(), d_taps.end()); + d_buffer = fft::malloc_float(2*d_ntaps); + memset(d_buffer, 0, 2*d_ntaps*sizeof(float)); + // Allocate aligned taps - d_aligned_taps = fft::malloc_float(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_aligned_taps[i] = d_taps[i]; + d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_float(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+d_naligned-1)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; } d_idx = 0; @@ -108,9 +121,12 @@ namespace gr { if(d_idx >= ntaps()) d_idx = 0; - volk_32f_x2_dot_prod_32f_a(d_output, d_buffer, - d_aligned_taps, - ntaps()); + const float *ar = (float*)((unsigned long)(&d_buffer[d_idx]) & ~(d_align-1)); + unsigned al = (&d_buffer[d_idx]) - ar; + + volk_32f_x2_dot_prod_32f_a(d_output, ar, + d_aligned_taps[al], + ntaps()+al); return *d_output; } @@ -128,9 +144,12 @@ namespace gr { d_idx = 0; } - volk_32f_x2_dot_prod_32f_a(d_output, d_buffer, - d_aligned_taps, - ntaps()); + const float *ar = (float*)((unsigned long)(&d_buffer[d_idx]) & ~(d_align-1)); + unsigned al = (&d_buffer[d_idx]) - ar; + + volk_32f_x2_dot_prod_32f_a(d_output, ar, + d_aligned_taps[al], + ntaps()+al); return *d_output; } @@ -182,8 +201,13 @@ namespace gr { } // Free aligned taps - fft::free(d_aligned_taps); - d_aligned_taps = NULL; + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + } // Free output sample fft::free(d_output); @@ -199,20 +223,27 @@ namespace gr { // Free the taps if already allocated if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } fft::free(d_aligned_taps); d_aligned_taps = NULL; } - d_buffer = fft::malloc_complex(d_ntaps); - d_ntaps = (int)taps.size(); d_taps = taps; std::reverse(d_taps.begin(), d_taps.end()); + d_buffer = fft::malloc_complex(2*d_ntaps); + memset(d_buffer, 0, 2*d_ntaps*sizeof(gr_complex)); + // Allocate aligned taps - d_aligned_taps = fft::malloc_complex(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_aligned_taps[i] = d_taps[i]; + d_aligned_taps = (gr_complex**)malloc(d_naligned*sizeof(gr_complex**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_complex(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(gr_complex)*(d_ntaps+d_naligned-1)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; } d_idx = 0; @@ -236,9 +267,12 @@ namespace gr { if(d_idx >= ntaps()) d_idx = 0; - volk_32fc_x2_dot_prod_32fc_a(d_output, d_buffer, - d_aligned_taps, - ntaps()); + const gr_complex *ar = (gr_complex *)((unsigned long)(&d_buffer[d_idx]) & ~(d_align-1)); + unsigned al = (&d_buffer[d_idx]) - ar; + + volk_32fc_x2_dot_prod_32fc_a(d_output, ar, + d_aligned_taps[al], + (ntaps()+al)*sizeof(gr_complex)); return *d_output; } @@ -256,9 +290,12 @@ namespace gr { d_idx = 0; } - volk_32fc_x2_dot_prod_32fc_a(d_output, d_buffer, - d_aligned_taps, - ntaps()); + const gr_complex *ar = (gr_complex *)((unsigned long)(&d_buffer[d_idx]) & ~(d_align-1)); + unsigned al = (&d_buffer[d_idx]) - ar; + + volk_32fc_x2_dot_prod_32fc_a(d_output, ar, + d_aligned_taps[al], + (ntaps()+al)*sizeof(gr_complex)); return *d_output; } @@ -310,8 +347,13 @@ namespace gr { } // Free aligned taps - fft::free(d_aligned_taps); - d_aligned_taps = NULL; + if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } + fft::free(d_aligned_taps); + d_aligned_taps = NULL; + } // Free output sample fft::free(d_output); @@ -327,20 +369,27 @@ namespace gr { // Free the taps if already allocated if(d_aligned_taps != NULL) { + for(int i = 0; i < d_naligned; i++) { + fft::free(d_aligned_taps[i]); + } fft::free(d_aligned_taps); d_aligned_taps = NULL; } - d_buffer = fft::malloc_complex(d_ntaps); - d_ntaps = (int)taps.size(); d_taps = taps; std::reverse(d_taps.begin(), d_taps.end()); + d_buffer = fft::malloc_complex(2*d_ntaps); + memset(d_buffer, 0, 2*d_ntaps*sizeof(gr_complex)); + // Allocate aligned taps - d_aligned_taps = fft::malloc_float(d_ntaps); - for(unsigned int i = 0; i < d_ntaps; i++) { - d_aligned_taps[i] = d_taps[i]; + d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); + for(int i = 0; i < d_naligned; i++) { + d_aligned_taps[i] = fft::malloc_float(d_ntaps+d_naligned-1); + memset(d_aligned_taps[i], 0, sizeof(float)*(d_ntaps+d_naligned-1)); + for(unsigned int j = 0; j < d_ntaps; j++) + d_aligned_taps[i][i+j] = d_taps[j]; } d_idx = 0; @@ -364,9 +413,12 @@ namespace gr { if(d_idx >= ntaps()) d_idx = 0; - volk_32fc_32f_dot_prod_32fc_a(d_output, d_buffer, - d_aligned_taps, - ntaps()); + const gr_complex *ar = (gr_complex *)((unsigned long)(&d_buffer[d_idx]) & ~(d_align-1)); + unsigned al = (&d_buffer[d_idx]) - ar; + + volk_32fc_32f_dot_prod_32fc_a(d_output, ar, + d_aligned_taps[al], + ntaps()+al); return *d_output; } @@ -384,9 +436,12 @@ namespace gr { d_idx = 0; } - volk_32fc_32f_dot_prod_32fc_a(d_output, d_buffer, - d_aligned_taps, - ntaps()); + const gr_complex *ar = (gr_complex *)((unsigned long)(&d_buffer[d_idx]) & ~(d_align-1)); + unsigned al = (&d_buffer[d_idx]) - ar; + + volk_32fc_32f_dot_prod_32fc_a(d_output, ar, + d_aligned_taps[al], + ntaps()+al); return *d_output; } diff --git a/gr-filter/lib/qa_filter.cc b/gr-filter/lib/qa_filter.cc index 8aa24651c..b7760b19e 100644 --- a/gr-filter/lib/qa_filter.cc +++ b/gr-filter/lib/qa_filter.cc @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -36,6 +37,9 @@ qa_gr_filter::suite () CppUnit::TestSuite *s = new CppUnit::TestSuite ("gr-filter"); s->addTest(gr::filter::qa_firdes::suite()); + s->addTest(gr::filter::fff::qa_fir_filter_with_buffer_fff::suite()); + s->addTest(gr::filter::ccc::qa_fir_filter_with_buffer_ccc::suite()); + s->addTest(gr::filter::ccf::qa_fir_filter_with_buffer_ccf::suite()); s->addTest(gr::filter::qa_mmse_fir_interpolator_cc::suite()); s->addTest(gr::filter::qa_mmse_fir_interpolator_ff::suite()); diff --git a/gr-filter/lib/qa_fir_filter_with_buffer.cc b/gr-filter/lib/qa_fir_filter_with_buffer.cc new file mode 100644 index 000000000..c97e2479c --- /dev/null +++ b/gr-filter/lib/qa_fir_filter_with_buffer.cc @@ -0,0 +1,408 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + + +namespace gr { + namespace filter { + +#define MAX_DATA (16383) +#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 () * MAX_DATA); + float im = rint(uniform () * MAX_DATA); + buf[i] = gr_complex(re, im); + } + } + + namespace fff { + + typedef float i_type; + typedef float o_type; + typedef float tap_type; + typedef float acc_type; + + using std::vector; + + 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; + } + + void + qa_fir_filter_with_buffer_fff::t1() + { + test_decimate(1); + } + + void + qa_fir_filter_with_buffer_fff::t2() + { + test_decimate(2); + } + + void + qa_fir_filter_with_buffer_fff::t3() + { + test_decimate(5); + } + + // + // 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_fir_filter_with_buffer_fff::test_decimate(unsigned int decimate) + { + const int MAX_TAPS = 29; + const int OUTPUT_LEN = 37; + const int INPUT_LEN = MAX_TAPS + OUTPUT_LEN; + + // Mem aligned buffer not really necessary, but why not? + i_type *input = fft::malloc_float(INPUT_LEN); + i_type *dline = fft::malloc_float(INPUT_LEN); + o_type *expected_output = fft::malloc_float(OUTPUT_LEN); + o_type *actual_output = fft::malloc_float(OUTPUT_LEN); + tap_type *taps = fft::malloc_float(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++) { + + // 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 < (int)(ol/decimate); o++) { + // use an actual delay line for this test + for(int dd = 0; dd < (int)decimate; dd++) { + for(int oo = INPUT_LEN-1; oo > 0; oo--) + dline[oo] = dline[oo-1]; + dline[0] = input[decimate*o+dd]; + } + expected_output[o] = ref_dotprod(dline, taps, n); + } + + // build filter + vector f1_taps(&taps[0], &taps[n]); + kernel::fir_filter_with_buffer_fff *f1 = \ + new kernel::fir_filter_with_buffer_fff(f1_taps); + + // zero the output, then do the filtering + memset(actual_output, 0, sizeof(actual_output)); + f1->filterNdec(actual_output, input, ol/decimate, decimate); + + // 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 < (int)(ol/decimate); o++) { + CPPUNIT_ASSERT_DOUBLES_EQUAL(expected_output[o], actual_output[o], + sqrt((float)n)*0.25*MAX_DATA*MAX_DATA * ERR_DELTA); + } + delete f1; + } + } + fft::free(input); + fft::free(dline); + fft::free(expected_output); + fft::free(actual_output); + fft::free(taps); + } + + } /* namespace fff */ + + + /**************************************************************/ + + + namespace ccc { + + typedef gr_complex i_type; + typedef gr_complex o_type; + typedef gr_complex tap_type; + typedef gr_complex acc_type; + + using std::vector; + + 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; + } + + void + qa_fir_filter_with_buffer_ccc::t1() + { + test_decimate(1); + } + + void + qa_fir_filter_with_buffer_ccc::t2() + { + test_decimate(2); + } + + void + qa_fir_filter_with_buffer_ccc::t3() + { + test_decimate(5); + } + + // + // 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_fir_filter_with_buffer_ccc::test_decimate(unsigned int decimate) + { + const int MAX_TAPS = 29; + const int OUTPUT_LEN = 37; + const int INPUT_LEN = MAX_TAPS + OUTPUT_LEN; + + // Mem aligned buffer not really necessary, but why not? + i_type *input = fft::malloc_complex(INPUT_LEN); + i_type *dline = fft::malloc_complex(INPUT_LEN); + o_type *expected_output = fft::malloc_complex(OUTPUT_LEN); + o_type *actual_output = fft::malloc_complex(OUTPUT_LEN); + tap_type *taps = fft::malloc_complex(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++) { + + // 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 < (int)(ol/decimate); o++) { + // use an actual delay line for this test + for(int dd = 0; dd < (int)decimate; dd++) { + for(int oo = INPUT_LEN-1; oo > 0; oo--) + dline[oo] = dline[oo-1]; + dline[0] = input[decimate*o+dd]; + } + expected_output[o] = ref_dotprod(dline, taps, n); + } + + // build filter + vector f1_taps(&taps[0], &taps[n]); + kernel::fir_filter_with_buffer_ccc *f1 = \ + new kernel::fir_filter_with_buffer_ccc(f1_taps); + + // zero the output, then do the filtering + memset(actual_output, 0, sizeof(actual_output)); + f1->filterNdec(actual_output, input, ol/decimate, decimate); + + // 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 < (int)(ol/decimate); o++) { + CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected_output[o], actual_output[o], + sqrt((float)n)*0.25*MAX_DATA*MAX_DATA * ERR_DELTA); + } + delete f1; + } + } + fft::free(input); + fft::free(dline); + fft::free(expected_output); + fft::free(actual_output); + fft::free(taps); + } + + } /* namespace ccc */ + + + /**************************************************************/ + + namespace ccf { + + typedef gr_complex i_type; + typedef gr_complex o_type; + typedef float tap_type; + typedef gr_complex acc_type; + + using std::vector; + + 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 gr_complex(121,9)*sum; + return sum; + } + + void + qa_fir_filter_with_buffer_ccf::t1() + { + test_decimate(1); + } + + void + qa_fir_filter_with_buffer_ccf::t2() + { + test_decimate(2); + } + + void + qa_fir_filter_with_buffer_ccf::t3() + { + test_decimate(5); + } + + // + // 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_fir_filter_with_buffer_ccf::test_decimate(unsigned int decimate) + { + const int MAX_TAPS = 29; + const int OUTPUT_LEN = 37; + const int INPUT_LEN = MAX_TAPS + OUTPUT_LEN; + + // Mem aligned buffer not really necessary, but why not? + i_type *input = fft::malloc_complex(INPUT_LEN); + i_type *dline = fft::malloc_complex(INPUT_LEN); + o_type *expected_output = fft::malloc_complex(OUTPUT_LEN); + o_type *actual_output = fft::malloc_complex(OUTPUT_LEN); + tap_type *taps = fft::malloc_float(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++) { + + // 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 < (int)(ol/decimate); o++) { + // use an actual delay line for this test + for(int dd = 0; dd < (int)decimate; dd++) { + for(int oo = INPUT_LEN-1; oo > 0; oo--) + dline[oo] = dline[oo-1]; + dline[0] = input[decimate*o+dd]; + } + expected_output[o] = ref_dotprod(dline, taps, n); + } + + // build filter + vector f1_taps(&taps[0], &taps[n]); + kernel::fir_filter_with_buffer_ccf *f1 = \ + new kernel::fir_filter_with_buffer_ccf(f1_taps); + + // zero the output, then do the filtering + memset(actual_output, 0, sizeof(actual_output)); + f1->filterNdec(actual_output, input, ol/decimate, decimate); + + // 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 < (int)(ol/decimate); o++) { + CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected_output[o], actual_output[o], + sqrt((float)n)*0.25*MAX_DATA*MAX_DATA * ERR_DELTA); + } + delete f1; + } + } + fft::free(input); + fft::free(dline); + fft::free(expected_output); + fft::free(actual_output); + fft::free(taps); + } + + } /* namespace ccf */ + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/qa_fir_filter_with_buffer.h b/gr-filter/lib/qa_fir_filter_with_buffer.h new file mode 100644 index 000000000..8850ada20 --- /dev/null +++ b/gr-filter/lib/qa_fir_filter_with_buffer.h @@ -0,0 +1,94 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef _QA_FIR_FILTER_WITH_BUFFER_H_ +#define _QA_FIR_FILTER_WITH_BUFFER_H_ + +#include +#include + +namespace gr { + namespace filter { + + namespace fff { + + class qa_fir_filter_with_buffer_fff : public CppUnit::TestCase + { + CPPUNIT_TEST_SUITE(qa_fir_filter_with_buffer_fff); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST_SUITE_END(); + + private: + void test_decimate(unsigned int decimate); + + void t1(); + void t2(); + void t3(); + }; + + } /* namespace fff */ + + namespace ccc { + + class qa_fir_filter_with_buffer_ccc : public CppUnit::TestCase + { + CPPUNIT_TEST_SUITE(qa_fir_filter_with_buffer_ccc); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST_SUITE_END(); + + private: + void test_decimate(unsigned int decimate); + + void t1(); + void t2(); + void t3(); + }; + + } /* namespace ccc */ + + namespace ccf { + + class qa_fir_filter_with_buffer_ccf : public CppUnit::TestCase + { + CPPUNIT_TEST_SUITE(qa_fir_filter_with_buffer_ccf); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST_SUITE_END(); + + private: + void test_decimate(unsigned int decimate); + + void t1(); + void t2(); + void t3(); + }; + + } /* namespace ccf */ + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* _QA_FIR_FILTER_WITH_BUFFER_H_ */ -- cgit From f049a184c38a9344efea24ec813a13499237e23b Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 17 Jun 2012 21:49:35 -0400 Subject: filter: adding fractional_interpolator_{cc,ff} with QA and GRC. --- gr-filter/lib/CMakeLists.txt | 2 + gr-filter/lib/fractional_interpolator_cc_impl.cc | 125 +++++++++++++++++++++++ gr-filter/lib/fractional_interpolator_cc_impl.h | 61 +++++++++++ gr-filter/lib/fractional_interpolator_ff_impl.cc | 125 +++++++++++++++++++++++ gr-filter/lib/fractional_interpolator_ff_impl.h | 61 +++++++++++ 5 files changed, 374 insertions(+) create mode 100644 gr-filter/lib/fractional_interpolator_cc_impl.cc create mode 100644 gr-filter/lib/fractional_interpolator_cc_impl.h create mode 100644 gr-filter/lib/fractional_interpolator_ff_impl.cc create mode 100644 gr-filter/lib/fractional_interpolator_ff_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 97afe7139..334720766 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -122,6 +122,8 @@ list(APPEND filter_sources filter_delay_fc_impl.cc fft_filter_ccc_impl.cc fft_filter_fff_impl.cc + fractional_interpolator_cc_impl.cc + fractional_interpolator_ff_impl.cc hilbert_fc_impl.cc iir_filter_ffd_impl.cc pfb_channelizer_ccf_impl.cc diff --git a/gr-filter/lib/fractional_interpolator_cc_impl.cc b/gr-filter/lib/fractional_interpolator_cc_impl.cc new file mode 100644 index 000000000..8fd89f437 --- /dev/null +++ b/gr-filter/lib/fractional_interpolator_cc_impl.cc @@ -0,0 +1,125 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "fractional_interpolator_cc_impl.h" +#include + +namespace gr { + namespace filter { + + fractional_interpolator_cc::sptr + fractional_interpolator_cc::make(float phase_shift, float interp_ratio) + { + return gnuradio::get_initial_sptr( + new fractional_interpolator_cc_impl(phase_shift, interp_ratio)); + } + + fractional_interpolator_cc_impl::fractional_interpolator_cc_impl + (float phase_shift, float interp_ratio) + : gr_block("fractional_interpolator_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))), + d_mu (phase_shift), d_mu_inc (interp_ratio), + d_interp(new mmse_fir_interpolator_cc()) + { + if(interp_ratio <= 0) + throw std::out_of_range("interpolation ratio must be > 0"); + if(phase_shift < 0 || phase_shift > 1) + throw std::out_of_range("phase shift ratio must be > 0 and < 1"); + + set_relative_rate(1.0 / interp_ratio); + } + + fractional_interpolator_cc_impl::~fractional_interpolator_cc_impl() + { + delete d_interp; + } + + void + fractional_interpolator_cc_impl::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for(unsigned i=0; i < ninputs; i++) { + ninput_items_required[i] = + (int)ceil((noutput_items * d_mu_inc) + d_interp->ntaps()); + } + } + + int + fractional_interpolator_cc_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + int ii = 0; // input index + int oo = 0; // output index + + while(oo < noutput_items) { + out[oo++] = d_interp->interpolate(&in[ii], d_mu); + + double s = d_mu + d_mu_inc; + double f = floor(s); + int incr = (int)f; + d_mu = s - f; + ii += incr; + } + + consume_each(ii); + + return noutput_items; + } + + float + fractional_interpolator_cc_impl::mu() const + { + return d_mu; + } + + float + fractional_interpolator_cc_impl::interp_ratio() const + { + return d_mu_inc; + } + + void + fractional_interpolator_cc_impl::set_mu(float mu) + { + d_mu = mu; + } + + void + fractional_interpolator_cc_impl::set_interp_ratio(float interp_ratio) + { + d_mu_inc = interp_ratio; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/fractional_interpolator_cc_impl.h b/gr-filter/lib/fractional_interpolator_cc_impl.h new file mode 100644 index 000000000..cb4218603 --- /dev/null +++ b/gr-filter/lib/fractional_interpolator_cc_impl.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FRACTIONAL_INTERPOLATOR_CC_IMPL_H +#define INCLUDED_FRACTIONAL_INTERPOLATOR_CC_IMPL_H + +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API fractional_interpolator_cc_impl + : public fractional_interpolator_cc + { + private: + float d_mu; + float d_mu_inc; + mmse_fir_interpolator_cc *d_interp; + + public: + fractional_interpolator_cc_impl(float phase_shift, + float interp_ratio); + ~fractional_interpolator_cc_impl(); + + void forecast(int noutput_items, + gr_vector_int &ninput_items_required); + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + float mu() const; + float interp_ratio() const; + void set_mu(float mu); + void set_interp_ratio(float interp_ratio); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FRACTIONAL_INTERPOLATOR_CC_IMPL_H */ diff --git a/gr-filter/lib/fractional_interpolator_ff_impl.cc b/gr-filter/lib/fractional_interpolator_ff_impl.cc new file mode 100644 index 000000000..6b35dc106 --- /dev/null +++ b/gr-filter/lib/fractional_interpolator_ff_impl.cc @@ -0,0 +1,125 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,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 +#include "fractional_interpolator_ff_impl.h" +#include + +namespace gr { + namespace filter { + + fractional_interpolator_ff::sptr + fractional_interpolator_ff::make(float phase_shift, float interp_ratio) + { + return gnuradio::get_initial_sptr( + new fractional_interpolator_ff_impl(phase_shift, interp_ratio)); + } + + fractional_interpolator_ff_impl::fractional_interpolator_ff_impl + (float phase_shift, float interp_ratio) + : gr_block("fractional_interpolator_ff", + gr_make_io_signature(1, 1, sizeof(float)), + gr_make_io_signature(1, 1, sizeof(float))), + d_mu (phase_shift), d_mu_inc (interp_ratio), + d_interp(new mmse_fir_interpolator_ff()) + { + if(interp_ratio <= 0) + throw std::out_of_range("interpolation ratio must be > 0"); + if(phase_shift < 0 || phase_shift > 1) + throw std::out_of_range("phase shift ratio must be > 0 and < 1"); + + set_relative_rate(1.0 / interp_ratio); + } + + fractional_interpolator_ff_impl::~fractional_interpolator_ff_impl() + { + delete d_interp; + } + + void + fractional_interpolator_ff_impl::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for(unsigned i=0; i < ninputs; i++) { + ninput_items_required[i] = + (int)ceil((noutput_items * d_mu_inc) + d_interp->ntaps()); + } + } + + int + fractional_interpolator_ff_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *in = (const float*)input_items[0]; + float *out = (float*)output_items[0]; + + int ii = 0; // input index + int oo = 0; // output index + + while(oo < noutput_items) { + out[oo++] = d_interp->interpolate(&in[ii], d_mu); + + double s = d_mu + d_mu_inc; + double f = floor(s); + int incr = (int)f; + d_mu = s - f; + ii += incr; + } + + consume_each(ii); + + return noutput_items; + } + + float + fractional_interpolator_ff_impl::mu() const + { + return d_mu; + } + + float + fractional_interpolator_ff_impl::interp_ratio() const + { + return d_mu_inc; + } + + void + fractional_interpolator_ff_impl::set_mu(float mu) + { + d_mu = mu; + } + + void + fractional_interpolator_ff_impl::set_interp_ratio(float interp_ratio) + { + d_mu_inc = interp_ratio; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/fractional_interpolator_ff_impl.h b/gr-filter/lib/fractional_interpolator_ff_impl.h new file mode 100644 index 000000000..d31385cc4 --- /dev/null +++ b/gr-filter/lib/fractional_interpolator_ff_impl.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FRACTIONAL_INTERPOLATOR_FF_IMPL_H +#define INCLUDED_FRACTIONAL_INTERPOLATOR_FF_IMPL_H + +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API fractional_interpolator_ff_impl + : public fractional_interpolator_ff + { + private: + float d_mu; + float d_mu_inc; + mmse_fir_interpolator_ff *d_interp; + + public: + fractional_interpolator_ff_impl(float phase_shift, + float interp_ratio); + ~fractional_interpolator_ff_impl(); + + void forecast(int noutput_items, + gr_vector_int &ninput_items_required); + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + float mu() const; + float interp_ratio() const; + void set_mu(float mu); + void set_interp_ratio(float interp_ratio); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FRACTIONAL_INTERPOLATOR_FF_IMPL_H */ -- cgit From f5449ce2e0a665b725a27855cd94f28a976da792 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Mon, 18 Jun 2012 13:34:51 -0400 Subject: filter: added interp_fir_filter with QA and GRC. --- gr-filter/lib/CMakeLists.txt | 5 +- gr-filter/lib/fir_filter_XXX_impl.cc.t | 2 + gr-filter/lib/interp_fir_filter_XXX_impl.cc.t | 151 ++++++++++++++++++++++++++ gr-filter/lib/interp_fir_filter_XXX_impl.h.t | 62 +++++++++++ 4 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 gr-filter/lib/interp_fir_filter_XXX_impl.cc.t create mode 100644 gr-filter/lib/interp_fir_filter_XXX_impl.h.t (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 334720766..11135b864 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -80,8 +80,9 @@ endmacro(expand_cc) ######################################################################## # Invoke macro to generate various sources ######################################################################## -expand_cc(fir_filter_XXX_impl fff ccf ccc scc fsf) -expand_cc(freq_xlating_fir_filter_XXX_impl ccc ccf fcc fcf scc scf) +expand_cc(fir_filter_XXX_impl ccc ccf fcc fff fsf scc) +expand_cc(freq_xlating_fir_filter_XXX_impl ccc ccf fcc fcf scf scc) +expand_cc(interp_fir_filter_XXX_impl ccc ccf fcc fff fsf scc) ######################################################################## diff --git a/gr-filter/lib/fir_filter_XXX_impl.cc.t b/gr-filter/lib/fir_filter_XXX_impl.cc.t index 8ea8151f8..529c51e2b 100644 --- a/gr-filter/lib/fir_filter_XXX_impl.cc.t +++ b/gr-filter/lib/fir_filter_XXX_impl.cc.t @@ -20,6 +20,8 @@ * Boston, MA 02110-1301, USA. */ +/* @WARNING@ */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/gr-filter/lib/interp_fir_filter_XXX_impl.cc.t b/gr-filter/lib/interp_fir_filter_XXX_impl.cc.t new file mode 100644 index 000000000..c9127d737 --- /dev/null +++ b/gr-filter/lib/interp_fir_filter_XXX_impl.cc.t @@ -0,0 +1,151 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* @WARNING@ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "@IMPL_NAME@.h" +#include +#include +#include + +namespace gr { + namespace filter { + + @BASE_NAME@::sptr + @BASE_NAME@::make(unsigned interpolation, + const std::vector<@TAP_TYPE@> &taps) + { + return gnuradio::get_initial_sptr(new @IMPL_NAME@ + (interpolation, taps)); + } + + @IMPL_NAME@::@IMPL_NAME@(unsigned interpolation, + const std::vector<@TAP_TYPE@> &taps) + : gr_sync_interpolator("@BASE_NAME@", + gr_make_io_signature(1, 1, sizeof(@I_TYPE@)), + gr_make_io_signature(1, 1, sizeof(@O_TYPE@)), + interpolation), + d_updated(false), d_firs(interpolation) + { + if(interpolation == 0) { + throw std::out_of_range("@IMPL_NAME@: interpolation must be > 0\n"); + } + + std::vector<@TAP_TYPE@> dummy_taps; + + for(unsigned i = 0; i < interpolation; i++) { + d_firs[i] = new kernel::@FIR_TYPE@(1, dummy_taps); + } + + set_taps(taps); + install_taps(d_new_taps); + } + + @IMPL_NAME@::~@IMPL_NAME@() + { + for(unsigned i = 0; i < interpolation(); i++) { + delete d_firs[i]; + } + } + + void + @IMPL_NAME@::set_taps(const std::vector<@TAP_TYPE@> &taps) + { + d_new_taps = taps; + d_updated = true; + + // round up length to a multiple of the interpolation factor + int n = taps.size() % interpolation(); + if(n > 0) { + n = interpolation() - n; + while(n-- > 0) { + d_new_taps.insert(d_new_taps.begin(), 0); + } + } + + if(d_new_taps.size() % interpolation() != 0) { + throw std::runtime_error("@IMPL_NAME@: error setting interpolator taps.\n"); + } + } + + void + @IMPL_NAME@::install_taps(const std::vector<@TAP_TYPE@> &taps) + { + unsigned nfilters = interpolation(); + int nt = taps.size() / nfilters; + + std::vector< std::vector <@TAP_TYPE@> > xtaps(nfilters); + + for(unsigned n = 0; n < nfilters; n++) { + xtaps[n].resize (nt); + } + + for(size_t i = 0; i < taps.size(); i++) { + xtaps[i % nfilters][i / nfilters] = taps[i]; + } + + for(unsigned n = 0; n < nfilters; n++) { + d_firs[n]->set_taps (xtaps[n]); + } + + set_history(nt); + d_updated = false; + } + + std::vector<@TAP_TYPE@> + @IMPL_NAME@::taps() const + { + return d_new_taps; + } + + int + @NAME@::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const @I_TYPE@ *in = (const @I_TYPE@ *)input_items[0]; + @O_TYPE@ *out = (@O_TYPE@ *)output_items[0]; + + if(d_updated) { + install_taps(d_new_taps); + return 0; // history requirements may have changed. + } + + int nfilters = interpolation(); + int ni = noutput_items / interpolation(); + + for(int i = 0; i < ni; i++) { + for(int nf = 0; nf < nfilters; nf++) { + out[nf] = d_firs[nf]->filter(&in[i]); + } + out += nfilters; + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/interp_fir_filter_XXX_impl.h.t b/gr-filter/lib/interp_fir_filter_XXX_impl.h.t new file mode 100644 index 000000000..e505fca69 --- /dev/null +++ b/gr-filter/lib/interp_fir_filter_XXX_impl.h.t @@ -0,0 +1,62 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* @WARNING@ */ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API @IMPL_NAME@ : public @BASE_NAME@ + { + private: + bool d_updated; + std::vector d_firs; + std::vector<@TAP_TYPE@> d_new_taps; + + void install_taps(const std::vector<@TAP_TYPE@> &taps); + + public: + @IMPL_NAME@(unsigned interpolation, + const std::vector<@TAP_TYPE@> &taps); + + ~@IMPL_NAME@(); + + void set_taps(const std::vector<@TAP_TYPE@> &taps); + std::vector<@TAP_TYPE@> taps() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* @GUARD_NAME@ */ -- cgit From 622464a324abc90f2724d3f846f0b1bdb38b97fc Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Mon, 18 Jun 2012 14:37:49 -0400 Subject: filter: adding PFB decimator with GRC and QA. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/pfb_channelizer_ccf_impl.h | 1 + gr-filter/lib/pfb_decimator_ccf_impl.cc | 137 +++++++++++++++++++++++++++++++ gr-filter/lib/pfb_decimator_ccf_impl.h | 65 +++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 gr-filter/lib/pfb_decimator_ccf_impl.cc create mode 100644 gr-filter/lib/pfb_decimator_ccf_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 11135b864..40faa8f0e 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -128,6 +128,7 @@ list(APPEND filter_sources hilbert_fc_impl.cc iir_filter_ffd_impl.cc pfb_channelizer_ccf_impl.cc + pfb_decimator_ccf_impl.cc single_pole_iir_filter_cc_impl.cc single_pole_iir_filter_ff_impl.cc ) diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.h b/gr-filter/lib/pfb_channelizer_ccf_impl.h index 8cabc4e34..16b112b9a 100644 --- a/gr-filter/lib/pfb_channelizer_ccf_impl.h +++ b/gr-filter/lib/pfb_channelizer_ccf_impl.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace gr { namespace filter { diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.cc b/gr-filter/lib/pfb_decimator_ccf_impl.cc new file mode 100644 index 000000000..139cd9bec --- /dev/null +++ b/gr-filter/lib/pfb_decimator_ccf_impl.cc @@ -0,0 +1,137 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pfb_decimator_ccf_impl.h" +#include + +namespace gr { + namespace filter { + + pfb_decimator_ccf::sptr + pfb_decimator_ccf::make(unsigned int nfilts, + const std::vector &taps, + unsigned int channel) + { + return gnuradio::get_initial_sptr + (new pfb_decimator_ccf_impl(nfilts, taps, channel)); + } + + + pfb_decimator_ccf_impl::pfb_decimator_ccf_impl(unsigned int decim, + const std::vector &taps, + unsigned int channel) + : gr_sync_block("pfb_decimator_ccf", + gr_make_io_signature(decim, decim, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))), + polyphase_filterbank(decim, taps), + d_updated(false), d_chan(channel) + { + d_rate = decim; + d_rotator = new gr_complex[d_rate]; + + set_relative_rate(1.0/(float)decim); + set_history(d_taps_per_filter+1); + } + + pfb_decimator_ccf_impl::~pfb_decimator_ccf_impl() + { + } + + void + pfb_decimator_ccf_impl::set_taps(const std::vector &taps) + { + gruel::scoped_lock guard(d_mutex); + + polyphase_filterbank::set_taps(taps); + set_history(d_taps_per_filter+1); + d_updated = true; + } + + void + pfb_decimator_ccf_impl::print_taps() + { + polyphase_filterbank::print_taps(); + } + + std::vector > + pfb_decimator_ccf_impl::taps() const + { + return polyphase_filterbank::taps(); + } + +#define ROTATEFFT + + int + pfb_decimator_ccf_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gruel::scoped_lock guard(d_mutex); + + gr_complex *in; + gr_complex *out = (gr_complex *)output_items[0]; + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + int i; + for(i = 0; i < noutput_items; i++) { + // Move through filters from bottom to top + out[i] = 0; + for(int j = d_rate-1; j >= 0; j--) { + // Take in the items from the first input stream to d_rate + in = (gr_complex*)input_items[d_rate - 1 - j]; + + // Filter current input stream from bottom filter to top + // The rotate them by expj(j*k*2pi/M) where M is the number of filters + // (the decimation rate) and k is the channel number to extract + + // This is the real math that goes on; we abuse the FFT to do this quickly + // for decimation rates > N where N is a small number (~5): + // out[i] += d_filters[j]->filter(&in[i])*gr_expj(j*d_chan*2*M_PI/d_rate); +#ifdef ROTATEFFT + d_fft->get_inbuf()[j] = d_filters[j]->filter(&in[i]); +#else + out[i] += d_filters[j]->filter(&in[i])*d_rotator[i]; +#endif + } + +#ifdef ROTATEFFT + // Perform the FFT to do the complex multiply despinning for all channels + d_fft->execute(); + + // Select only the desired channel out + out[i] = d_fft->get_outbuf()[d_chan]; +#endif + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.h b/gr-filter/lib/pfb_decimator_ccf_impl.h new file mode 100644 index 000000000..c4338a5ec --- /dev/null +++ b/gr-filter/lib/pfb_decimator_ccf_impl.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_PFB_DECIMATOR_CCF_IMPL_H +#define INCLUDED_PFB_DECIMATOR_CCF_IMPL_H + +#include +#include +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API pfb_decimator_ccf_impl : public pfb_decimator_ccf, kernel::polyphase_filterbank + { + private: + bool d_updated; + unsigned int d_rate; + unsigned int d_chan; + gr_complex *d_rotator; + gruel::mutex d_mutex; // mutex to protect set/work access + + public: + pfb_decimator_ccf_impl(unsigned int decim, + const std::vector &taps, + unsigned int channel); + + ~pfb_decimator_ccf_impl(); + + void set_taps(const std::vector &taps); + void print_taps(); + std::vector > taps() const; + //void set_channel(unsigned int channel); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_PFB_DECIMATOR_CCF_IMPL_H */ -- cgit From 5365daf7ae85c9df88f0b8f3667ece022d93f637 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Mon, 18 Jun 2012 15:42:14 -0400 Subject: filter: adding PFB interpolator with GRC and QA. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/pfb_decimator_ccf_impl.cc | 4 +- gr-filter/lib/pfb_interpolator_ccf_impl.cc | 107 +++++++++++++++++++++++++++++ gr-filter/lib/pfb_interpolator_ccf_impl.h | 61 ++++++++++++++++ 4 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 gr-filter/lib/pfb_interpolator_ccf_impl.cc create mode 100644 gr-filter/lib/pfb_interpolator_ccf_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 40faa8f0e..d1ddd2a92 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -129,6 +129,7 @@ list(APPEND filter_sources iir_filter_ffd_impl.cc pfb_channelizer_ccf_impl.cc pfb_decimator_ccf_impl.cc + pfb_interpolator_ccf_impl.cc single_pole_iir_filter_cc_impl.cc single_pole_iir_filter_ff_impl.cc ) diff --git a/gr-filter/lib/pfb_decimator_ccf_impl.cc b/gr-filter/lib/pfb_decimator_ccf_impl.cc index 139cd9bec..f9a60cb28 100644 --- a/gr-filter/lib/pfb_decimator_ccf_impl.cc +++ b/gr-filter/lib/pfb_decimator_ccf_impl.cc @@ -31,12 +31,12 @@ namespace gr { namespace filter { pfb_decimator_ccf::sptr - pfb_decimator_ccf::make(unsigned int nfilts, + pfb_decimator_ccf::make(unsigned int decim, const std::vector &taps, unsigned int channel) { return gnuradio::get_initial_sptr - (new pfb_decimator_ccf_impl(nfilts, taps, channel)); + (new pfb_decimator_ccf_impl(decim, taps, channel)); } diff --git a/gr-filter/lib/pfb_interpolator_ccf_impl.cc b/gr-filter/lib/pfb_interpolator_ccf_impl.cc new file mode 100644 index 000000000..572db728b --- /dev/null +++ b/gr-filter/lib/pfb_interpolator_ccf_impl.cc @@ -0,0 +1,107 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pfb_interpolator_ccf_impl.h" +#include + +namespace gr { + namespace filter { + + pfb_interpolator_ccf::sptr + pfb_interpolator_ccf::make(unsigned int interp, + const std::vector &taps) + { + return gnuradio::get_initial_sptr + (new pfb_interpolator_ccf_impl(interp, taps)); + } + + + pfb_interpolator_ccf_impl::pfb_interpolator_ccf_impl(unsigned int interp, + const std::vector &taps) + : gr_sync_interpolator("pfb_interpolator_ccf", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + interp), + polyphase_filterbank(interp, taps), + d_updated (false), d_rate(interp) + { + set_history(d_taps_per_filter+1); + } + + pfb_interpolator_ccf_impl::~pfb_interpolator_ccf_impl() + { + } + + void + pfb_interpolator_ccf_impl::set_taps(const std::vector &taps) + { + gruel::scoped_lock guard(d_mutex); + + polyphase_filterbank::set_taps(taps); + set_history(d_taps_per_filter+1); + d_updated = true; + } + + void + pfb_interpolator_ccf_impl::print_taps() + { + polyphase_filterbank::print_taps(); + } + + std::vector > + pfb_interpolator_ccf_impl::taps() const + { + return polyphase_filterbank::taps(); + } + + int + pfb_interpolator_ccf_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr_complex *in = (gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + int i = 0, count = 0; + + while(i < noutput_items) { + for(unsigned int j = 0; j < d_rate; j++) { + out[i] = d_filters[j]->filter(&in[count]); + i++; + } + count++; + } + + return i; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/pfb_interpolator_ccf_impl.h b/gr-filter/lib/pfb_interpolator_ccf_impl.h new file mode 100644 index 000000000..7e1fe2ca1 --- /dev/null +++ b/gr-filter/lib/pfb_interpolator_ccf_impl.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_PFB_INTERPOLATOR_CCF_IMPL_H +#define INCLUDED_PFB_INTERPOLATOR_CCF_IMPL_H + +#include +#include +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API pfb_interpolator_ccf_impl : public pfb_interpolator_ccf, kernel::polyphase_filterbank + { + private: + bool d_updated; + unsigned int d_rate; + gruel::mutex d_mutex; // mutex to protect set/work access + + public: + pfb_interpolator_ccf_impl(unsigned int interp, + const std::vector &taps); + + ~pfb_interpolator_ccf_impl(); + + void set_taps(const std::vector &taps); + void print_taps(); + std::vector > taps() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_PFB_INTERPOLATOR_CCF_IMPL_H */ -- cgit From e5aead883b8bf82cb0ebd63e825b99b5172048cd Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 19 Jun 2012 00:07:58 -0400 Subject: filter: adding PFB arbitrary resampler (ccf and fff) with GRC and QA. --- gr-filter/lib/CMakeLists.txt | 2 + gr-filter/lib/pfb_arb_resampler_ccf_impl.cc | 235 +++++++++++++++++++++++++++ gr-filter/lib/pfb_arb_resampler_ccf_impl.h | 86 ++++++++++ gr-filter/lib/pfb_arb_resampler_fff_impl.cc | 237 ++++++++++++++++++++++++++++ gr-filter/lib/pfb_arb_resampler_fff_impl.h | 85 ++++++++++ 5 files changed, 645 insertions(+) create mode 100644 gr-filter/lib/pfb_arb_resampler_ccf_impl.cc create mode 100644 gr-filter/lib/pfb_arb_resampler_ccf_impl.h create mode 100644 gr-filter/lib/pfb_arb_resampler_fff_impl.cc create mode 100644 gr-filter/lib/pfb_arb_resampler_fff_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index d1ddd2a92..8077baf9c 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -127,6 +127,8 @@ list(APPEND filter_sources fractional_interpolator_ff_impl.cc hilbert_fc_impl.cc iir_filter_ffd_impl.cc + pfb_arb_resampler_ccf_impl.cc + pfb_arb_resampler_fff_impl.cc pfb_channelizer_ccf_impl.cc pfb_decimator_ccf_impl.cc pfb_interpolator_ccf_impl.cc diff --git a/gr-filter/lib/pfb_arb_resampler_ccf_impl.cc b/gr-filter/lib/pfb_arb_resampler_ccf_impl.cc new file mode 100644 index 000000000..bb0906aa5 --- /dev/null +++ b/gr-filter/lib/pfb_arb_resampler_ccf_impl.cc @@ -0,0 +1,235 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pfb_arb_resampler_ccf_impl.h" +#include +#include + +namespace gr { + namespace filter { + + pfb_arb_resampler_ccf::sptr + pfb_arb_resampler_ccf::make(float rate, + const std::vector &taps, + unsigned int filter_size) + { + return gnuradio::get_initial_sptr + (new pfb_arb_resampler_ccf_impl(rate, taps, filter_size)); + } + + + pfb_arb_resampler_ccf_impl::pfb_arb_resampler_ccf_impl(float rate, + const std::vector &taps, + unsigned int filter_size) + : gr_block("pfb_arb_resampler_ccf", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))), + d_updated (false) + { + d_acc = 0; // start accumulator at 0 + + /* The number of filters is specified by the user as the filter + size; this is also the interpolation rate of the filter. We + use it and the rate provided to determine the decimation + rate. This acts as a rational resampler. The flt_rate is + calculated as the residual between the integer decimation + rate and the real decimation rate and will be used to + determine to interpolation point of the resampling process. + */ + d_int_rate = filter_size; + set_rate(rate); + + // Store the last filter between calls to work + d_last_filter = 0; + + d_start_index = 0; + + d_filters = std::vector(d_int_rate); + d_diff_filters = std::vector(d_int_rate); + + // Create an FIR filter for each channel and zero out the taps + std::vector vtaps(0, d_int_rate); + for(unsigned int i = 0; i < d_int_rate; i++) { + d_filters[i] = new kernel::fir_filter_ccf(1, vtaps); + d_diff_filters[i] = new kernel::fir_filter_ccf(1, vtaps); + } + + // Now, actually set the filters' taps + std::vector dtaps; + create_diff_taps(taps, dtaps); + create_taps(taps, d_taps, d_filters); + create_taps(dtaps, d_dtaps, d_diff_filters); + } + + pfb_arb_resampler_ccf_impl::~pfb_arb_resampler_ccf_impl() + { + for(unsigned int i = 0; i < d_int_rate; i++) { + delete d_filters[i]; + delete d_diff_filters[i]; + } + } + + void + pfb_arb_resampler_ccf_impl::create_taps(const std::vector &newtaps, + std::vector< std::vector > &ourtaps, + std::vector &ourfilter) + { + unsigned int ntaps = newtaps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate); + + // Create d_numchan vectors to store each channel's taps + ourtaps.resize(d_int_rate); + + // Make a vector of the taps plus fill it out with 0's to fill + // each polyphase filter with exactly d_taps_per_filter + std::vector tmp_taps; + tmp_taps = newtaps; + while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(unsigned int i = 0; i < d_int_rate; i++) { + // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out + ourtaps[d_int_rate-1-i] = std::vector(d_taps_per_filter, 0); + for(unsigned int j = 0; j < d_taps_per_filter; j++) { + ourtaps[d_int_rate - 1 - i][j] = tmp_taps[i + j*d_int_rate]; + } + + // Build a filter for each channel and add it's taps to it + ourfilter[i]->set_taps(ourtaps[d_int_rate-1-i]); + } + + // Set the history to ensure enough input items for each filter + set_history (d_taps_per_filter + 1); + + d_updated = true; + } + + void + pfb_arb_resampler_ccf_impl::create_diff_taps(const std::vector &newtaps, + std::vector &difftaps) + { + // Calculate the differential taps (derivative filter) by taking the difference + // between two taps. Duplicate the last one to make both filters the same length. + float tap; + difftaps.clear(); + for(unsigned int i = 0; i < newtaps.size()-1; i++) { + tap = newtaps[i+1] - newtaps[i]; + difftaps.push_back(tap); + } + difftaps.push_back(tap); + } + + void + pfb_arb_resampler_ccf_impl::set_taps(const std::vector &taps) + { + gruel::scoped_lock guard(d_mutex); + } + + std::vector > + pfb_arb_resampler_ccf_impl::taps() const + { + return d_taps; + } + + void + pfb_arb_resampler_ccf_impl::print_taps() + { + unsigned int i, j; + for(i = 0; i < d_int_rate; i++) { + printf("filter[%d]: [", i); + for(j = 0; j < d_taps_per_filter; j++) { + printf(" %.4e", d_taps[i][j]); + } + printf("]\n"); + } + } + + void + pfb_arb_resampler_ccf_impl::set_rate(float rate) + { + d_dec_rate = (unsigned int)floor(d_int_rate/rate); + d_flt_rate = (d_int_rate/rate) - d_dec_rate; + set_relative_rate(rate); + } + + int + pfb_arb_resampler_ccf_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr_complex *in = (gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + int i = 0, count = d_start_index; + unsigned int j; + gr_complex o0, o1; + + // Restore the last filter position + j = d_last_filter; + + // produce output as long as we can and there are enough input samples + int max_input = ninput_items[0] - (int)d_taps_per_filter; + while((i < noutput_items) && (count < max_input)) { + // start j by wrapping around mod the number of channels + while((j < d_int_rate) && (i < noutput_items)) { + // Take the current filter and derivative filter output + o0 = d_filters[j]->filter(&in[count]); + o1 = d_diff_filters[j]->filter(&in[count]); + + out[i] = o0 + o1*d_acc; // linearly interpolate between samples + i++; + + // Adjust accumulator and index into filterbank + d_acc += d_flt_rate; + j += d_dec_rate + (int)floor(d_acc); + d_acc = fmodf(d_acc, 1.0); + } + if(i < noutput_items) { // keep state for next entry + float ss = (int)(j / d_int_rate); // number of items to skip ahead by + count += ss; // we have fully consumed another input + j = j % d_int_rate; // roll filter around + } + } + + // Store the current filter position and start of next sample + d_last_filter = j; + d_start_index = std::max(0, count - ninput_items[0]); + + // consume all we've processed but no more than we can + consume_each(std::min(count, ninput_items[0])); + return i; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/pfb_arb_resampler_ccf_impl.h b/gr-filter/lib/pfb_arb_resampler_ccf_impl.h new file mode 100644 index 000000000..8e7e993cb --- /dev/null +++ b/gr-filter/lib/pfb_arb_resampler_ccf_impl.h @@ -0,0 +1,86 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_PFB_ARB_RESAMPLER_CCF_IMPL_H +#define INCLUDED_PFB_ARB_RESAMPLER_CCF_IMPL_H + +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API pfb_arb_resampler_ccf_impl : public pfb_arb_resampler_ccf + { + private: + std::vector d_filters; + std::vector d_diff_filters; + std::vector< std::vector > d_taps; + std::vector< std::vector > d_dtaps; + unsigned int d_int_rate; // the number of filters (interpolation rate) + unsigned int d_dec_rate; // the stride through the filters (decimation rate) + float d_flt_rate; // residual rate for the linear interpolation + float d_acc; + unsigned int d_last_filter; + int d_start_index; + unsigned int d_taps_per_filter; + bool d_updated; + gruel::mutex d_mutex; // mutex to protect set/work access + + void create_diff_taps(const std::vector &newtaps, + std::vector &difftaps); + + /*! + * Resets the filterbank's filter taps with the new prototype filter + * \param newtaps (vector of floats) The prototype filter to populate the filterbank. + * The taps should be generated at the interpolated sampling rate. + * \param ourtaps (vector of floats) Reference to our internal member of holding the taps. + * \param ourfilter (vector of filters) Reference to our internal filter to set the taps for. + */ + void create_taps(const std::vector &newtaps, + std::vector< std::vector > &ourtaps, + std::vector &ourfilter); + + public: + pfb_arb_resampler_ccf_impl(float rate, + const std::vector &taps, + unsigned int filter_size); + + ~pfb_arb_resampler_ccf_impl(); + + void set_taps(const std::vector &taps); + std::vector > taps() const; + void print_taps(); + void set_rate(float rate); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_PFB_ARB_RESAMPLER_CCF_IMPL_H */ diff --git a/gr-filter/lib/pfb_arb_resampler_fff_impl.cc b/gr-filter/lib/pfb_arb_resampler_fff_impl.cc new file mode 100644 index 000000000..79c19655a --- /dev/null +++ b/gr-filter/lib/pfb_arb_resampler_fff_impl.cc @@ -0,0 +1,237 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pfb_arb_resampler_fff_impl.h" +#include +#include + +namespace gr { + namespace filter { + + pfb_arb_resampler_fff::sptr + pfb_arb_resampler_fff::make(float rate, + const std::vector &taps, + unsigned int filter_size) + { + return gnuradio::get_initial_sptr + (new pfb_arb_resampler_fff_impl(rate, taps, filter_size)); + } + + + pfb_arb_resampler_fff_impl::pfb_arb_resampler_fff_impl(float rate, + const std::vector &taps, + unsigned int filter_size) + : gr_block("pfb_arb_resampler_fff", + gr_make_io_signature(1, 1, sizeof(float)), + gr_make_io_signature(1, 1, sizeof(float))), + d_updated(false) + { + d_acc = 0; // start accumulator at 0 + + /* The number of filters is specified by the user as the filter + size; this is also the interpolation rate of the filter. We + use it and the rate provided to determine the decimation + rate. This acts as a rational resampler. The flt_rate is + calculated as the residual between the integer decimation + rate and the real decimation rate and will be used to + determine to interpolation point of the resampling process. + */ + d_int_rate = filter_size; + set_rate(rate); + + // Store the last filter between calls to work + d_last_filter = 0; + + d_start_index = 0; + + d_filters = std::vector(d_int_rate); + d_diff_filters = std::vector(d_int_rate); + + // Create an FIR filter for each channel and zero out the taps + std::vector vtaps(0, d_int_rate); + for(unsigned int i = 0; i < d_int_rate; i++) { + d_filters[i] = new kernel::fir_filter_fff(1, vtaps); + d_diff_filters[i] = new kernel::fir_filter_fff(1, vtaps); + } + + // Now, actually set the filters' taps + std::vector dtaps; + create_diff_taps(taps, dtaps); + create_taps(taps, d_taps, d_filters); + create_taps(dtaps, d_dtaps, d_diff_filters); + } + + pfb_arb_resampler_fff_impl::~pfb_arb_resampler_fff_impl() + { + for(unsigned int i = 0; i < d_int_rate; i++) { + delete d_filters[i]; + delete d_diff_filters[i]; + } + } + + void + pfb_arb_resampler_fff_impl::create_taps(const std::vector &newtaps, + std::vector< std::vector > &ourtaps, + std::vector &ourfilter) + { + unsigned int ntaps = newtaps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_int_rate); + + // Create d_numchan vectors to store each channel's taps + ourtaps.resize(d_int_rate); + + // Make a vector of the taps plus fill it out with 0's to fill + // each polyphase filter with exactly d_taps_per_filter + std::vector tmp_taps; + tmp_taps = newtaps; + while((float)(tmp_taps.size()) < d_int_rate*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(unsigned int i = 0; i < d_int_rate; i++) { + // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out + ourtaps[d_int_rate-1-i] = std::vector(d_taps_per_filter, 0); + for(unsigned int j = 0; j < d_taps_per_filter; j++) { + ourtaps[d_int_rate - 1 - i][j] = tmp_taps[i + j*d_int_rate]; + } + + // Build a filter for each channel and add it's taps to it + ourfilter[i]->set_taps(ourtaps[d_int_rate-1-i]); + } + + // Set the history to ensure enough input items for each filter + set_history(d_taps_per_filter + 1); + + d_updated = true; + } + + void + pfb_arb_resampler_fff_impl::create_diff_taps(const std::vector &newtaps, + std::vector &difftaps) + { + // Calculate the differential taps (derivative filter) by taking the difference + // between two taps. Duplicate the last one to make both filters the same length. + float tap; + difftaps.clear(); + for(unsigned int i = 0; i < newtaps.size()-1; i++) { + tap = newtaps[i+1] - newtaps[i]; + difftaps.push_back(tap); + } + difftaps.push_back(tap); + } + + void + pfb_arb_resampler_fff_impl::set_taps(const std::vector &taps) + { + gruel::scoped_lock guard(d_mutex); + } + + std::vector > + pfb_arb_resampler_fff_impl::taps() const + { + return d_taps; + } + + void + pfb_arb_resampler_fff_impl::print_taps() + { + unsigned int i, j; + for(i = 0; i < d_int_rate; i++) { + printf("filter[%d]: [", i); + for(j = 0; j < d_taps_per_filter; j++) { + printf(" %.4e", d_taps[i][j]); + } + printf("]\n"); + } + } + + void + pfb_arb_resampler_fff_impl::set_rate(float rate) + { + d_dec_rate = (unsigned int)floor(d_int_rate/rate); + d_flt_rate = (d_int_rate/rate) - d_dec_rate; + set_relative_rate(rate); + } + + int + pfb_arb_resampler_fff_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gruel::scoped_lock guard(d_mutex); + + float *in = (float*)input_items[0]; + float *out = (float*)output_items[0]; + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + int i = 0, count = d_start_index; + unsigned int j; + float o0, o1; + + // Restore the last filter position + j = d_last_filter; + + // produce output as long as we can and there are enough input samples + int max_input = ninput_items[0] - (int)d_taps_per_filter; + while((i < noutput_items) && (count < max_input)) { + // start j by wrapping around mod the number of channels + while((j < d_int_rate) && (i < noutput_items)) { + // Take the current filter and derivative filter output + o0 = d_filters[j]->filter(&in[count]); + o1 = d_diff_filters[j]->filter(&in[count]); + + out[i] = o0 + o1*d_acc; // linearly interpolate between samples + i++; + + // Adjust accumulator and index into filterbank + d_acc += d_flt_rate; + j += d_dec_rate + (int)floor(d_acc); + d_acc = fmodf(d_acc, 1.0); + } + if(i < noutput_items) { // keep state for next entry + float ss = (int)(j / d_int_rate); // number of items to skip ahead by + count += ss; // we have fully consumed another input + j = j % d_int_rate; // roll filter around + } + } + + // Store the current filter position and start of next sample + d_last_filter = j; + d_start_index = std::max(0, count - ninput_items[0]); + + // consume all we've processed but no more than we can + consume_each(std::min(count, ninput_items[0])); + return i; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/pfb_arb_resampler_fff_impl.h b/gr-filter/lib/pfb_arb_resampler_fff_impl.h new file mode 100644 index 000000000..54e01375a --- /dev/null +++ b/gr-filter/lib/pfb_arb_resampler_fff_impl.h @@ -0,0 +1,85 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_PFB_ARB_RESAMPLER_FFF_IMPL_H +#define INCLUDED_PFB_ARB_RESAMPLER_FFF_IMPL_H + +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API pfb_arb_resampler_fff_impl : public pfb_arb_resampler_fff + { + private: + std::vector d_filters; + std::vector d_diff_filters; + std::vector< std::vector > d_taps; + std::vector< std::vector > d_dtaps; + unsigned int d_int_rate; // the number of filters (interpolation rate) + unsigned int d_dec_rate; // the stride through the filters (decimation rate) + float d_flt_rate; // residual rate for the linear interpolation + float d_acc; + unsigned int d_last_filter; + int d_start_index; + unsigned int d_taps_per_filter; + bool d_updated; + gruel::mutex d_mutex; // mutex to protect set/work access + + void create_diff_taps(const std::vector &newtaps, + std::vector &difftaps); + + /*! + * Resets the filterbank's filter taps with the new prototype filter + * \param newtaps (vector of floats) The prototype filter to populate the filterbank. + * The taps should be generated at the interpolated sampling rate. + * \param ourtaps (vector of floats) Reference to our internal member of holding the taps. + * \param ourfilter (vector of filters) Reference to our internal filter to set the taps for. + */ + void create_taps(const std::vector &newtaps, + std::vector< std::vector > &ourtaps, + std::vector &ourfilter); + public: + pfb_arb_resampler_fff_impl(float rate, + const std::vector &taps, + unsigned int filter_size); + + ~pfb_arb_resampler_fff_impl(); + + void set_taps(const std::vector &taps); + std::vector > taps() const; + void print_taps(); + void set_rate(float rate); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_PFB_ARB_RESAMPLER_FFF_IMPL_H */ -- cgit From 5ab78aaeedb87f4a30c41dd9e7ede56b5dc01d04 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 19 Jun 2012 18:10:59 -0400 Subject: filter: adding rational resampler with GRC and QA. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/fir_filter_XXX_impl.h.t | 1 - .../lib/rational_resampler_base_XXX_impl.cc.t | 174 +++++++++++++++++++++ gr-filter/lib/rational_resampler_base_XXX_impl.h.t | 72 +++++++++ 4 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 gr-filter/lib/rational_resampler_base_XXX_impl.cc.t create mode 100644 gr-filter/lib/rational_resampler_base_XXX_impl.h.t (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 8077baf9c..b3d456ec9 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -83,6 +83,7 @@ endmacro(expand_cc) expand_cc(fir_filter_XXX_impl ccc ccf fcc fff fsf scc) expand_cc(freq_xlating_fir_filter_XXX_impl ccc ccf fcc fcf scf scc) expand_cc(interp_fir_filter_XXX_impl ccc ccf fcc fff fsf scc) +expand_cc(rational_resampler_base_XXX_impl ccc ccf fcc fff fsf scc) ######################################################################## diff --git a/gr-filter/lib/fir_filter_XXX_impl.h.t b/gr-filter/lib/fir_filter_XXX_impl.h.t index d5bf7104d..ef0a7adfe 100644 --- a/gr-filter/lib/fir_filter_XXX_impl.h.t +++ b/gr-filter/lib/fir_filter_XXX_impl.h.t @@ -25,7 +25,6 @@ #ifndef @GUARD_NAME@ #define @GUARD_NAME@ -#include #include #include diff --git a/gr-filter/lib/rational_resampler_base_XXX_impl.cc.t b/gr-filter/lib/rational_resampler_base_XXX_impl.cc.t new file mode 100644 index 000000000..2e9161eeb --- /dev/null +++ b/gr-filter/lib/rational_resampler_base_XXX_impl.cc.t @@ -0,0 +1,174 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* @WARNING@ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "@IMPL_NAME@.h" +#include +#include +#include + +namespace gr { + namespace filter { + + @BASE_NAME@::sptr + @BASE_NAME@::make(unsigned interpolation, + unsigned decimation, + const std::vector<@TAP_TYPE@> &taps) + { + return gnuradio::get_initial_sptr + (new @IMPL_NAME@(interpolation, decimation, taps)); + } + + @IMPL_NAME@::@IMPL_NAME@(unsigned interpolation, + unsigned decimation, + const std::vector<@TAP_TYPE@> &taps) + : gr_block("@BASE_NAME@", + gr_make_io_signature(1, 1, sizeof(@I_TYPE@)), + gr_make_io_signature(1, 1, sizeof(@O_TYPE@))), + d_history(1), + d_interpolation(interpolation), + d_decimation(decimation), + d_ctr(0), + d_firs(interpolation), + d_updated(false) + { + if(interpolation == 0) + throw std::out_of_range("@IMPL_NAME@: interpolation must be > 0"); + if(decimation == 0) + throw std::out_of_range("@IMPL_NAME@: decimation must be > 0"); + + set_relative_rate(1.0 * interpolation / decimation); + set_output_multiple(1); + + std::vector<@TAP_TYPE@> dummy_taps; + + for(unsigned i = 0; i < interpolation; i++) { + d_firs[i] = new kernel::@FIR_TYPE@(1, dummy_taps); + } + + set_taps(taps); + install_taps(d_new_taps); + } + + @IMPL_NAME@::~@IMPL_NAME@() + { + int interp = interpolation(); + for(int i = 0; i < interp; i++) { + delete d_firs[i]; + } + } + + void + @IMPL_NAME@::set_taps(const std::vector<@TAP_TYPE@> &taps) + { + d_new_taps = taps; + d_updated = true; + + // round up length to a multiple of the interpolation factor + int n = taps.size() % interpolation(); + if(n > 0) { + n = interpolation() - n; + while(n-- > 0) { + d_new_taps.insert(d_new_taps.begin(), 0); + } + } + + assert(d_new_taps.size() % interpolation() == 0); + } + + void + @IMPL_NAME@::install_taps(const std::vector<@TAP_TYPE@> &taps) + { + int nfilters = interpolation(); + int nt = taps.size() / nfilters; + + assert(nt * nfilters == (int) taps.size()); + + std::vector< std::vector <@TAP_TYPE@> > xtaps(nfilters); + + for(int n = 0; n < nfilters; n++) + xtaps[n].resize (nt); + + for(int i = 0; i < (int)taps.size(); i++) + xtaps[i % nfilters][i / nfilters] = taps[i]; + + for(int n = 0; n < nfilters; n++) + d_firs[n]->set_taps(xtaps[n]); + + set_history(nt); + d_updated = false; + } + + std::vector<@TAP_TYPE@> + @IMPL_NAME@::taps() const + { + return d_new_taps; + } + + void + @IMPL_NAME@::forecast(int noutput_items, gr_vector_int &ninput_items_required) + { + int nreqd = std::max((unsigned)1, (int)((double) (noutput_items+1) * \ + decimation() / interpolation()) + history() - 1); + unsigned ninputs = ninput_items_required.size(); + for(unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = nreqd; + } + + int + @IMPL_NAME@::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const @I_TYPE@ *in = (const @I_TYPE@ *)input_items[0]; + @O_TYPE@ *out = (@O_TYPE@ *)output_items[0]; + + if(d_updated) { + install_taps(d_new_taps); + return 0; // history requirement may have increased. + } + + unsigned int ctr = d_ctr; + + int i = 0; + while(i < noutput_items) { + out[i++] = d_firs[ctr]->filter(in); + ctr += decimation(); + while(ctr >= interpolation()) { + ctr -= interpolation(); + in++; + } + } + + d_ctr = ctr; + consume_each(in - (@I_TYPE@*)input_items[0]); + return i; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/rational_resampler_base_XXX_impl.h.t b/gr-filter/lib/rational_resampler_base_XXX_impl.h.t new file mode 100644 index 000000000..4396656da --- /dev/null +++ b/gr-filter/lib/rational_resampler_base_XXX_impl.h.t @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* @WARNING@ */ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API @IMPL_NAME@ : public @BASE_NAME@ + { + private: + unsigned d_history; + unsigned d_interpolation; + unsigned d_decimation; + unsigned d_ctr; + std::vector<@TAP_TYPE@> d_new_taps; + std::vector d_firs; + bool d_updated; + + void install_taps(const std::vector<@TAP_TYPE@> &taps); + + public: + @IMPL_NAME@(unsigned interpolation, unsigned decimation, + const std::vector<@TAP_TYPE@> &taps); + + ~@IMPL_NAME@(); + + unsigned history() const { return d_history; } + void set_history(unsigned history) { d_history = history; } + + unsigned interpolation() const { return d_interpolation; } + unsigned decimation() const { return d_decimation; } + + void set_taps(const std::vector<@TAP_TYPE@> &taps); + std::vector<@TAP_TYPE@> taps() const; + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* @GUARD_NAME@ */ -- cgit From fad32dc397d731493dc88367d2b4648b35bb905b Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 19 Jun 2012 20:36:04 -0400 Subject: filter: adding PFB synthesis filter with GRC and QA. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/pfb_synthesizer_ccf_impl.cc | 288 ++++++++++++++++++++++++++++++ gr-filter/lib/pfb_synthesizer_ccf_impl.h | 85 +++++++++ 3 files changed, 374 insertions(+) create mode 100644 gr-filter/lib/pfb_synthesizer_ccf_impl.cc create mode 100644 gr-filter/lib/pfb_synthesizer_ccf_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index b3d456ec9..e29d69db5 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -133,6 +133,7 @@ list(APPEND filter_sources pfb_channelizer_ccf_impl.cc pfb_decimator_ccf_impl.cc pfb_interpolator_ccf_impl.cc + pfb_synthesizer_ccf_impl.cc single_pole_iir_filter_cc_impl.cc single_pole_iir_filter_ff_impl.cc ) diff --git a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc new file mode 100644 index 000000000..1e9c099c1 --- /dev/null +++ b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc @@ -0,0 +1,288 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pfb_synthesizer_ccf_impl.h" +#include +#include + +namespace gr { + namespace filter { + + pfb_synthesizer_ccf::sptr + pfb_synthesizer_ccf::make(unsigned int numchans, + const std::vector &taps, + bool twox) + { + return gnuradio::get_initial_sptr + (new pfb_synthesizer_ccf_impl(numchans, taps, twox)); + } + + + pfb_synthesizer_ccf_impl::pfb_synthesizer_ccf_impl(unsigned int numchans, + const std::vector &taps, + bool twox) + : gr_sync_interpolator("pfb_synthesizer_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_state(0) + { + // set up 2x multiplier; if twox==True, set to 2, otherwise to 1 + d_twox = (twox ? 2 : 1); + if(d_numchans % d_twox != 0) { + throw std::invalid_argument("pfb_synthesizer_ccf: number of channels must be even for 2x oversampling.\n"); + } + + d_filters = std::vector(d_twox*d_numchans); + d_channel_map.resize(d_twox*d_numchans); + + // Create a FIR filter for each channel and zero out the taps + std::vector vtaps(0, d_twox*d_numchans); + for(unsigned int i = 0; i < d_twox*d_numchans; i++) { + d_filters[i] = new kernel::fir_filter_with_buffer_ccf(vtaps); + d_channel_map[i] = i; + } + + // Now, actually set the filters' taps + set_taps(taps); + + // Create the IFFT to handle the input channel rotations + d_fft = new fft::fft_complex(d_twox*d_numchans, false); + memset(d_fft->get_inbuf(), 0, d_twox*d_numchans*sizeof(gr_complex)); + + set_output_multiple(d_numchans); + } + + pfb_synthesizer_ccf_impl::~pfb_synthesizer_ccf_impl() + { + for(unsigned int i = 0; i < d_twox*d_numchans; i++) { + delete d_filters[i]; + } + } + + void + pfb_synthesizer_ccf_impl::set_taps(const std::vector &taps) + { + gruel::scoped_lock guard(d_mutex); + + if(d_twox == 1) + set_taps1(taps); + else + set_taps2(taps); + + // Set the history to ensure enough input items for each filter + set_history(d_taps_per_filter+1); + + d_updated = true; + } + + void + pfb_synthesizer_ccf_impl::set_taps1(const std::vector &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 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(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]); + } + } + + void + pfb_synthesizer_ccf_impl::set_taps2 (const std::vector &taps) + { + unsigned int i,j; + int state = 0; + + 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_twox*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 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(d_taps_per_filter, 0); + d_taps[d_numchans+i] = std::vector(d_taps_per_filter, 0); + state = 0; + for(j = 0; j < d_taps_per_filter; j++) { + // add taps to channels in reverse order + // Zero out every other tap + if(state == 0) { + d_taps[i][j] = tmp_taps[i + j*d_numchans]; + d_taps[d_numchans + i][j] = 0; + state = 1; + } + else { + d_taps[i][j] = 0; + d_taps[d_numchans + i][j] = tmp_taps[i + j*d_numchans]; + state = 0; + } + } + + // Build a filter for each channel and add it's taps to it + d_filters[i]->set_taps(d_taps[i]); + d_filters[d_numchans + i]->set_taps(d_taps[d_numchans + i]); + } + } + + void + pfb_synthesizer_ccf_impl::print_taps() + { + unsigned int i, j; + for(i = 0; i < d_twox*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"); + } + } + + std::vector< std::vector > + pfb_synthesizer_ccf_impl::taps() const + { + return d_taps; + } + + void + pfb_synthesizer_ccf_impl::set_channel_map(const std::vector &map) + { + gruel::scoped_lock guard(d_mutex); + + if(map.size() > 0) { + unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); + unsigned int min = (unsigned int)*std::min_element(map.begin(), map.end()); + if((max >= d_twox*d_numchans) || (min < 0)) { + throw std::invalid_argument("gr_pfb_synthesizer_ccf::set_channel_map: map range out of bounds.\n"); + } + d_channel_map = map; + + // Zero out fft buffer so that unused channels are always 0 + memset(d_fft->get_inbuf(), 0,d_twox*d_numchans*sizeof(gr_complex)); + } + } + + std::vector + pfb_synthesizer_ccf_impl::channel_map() const + { + return d_channel_map; + } + + int + pfb_synthesizer_ccf_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gruel::scoped_lock guard(d_mutex); + + gr_complex *in = (gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + unsigned int n, i; + size_t ninputs = input_items.size(); + + // Algoritm for critically sampled channels + if(d_twox == 1) { + for(n = 0; n < noutput_items/d_numchans; n++) { + for(i = 0; i < ninputs; i++) { + in = (gr_complex*)input_items[i]; + d_fft->get_inbuf()[d_channel_map[i]] = in[n]; + } + + // spin through IFFT + d_fft->execute(); + + for(i = 0; i < d_numchans; i++) { + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[i]); + } + out += d_numchans; + } + } + + // Algorithm for oversampling by 2x + else { + for(n = 0; n < noutput_items/d_numchans; n++) { + for(i = 0; i < ninputs; i++) { + in = (gr_complex*)input_items[i]; + d_fft->get_inbuf()[d_channel_map[i]] = in[n]; + } + + // spin through IFFT + d_fft->execute(); + + // Output is sum of two filters, but the input buffer to the filters must be circularly + // shifted by numchans every time through, done by using d_state to determine which IFFT + // buffer position to pull from. + for(i = 0; i < d_numchans; i++) { + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*d_numchans+i]); + out[i] += d_filters[d_numchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*d_numchans+i]); + } + d_state ^= 1; + + out += d_numchans; + } + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/pfb_synthesizer_ccf_impl.h b/gr-filter/lib/pfb_synthesizer_ccf_impl.h new file mode 100644 index 000000000..adffc143f --- /dev/null +++ b/gr-filter/lib/pfb_synthesizer_ccf_impl.h @@ -0,0 +1,85 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_PFB_SYNTHESIZER_CCF_IMPL_H +#define INCLUDED_PFB_SYNTHESIZER_CCF_IMPL_H + +#include +#include +#include +#include + +namespace gr { + namespace filter { + + // While this is a polyphase_filterbank, we don't use the normal + // parent class because we have to use the fir_filter_with_buffer + // objects instead of normal filters. + + class FILTER_API pfb_synthesizer_ccf_impl : public pfb_synthesizer_ccf + { + private: + bool d_updated; + unsigned int d_numchans; + unsigned int d_taps_per_filter; + fft::fft_complex *d_fft; + std::vector< kernel::fir_filter_with_buffer_ccf*> d_filters; + std::vector< std::vector > d_taps; + int d_state; + std::vector d_channel_map; + unsigned int d_twox; + gruel::mutex d_mutex; // mutex to protect set/work access + + /*! + * \brief Tap setting algorithm for critically sampled channels + */ + void set_taps1(const std::vector &taps); + + /*! + * \brief Tap setting algorithm for 2x over-sampled channels + */ + void set_taps2(const std::vector &taps); + + + public: + pfb_synthesizer_ccf_impl(unsigned int numchans, + const std::vector &taps, + bool twox); + ~pfb_synthesizer_ccf_impl(); + + void set_taps(const std::vector &taps); + std::vector > taps() const; + void print_taps(); + + void set_channel_map(const std::vector &map); + std::vector channel_map() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_PFB_SYNTHESIZER_CCF_IMPL_H */ -- cgit From d8d8e992e3f94792fefa74c61d32494903f77dfb Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 19 Jun 2012 22:22:06 -0400 Subject: filter: added channel_model block with GRC. Dummy QA test needs work. More documentation. --- gr-filter/lib/CMakeLists.txt | 1 + gr-filter/lib/channel_model_impl.cc | 135 ++++++++++++++++++++++++++++++++++++ gr-filter/lib/channel_model_impl.h | 74 ++++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 gr-filter/lib/channel_model_impl.cc create mode 100644 gr-filter/lib/channel_model_impl.h (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index e29d69db5..a54cd7b1d 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -136,6 +136,7 @@ list(APPEND filter_sources pfb_synthesizer_ccf_impl.cc single_pole_iir_filter_cc_impl.cc single_pole_iir_filter_ff_impl.cc + channel_model_impl.cc ) list(APPEND filter_libs diff --git a/gr-filter/lib/channel_model_impl.cc b/gr-filter/lib/channel_model_impl.cc new file mode 100644 index 000000000..f9e995479 --- /dev/null +++ b/gr-filter/lib/channel_model_impl.cc @@ -0,0 +1,135 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "channel_model_impl.h" +#include +#include + +namespace gr { + namespace filter { + + channel_model::sptr + channel_model::make(double noise_voltage, + double frequency_offset, + double epsilon, + const std::vector &taps, + double noise_seed) + { + return gnuradio::get_initial_sptr + (new channel_model_impl(noise_voltage, + frequency_offset, + epsilon, + taps, + noise_seed)); + } + + // Hierarchical block constructor + channel_model_impl::channel_model_impl(double noise_voltage, + double frequency_offset, + double epsilon, + const std::vector &taps, + double noise_seed) + : gr_hier_block2("gr_channel_model", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))) + { + d_taps = taps; + while(d_taps.size() < 2) { + d_taps.push_back(0); + } + + d_timing_offset = fractional_interpolator_cc::make(0, epsilon); + + d_multipath = fir_filter_ccc::make(1, d_taps); + + d_noise_adder = gr_make_add_cc(); + d_noise = gr_make_noise_source_c(GR_GAUSSIAN, noise_voltage, noise_seed); + d_freq_offset = gr_make_sig_source_c(1, GR_SIN_WAVE, frequency_offset, 1.0, 0.0); + d_mixer_offset = gr_make_multiply_cc(); + + connect(self(), 0, d_timing_offset, 0); + connect(d_timing_offset, 0, d_multipath, 0); + connect(d_multipath, 0, d_mixer_offset, 0); + connect(d_freq_offset, 0, d_mixer_offset, 1); + connect(d_mixer_offset, 0, d_noise_adder, 1); + connect(d_noise, 0, d_noise_adder, 0); + connect(d_noise_adder, 0, self(), 0); + } + + channel_model_impl::~channel_model_impl() + { + } + + void + channel_model_impl::set_noise_voltage(double noise_voltage) + { + d_noise->set_amplitude(noise_voltage); + } + + void + channel_model_impl::set_frequency_offset(double frequency_offset) + { + d_freq_offset->set_frequency(frequency_offset); + } + + void + channel_model_impl::set_taps(const std::vector &taps) + { + d_taps = taps; + while(d_taps.size() < 2) { + d_taps.push_back(0); + } + d_multipath->set_taps(d_taps); + } + + void + channel_model_impl::set_timing_offset(double epsilon) + { + d_timing_offset->set_interp_ratio(epsilon); + } + + double + channel_model_impl::noise_voltage() const + { + return d_noise->amplitude(); + } + + double + channel_model_impl::frequency_offset() const + { + return d_freq_offset->frequency(); + } + + std::vector + channel_model_impl::taps() const + { + return d_multipath->taps(); + } + + double + channel_model_impl::timing_offset() const + { + return d_timing_offset->interp_ratio(); + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/channel_model_impl.h b/gr-filter/lib/channel_model_impl.h new file mode 100644 index 000000000..95a63d790 --- /dev/null +++ b/gr-filter/lib/channel_model_impl.h @@ -0,0 +1,74 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FILTER_CHANNEL_MODEL_IMPL_H +#define INCLUDED_FILTER_CHANNEL_MODEL_IMPL_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace gr { + namespace filter { + + class FILTER_API channel_model_impl : public channel_model + { + private: + gr_sig_source_c_sptr d_freq_offset; + gr_add_cc_sptr d_noise_adder; + gr_noise_source_c_sptr d_noise; + gr_multiply_cc_sptr d_mixer_offset; + + fractional_interpolator_cc::sptr d_timing_offset; + fir_filter_ccc::sptr d_multipath; + + std::vector d_taps; + + public: + channel_model_impl(double noise_voltage, + double frequency_offset, + double epsilon, + const std::vector &taps, + double noise_seed); + + ~channel_model_impl(); + + void set_noise_voltage(double noise_voltage); + void set_frequency_offset(double frequency_offset); + void set_taps(const std::vector &taps); + void set_timing_offset(double epsilon); + + double noise_voltage() const; + double frequency_offset() const; + std::vector taps() const; + double timing_offset() const; + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_FILTER_CHANNEL_MODEL_IMPL_H */ -- cgit From a04d3d784fe25447ad653ba28d243fa40d268c52 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 19 Jun 2012 22:25:40 -0400 Subject: filter: fixed some include issues. --- gr-filter/lib/fft_filter.cc | 1 + gr-filter/lib/qa_fir_filter_with_buffer.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fft_filter.cc b/gr-filter/lib/fft_filter.cc index 130886d7f..1b256a3da 100644 --- a/gr-filter/lib/fft_filter.cc +++ b/gr-filter/lib/fft_filter.cc @@ -27,6 +27,7 @@ #include #include #include +#include namespace gr { namespace filter { diff --git a/gr-filter/lib/qa_fir_filter_with_buffer.cc b/gr-filter/lib/qa_fir_filter_with_buffer.cc index c97e2479c..f8af9ea0b 100644 --- a/gr-filter/lib/qa_fir_filter_with_buffer.cc +++ b/gr-filter/lib/qa_fir_filter_with_buffer.cc @@ -31,7 +31,7 @@ #include #include #include - +#include namespace gr { namespace filter { -- cgit From edfa18840e2caf738596578acd0bf4efedc88fd1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 20 Jun 2012 09:10:23 -0400 Subject: filter: added documentation to adaptive_filter blocks. --- gr-filter/lib/adaptive_fir_ccf_impl.cc | 2 +- gr-filter/lib/adaptive_fir_ccf_impl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/adaptive_fir_ccf_impl.cc b/gr-filter/lib/adaptive_fir_ccf_impl.cc index 62d7e5337..004a9286b 100644 --- a/gr-filter/lib/adaptive_fir_ccf_impl.cc +++ b/gr-filter/lib/adaptive_fir_ccf_impl.cc @@ -69,7 +69,7 @@ namespace gr { } void - adaptive_fir_ccf_impl::update_tap(gr_complex &tap, const gr_complex &in) + adaptive_fir_ccf_impl::update_tap(float &tap, const gr_complex &in) { tap = tap; } diff --git a/gr-filter/lib/adaptive_fir_ccf_impl.h b/gr-filter/lib/adaptive_fir_ccf_impl.h index 2a1c7e5e9..a0c9581ea 100644 --- a/gr-filter/lib/adaptive_fir_ccf_impl.h +++ b/gr-filter/lib/adaptive_fir_ccf_impl.h @@ -41,7 +41,7 @@ namespace gr { float error(const gr_complex &out); // Override to calculate new weight from old, corresponding input - void update_tap(gr_complex &tap, const gr_complex &in); + void update_tap(float &tap, const gr_complex &in); public: void set_taps(const std::vector &taps); -- cgit From 81bb55f3a7bb8f64c2bc75b02306700fb5b60a43 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 20 Jun 2012 10:27:32 -0400 Subject: filter: fixed bug with includes. --- gr-filter/lib/fir_filter.cc | 1 + gr-filter/lib/fir_filter_with_buffer.cc | 1 + 2 files changed, 2 insertions(+) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 8e585f245..233405824 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -24,6 +24,7 @@ #include #include #include +#include namespace gr { namespace filter { diff --git a/gr-filter/lib/fir_filter_with_buffer.cc b/gr-filter/lib/fir_filter_with_buffer.cc index 58ef67fb7..105214087 100644 --- a/gr-filter/lib/fir_filter_with_buffer.cc +++ b/gr-filter/lib/fir_filter_with_buffer.cc @@ -29,6 +29,7 @@ #include #include #include +#include namespace gr { namespace filter { -- cgit From 958bc6f7365a19b42b0acc98e4c082eee6cf6e51 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 20 Jun 2012 11:01:54 -0400 Subject: filter: adding set/get for phase of arb resampler. --- gr-filter/lib/pfb_arb_resampler_ccf_impl.cc | 41 ++++++++++++++++++++++------- gr-filter/lib/pfb_arb_resampler_ccf_impl.h | 3 +++ gr-filter/lib/pfb_arb_resampler_fff_impl.cc | 21 +++++++++++++++ gr-filter/lib/pfb_arb_resampler_fff_impl.h | 3 +++ 4 files changed, 59 insertions(+), 9 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/pfb_arb_resampler_ccf_impl.cc b/gr-filter/lib/pfb_arb_resampler_ccf_impl.cc index bb0906aa5..5480366de 100644 --- a/gr-filter/lib/pfb_arb_resampler_ccf_impl.cc +++ b/gr-filter/lib/pfb_arb_resampler_ccf_impl.cc @@ -78,10 +78,8 @@ namespace gr { } // Now, actually set the filters' taps - std::vector dtaps; - create_diff_taps(taps, dtaps); - create_taps(taps, d_taps, d_filters); - create_taps(dtaps, d_dtaps, d_diff_filters); + set_taps(taps); + d_updated = false; } pfb_arb_resampler_ccf_impl::~pfb_arb_resampler_ccf_impl() @@ -122,11 +120,6 @@ namespace gr { // Build a filter for each channel and add it's taps to it ourfilter[i]->set_taps(ourtaps[d_int_rate-1-i]); } - - // Set the history to ensure enough input items for each filter - set_history (d_taps_per_filter + 1); - - d_updated = true; } void @@ -148,6 +141,13 @@ namespace gr { pfb_arb_resampler_ccf_impl::set_taps(const std::vector &taps) { gruel::scoped_lock guard(d_mutex); + + std::vector dtaps; + create_diff_taps(taps, dtaps); + create_taps(taps, d_taps, d_filters); + create_taps(dtaps, d_dtaps, d_diff_filters); + set_history(d_taps_per_filter + 1); + d_updated = true; } std::vector > @@ -172,17 +172,40 @@ namespace gr { void pfb_arb_resampler_ccf_impl::set_rate(float rate) { + gruel::scoped_lock guard(d_mutex); + d_dec_rate = (unsigned int)floor(d_int_rate/rate); d_flt_rate = (d_int_rate/rate) - d_dec_rate; set_relative_rate(rate); } + void + pfb_arb_resampler_ccf_impl::set_phase(float ph) + { + gruel::scoped_lock guard(d_mutex); + if((ph < 0) || (ph >= 2.0*M_PI)) { + throw std::runtime_error("pfb_arb_resampler_ccf: set_phase value out of bounds [0, 2pi).\n"); + } + + float ph_diff = 2.0*M_PI / (float)d_filters.size(); + d_last_filter = static_cast(ph / ph_diff); + } + + float + pfb_arb_resampler_ccf_impl::phase() const + { + float ph_diff = 2.0*M_PI / static_cast(d_filters.size()); + return d_last_filter * ph_diff; + } + int pfb_arb_resampler_ccf_impl::general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { + gruel::scoped_lock guard(d_mutex); + gr_complex *in = (gr_complex*)input_items[0]; gr_complex *out = (gr_complex*)output_items[0]; diff --git a/gr-filter/lib/pfb_arb_resampler_ccf_impl.h b/gr-filter/lib/pfb_arb_resampler_ccf_impl.h index 8e7e993cb..891e601e0 100644 --- a/gr-filter/lib/pfb_arb_resampler_ccf_impl.h +++ b/gr-filter/lib/pfb_arb_resampler_ccf_impl.h @@ -74,6 +74,9 @@ namespace gr { void print_taps(); void set_rate(float rate); + void set_phase(float ph); + float phase() const; + int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, diff --git a/gr-filter/lib/pfb_arb_resampler_fff_impl.cc b/gr-filter/lib/pfb_arb_resampler_fff_impl.cc index 79c19655a..6aff374fd 100644 --- a/gr-filter/lib/pfb_arb_resampler_fff_impl.cc +++ b/gr-filter/lib/pfb_arb_resampler_fff_impl.cc @@ -172,11 +172,32 @@ namespace gr { void pfb_arb_resampler_fff_impl::set_rate(float rate) { + gruel::scoped_lock guard(d_mutex); + d_dec_rate = (unsigned int)floor(d_int_rate/rate); d_flt_rate = (d_int_rate/rate) - d_dec_rate; set_relative_rate(rate); } + void + pfb_arb_resampler_fff_impl::set_phase(float ph) + { + gruel::scoped_lock guard(d_mutex); + if((ph < 0) || (ph >= 2.0*M_PI)) { + throw std::runtime_error("pfb_arb_resampler_ccf: set_phase value out of bounds [0, 2pi).\n"); + } + + float ph_diff = 2.0*M_PI / (float)d_filters.size(); + d_last_filter = static_cast(ph / ph_diff); + } + + float + pfb_arb_resampler_fff_impl::phase() const + { + float ph_diff = 2.0*M_PI / static_cast(d_filters.size()); + return d_last_filter * ph_diff; + } + int pfb_arb_resampler_fff_impl::general_work(int noutput_items, gr_vector_int &ninput_items, diff --git a/gr-filter/lib/pfb_arb_resampler_fff_impl.h b/gr-filter/lib/pfb_arb_resampler_fff_impl.h index 54e01375a..588962711 100644 --- a/gr-filter/lib/pfb_arb_resampler_fff_impl.h +++ b/gr-filter/lib/pfb_arb_resampler_fff_impl.h @@ -73,6 +73,9 @@ namespace gr { void print_taps(); void set_rate(float rate); + void set_phase(float ph); + float phase() const; + int general_work(int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, -- cgit From 52bda3a2504638f3c0cc832b141dc138dfcd4800 Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Wed, 20 Jun 2012 22:11:46 -0400 Subject: filter: adding stdint.h fixes Fedora 17/GCC 4.7.0 build. --- gr-filter/lib/qa_mmse_fir_interpolator_cc.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc b/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc index 5850cb86c..02e0b32fe 100644 --- a/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc +++ b/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc @@ -30,6 +30,7 @@ #include #include #include +#include namespace gr { namespace filter { -- cgit From ad8ef97e44af5e4015ee74bea1732c7dd5b80dd0 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 21 Jun 2012 22:43:34 -0400 Subject: filer: fixed link to libvolk. --- gr-filter/lib/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index a54cd7b1d..048a948e6 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -142,9 +142,9 @@ list(APPEND filter_sources list(APPEND filter_libs gnuradio-core gnuradio-fft + volk ${Boost_LIBRARIES} ${FFTW3F_LIBRARIES} - ${VOLK_LIBRARIES} ) add_library(gnuradio-filter SHARED ${filter_sources}) -- cgit From d511ba0468da7a1e3685eaeab9645847b4384ff4 Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Thu, 21 Jun 2012 20:54:17 -0700 Subject: gr-filter: added CPPUNIT_INCLUDE_DIRS to lib/CMakeLists.txt --- gr-filter/lib/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 048a948e6..73d7d7bae 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -98,6 +98,7 @@ include_directories( ${GR_FFT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${FFTW3F_INCLUDE_DIRS} + ${CPPUNIT_INCLUDE_DIRS} ) link_directories(${FFT_LIBRARY_DIRS}) -- cgit From 5cf2674681b3fd68c528eaeac57edf1ec94bee71 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 22 Jun 2012 14:13:27 -0400 Subject: filter: fix mmse_fir_interpolator QA code to initialize an aligned input buffer. --- gr-filter/lib/qa_mmse_fir_interpolator_cc.cc | 8 ++++---- gr-filter/lib/qa_mmse_fir_interpolator_ff.cc | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc b/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc index 02e0b32fe..268b8801c 100644 --- a/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc +++ b/gr-filter/lib/qa_mmse_fir_interpolator_cc.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -35,8 +36,6 @@ namespace gr { namespace filter { -#define NELEM(x) (sizeof(x) / sizeof(x[0])) - static float test_fcn_sin(double index) { @@ -62,9 +61,9 @@ namespace gr { qa_mmse_fir_interpolator_cc::t1() { static const unsigned N = 100; - __GR_ATTR_ALIGNED(8) gr_complex input[N + 10]; + gr_complex *input = fft::malloc_complex(N + 10); - for(unsigned i = 0; i < NELEM(input); i++) + for(unsigned i = 0; i < N+10; i++) input[i] = test_fcn((double) i); mmse_fir_interpolator_cc intr; @@ -79,6 +78,7 @@ namespace gr { // printf ("%9.6f %9.6f %9.6f\n", expected, actual, expected - actual); } } + fft::free(input); } /* diff --git a/gr-filter/lib/qa_mmse_fir_interpolator_ff.cc b/gr-filter/lib/qa_mmse_fir_interpolator_ff.cc index 128b638b9..54387fd9b 100644 --- a/gr-filter/lib/qa_mmse_fir_interpolator_ff.cc +++ b/gr-filter/lib/qa_mmse_fir_interpolator_ff.cc @@ -27,14 +27,13 @@ #include #include #include +#include #include #include namespace gr { namespace filter { -#define NELEM(x) (sizeof(x) / sizeof(x[0])) - static float test_fcn(double index) { @@ -45,10 +44,12 @@ namespace gr { void qa_mmse_fir_interpolator_ff::t1() { + // use aligned malloc and make sure that everything in this + // buffer is properly initialized. static const unsigned N = 100; - float input[N + 10]; + float *input = fft::malloc_float(N + 10); - for(unsigned i = 0; i < NELEM(input); i++) + for(unsigned i = 0; i < N+10; i++) input[i] = test_fcn((double) i); mmse_fir_interpolator_ff intr; @@ -63,6 +64,7 @@ namespace gr { // printf ("%9.6f %9.6f %9.6f\n", expected, actual, expected - actual); } } + fft::free(input); } } /* namespace filter */ -- cgit From 81589710a52c0e1b087f28ac54e83b9cbfa477d1 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 22 Jun 2012 18:58:33 -0400 Subject: volk: fixing some volk kernels. This should fix some problems with gr-filter QA tests. Also removes some warnings. --- gr-filter/lib/qa_fir_filter_with_buffer.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/qa_fir_filter_with_buffer.cc b/gr-filter/lib/qa_fir_filter_with_buffer.cc index f8af9ea0b..eaa0359d0 100644 --- a/gr-filter/lib/qa_fir_filter_with_buffer.cc +++ b/gr-filter/lib/qa_fir_filter_with_buffer.cc @@ -39,8 +39,6 @@ namespace gr { #define MAX_DATA (16383) #define ERR_DELTA (1e-5) -#define NELEM(x) (sizeof(x) / sizeof(x[0])) - static float uniform() { @@ -58,8 +56,8 @@ namespace gr { random_complex(gr_complex *buf, unsigned n) { for(unsigned i = 0; i < n; i++) { - float re = rint(uniform () * MAX_DATA); - float im = rint(uniform () * MAX_DATA); + float re = rint(uniform() * MAX_DATA); + float im = rint(uniform() * MAX_DATA); buf[i] = gr_complex(re, im); } } @@ -263,7 +261,7 @@ namespace gr { new kernel::fir_filter_with_buffer_ccc(f1_taps); // zero the output, then do the filtering - memset(actual_output, 0, sizeof(actual_output)); + memset(actual_output, 0, OUTPUT_LEN*sizeof(o_type)); f1->filterNdec(actual_output, input, ol/decimate, decimate); // check results -- cgit From c94ddc5e0c08693c023c099bd8946ca6e143f471 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 22 Jun 2012 20:08:06 -0400 Subject: filter: fixed fir_filter_with_buffer to make sure nothing that volk looks at could be improperly set. This fixed issues with qa_fir_filter_with_buffer. --- gr-filter/lib/fir_filter_with_buffer.cc | 75 +++++++++++++++++++----------- gr-filter/lib/qa_fir_filter_with_buffer.cc | 2 +- 2 files changed, 49 insertions(+), 28 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter_with_buffer.cc b/gr-filter/lib/fir_filter_with_buffer.cc index 105214087..7a35a9225 100644 --- a/gr-filter/lib/fir_filter_with_buffer.cc +++ b/gr-filter/lib/fir_filter_with_buffer.cc @@ -40,7 +40,7 @@ namespace gr { d_align = volk_get_alignment(); d_naligned = d_align / sizeof(float); - d_buffer = NULL; + d_buffer_ptr = NULL; d_aligned_taps = NULL; set_taps(taps); @@ -50,9 +50,9 @@ namespace gr { fir_filter_with_buffer_fff::~fir_filter_with_buffer_fff() { - if(d_buffer != NULL) { - fft::free(d_buffer); - d_buffer = NULL; + if(d_buffer_ptr != NULL) { + fft::free(d_buffer_ptr); + d_buffer_ptr = NULL; } // Free aligned taps @@ -71,9 +71,9 @@ namespace gr { void fir_filter_with_buffer_fff::set_taps(const std::vector &taps) { - if(d_buffer != NULL) { - fft::free(d_buffer); - d_buffer = NULL; + if(d_buffer_ptr != NULL) { + fft::free(d_buffer_ptr); + d_buffer_ptr = NULL; } // Free the taps if already allocated @@ -89,8 +89,15 @@ namespace gr { d_taps = taps; std::reverse(d_taps.begin(), d_taps.end()); - d_buffer = fft::malloc_float(2*d_ntaps); - memset(d_buffer, 0, 2*d_ntaps*sizeof(float)); + // We allocate enough to be able to look back and forth + // d_naligned beyond the buffer boundaries and make sure these + // are zeroed out (or they may be nan, which will cause + // problems). We then set d_buffer to the position in the + // d_buffer_ptr such that we only touch the internally + // allocated space. + d_buffer_ptr = fft::malloc_float(2*(d_ntaps + d_naligned)); + memset(d_buffer_ptr, 0, 2*(d_ntaps + d_naligned)*sizeof(float)); + d_buffer = d_buffer_ptr + d_naligned; // Allocate aligned taps d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); @@ -186,7 +193,7 @@ namespace gr { d_align = volk_get_alignment(); d_naligned = d_align / sizeof(gr_complex); - d_buffer = NULL; + d_buffer_ptr = NULL; d_aligned_taps = NULL; set_taps(taps); @@ -196,9 +203,9 @@ namespace gr { fir_filter_with_buffer_ccc::~fir_filter_with_buffer_ccc() { - if(d_buffer != NULL) { - fft::free(d_buffer); - d_buffer = NULL; + if(d_buffer_ptr != NULL) { + fft::free(d_buffer_ptr); + d_buffer_ptr = NULL; } // Free aligned taps @@ -217,9 +224,9 @@ namespace gr { void fir_filter_with_buffer_ccc::set_taps(const std::vector &taps) { - if(d_buffer != NULL) { - fft::free(d_buffer); - d_buffer = NULL; + if(d_buffer_ptr != NULL) { + fft::free(d_buffer_ptr); + d_buffer_ptr = NULL; } // Free the taps if already allocated @@ -235,8 +242,15 @@ namespace gr { d_taps = taps; std::reverse(d_taps.begin(), d_taps.end()); - d_buffer = fft::malloc_complex(2*d_ntaps); - memset(d_buffer, 0, 2*d_ntaps*sizeof(gr_complex)); + // We allocate enough to be able to look back and forth + // d_naligned beyond the buffer boundaries and make sure these + // are zeroed out (or they may be nan, which will cause + // problems). We then set d_buffer to the position in the + // d_buffer_ptr such that we only touch the internally + // allocated space. + d_buffer_ptr = fft::malloc_complex(2*(d_ntaps + d_naligned)); + memset(d_buffer_ptr, 0, 2*(d_ntaps + d_naligned)*sizeof(gr_complex)); + d_buffer = d_buffer_ptr + d_naligned; // Allocate aligned taps d_aligned_taps = (gr_complex**)malloc(d_naligned*sizeof(gr_complex**)); @@ -332,7 +346,7 @@ namespace gr { d_align = volk_get_alignment(); d_naligned = d_align / sizeof(gr_complex); - d_buffer = NULL; + d_buffer_ptr = NULL; d_aligned_taps = NULL; set_taps(taps); @@ -342,9 +356,9 @@ namespace gr { fir_filter_with_buffer_ccf::~fir_filter_with_buffer_ccf() { - if(d_buffer != NULL) { - fft::free(d_buffer); - d_buffer = NULL; + if(d_buffer_ptr != NULL) { + fft::free(d_buffer_ptr); + d_buffer_ptr = NULL; } // Free aligned taps @@ -363,9 +377,9 @@ namespace gr { void fir_filter_with_buffer_ccf::set_taps(const std::vector &taps) { - if(d_buffer != NULL) { - fft::free(d_buffer); - d_buffer = NULL; + if(d_buffer_ptr != NULL) { + fft::free(d_buffer_ptr); + d_buffer_ptr = NULL; } // Free the taps if already allocated @@ -381,8 +395,15 @@ namespace gr { d_taps = taps; std::reverse(d_taps.begin(), d_taps.end()); - d_buffer = fft::malloc_complex(2*d_ntaps); - memset(d_buffer, 0, 2*d_ntaps*sizeof(gr_complex)); + // We allocate enough to be able to look back and forth + // d_naligned beyond the buffer boundaries and make sure these + // are zeroed out (or they may be nan, which will cause + // problems). We then set d_buffer to the position in the + // d_buffer_ptr such that we only touch the internally + // allocated space. + d_buffer_ptr = fft::malloc_complex(2*(d_ntaps + d_naligned)); + memset(d_buffer_ptr, 0, 2*(d_ntaps + d_naligned)*sizeof(gr_complex)); + d_buffer = d_buffer_ptr + d_naligned; // Allocate aligned taps d_aligned_taps = (float**)malloc(d_naligned*sizeof(float**)); diff --git a/gr-filter/lib/qa_fir_filter_with_buffer.cc b/gr-filter/lib/qa_fir_filter_with_buffer.cc index eaa0359d0..6a1744b0a 100644 --- a/gr-filter/lib/qa_fir_filter_with_buffer.cc +++ b/gr-filter/lib/qa_fir_filter_with_buffer.cc @@ -146,7 +146,7 @@ namespace gr { new kernel::fir_filter_with_buffer_fff(f1_taps); // zero the output, then do the filtering - memset(actual_output, 0, sizeof(actual_output)); + memset(actual_output, 0, OUTPUT_LEN*sizeof(o_type)); f1->filterNdec(actual_output, input, ol/decimate, decimate); // check results -- cgit From e1cfa5eeeaebce6720dd98001c83b84218ae4d80 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Sun, 8 Jul 2012 18:08:17 -0400 Subject: filter: warning fixes. --- gr-filter/lib/pfb_channelizer_ccf_impl.cc | 3 +-- gr-filter/lib/pfb_synthesizer_ccf_impl.cc | 3 +-- gr-filter/lib/qa_fir_filter_with_buffer.cc | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/pfb_channelizer_ccf_impl.cc b/gr-filter/lib/pfb_channelizer_ccf_impl.cc index ca92066f5..28fc1dcc1 100644 --- a/gr-filter/lib/pfb_channelizer_ccf_impl.cc +++ b/gr-filter/lib/pfb_channelizer_ccf_impl.cc @@ -118,8 +118,7 @@ namespace gr { if(map.size() > 0) { unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); - unsigned int min = (unsigned int)*std::min_element(map.begin(), map.end()); - if((max >= d_nfilts) || (min < 0)) { + if(max >= d_nfilts) { throw std::invalid_argument("pfb_channelizer_ccf_impl::set_channel_map: map range out of bounds.\n"); } d_channel_map = map; diff --git a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc index 1e9c099c1..9dd519d57 100644 --- a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc +++ b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc @@ -204,8 +204,7 @@ namespace gr { if(map.size() > 0) { unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); - unsigned int min = (unsigned int)*std::min_element(map.begin(), map.end()); - if((max >= d_twox*d_numchans) || (min < 0)) { + if(max >= d_twox*d_numchans) { throw std::invalid_argument("gr_pfb_synthesizer_ccf::set_channel_map: map range out of bounds.\n"); } d_channel_map = map; diff --git a/gr-filter/lib/qa_fir_filter_with_buffer.cc b/gr-filter/lib/qa_fir_filter_with_buffer.cc index 6a1744b0a..ab2958ed1 100644 --- a/gr-filter/lib/qa_fir_filter_with_buffer.cc +++ b/gr-filter/lib/qa_fir_filter_with_buffer.cc @@ -376,7 +376,7 @@ namespace gr { new kernel::fir_filter_with_buffer_ccf(f1_taps); // zero the output, then do the filtering - memset(actual_output, 0, sizeof(actual_output)); + memset(actual_output, 0, sizeof(OUTPUT_LEN*sizeof(gr_complex))); f1->filterNdec(actual_output, input, ol/decimate, decimate); // check results -- cgit From 267ac52b5b3297816bab8454ec60cd927fcc3182 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 19 Jul 2012 19:27:15 -0400 Subject: filter: fixing cppunit test QA to work properly with testing disabled. --- gr-filter/lib/CMakeLists.txt | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 73d7d7bae..532bd1992 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -98,7 +98,6 @@ include_directories( ${GR_FFT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${FFTW3F_INCLUDE_DIRS} - ${CPPUNIT_INCLUDE_DIRS} ) link_directories(${FFT_LIBRARY_DIRS}) @@ -157,22 +156,30 @@ add_dependencies(gnuradio-filter gnuradio-fft filter_generated_includes filter_g ######################################################################## # QA C++ Code for gr-filter ######################################################################## -list(APPEND test_gr_filter_sources +if(ENABLE_TESTING) + include(GrTest) + + include_directories(${CPPUNIT_INCLUDE_DIRS}) + link_directories(${CPPUNIT_LIBRARY_DIRS}) + + list(APPEND test_gr_filter_sources ${CMAKE_CURRENT_SOURCE_DIR}/test_gr_filter.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_filter.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_firdes.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_fir_filter_with_buffer.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_fir_interpolator_cc.cc ${CMAKE_CURRENT_SOURCE_DIR}/qa_mmse_fir_interpolator_ff.cc -) + ) -add_executable(test-gr-filter ${test_gr_filter_sources}) -target_link_libraries( - test-gr-filter - gnuradio-core - gnuradio-filter - ${CPPUNIT_LIBRARIES} - ${Boost_LIBRARIES} -) + add_executable(test-gr-filter ${test_gr_filter_sources}) + + target_link_libraries( + test-gr-filter + gnuradio-core + gnuradio-filter + ${Boost_LIBRARIES} + ${CPPUNIT_LIBRARIES} + ) -GR_ADD_TEST(test_gr_filter test-gr-filter) + GR_ADD_TEST(test_gr_filter test-gr-filter) +endif(ENABLE_TESTING) -- cgit From 853920e9aaa32f9f0dda2cdc75ded4eee738117f Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 30 Aug 2012 20:43:41 -0400 Subject: filter: fixes naligned value when volk alignment is 1. --- gr-filter/lib/fir_filter.cc | 12 ++++++------ gr-filter/lib/fir_filter_with_buffer.cc | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 233405824..6137dd269 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -34,7 +34,7 @@ namespace gr { const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(float); + d_naligned = std::max((size_t)1, d_align / sizeof(float)); d_aligned_taps = NULL; set_taps(taps); @@ -139,7 +139,7 @@ namespace gr { const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(gr_complex); + d_naligned = std::max((size_t)1, d_align / sizeof(gr_complex)); d_aligned_taps = NULL; set_taps(taps); @@ -246,7 +246,7 @@ namespace gr { const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(float); + d_naligned = std::max((size_t)1, d_align / sizeof(float)); d_aligned_taps = NULL; set_taps(taps); @@ -352,7 +352,7 @@ namespace gr { const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(gr_complex); + d_naligned = std::max((size_t)1, d_align / sizeof(gr_complex)); d_aligned_taps = NULL; set_taps(taps); @@ -457,7 +457,7 @@ namespace gr { const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(short); + d_naligned = std::max((size_t)1, d_align / sizeof(short)); d_aligned_taps = NULL; set_taps(taps); @@ -563,7 +563,7 @@ namespace gr { const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(float); + d_naligned = std::max((size_t)1, d_align / sizeof(float)); d_aligned_taps = NULL; set_taps(taps); diff --git a/gr-filter/lib/fir_filter_with_buffer.cc b/gr-filter/lib/fir_filter_with_buffer.cc index 7a35a9225..7bff8d4a7 100644 --- a/gr-filter/lib/fir_filter_with_buffer.cc +++ b/gr-filter/lib/fir_filter_with_buffer.cc @@ -38,7 +38,7 @@ namespace gr { fir_filter_with_buffer_fff::fir_filter_with_buffer_fff(const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(float); + d_naligned = std::max((size_t)1, d_align / sizeof(float)); d_buffer_ptr = NULL; d_aligned_taps = NULL; @@ -191,7 +191,7 @@ namespace gr { fir_filter_with_buffer_ccc::fir_filter_with_buffer_ccc(const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(gr_complex); + d_naligned = std::max((size_t)1, d_align / sizeof(gr_complex)); d_buffer_ptr = NULL; d_aligned_taps = NULL; @@ -344,7 +344,7 @@ namespace gr { fir_filter_with_buffer_ccf::fir_filter_with_buffer_ccf(const std::vector &taps) { d_align = volk_get_alignment(); - d_naligned = d_align / sizeof(gr_complex); + d_naligned = std::max((size_t)1, d_align / sizeof(gr_complex)); d_buffer_ptr = NULL; d_aligned_taps = NULL; -- cgit From f986d38812c3fe93087c1e42a5aef966f1e9d659 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 13 Nov 2012 18:06:06 -0800 Subject: fft: added gnuradio-fft dep for some tests --- gr-filter/lib/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 532bd1992..b0bae6774 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -173,10 +173,12 @@ if(ENABLE_TESTING) add_executable(test-gr-filter ${test_gr_filter_sources}) + list(APPEND GR_TEST_TARGET_DEPS test-gr-filter gnuradio-filter gnuradio-fft) + target_link_libraries( test-gr-filter gnuradio-core - gnuradio-filter + gnuradio-filter ${Boost_LIBRARIES} ${CPPUNIT_LIBRARIES} ) -- cgit From 83ba8a2dd64c821458e9d7ab89c89a08ef8bc31d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 13 Nov 2012 18:07:46 -0800 Subject: fft: removed non-existant FFT_LIBRARY_DIRS FFT_LIBRARIES --- gr-filter/lib/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index b0bae6774..c7f06d1f8 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -100,7 +100,6 @@ include_directories( ${FFTW3F_INCLUDE_DIRS} ) -link_directories(${FFT_LIBRARY_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) link_directories(${FFTW3F_LIBRARY_DIRS}) -- cgit From b22ff660f8a710aea6e1ca75075d2265478b0465 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 13 Nov 2012 18:28:06 -0800 Subject: filter: removed undefined FFTW3F_ libs/incs --- gr-filter/lib/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index c7f06d1f8..81f62aa54 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -97,11 +97,9 @@ include_directories( ${GNURADIO_CORE_INCLUDE_DIRS} ${GR_FFT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} - ${FFTW3F_INCLUDE_DIRS} ) link_directories(${Boost_LIBRARY_DIRS}) -link_directories(${FFTW3F_LIBRARY_DIRS}) ######################################################################## # Setup library @@ -143,7 +141,6 @@ list(APPEND filter_libs gnuradio-fft volk ${Boost_LIBRARIES} - ${FFTW3F_LIBRARIES} ) add_library(gnuradio-filter SHARED ${filter_sources}) -- cgit From 64913ee414f2c8a51afb2277b16b957fa2e7e066 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 13 Nov 2012 19:32:45 -0800 Subject: filter: use matching free for malloc, fixes access violation --- gr-filter/lib/fir_filter.cc | 24 ++++++++++++------------ gr-filter/lib/fir_filter_with_buffer.cc | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index 6137dd269..d7a0a0c70 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -50,7 +50,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -66,7 +66,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -155,7 +155,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -171,7 +171,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -262,7 +262,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -278,7 +278,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -368,7 +368,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -384,7 +384,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -473,7 +473,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -489,7 +489,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -579,7 +579,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -595,7 +595,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } diff --git a/gr-filter/lib/fir_filter_with_buffer.cc b/gr-filter/lib/fir_filter_with_buffer.cc index 7bff8d4a7..181630d48 100644 --- a/gr-filter/lib/fir_filter_with_buffer.cc +++ b/gr-filter/lib/fir_filter_with_buffer.cc @@ -60,7 +60,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -81,7 +81,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -213,7 +213,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -234,7 +234,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -366,7 +366,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } @@ -387,7 +387,7 @@ namespace gr { for(int i = 0; i < d_naligned; i++) { fft::free(d_aligned_taps[i]); } - fft::free(d_aligned_taps); + ::free(d_aligned_taps); d_aligned_taps = NULL; } -- cgit From e788c523d4f8de3efd64a64f148ac1bf25ea032d Mon Sep 17 00:00:00 2001 From: Michael L Dickens Date: Tue, 1 Jan 2013 21:42:23 -0500 Subject: Tweak INCLUDE dirs such that INCLUDE_DIRECTORIES and LINK_DIRECTORIES are ordered as: internal build and source for this component, other components (internal build and source, or already installed), non-project non-system dependencies (e.g., Qt, Boost, Python), system dependencies (e.g., CoreAudio). --- gr-filter/lib/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index 81f62aa54..626f5521f 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -90,12 +90,13 @@ expand_cc(rational_resampler_base_XXX_impl ccc ccf fcc fff fsf scc) # Setup the include and linker paths ######################################################################## include_directories( - ${GR_FILTER_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${VOLK_INCLUDE_DIRS} - ${GNURADIO_CORE_INCLUDE_DIRS} + ${GR_FILTER_INCLUDE_DIRS} ${GR_FFT_INCLUDE_DIRS} + ${GNURADIO_CORE_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} + ${GRUEL_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ) -- cgit From 1e6db7d187f0bb9835872d659fcaa4e7f3ba577f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 13 Jan 2013 17:43:01 -0800 Subject: filter: bring in fix for volk update --- gr-filter/lib/fir_filter.cc | 2 +- gr-filter/lib/fir_filter_with_buffer.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter.cc b/gr-filter/lib/fir_filter.cc index d7a0a0c70..d5cf3cd54 100644 --- a/gr-filter/lib/fir_filter.cc +++ b/gr-filter/lib/fir_filter.cc @@ -424,7 +424,7 @@ namespace gr { volk_32fc_x2_dot_prod_32fc_a(d_output, ar, d_aligned_taps[al], - (d_ntaps+al)*sizeof(gr_complex)); + (d_ntaps+al)); return *d_output; } diff --git a/gr-filter/lib/fir_filter_with_buffer.cc b/gr-filter/lib/fir_filter_with_buffer.cc index 181630d48..7c37361c1 100644 --- a/gr-filter/lib/fir_filter_with_buffer.cc +++ b/gr-filter/lib/fir_filter_with_buffer.cc @@ -287,7 +287,7 @@ namespace gr { volk_32fc_x2_dot_prod_32fc_a(d_output, ar, d_aligned_taps[al], - (ntaps()+al)*sizeof(gr_complex)); + (ntaps()+al)); return *d_output; } @@ -310,7 +310,7 @@ namespace gr { volk_32fc_x2_dot_prod_32fc_a(d_output, ar, d_aligned_taps[al], - (ntaps()+al)*sizeof(gr_complex)); + (ntaps()+al)); return *d_output; } -- cgit From 5f90465feed9949d00bc8c639fa4e911162449bd Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Thu, 14 Feb 2013 09:50:52 -0500 Subject: filter: fixing synthesis filter output rate when using 2x oversampling. --- gr-filter/lib/pfb_synthesizer_ccf_impl.cc | 52 ++++++++++++++++--------------- 1 file changed, 27 insertions(+), 25 deletions(-) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc index 9dd519d57..f89b48b12 100644 --- a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc +++ b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc @@ -47,8 +47,8 @@ namespace gr { : gr_sync_interpolator("pfb_synthesizer_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_state(0) + (twox ? numchans/2 : numchans)), + d_updated(false), d_numchans(numchans), d_state(0) { // set up 2x multiplier; if twox==True, set to 2, otherwise to 1 d_twox = (twox ? 2 : 1); @@ -56,12 +56,12 @@ namespace gr { throw std::invalid_argument("pfb_synthesizer_ccf: number of channels must be even for 2x oversampling.\n"); } - d_filters = std::vector(d_twox*d_numchans); - d_channel_map.resize(d_twox*d_numchans); + d_filters = std::vector(d_numchans); + d_channel_map.resize(d_numchans); // Create a FIR filter for each channel and zero out the taps - std::vector vtaps(0, d_twox*d_numchans); - for(unsigned int i = 0; i < d_twox*d_numchans; i++) { + std::vector vtaps(0, d_numchans); + for(unsigned int i = 0; i < d_numchans; i++) { d_filters[i] = new kernel::fir_filter_with_buffer_ccf(vtaps); d_channel_map[i] = i; } @@ -70,15 +70,15 @@ namespace gr { set_taps(taps); // Create the IFFT to handle the input channel rotations - d_fft = new fft::fft_complex(d_twox*d_numchans, false); - memset(d_fft->get_inbuf(), 0, d_twox*d_numchans*sizeof(gr_complex)); + d_fft = new fft::fft_complex(d_numchans, false); + memset(d_fft->get_inbuf(), 0, d_numchans*sizeof(gr_complex)); set_output_multiple(d_numchans); } pfb_synthesizer_ccf_impl::~pfb_synthesizer_ccf_impl() { - for(unsigned int i = 0; i < d_twox*d_numchans; i++) { + for(unsigned int i = 0; i < d_numchans; i++) { delete d_filters[i]; } } @@ -137,11 +137,11 @@ namespace gr { unsigned int i,j; int state = 0; - unsigned int ntaps = taps.size(); + unsigned int ntaps = 2*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_twox*d_numchans); + 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 @@ -152,29 +152,30 @@ namespace gr { } // Partition the filter - for(i = 0; i < d_numchans; i++) { + unsigned int halfchans = d_numchans/2; + for(i = 0; i < halfchans; i++) { // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out d_taps[i] = std::vector(d_taps_per_filter, 0); - d_taps[d_numchans+i] = std::vector(d_taps_per_filter, 0); + d_taps[halfchans+i] = std::vector(d_taps_per_filter, 0); state = 0; for(j = 0; j < d_taps_per_filter; j++) { // add taps to channels in reverse order // Zero out every other tap if(state == 0) { - d_taps[i][j] = tmp_taps[i + j*d_numchans]; - d_taps[d_numchans + i][j] = 0; + d_taps[i][j] = tmp_taps[i + j*halfchans]; + d_taps[halfchans + i][j] = 0; state = 1; } else { d_taps[i][j] = 0; - d_taps[d_numchans + i][j] = tmp_taps[i + j*d_numchans]; + d_taps[halfchans + i][j] = tmp_taps[i + j*halfchans]; state = 0; } } // Build a filter for each channel and add it's taps to it d_filters[i]->set_taps(d_taps[i]); - d_filters[d_numchans + i]->set_taps(d_taps[d_numchans + i]); + d_filters[halfchans + i]->set_taps(d_taps[halfchans + i]); } } @@ -182,7 +183,7 @@ namespace gr { pfb_synthesizer_ccf_impl::print_taps() { unsigned int i, j; - for(i = 0; i < d_twox*d_numchans; i++) { + 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]); @@ -204,13 +205,13 @@ namespace gr { if(map.size() > 0) { unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); - if(max >= d_twox*d_numchans) { + if(max >= d_numchans) { throw std::invalid_argument("gr_pfb_synthesizer_ccf::set_channel_map: map range out of bounds.\n"); } d_channel_map = map; // Zero out fft buffer so that unused channels are always 0 - memset(d_fft->get_inbuf(), 0,d_twox*d_numchans*sizeof(gr_complex)); + memset(d_fft->get_inbuf(), 0, d_numchans*sizeof(gr_complex)); } } @@ -258,7 +259,8 @@ namespace gr { // Algorithm for oversampling by 2x else { - for(n = 0; n < noutput_items/d_numchans; n++) { + unsigned int halfchans = d_numchans/2; + for(n = 0; n < noutput_items/halfchans; n++) { for(i = 0; i < ninputs; i++) { in = (gr_complex*)input_items[i]; d_fft->get_inbuf()[d_channel_map[i]] = in[n]; @@ -270,13 +272,13 @@ namespace gr { // Output is sum of two filters, but the input buffer to the filters must be circularly // shifted by numchans every time through, done by using d_state to determine which IFFT // buffer position to pull from. - for(i = 0; i < d_numchans; i++) { - out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*d_numchans+i]); - out[i] += d_filters[d_numchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*d_numchans+i]); + for(i = 0; i < halfchans; i++) { + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*halfchans+i]); + out[i] += d_filters[halfchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*halfchans+i]); } d_state ^= 1; - out += d_numchans; + out += halfchans; } } -- cgit From d8e73d63c0af6ba6810319d866cab07b332d0e42 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Tue, 26 Feb 2013 12:00:47 -0500 Subject: core: adding a mutex as a protected member of gr_block for use in protecting set and work function access to variables. This is used in gr-analog's noise_source and gr-filter's fir_filter_XXX since these two cause particular problems (in next's channel model). This shows the use of the mutex for general protection when needed. --- gr-filter/lib/fir_filter_XXX_impl.cc.t | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/fir_filter_XXX_impl.cc.t b/gr-filter/lib/fir_filter_XXX_impl.cc.t index 529c51e2b..319c26727 100644 --- a/gr-filter/lib/fir_filter_XXX_impl.cc.t +++ b/gr-filter/lib/fir_filter_XXX_impl.cc.t @@ -64,6 +64,7 @@ namespace gr { void @IMPL_NAME@::set_taps(const std::vector<@TAP_TYPE@> &taps) { + gruel::scoped_lock l(d_setlock); d_fir->set_taps(taps); d_updated = true; } @@ -79,6 +80,8 @@ namespace gr { gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { + gruel::scoped_lock l(d_setlock); + const @I_TYPE@ *in = (const @I_TYPE@*)input_items[0]; @O_TYPE@ *out = (@O_TYPE@*)output_items[0]; -- cgit From 19ca8542d138398c2ef3c81ed0ecf5af628a0f44 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Fri, 5 Apr 2013 10:02:16 -0400 Subject: filter: added exception when using interpolating filter with no taps provided. --- gr-filter/lib/interp_fir_filter_XXX_impl.cc.t | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gr-filter/lib') diff --git a/gr-filter/lib/interp_fir_filter_XXX_impl.cc.t b/gr-filter/lib/interp_fir_filter_XXX_impl.cc.t index c9127d737..fea3b1c8e 100644 --- a/gr-filter/lib/interp_fir_filter_XXX_impl.cc.t +++ b/gr-filter/lib/interp_fir_filter_XXX_impl.cc.t @@ -54,6 +54,10 @@ namespace gr { throw std::out_of_range("@IMPL_NAME@: interpolation must be > 0\n"); } + if(taps.size() == 0) { + throw std::runtime_error("@IMPL_NAME@: no filter taps provided.\n"); + } + std::vector<@TAP_TYPE@> dummy_taps; for(unsigned i = 0; i < interpolation; i++) { -- cgit