diff options
author | eb | 2008-08-23 21:26:19 +0000 |
---|---|---|
committer | eb | 2008-08-23 21:26:19 +0000 |
commit | 5b313df46a91b36f0698e5b369dba57f7ea8d879 (patch) | |
tree | b09e14d9026b2686b617a60d40757956b6e25e15 | |
parent | 0da73b85fc0a8bf49e84c46e29b045d76defa984 (diff) | |
download | gnuradio-5b313df46a91b36f0698e5b369dba57f7ea8d879.tar.gz gnuradio-5b313df46a91b36f0698e5b369dba57f7ea8d879.tar.bz2 gnuradio-5b313df46a91b36f0698e5b369dba57f7ea8d879.zip |
Fix for ticket:214, gr_rotate speedup. We now normalize once every
512 cycles. We also now compute the return value based on the
preincremented phase value, thus shortening the dependency chain.
This does put the computed result 1 tick ahead of the previous version
of the code, but none of the code in the tree depends on the absolute
phase. If yours does, sorry. You can work around it by initializing
the phase to conj(gr_expj(phase_incr)) instead of gr_complex(1,0).
Added QA code to ensure I didn't break anything.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@9384 221aa14e-8319-0410-a670-987f0aec2ac5
-rw-r--r-- | gnuradio-core/src/lib/filter/Makefile.am | 2 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_rotator.h | 21 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/qa_filter.cc | 2 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/qa_gr_rotator.cc | 70 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/qa_gr_rotator.h | 39 |
5 files changed, 125 insertions, 9 deletions
diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am index 669461632..14800cd94 100644 --- a/gnuradio-core/src/lib/filter/Makefile.am +++ b/gnuradio-core/src/lib/filter/Makefile.am @@ -230,6 +230,7 @@ libfilter_qa_la_common_SOURCES = \ qa_gr_fir_fff.cc \ qa_gr_fir_ccc.cc \ qa_gr_fir_scc.cc \ + qa_gr_rotator.cc \ qa_gri_mmse_fir_interpolator.cc \ qa_gri_mmse_fir_interpolator_cc.cc @@ -317,6 +318,7 @@ noinst_HEADERS = \ qa_gr_fir_fff.h \ qa_gr_fir_ccc.h \ qa_gr_fir_scc.h \ + qa_gr_rotator.h \ qa_gri_mmse_fir_interpolator.h \ qa_gri_mmse_fir_interpolator_cc.h diff --git a/gnuradio-core/src/lib/filter/gr_rotator.h b/gnuradio-core/src/lib/filter/gr_rotator.h index ccc08c9c2..cb8f21a40 100644 --- a/gnuradio-core/src/lib/filter/gr_rotator.h +++ b/gnuradio-core/src/lib/filter/gr_rotator.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003 Free Software Foundation, Inc. + * Copyright 2003,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -28,21 +28,24 @@ class gr_rotator { gr_complex d_phase; gr_complex d_phase_incr; + unsigned int d_counter; public: - gr_rotator () : d_phase (1), d_phase_incr (0) { } + gr_rotator () : d_phase (1), d_phase_incr (1), d_counter(0) { } - void set_phase (gr_complex phase) { d_phase = phase; } - void set_phase_incr (gr_complex incr) { d_phase_incr = incr; } + void set_phase (gr_complex phase) { d_phase = phase / abs(phase); } + void set_phase_incr (gr_complex incr) { d_phase_incr = incr / abs(incr); } gr_complex rotate (gr_complex in){ - d_phase *= d_phase_incr; // incr our phase (complex mult == add phases) + d_counter++; - d_phase /= abs(d_phase); // ensure multiplication is rotation - // FIXME. This is expensive. Maybe workaround using - // double precision complex??? + gr_complex z = in * d_phase; // rotate in by phase + d_phase *= d_phase_incr; // incr our phase (complex mult == add phases) - return in * d_phase; // rotate in by phase + if ((d_counter % 512) == 0) + d_phase /= abs(d_phase); // Normalize to ensure multiplication is rotation + + return z; } }; diff --git a/gnuradio-core/src/lib/filter/qa_filter.cc b/gnuradio-core/src/lib/filter/qa_filter.cc index e2fa72add..878d48023 100644 --- a/gnuradio-core/src/lib/filter/qa_filter.cc +++ b/gnuradio-core/src/lib/filter/qa_filter.cc @@ -35,6 +35,7 @@ #include <qa_dotprod.h> #include <qa_gri_mmse_fir_interpolator.h> #include <qa_gri_mmse_fir_interpolator_cc.h> +#include <qa_gr_rotator.h> CppUnit::TestSuite * qa_filter::suite () @@ -49,6 +50,7 @@ qa_filter::suite () s->addTest (qa_gr_fir_ccf::suite ()); s->addTest (qa_gri_mmse_fir_interpolator::suite ()); s->addTest (qa_gri_mmse_fir_interpolator_cc::suite ()); + s->addTest (qa_gr_rotator::suite ()); return s; } diff --git a/gnuradio-core/src/lib/filter/qa_gr_rotator.cc b/gnuradio-core/src/lib/filter/qa_gr_rotator.cc new file mode 100644 index 000000000..ce71a3d88 --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gr_rotator.cc @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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 <cppunit/TestAssert.h> +#include <qa_gr_rotator.h> +#include <gr_rotator.h> +#include <stdio.h> +#include <cmath> +#include <gr_expj.h> + + +// error vector magnitude +__attribute__((unused)) static float +error_vector_mag(gr_complex a, gr_complex b) +{ + return abs(a-b); +} + +void +qa_gr_rotator::t1 () +{ + static const unsigned int N = 100000; + + gr_rotator r; + + double phase_incr = 2*M_PI / 1003; + double phase = 0; + + // Old code: We increment then return the rotated value, thus we need to start one tick back + // r.set_phase(gr_complex(1,0) * conj(gr_expj(phase_incr))); + + r.set_phase(gr_complex(1,0)); + r.set_phase_incr(gr_expj(phase_incr)); + + for (unsigned i = 0; i < N; i++){ + gr_complex expected = gr_expj(phase); + gr_complex actual = r.rotate(gr_complex(1, 0)); + +#if 0 + float evm = error_vector_mag(expected, actual); + printf("[%6d] expected: (%8.6f, %8.6f) actual: (%8.6f, %8.6f) evm: %8.6f\n", + i, expected.real(), expected.imag(), actual.real(), actual.imag(), evm); +#endif + + CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected, actual, 0.0001); + + phase += phase_incr; + if (phase >= 2*M_PI) + phase -= 2*M_PI; + } +} diff --git a/gnuradio-core/src/lib/filter/qa_gr_rotator.h b/gnuradio-core/src/lib/filter/qa_gr_rotator.h new file mode 100644 index 000000000..2cc6006aa --- /dev/null +++ b/gnuradio-core/src/lib/filter/qa_gr_rotator.h @@ -0,0 +1,39 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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_ROTATOR_H_ +#define _QA_GR_ROTATOR_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_gr_rotator : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE (qa_gr_rotator); + CPPUNIT_TEST (t1); + CPPUNIT_TEST_SUITE_END (); + + private: + void t1 (); + +}; + +#endif /* _QA_GR_ROTATOR_H_ */ |