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
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
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
/* -*- c++ -*- */
/*
- * Copyright 2003 Free Software Foundation, Inc.
+ * Copyright 2003,2008 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
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;
}
};
#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 ()
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;
}
--- /dev/null
+/* -*- 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;
+ }
+}
--- /dev/null
+/* -*- 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_ */