Fix for ticket:214, gr_rotate speedup. We now normalize once every
authoreb <eb@221aa14e-8319-0410-a670-987f0aec2ac5>
Sat, 23 Aug 2008 21:26:19 +0000 (21:26 +0000)
committereb <eb@221aa14e-8319-0410-a670-987f0aec2ac5>
Sat, 23 Aug 2008 21:26:19 +0000 (21:26 +0000)
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

gnuradio-core/src/lib/filter/Makefile.am
gnuradio-core/src/lib/filter/gr_rotator.h
gnuradio-core/src/lib/filter/qa_filter.cc
gnuradio-core/src/lib/filter/qa_gr_rotator.cc [new file with mode: 0644]
gnuradio-core/src/lib/filter/qa_gr_rotator.h [new file with mode: 0644]

index 66946163201ed758ee25374a07bcdd7044d96808..14800cd947b0fd326b1f0d5648f08233d93e6f8e 100644 (file)
@@ -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       
 
index ccc08c9c256bbe08a0a4e8fd336d20f148a2da4d..cb8f21a4030955b4d88a178c7bf035647182b616 100644 (file)
@@ -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
  * 
 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;
   }
 
 };
index e2fa72adda0156a9e27ce3bbdc0f4951c3952898..878d48023b717bad84eed436e57679841ab643e1 100644 (file)
@@ -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 (file)
index 0000000..ce71a3d
--- /dev/null
@@ -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 (file)
index 0000000..2cc6006
--- /dev/null
@@ -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_ */