summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rondeau2012-06-17 16:44:04 -0400
committerTom Rondeau2012-06-17 16:44:04 -0400
commitce3d887a47b47cb2d5351e14066ceb56b2b3c892 (patch)
treee27110a4dd06f2c918cef7cc9a3e164010434b51
parentd647fbbaa07554ad314c9eb2b5c1735b6265d13a (diff)
downloadgnuradio-ce3d887a47b47cb2d5351e14066ceb56b2b3c892.tar.gz
gnuradio-ce3d887a47b47cb2d5351e14066ceb56b2b3c892.tar.bz2
gnuradio-ce3d887a47b47cb2d5351e14066ceb56b2b3c892.zip
filter: added mmse_fir_interpolator with QA code.
-rw-r--r--gr-filter/include/filter/CMakeLists.txt2
-rw-r--r--gr-filter/include/filter/fir_filter.h2
-rw-r--r--gr-filter/include/filter/mmse_fir_interpolator_cc.h79
-rw-r--r--gr-filter/include/filter/mmse_fir_interpolator_ff.h76
-rw-r--r--gr-filter/lib/CMakeLists.txt4
-rw-r--r--gr-filter/lib/mmse_fir_interpolator_cc.cc77
-rw-r--r--gr-filter/lib/mmse_fir_interpolator_ff.cc77
-rw-r--r--gr-filter/lib/qa_filter.cc6
-rw-r--r--gr-filter/lib/qa_mmse_fir_interpolator_cc.cc125
-rw-r--r--gr-filter/lib/qa_mmse_fir_interpolator_cc.h48
-rw-r--r--gr-filter/lib/qa_mmse_fir_interpolator_ff.cc69
-rw-r--r--gr-filter/lib/qa_mmse_fir_interpolator_ff.h45
12 files changed, 608 insertions, 2 deletions
diff --git a/gr-filter/include/filter/CMakeLists.txt b/gr-filter/include/filter/CMakeLists.txt
index 5da171ffa..3a1b5f150 100644
--- a/gr-filter/include/filter/CMakeLists.txt
+++ b/gr-filter/include/filter/CMakeLists.txt
@@ -82,6 +82,8 @@ install(FILES
fft_filter.h
iir_filter.h
interpolator_taps.h
+ mmse_fir_interpolator_cc.h
+ mmse_fir_interpolator_ff.h
pm_remez.h
polyphase_filterbank.h
single_pole_iir.h
diff --git a/gr-filter/include/filter/fir_filter.h b/gr-filter/include/filter/fir_filter.h
index 42b4ac2e0..e86111268 100644
--- a/gr-filter/include/filter/fir_filter.h
+++ b/gr-filter/include/filter/fir_filter.h
@@ -42,7 +42,7 @@ namespace gr {
std::vector<float> taps() const;
unsigned int ntaps() const;
- inline float filter(const float input[]);
+ float filter(const float input[]);
void filterN(float output[],
const float input[],
unsigned long n);
diff --git a/gr-filter/include/filter/mmse_fir_interpolator_cc.h b/gr-filter/include/filter/mmse_fir_interpolator_cc.h
new file mode 100644
index 000000000..0436b4a0f
--- /dev/null
+++ b/gr-filter/include/filter/mmse_fir_interpolator_cc.h
@@ -0,0 +1,79 @@
+/* -*- 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 _GRI_MMSE_FIR_INTERPOLATOR_CC_H_
+#define _GRI_MMSE_FIR_INTERPOLATOR_CC_H_
+
+#include <filter/api.h>
+#include <filter/fir_filter.h>
+#include <gr_complex.h>
+#include <vector>
+
+namespace gr {
+ namespace filter {
+
+ /*!
+ * \brief Compute intermediate samples between signal samples x(k*Ts)
+ * \ingroup filter_primitive
+ *
+ * This implements a Mininum Mean Squared Error interpolator with
+ * 8 taps. It is suitable for signals where the bandwidth of
+ * interest B = 1/(4*Ts) Where Ts is the time between samples.
+ *
+ * Although mu, the fractional delay, is specified as a float, it
+ * is actually quantized. 0.0 <= mu <= 1.0. That is, mu is
+ * quantized in the interpolate method to 32nd's of a sample.
+ *
+ * For more information, in the GNU Radio source code, see:
+ * \li gnuradio-core/src/gen_interpolator_taps/README
+ * \li gnuradio-core/src/gen_interpolator_taps/praxis.txt
+ */
+
+ class FILTER_API mmse_fir_interpolator_cc
+ {
+ public:
+ mmse_fir_interpolator_cc();
+ ~mmse_fir_interpolator_cc();
+
+ unsigned ntaps() const;
+ unsigned nsteps() const;
+
+ /*!
+ * \brief compute a single interpolated output value.
+ *
+ * \p input must have ntaps() valid entries and be 8-byte aligned.
+ * input[0] .. input[ntaps() - 1] are referenced to compute the output value.
+ * \throws std::invalid_argument if input is not 8-byte aligned.
+ *
+ * \p mu must be in the range [0, 1] and specifies the fractional delay.
+ *
+ * \returns the interpolated input value.
+ */
+ gr_complex interpolate(const gr_complex input[], float mu) const;
+
+ protected:
+ std::vector<kernel::fir_filter_ccf *> filters;
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* _MMSE_FIR_INTERPOLATOR_CC_H_ */
diff --git a/gr-filter/include/filter/mmse_fir_interpolator_ff.h b/gr-filter/include/filter/mmse_fir_interpolator_ff.h
new file mode 100644
index 000000000..4353aa94f
--- /dev/null
+++ b/gr-filter/include/filter/mmse_fir_interpolator_ff.h
@@ -0,0 +1,76 @@
+/* -*- 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 _MMSE_FIR_INTERPOLATOR_FF_H_
+#define _MMSE_FIR_INTERPOLATOR_FF_H_
+
+#include <filter/api.h>
+#include <filter/fir_filter.h>
+#include <vector>
+
+namespace gr {
+ namespace filter {
+
+ /*!
+ * \brief Compute intermediate samples between signal samples x(k*Ts)
+ * \ingroup filter_primitive
+ *
+ * This implements a Mininum Mean Squared Error interpolator with
+ * 8 taps. It is suitable for signals where the bandwidth of
+ * interest B = 1/(4*Ts) Where Ts is the time between samples.
+ *
+ * Although mu, the fractional delay, is specified as a float, it
+ * is actually quantized. 0.0 <= mu <= 1.0. That is, mu is
+ * quantized in the interpolate method to 32nd's of a sample.
+ *
+ * For more information, in the GNU Radio source code, see:
+ * \li gnuradio-core/src/gen_interpolator_taps/README
+ * \li gnuradio-core/src/gen_interpolator_taps/praxis.txt
+ */
+ class FILTER_API mmse_fir_interpolator_ff
+ {
+ public:
+ mmse_fir_interpolator_ff();
+ ~mmse_fir_interpolator_ff();
+
+ unsigned ntaps() const;
+ unsigned nsteps() const;
+
+ /*!
+ * \brief compute a single interpolated output value.
+ * \p input must have ntaps() valid entries.
+ * input[0] .. input[ntaps() - 1] are referenced to compute the output value.
+ *
+ * \p mu must be in the range [0, 1] and specifies the fractional delay.
+ *
+ * \returns the interpolated input value.
+ */
+ float interpolate(const float input[], float mu) const;
+
+ protected:
+ std::vector<kernel::fir_filter_fff*> filters;
+ };
+
+ } /* namespace filter */
+} /* namespace gr */
+
+#endif /* _MMSE_FIR_INTERPOLATOR_FF_H_ */
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 <config.h>
+#endif
+
+#include <filter/mmse_fir_interpolator_cc.h>
+#include <filter/interpolator_taps.h>
+#include <stdexcept>
+
+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<float> 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 <config.h>
+#endif
+
+#include <filter/mmse_fir_interpolator_ff.h>
+#include <filter/interpolator_taps.h>
+#include <stdexcept>
+
+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<float> 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 <qa_filter.h>
#include <qa_firdes.h>
+#include <qa_mmse_fir_interpolator_cc.h>
+#include <qa_mmse_fir_interpolator_ff.h>
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 <config.h>
+#endif
+
+#include <cppunit/TestAssert.h>
+#include <qa_mmse_fir_interpolator_cc.h>
+#include <filter/mmse_fir_interpolator_cc.h>
+#include <cstdio>
+#include <cmath>
+#include <stdexcept>
+
+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<gr_complex *>(&float_input[1]);
+ else
+ input = reinterpret_cast<gr_complex *>(&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 <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+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 <config.h>
+#endif
+
+#include <cppunit/TestAssert.h>
+#include <qa_mmse_fir_interpolator_ff.h>
+#include <filter/mmse_fir_interpolator_ff.h>
+#include <cstdio>
+#include <cmath>
+
+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 <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+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_ */