From 42f8854f6d13de7e3f142f3f80233066a032d627 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Thu, 7 Mar 2013 22:35:48 -0500
Subject: blocks: moved fxpt generators to gr-blocks.

Added C++ QA test setup.
---
 gr-blocks/include/blocks/CMakeLists.txt | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'gr-blocks/include/blocks/CMakeLists.txt')

diff --git a/gr-blocks/include/blocks/CMakeLists.txt b/gr-blocks/include/blocks/CMakeLists.txt
index 684639e07e..91d1ee4289 100644
--- a/gr-blocks/include/blocks/CMakeLists.txt
+++ b/gr-blocks/include/blocks/CMakeLists.txt
@@ -100,6 +100,9 @@ install(FILES
     ${generated_includes}
     api.h
     count_bits.h
+    fxpt.h
+    fxpt_nco.h
+    fxpt_vco.h
     log2_const.h
     add_ff.h
     bin_statistics_f.h
-- 
cgit v1.2.3


From 4389b769891283face9aa397bd4d736f478e97e4 Mon Sep 17 00:00:00 2001
From: Tom Rondeau <trondeau@vt.edu>
Date: Fri, 8 Mar 2013 08:57:46 -0500
Subject: blocks: moving vco/nco bases to gr-blocks.

---
 gr-blocks/CMakeLists.txt                |   3 +
 gr-blocks/grc/blocks_block_tree.xml     |   1 +
 gr-blocks/grc/blocks_vco_f.xml          |  35 +++++
 gr-blocks/include/blocks/CMakeLists.txt |   3 +
 gr-blocks/include/blocks/fxpt_nco.h     |   1 +
 gr-blocks/include/blocks/nco.h          | 210 +++++++++++++++++++++++++++++
 gr-blocks/include/blocks/vco.h          | 113 ++++++++++++++++
 gr-blocks/include/blocks/vco_f.h        |  57 ++++++++
 gr-blocks/lib/CMakeLists.txt            |   1 +
 gr-blocks/lib/qa_fxpt_nco.cc            |   6 +-
 gr-blocks/lib/qa_fxpt_vco.cc            |   6 +-
 gr-blocks/lib/vco_f_impl.cc             |  68 ++++++++++
 gr-blocks/lib/vco_f_impl.h              |  53 ++++++++
 gr-blocks/python/qa_vco.py              |  59 +++++++++
 gr-blocks/swig/blocks_swig.i            |   3 +
 gr-blocks/tests/CMakeLists.txt          |  56 ++++++++
 gr-blocks/tests/benchmark_nco.cc        | 225 ++++++++++++++++++++++++++++++++
 gr-blocks/tests/benchmark_vco.cc        | 172 ++++++++++++++++++++++++
 gr-blocks/tests/nco_results             |  48 +++++++
 19 files changed, 1114 insertions(+), 6 deletions(-)
 create mode 100644 gr-blocks/grc/blocks_vco_f.xml
 create mode 100644 gr-blocks/include/blocks/nco.h
 create mode 100644 gr-blocks/include/blocks/vco.h
 create mode 100644 gr-blocks/include/blocks/vco_f.h
 create mode 100644 gr-blocks/lib/vco_f_impl.cc
 create mode 100644 gr-blocks/lib/vco_f_impl.h
 create mode 100644 gr-blocks/python/qa_vco.py
 create mode 100644 gr-blocks/tests/CMakeLists.txt
 create mode 100644 gr-blocks/tests/benchmark_nco.cc
 create mode 100644 gr-blocks/tests/benchmark_vco.cc
 create mode 100644 gr-blocks/tests/nco_results

(limited to 'gr-blocks/include/blocks/CMakeLists.txt')

diff --git a/gr-blocks/CMakeLists.txt b/gr-blocks/CMakeLists.txt
index 7e2f43562f..e92e4c2808 100644
--- a/gr-blocks/CMakeLists.txt
+++ b/gr-blocks/CMakeLists.txt
@@ -80,6 +80,9 @@ CPACK_COMPONENT("blocks_swig"
 ########################################################################
 add_subdirectory(include/blocks)
 add_subdirectory(lib)
+#if(ENABLE_TESTING)
+#  add_subdirectory(tests)
+#endif(ENABLE_TESTING)
 if(ENABLE_PYTHON)
      add_subdirectory(python)
      add_subdirectory(swig)
diff --git a/gr-blocks/grc/blocks_block_tree.xml b/gr-blocks/grc/blocks_block_tree.xml
index 40061dd663..dc5fb6606d 100644
--- a/gr-blocks/grc/blocks_block_tree.xml
+++ b/gr-blocks/grc/blocks_block_tree.xml
@@ -59,6 +59,7 @@
                 <block>blocks_transcendental</block>
                 <block>blocks_argmax_xx</block>
                 <block>blocks_max_xx</block>
+                <block>blocks_vco_f</block>
 	</cat>
 	<cat>
 		<name>Boolean Operations (New) </name>
diff --git a/gr-blocks/grc/blocks_vco_f.xml b/gr-blocks/grc/blocks_vco_f.xml
new file mode 100644
index 0000000000..77a3ba0bd4
--- /dev/null
+++ b/gr-blocks/grc/blocks_vco_f.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+###################################################
+##VCO
+###################################################
+ -->
+<block>
+	<name>VCO</name>
+	<key>blocks_vco_f</key>
+	<import>from gnuradio import blocks</import>
+	<make>blocks.vco_f($samp_rate, $sensitivity, $amplitude)</make>
+	<param>
+		<name>Sample Rate</name>
+		<key>samp_rate</key>
+		<type>real</type>
+	</param>
+	<param>
+		<name>Sensitivity</name>
+		<key>sensitivity</key>
+		<type>real</type>
+	</param>
+	<param>
+		<name>Amplitude</name>
+		<key>amplitude</key>
+		<type>real</type>
+	</param>
+	<sink>
+		<name>in</name>
+		<type>float</type>
+	</sink>
+	<source>
+		<name>out</name>
+		<type>float</type>
+	</source>
+</block>
diff --git a/gr-blocks/include/blocks/CMakeLists.txt b/gr-blocks/include/blocks/CMakeLists.txt
index 91d1ee4289..8ffbdf0b19 100644
--- a/gr-blocks/include/blocks/CMakeLists.txt
+++ b/gr-blocks/include/blocks/CMakeLists.txt
@@ -104,6 +104,8 @@ install(FILES
     fxpt_nco.h
     fxpt_vco.h
     log2_const.h
+    nco.h
+    vco.h
     add_ff.h
     bin_statistics_f.h
     burst_tagger.h
@@ -169,6 +171,7 @@ install(FILES
     tuntap_pdu.h
     uchar_to_float.h
     unpack_k_bits_bb.h
+    vco_f.h
     vector_to_stream.h
     vector_to_streams.h
     DESTINATION ${GR_INCLUDE_DIR}/gnuradio/blocks
diff --git a/gr-blocks/include/blocks/fxpt_nco.h b/gr-blocks/include/blocks/fxpt_nco.h
index ea266552b3..0faa731763 100644
--- a/gr-blocks/include/blocks/fxpt_nco.h
+++ b/gr-blocks/include/blocks/fxpt_nco.h
@@ -77,6 +77,7 @@ namespace gr {
         d_phase += d_phase_inc;
       }
 
+      //! increment current phase angle n times
       void step(int n) {
         d_phase += d_phase_inc * n;
       }
diff --git a/gr-blocks/include/blocks/nco.h b/gr-blocks/include/blocks/nco.h
new file mode 100644
index 0000000000..e6658a3572
--- /dev/null
+++ b/gr-blocks/include/blocks/nco.h
@@ -0,0 +1,210 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2013 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 _GR_NCO_H_
+#define _GR_NCO_H_
+
+#include <vector>
+#include <gr_sincos.h>
+#include <cmath>
+#include <gr_complex.h>
+
+namespace gr {
+  namespace blocks {
+
+    /*!
+     * \brief base class template for Numerically Controlled Oscillator (NCO)
+     * \ingroup misc
+     *
+     * Calculate sine and cosine based on the current phase. This
+     * class has multiple ways to calculate sin/cos and when
+     * requensting a range will increment the phase based on a
+     * frequency, which can be set using set_freq. Similar interfaces
+     * to the fxpt_vco can also be used to set or adjust the current
+     * phase.
+     *
+     * \sa fxpt_nco.h for fixed-point implementation.
+     */
+    template<class o_type, class i_type>
+    class nco
+    {
+    public:
+      nco() : phase(0), phase_inc(0) {}
+
+      virtual ~nco() {}
+
+      //! Set the current phase \p angle in radians 
+      void set_phase(double angle) {
+        phase = angle;
+      }
+
+      //! Update the current phase in radians by \p delta_phase
+      void adjust_phase(double delta_phase) {
+        phase += delta_phase;
+      }
+
+      //! angle_rate is in radians / step
+      void set_freq(double angle_rate) {
+        phase_inc = angle_rate;
+      }
+
+      //! angle_rate is a delta in radians / step
+      void adjust_freq(double delta_angle_rate) {
+        phase_inc += delta_angle_rate;
+      }
+
+      //! increment current phase angle
+      void step()
+      {
+        phase += phase_inc;
+        if(fabs (phase) > M_PI) {
+
+          while(phase > M_PI)
+            phase -= 2*M_PI;
+
+          while(phase < -M_PI)
+            phase += 2*M_PI;
+        }
+      }
+
+      //! increment current phase angle n times
+      void step(int n)
+      {
+        phase += phase_inc * n;
+        if(fabs (phase) > M_PI) {
+
+          while(phase > M_PI)
+            phase -= 2*M_PI;
+
+          while(phase < -M_PI)
+            phase += 2*M_PI;
+        }
+      }
+
+      //! units are radians / step
+      double get_phase() const { return phase; }
+      double get_freq() const { return phase_inc; }
+
+      //! compute sin and cos for current phase angle
+      void sincos(float *sinx, float *cosx) const;
+
+      //! compute cos or sin for current phase angle
+      float cos() const { return std::cos (phase); }
+      float sin() const { return std::sin (phase); }
+
+      //! compute a block at a time
+      void sin(float *output, int noutput_items, double ampl = 1.0);
+      void cos(float *output, int noutput_items, double ampl = 1.0);
+      void sincos(gr_complex *output, int noutput_items, double ampl = 1.0);
+      void sin(short *output, int noutput_items, double ampl = 1.0);
+      void cos(short *output, int noutput_items, double ampl = 1.0);
+      void sin(int *output, int noutput_items, double ampl = 1.0);
+      void cos(int *output, int noutput_items, double ampl = 1.0);
+
+    protected:
+      double phase;
+      double phase_inc;
+    };
+
+    template<class o_type, class i_type>
+    void
+    nco<o_type,i_type>::sincos(float *sinx, float *cosx) const
+    {
+      gr_sincosf(phase, sinx, cosx);
+    }
+
+    template<class o_type, class i_type>
+    void
+    nco<o_type,i_type>::sin(float *output, int noutput_items, double ampl)
+    {
+      for(int i = 0; i < noutput_items; i++) {
+        output[i] = (float)(sin() * ampl);
+        step();
+      }
+    }
+
+    template<class o_type, class i_type>
+    void
+    nco<o_type,i_type>::cos(float *output, int noutput_items, double ampl)
+    {
+      for(int i = 0; i < noutput_items; i++){
+        output[i] = (float)(cos() * ampl);
+        step();
+      }
+    }
+
+    template<class o_type, class i_type>
+    void
+    nco<o_type,i_type>::sin(short *output, int noutput_items, double ampl)
+    {
+      for(int i = 0; i < noutput_items; i++) {
+        output[i] = (short)(sin() * ampl);
+        step();
+      }
+    }
+
+    template<class o_type, class i_type>
+    void
+    nco<o_type,i_type>::cos(short *output, int noutput_items, double ampl)
+    {
+      for(int i = 0; i < noutput_items; i++) {
+        output[i] = (short)(cos() * ampl);
+        step();
+      }
+    }
+
+    template<class o_type, class i_type>
+    void
+    nco<o_type,i_type>::sin(int *output, int noutput_items, double ampl)
+    {
+      for(int i = 0; i < noutput_items; i++) {
+        output[i] = (int)(sin() * ampl);
+        step();
+      }
+    }
+
+    template<class o_type, class i_type>
+    void
+    nco<o_type,i_type>::cos(int *output, int noutput_items, double ampl)
+    {
+      for(int i = 0; i < noutput_items; i++) {
+        output[i] = (int)(cos() * ampl);
+        step();
+      }
+    }
+
+    template<class o_type, class i_type>
+    void
+    nco<o_type,i_type>::sincos(gr_complex *output, int noutput_items, double ampl)
+    {
+      for(int i = 0; i < noutput_items; i++) {
+        float cosx, sinx;
+        sincos(&sinx, &cosx);
+        output[i] = gr_complex(cosx * ampl, sinx * ampl);
+        step();
+      }
+    }
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* _NCO_H_ */
diff --git a/gr-blocks/include/blocks/vco.h b/gr-blocks/include/blocks/vco.h
new file mode 100644
index 0000000000..4417d588ae
--- /dev/null
+++ b/gr-blocks/include/blocks/vco.h
@@ -0,0 +1,113 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2013 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 _GR_VCO_H_
+#define _GR_VCO_H_
+
+#include <vector>
+#include <gr_sincos.h>
+#include <cmath>
+#include <gr_complex.h>
+
+namespace gr {
+  namespace blocks {
+
+    /*!
+     * \brief base class template for Voltage Controlled Oscillator (VCO)
+     * \ingroup misc
+     *
+     * Simple calculations of sine and cosine. Set the phase using
+     * set_phase or adjust it by some delta using adjust_phase. Sine
+     * and cosine can be retrieved together with sincos(sinx, cosx)
+     * where sinx and cosx are the returned values at the current
+     * phase. They can be retrieved individually using either sin() or
+     * cos().
+     *
+     * \sa fxpt_nco.h for fixed-point implementation.
+     */
+
+    template<class o_type, class i_type>
+    class vco
+    {
+    public:
+      vco() : d_phase(0) {}
+
+      virtual ~vco() {}
+
+      //! Set the current phase \p angle in radians 
+      void set_phase(double angle) {
+        d_phase = angle;
+      }
+
+      //! Update the current phase in radians by \p delta_phase
+      void adjust_phase(double delta_phase) {
+        d_phase += delta_phase;
+        if(fabs(d_phase) > M_PI) {
+
+          while(d_phase > M_PI)
+            d_phase -= 2*M_PI;
+
+          while(d_phase < -M_PI)
+            d_phase += 2*M_PI;
+        }
+      }
+
+      //! Get the current phase in radians
+      double get_phase() const { return d_phase; }
+
+      //! compute sin and cos for current phase angle
+      void sincos(float *sinx, float *cosx) const;
+
+      //! compute cos or sin for current phase angle
+      float cos() const { return std::cos(d_phase); }
+      float sin() const { return std::sin(d_phase); }
+
+      //! compute a block at a time
+      void cos(float *output, const float *input, int noutput_items,
+               double k, double ampl = 1.0);
+
+    protected:
+      double d_phase;
+    };
+
+    template<class o_type, class i_type>
+    void
+    vco<o_type,i_type>::sincos(float *sinx, float *cosx) const
+    {
+      gr_sincosf(d_phase, sinx, cosx);
+    }
+
+    template<class o_type, class i_type>
+    void
+    vco<o_type,i_type>::cos(float *output, const float *input, int noutput_items,
+                            double k, double ampl)
+    {
+      for(int i = 0; i < noutput_items; i++) {
+        output[i] = cos() * ampl;
+        adjust_phase(input[i] * k);
+      }
+    }
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* _VCO_H_ */
diff --git a/gr-blocks/include/blocks/vco_f.h b/gr-blocks/include/blocks/vco_f.h
new file mode 100644
index 0000000000..0a5bf97d1f
--- /dev/null
+++ b/gr-blocks/include/blocks/vco_f.h
@@ -0,0 +1,57 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2013 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_VCO_F_H
+#define INCLUDED_GR_VCO_F_H
+
+#include <blocks/api.h>
+#include <gr_sync_block.h>
+
+namespace gr {
+  namespace blocks {
+
+    /*!
+     * \brief VCO - Voltage controlled oscillator
+     * \ingroup misc
+     *
+     * input: float stream of control voltages; output: float oscillator output
+     */
+    class BLOCKS_API vco_f : virtual public gr_sync_block
+    {
+    public:
+      // gr::blocks::vco_f::sptr
+      typedef boost::shared_ptr<vco_f> sptr;
+
+      /*!
+       * \brief VCO - Voltage controlled oscillator
+       *
+       * \param sampling_rate sampling rate (Hz)
+       * \param sensitivity units are radians/sec/volt
+       * \param amplitude output amplitude
+       */
+      static sptr make(double sampling_rate, double sensitivity, double amplitude);
+    };
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GR_VCO_F_H */
diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt
index ad0af831f4..4506eaca39 100644
--- a/gr-blocks/lib/CMakeLists.txt
+++ b/gr-blocks/lib/CMakeLists.txt
@@ -209,6 +209,7 @@ list(APPEND gr_blocks_sources
     uchar_array_to_float.cc
     uchar_to_float_impl.cc
     unpack_k_bits_bb_impl.cc
+    vco_f_impl.cc
     vector_to_stream_impl.cc
     vector_to_streams_impl.cc
 )
diff --git a/gr-blocks/lib/qa_fxpt_nco.cc b/gr-blocks/lib/qa_fxpt_nco.cc
index 12135dcf91..63c0a92902 100644
--- a/gr-blocks/lib/qa_fxpt_nco.cc
+++ b/gr-blocks/lib/qa_fxpt_nco.cc
@@ -26,7 +26,7 @@
 
 #include <qa_fxpt_nco.h>
 #include <blocks/fxpt_nco.h>
-#include <gr_nco.h>
+#include <blocks/nco.h>
 #include <cppunit/TestAssert.h>
 #include <iostream>
 #include <stdio.h>
@@ -50,7 +50,7 @@ static double max_d(double a, double b)
 void
 qa_fxpt_nco::t0()
 {
-  gr_nco<float,float>	ref_nco;
+  nco<float,float>	ref_nco;
   fxpt_nco		new_nco;
   double max_error = 0, max_phase_error = 0;
 
@@ -86,7 +86,7 @@ qa_fxpt_nco::t0()
 void
 qa_fxpt_nco::t1()
 {
-  gr_nco<float,float>	ref_nco;
+  nco<float,float>	ref_nco;
   fxpt_nco		new_nco;
   gr_complex		ref_block[SIN_COS_BLOCK_SIZE];
   gr_complex		new_block[SIN_COS_BLOCK_SIZE];
diff --git a/gr-blocks/lib/qa_fxpt_vco.cc b/gr-blocks/lib/qa_fxpt_vco.cc
index ff26e0129e..2efce0506b 100644
--- a/gr-blocks/lib/qa_fxpt_vco.cc
+++ b/gr-blocks/lib/qa_fxpt_vco.cc
@@ -26,7 +26,7 @@
 
 #include <qa_fxpt_vco.h>
 #include <blocks/fxpt_vco.h>
-#include <gr_vco.h>
+#include <blocks/vco.h>
 #include <cppunit/TestAssert.h>
 #include <iostream>
 #include <stdio.h>
@@ -50,7 +50,7 @@ static double max_d(double a, double b)
 void
 qa_fxpt_vco::t0()
 {
-  gr_vco<float,float>	ref_vco;
+  vco<float,float>	ref_vco;
   fxpt_vco		new_vco;
   double max_error = 0, max_phase_error = 0;
   float			input[SIN_COS_BLOCK_SIZE];
@@ -79,7 +79,7 @@ qa_fxpt_vco::t0()
 void
 qa_fxpt_vco::t1()
 {
-  gr_vco<float,float>	ref_vco;
+  vco<float,float>	ref_vco;
   fxpt_vco		new_vco;
   float			ref_block[SIN_COS_BLOCK_SIZE];
   float			new_block[SIN_COS_BLOCK_SIZE];
diff --git a/gr-blocks/lib/vco_f_impl.cc b/gr-blocks/lib/vco_f_impl.cc
new file mode 100644
index 0000000000..21e7d0a0f2
--- /dev/null
+++ b/gr-blocks/lib/vco_f_impl.cc
@@ -0,0 +1,68 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2010,2013 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 "vco_f_impl.h"
+#include <gr_io_signature.h>
+#include <math.h>
+
+namespace gr {
+  namespace blocks {
+
+    vco_f::sptr
+    vco_f::make(double sampling_rate, double sensitivity, double amplitude)
+    {
+      return gnuradio::get_initial_sptr
+        (new vco_f_impl(sampling_rate, sensitivity, amplitude));
+    }
+
+    vco_f_impl::vco_f_impl(double sampling_rate, double sensitivity, double amplitude)
+      : gr_sync_block("vco_f",
+                      gr_make_io_signature(1, 1, sizeof(float)),
+                      gr_make_io_signature(1, 1, sizeof(float))),
+        d_sampling_rate(sampling_rate), d_sensitivity(sensitivity),
+        d_amplitude(amplitude), d_k(d_sensitivity/d_sampling_rate)
+    {
+    }
+
+    vco_f_impl::~vco_f_impl()
+    {
+    }
+
+    int
+    vco_f_impl::work(int noutput_items,
+                     gr_vector_const_void_star &input_items,
+                     gr_vector_void_star &output_items)
+    {
+      const float *input = (const float*)input_items[0];
+      float *output = (float*)output_items[0];
+
+      d_vco.cos(output, input, noutput_items, d_k, d_amplitude);
+
+      return noutput_items;
+    }
+
+  } /* namespace blocks */
+} /* namespace gr */
diff --git a/gr-blocks/lib/vco_f_impl.h b/gr-blocks/lib/vco_f_impl.h
new file mode 100644
index 0000000000..cecf72441f
--- /dev/null
+++ b/gr-blocks/lib/vco_f_impl.h
@@ -0,0 +1,53 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005,2013 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_VCO_F_IMPL_H
+#define INCLUDED_GR_VCO_F_IMPL_H
+
+#include <blocks/vco_f.h>
+#include <blocks/fxpt_vco.h>
+
+namespace gr {
+  namespace blocks {
+
+    class vco_f_impl : public vco_f
+    {
+    private:
+      double d_sampling_rate;
+      double d_sensitivity;
+      double d_amplitude;
+      double d_k;
+      fxpt_vco d_vco;
+
+    public:
+      vco_f_impl(double sampling_rate, double sensitivity, double amplitude);
+      ~vco_f_impl();
+
+      int work(int noutput_items,
+               gr_vector_const_void_star &input_items,
+               gr_vector_void_star &output_items);
+    };
+
+  } /* namespace blocks */
+} /* namespace gr */
+
+#endif /* INCLUDED_GR_VCO_F_H */
diff --git a/gr-blocks/python/qa_vco.py b/gr-blocks/python/qa_vco.py
new file mode 100644
index 0000000000..721eb9471b
--- /dev/null
+++ b/gr-blocks/python/qa_vco.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# Copyright 2013 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.
+#
+
+from gnuradio import gr, gr_unittest
+import blocks_swig
+import math
+
+def sig_source_f(samp_rate, freq, amp, N):
+    t = map(lambda x: float(x)/samp_rate, xrange(N))
+    y = map(lambda x: amp*math.cos(2.*math.pi*freq*x), t)
+    return y
+
+class test_vco(gr_unittest.TestCase):
+
+    def setUp (self):
+        self.tb = gr.top_block ()
+
+    def tearDown (self):
+        self.tb = None
+
+    def test_001(self):
+        src_data = 200*[0,] + 200*[0.5,] + 200*[1,]
+        expected_result = 200*[1,] + \
+            sig_source_f(1, 0.125, 1, 200) + \
+            sig_source_f(1, 0.25, 1, 200)
+
+        src = gr.vector_source_f(src_data)
+        op = blocks_swig.vco_f(1, math.pi/2.0, 1)
+        dst = gr.vector_sink_f()
+
+        self.tb.connect(src, op, dst)
+        self.tb.run()
+
+        result_data = dst.data()
+        self.assertFloatTuplesAlmostEqual(expected_result, result_data, 5)
+
+
+if __name__ == '__main__':
+    gr_unittest.run(test_vco, "test_vco.xml")
+
diff --git a/gr-blocks/swig/blocks_swig.i b/gr-blocks/swig/blocks_swig.i
index 1c0f49dfeb..19f1c949ca 100644
--- a/gr-blocks/swig/blocks_swig.i
+++ b/gr-blocks/swig/blocks_swig.i
@@ -175,6 +175,7 @@
 #include "blocks/unpacked_to_packed_bb.h"
 #include "blocks/unpacked_to_packed_ss.h"
 #include "blocks/unpacked_to_packed_ii.h"
+#include "blocks/vco_f.h"
 #include "blocks/vector_to_stream.h"
 #include "blocks/vector_to_streams.h"
 #include "blocks/xor_bb.h"
@@ -326,6 +327,7 @@
 %include "blocks/unpacked_to_packed_bb.h"
 %include "blocks/unpacked_to_packed_ss.h"
 %include "blocks/unpacked_to_packed_ii.h"
+%include "blocks/vco_f.h"
 %include "blocks/vector_to_stream.h"
 %include "blocks/vector_to_streams.h"
 %include "blocks/xor_bb.h"
@@ -476,6 +478,7 @@ GR_SWIG_BLOCK_MAGIC2(blocks, unpack_k_bits_bb);
 GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_bb);
 GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_ss);
 GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_ii);
+GR_SWIG_BLOCK_MAGIC2(blocks, vco_f);
 GR_SWIG_BLOCK_MAGIC2(blocks, vector_to_stream);
 GR_SWIG_BLOCK_MAGIC2(blocks, vector_to_streams);
 GR_SWIG_BLOCK_MAGIC2(blocks, xor_bb);
diff --git a/gr-blocks/tests/CMakeLists.txt b/gr-blocks/tests/CMakeLists.txt
new file mode 100644
index 0000000000..8f7ba2f64f
--- /dev/null
+++ b/gr-blocks/tests/CMakeLists.txt
@@ -0,0 +1,56 @@
+# Copyright 2010-2013 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(GrMiscUtils) #check n def
+GR_CHECK_HDR_N_DEF(sys/resource.h HAVE_SYS_RESOURCE_H)
+
+########################################################################
+# Setup the include and linker paths
+########################################################################
+include_directories(
+    ${GR_BLOCKS_INCLUDE_DIRS}
+    ${GNURADIO_CORE_INCLUDE_DIRS}
+    ${GRUEL_INCLUDE_DIRS}
+    ${Boost_INCLUDE_DIRS}
+    ${CPPUNIT_INCLUDE_DIRS}
+)
+
+link_directories(
+    ${Boost_LIBRARY_DIRS}
+    ${CPPUNIT_LIBRARY_DIRS}
+)
+
+include_directories(${LOG4CXX_INCLUDE_DIRS})
+link_directories(${LOG4CXX_LIBRARY_DIRS})
+
+########################################################################
+# Build benchmarks and non-registered tests
+########################################################################
+set(tests_not_run #single source per test
+    benchmark_nco.cc
+    benchmark_vco.cc
+)
+
+foreach(test_not_run_src ${tests_not_run})
+    get_filename_component(name ${test_not_run_src} NAME_WE)
+    add_executable(${name} ${test_not_run_src})
+    target_link_libraries(${name} test-gnuradio-core gnuradio-blocks)
+endforeach(test_not_run_src)
+
diff --git a/gr-blocks/tests/benchmark_nco.cc b/gr-blocks/tests/benchmark_nco.cc
new file mode 100644
index 0000000000..4c2ed120db
--- /dev/null
+++ b/gr-blocks/tests/benchmark_nco.cc
@@ -0,0 +1,225 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2004,2013 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include <unistd.h>
+#include <blocks/nco.h>
+#include <blocks/fxpt_nco.h>
+#include <string.h>
+
+#define ITERATIONS 20000000
+#define BLOCK_SIZE (10 * 1000)	// fits in cache
+
+#define FREQ 5003.123
+
+static double
+timeval_to_double(const struct timeval *tv)
+{
+  return (double)tv->tv_sec + (double)tv->tv_usec * 1e-6;
+}
+
+
+static void
+benchmark(void test (float *x, float *y), const char *implementation_name)
+{
+#ifdef HAVE_SYS_RESOURCE_H
+  struct rusage	rusage_start;
+  struct rusage	rusage_stop;
+#else
+  double clock_start;
+  double clock_end;
+#endif
+  float output[2*BLOCK_SIZE];
+  float *x = &output[0], *y = &output[BLOCK_SIZE];
+
+  // touch memory
+  memset(output, 0, 2*BLOCK_SIZE*sizeof(float));
+
+  // get starting CPU usage
+#ifdef HAVE_SYS_RESOURCE_H
+  if(getrusage(RUSAGE_SELF, &rusage_start) < 0) {
+    perror("getrusage");
+    exit(1);
+  }
+#else
+  clock_start = (double)clock() * (1000000. / CLOCKS_PER_SEC);
+#endif
+  // do the actual work
+
+  test(x, y);
+
+  // get ending CPU usage
+
+#ifdef HAVE_SYS_RESOURCE_H
+  if(getrusage(RUSAGE_SELF, &rusage_stop) < 0) {
+    perror("getrusage");
+    exit(1);
+  }
+
+  // compute results
+
+  double user =
+    timeval_to_double(&rusage_stop.ru_utime)
+    - timeval_to_double(&rusage_start.ru_utime);
+
+  double sys =
+    timeval_to_double(&rusage_stop.ru_stime)
+    - timeval_to_double(&rusage_start.ru_stime);
+
+  double total = user + sys;
+#else
+  clock_end = (double)clock() * (1000000. / CLOCKS_PER_SEC);
+  double total = clock_end - clock_start;
+#endif
+
+  printf("%18s:  cpu: %6.3f  steps/sec: %10.3e\n",
+         implementation_name, total, ITERATIONS / total);
+}
+
+// ----------------------------------------------------------------
+// Don't compare the _vec with other functions since memory store's
+// are involved.
+
+void basic_sincos_vec(float *x, float *y)
+{
+  gr::blocks::nco<float,float> nco;
+
+  nco.set_freq(2 * M_PI / FREQ);
+
+  for(int i = 0; i < ITERATIONS/BLOCK_SIZE; i++) {
+    for(int j = 0; j < BLOCK_SIZE; j++) {
+      nco.sincos(&x[2*j+1], &x[2*j]);
+      nco.step();
+    }
+  }
+}
+
+void native_sincos_vec(float *x, float *y)
+{
+  gr::blocks::nco<float,float> nco;
+
+  nco.set_freq(2 * M_PI / FREQ);
+
+  for(int i = 0; i < ITERATIONS/BLOCK_SIZE; i++) {
+    nco.sincos((gr_complex*)x, BLOCK_SIZE);
+  }
+}
+
+void fxpt_sincos_vec(float *x, float *y)
+{
+  gr::blocks::fxpt_nco nco;
+
+  nco.set_freq (2 * M_PI / FREQ);
+
+  for(int i = 0; i < ITERATIONS/BLOCK_SIZE; i++) {
+    nco.sincos((gr_complex*)x, BLOCK_SIZE);
+  }
+}
+
+// ----------------------------------------------------------------
+
+void native_sincos(float *x, float *y)
+{
+  gr::blocks::nco<float,float> nco;
+
+  nco.set_freq(2 * M_PI / FREQ);
+
+  for(int i = 0; i < ITERATIONS; i++) {
+    nco.sincos(x, y);
+    nco.step();
+  }
+}
+
+void fxpt_sincos(float *x, float *y)
+{
+  gr::blocks::fxpt_nco nco;
+
+  nco.set_freq(2 * M_PI / FREQ);
+
+  for(int i = 0; i < ITERATIONS; i++) {
+    nco.sincos(x, y);
+    nco.step();
+  }
+}
+
+// ----------------------------------------------------------------
+
+void native_sin(float *x, float *y)
+{
+  gr::blocks::nco<float,float> nco;
+
+  nco.set_freq(2 * M_PI / FREQ);
+
+  for(int i = 0; i < ITERATIONS; i++) {
+    *x = nco.sin();
+    nco.step();
+  }
+}
+
+void fxpt_sin(float *x, float *y)
+{
+  gr::blocks::fxpt_nco nco;
+
+  nco.set_freq(2 * M_PI / FREQ);
+
+  for(int i = 0; i < ITERATIONS; i++) {
+    *x = nco.sin();
+    nco.step();
+  }
+}
+
+// ----------------------------------------------------------------
+
+void nop_fct(float *x, float *y)
+{
+}
+
+void nop_loop(float *x, float *y)
+{
+  for(int i = 0; i < ITERATIONS; i++) {
+    nop_fct(x, y);
+  }
+}
+
+int
+main(int argc, char **argv)
+{
+  benchmark(nop_loop, "nop loop");
+  benchmark(native_sin, "native sine");
+  benchmark(fxpt_sin, "fxpt sine");
+  benchmark(native_sincos, "native sin/cos");
+  benchmark(fxpt_sincos, "fxpt sin/cos");
+  benchmark(basic_sincos_vec, "basic sin/cos vec");
+  benchmark(native_sincos_vec, "native sin/cos vec");
+  benchmark(fxpt_sincos_vec, "fxpt sin/cos vec");
+}
diff --git a/gr-blocks/tests/benchmark_vco.cc b/gr-blocks/tests/benchmark_vco.cc
new file mode 100644
index 0000000000..955dc08051
--- /dev/null
+++ b/gr-blocks/tests/benchmark_vco.cc
@@ -0,0 +1,172 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2004,2005,2013 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include <unistd.h>
+#include <blocks/vco.h>
+#include <blocks/fxpt_vco.h>
+#include <string.h>
+
+#define ITERATIONS 5000000
+#define BLOCK_SIZE (10 * 1000)	// fits in cache
+
+#define FREQ 5003.123
+#define K 4.9999999
+#define AMPLITUDE 2.444444444
+
+
+static double
+timeval_to_double(const struct timeval *tv)
+{
+  return (double) tv->tv_sec + (double) tv->tv_usec * 1e-6;
+}
+
+
+static void
+benchmark(void test (float *x, const float *y), const char *implementation_name)
+{
+#ifdef HAVE_SYS_RESOURCE_H
+  struct rusage	rusage_start;
+  struct rusage	rusage_stop;
+#else
+  double clock_start;
+  double clock_end;
+#endif
+  float output[BLOCK_SIZE];
+  float input[BLOCK_SIZE];
+
+  // touch memory
+  memset(output, 0, BLOCK_SIZE*sizeof(float));
+  for(int i = 0; i<BLOCK_SIZE; i++)
+    input[i] = sin(double(i));
+
+  // get starting CPU usage
+#ifdef HAVE_SYS_RESOURCE_H
+  if(getrusage (RUSAGE_SELF, &rusage_start) < 0) {
+    perror("getrusage");
+    exit(1);
+  }
+#else
+  clock_start = (double)clock() * (1000000. / CLOCKS_PER_SEC);
+#endif
+  // do the actual work
+
+  test(output, input);
+
+  // get ending CPU usage
+
+#ifdef HAVE_SYS_RESOURCE_H
+  if(getrusage (RUSAGE_SELF, &rusage_stop) < 0) {
+    perror("getrusage");
+    exit(1);
+  }
+
+  // compute results
+
+  double user =
+    timeval_to_double(&rusage_stop.ru_utime)
+    - timeval_to_double(&rusage_start.ru_utime);
+
+  double sys =
+    timeval_to_double(&rusage_stop.ru_stime)
+    - timeval_to_double(&rusage_start.ru_stime);
+
+  double total = user + sys;
+#else
+  clock_end = (double)clock() * (1000000. / CLOCKS_PER_SEC);
+  double total = clock_end - clock_start;
+#endif
+
+  printf("%18s:  cpu: %6.3f  steps/sec: %10.3e\n",
+         implementation_name, total, ITERATIONS / total);
+}
+
+// ----------------------------------------------------------------
+
+void basic_vco(float *output, const float *input)
+{
+  double phase = 0;
+
+  for(int j = 0; j < ITERATIONS/BLOCK_SIZE; j++) {
+    for(int i = 0; i < BLOCK_SIZE; i++) {
+      output[i] = cos(phase) * AMPLITUDE;
+      phase += input[i] * K;
+
+      while(phase > 2 * M_PI)
+	phase -= 2 * M_PI;
+
+      while(phase < -2 * M_PI)
+	phase += 2 * M_PI;
+    }
+  }
+}
+
+void native_vco(float *output, const float *input)
+{
+  gr::blocks::vco<float,float> vco;
+
+  for(int j = 0; j < ITERATIONS/BLOCK_SIZE; j++) {
+    vco.cos(output, input, BLOCK_SIZE, K, AMPLITUDE);
+  }
+}
+
+void fxpt_vco(float *output, const float *input)
+{
+  gr::blocks::fxpt_vco vco;
+
+  for(int j = 0; j < ITERATIONS/BLOCK_SIZE; j++) {
+    vco.cos(output, input, BLOCK_SIZE, K, AMPLITUDE);
+  }
+}
+
+// ----------------------------------------------------------------
+
+void nop_fct(float *x, const float *y)
+{
+}
+
+void nop_loop(float *x, const float *y)
+{
+  for(int i = 0; i < ITERATIONS; i++) {
+    nop_fct(x, y);
+  }
+}
+
+int
+main(int argc, char **argv)
+{
+  benchmark(nop_loop, "nop loop");
+  benchmark(basic_vco, "basic vco");
+  benchmark(native_vco, "native vco");
+  benchmark(fxpt_vco, "fxpt vco");
+}
diff --git a/gr-blocks/tests/nco_results b/gr-blocks/tests/nco_results
new file mode 100644
index 0000000000..5bdf5dd1cb
--- /dev/null
+++ b/gr-blocks/tests/nco_results
@@ -0,0 +1,48 @@
+================================================================
+These are on a 1.4 GHz Pentium M using g++ 3.4.1
+================================================================
+
+Default compiler options -O2
+
+        nop loop:  cpu:  0.015  steps/sec:  6.668e+08
+     native sine:  cpu:  0.900  steps/sec:  1.111e+07
+       fxpt sine:  cpu:  0.281  steps/sec:  3.559e+07
+  native sin/cos:  cpu:  1.138  steps/sec:  8.789e+06
+    fxpt sin/cos:  cpu:  0.550  steps/sec:  1.818e+07
+
+-O2 -march=pentium-m -fomit-frame-pointer
+
+        nop loop:  cpu:  0.015  steps/sec:  6.668e+08
+     native sine:  cpu:  0.903  steps/sec:  1.108e+07
+       fxpt sine:  cpu:  0.271  steps/sec:  3.691e+07
+  native sin/cos:  cpu:  1.092  steps/sec:  9.159e+06
+    fxpt sin/cos:  cpu:  0.542  steps/sec:  1.845e+07
+
+Inlined fxpt::sin & cos
+-O2 -march=pentium-m -fomit-frame-pointer
+
+        nop loop:  cpu:  0.015  steps/sec:  6.668e+08
+     native sine:  cpu:  0.904  steps/sec:  1.106e+07
+       fxpt sine:  cpu:  0.187  steps/sec:  5.348e+07
+  native sin/cos:  cpu:  1.091  steps/sec:  9.167e+06
+    fxpt sin/cos:  cpu:  0.373  steps/sec:  2.681e+07
+
+================================================================
+These are on a 1.5 GHz Athon MP 1800+
+================================================================
+
+Default compiler options: -O2
+
+        nop loop:  cpu:  0.013  steps/sec:  7.693e+08
+     native sine:  cpu:  0.733  steps/sec:  1.364e+07
+       fxpt sine:  cpu:  0.210  steps/sec:  4.763e+07
+  native sin/cos:  cpu:  1.183  steps/sec:  8.454e+06
+    fxpt sin/cos:  cpu:  0.420  steps/sec:  2.381e+07
+
+-O2 -fomit-frame-pointer -march=athlon-mp
+
+        nop loop:  cpu:  0.013  steps/sec:  7.693e+08
+     native sine:  cpu:  0.679  steps/sec:  1.473e+07
+       fxpt sine:  cpu:  0.200  steps/sec:  5.001e+07
+  native sin/cos:  cpu:  1.147  steps/sec:  8.720e+06
+    fxpt sin/cos:  cpu:  0.444  steps/sec:  2.253e+07
-- 
cgit v1.2.3