summaryrefslogtreecommitdiff
path: root/gnuradio-core
diff options
context:
space:
mode:
authortrondeau2008-01-09 23:27:36 +0000
committertrondeau2008-01-09 23:27:36 +0000
commitee31bc0892dbd2c1d5ecae3a9ce9e54ed1bdf8c5 (patch)
tree82bb22ba7c095742f9c5cc83bfa17747d2c829c7 /gnuradio-core
parent97dca638c9d58fe50a535719c2956ca9c937d963 (diff)
downloadgnuradio-ee31bc0892dbd2c1d5ecae3a9ce9e54ed1bdf8c5.tar.gz
gnuradio-ee31bc0892dbd2c1d5ecae3a9ce9e54ed1bdf8c5.tar.bz2
gnuradio-ee31bc0892dbd2c1d5ecae3a9ce9e54ed1bdf8c5.zip
merging receiver branch -r6837:7375 into trunk. Improves speed of MPSK receiver; adds branching and branchless versions of clipping and slicing routines to gr_math.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7389 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gnuradio-core')
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am6
-rw-r--r--gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc29
-rw-r--r--gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.h3
-rw-r--r--gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.cc6
-rw-r--r--gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.h5
-rw-r--r--gnuradio-core/src/lib/general/gr_math.h96
-rw-r--r--gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.cc72
-rw-r--r--gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.h3
-rw-r--r--gnuradio-core/src/lib/general/qa_general.cc2
-rw-r--r--gnuradio-core/src/lib/general/qa_gr_math.cc105
-rw-r--r--gnuradio-core/src/lib/general/qa_gr_math.h42
11 files changed, 281 insertions, 88 deletions
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index cde6a7549..238c56d84 100644
--- a/gnuradio-core/src/lib/general/Makefile.am
+++ b/gnuradio-core/src/lib/general/Makefile.am
@@ -169,7 +169,8 @@ libgeneral_qa_la_SOURCES = \
qa_gr_firdes.cc \
qa_gr_fxpt.cc \
qa_gr_fxpt_nco.cc \
- qa_gr_fxpt_vco.cc
+ qa_gr_fxpt_vco.cc \
+ qa_gr_math.cc
@@ -325,7 +326,8 @@ noinst_HEADERS = \
qa_gr_fxpt.h \
qa_gr_fxpt_nco.h \
qa_gr_fxpt_vco.h \
- sine_table.h
+ sine_table.h \
+ qa_gr_math.h
swiginclude_HEADERS = \
general.i \
diff --git a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc
index 6761392e6..675b8611f 100644
--- a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc
+++ b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc
@@ -151,25 +151,14 @@ gr_clock_recovery_mm_cc::general_work (int noutput_items,
out[oo++] = d_p_0T;
// limit mm_val
- if (mm_val > 1.0)
- mm_val = 1.0;
- else if (mm_val < -1.0)
- mm_val = -1.0;
-
+ gr_branchless_clip(mm_val,1.0);
d_omega = d_omega + d_gain_omega * mm_val;
- if (d_omega > d_max_omega)
- d_omega = d_max_omega;
- else if (d_omega < d_min_omega)
- d_omega = d_min_omega;
-
+ d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
+
d_mu = d_mu + d_omega + d_gain_mu * mm_val;
ii += (int)floor(d_mu);
d_mu -= floor(d_mu);
-
- #if 0
- printf("%f\t%f\n", d_omega, d_mu);
- #endif
-
+
// write the error signal to the second output
foptr[oo-1] = gr_complex(d_mu,0);
@@ -195,16 +184,10 @@ gr_clock_recovery_mm_cc::general_work (int noutput_items,
out[oo++] = d_p_0T;
// limit mm_val
- if (mm_val > 1.0)
- mm_val = 1.0;
- else if (mm_val < -1.0)
- mm_val = -1.0;
+ gr_branchless_clip(mm_val,1.0);
d_omega = d_omega + d_gain_omega * mm_val;
- if (d_omega > d_max_omega)
- d_omega = d_max_omega;
- else if (d_omega < d_min_omega)
- d_omega = d_min_omega;
+ d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
d_mu = d_mu + d_omega + d_gain_mu * mm_val;
ii += (int)floor(d_mu);
diff --git a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.h b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.h
index 453bafbe1..866732286 100644
--- a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.h
+++ b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.h
@@ -25,6 +25,7 @@
#include <gr_block.h>
#include <gr_complex.h>
+#include <gr_math.h>
class gri_mmse_fir_interpolator_cc;
@@ -69,6 +70,7 @@ class gr_clock_recovery_mm_cc : public gr_block
d_omega = omega;
d_min_omega = omega*(1.0 - d_omega_relative_limit);
d_max_omega = omega*(1.0 + d_omega_relative_limit);
+ d_omega_mid = 0.5*(d_min_omega+d_max_omega);
}
protected:
@@ -82,6 +84,7 @@ protected:
float d_min_omega; // minimum allowed omega
float d_max_omega; // maximum allowed omeg
float d_omega_relative_limit; // used to compute min and max omega
+ float d_omega_mid;
float d_gain_mu;
gr_complex d_last_sample;
gri_mmse_fir_interpolator_cc *d_interp;
diff --git a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.cc b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.cc
index d27ab9d65..fdf82667a 100644
--- a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.cc
+++ b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.cc
@@ -118,11 +118,7 @@ gr_clock_recovery_mm_ff::general_work (int noutput_items,
d_last_sample = out[oo];
d_omega = d_omega + d_gain_omega * mm_val;
- if (d_omega > d_max_omega)
- d_omega = d_max_omega;
- else if (d_omega < d_min_omega)
- d_omega = d_min_omega;
-
+ d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away
d_mu = d_mu + d_omega + d_gain_mu * mm_val;
ii += (int) floor(d_mu);
diff --git a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.h b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.h
index 87823c44e..a121fe821 100644
--- a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.h
+++ b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_ff.h
@@ -24,6 +24,7 @@
#define INCLUDED_GR_CLOCK_RECOVERY_MM_FF_H
#include <gr_block.h>
+#include <gr_math.h>
#include <stdio.h>
class gri_mmse_fir_interpolator;
@@ -67,6 +68,7 @@ class gr_clock_recovery_mm_ff : public gr_block
d_omega = omega;
d_min_omega = omega*(1.0 - d_omega_relative_limit);
d_max_omega = omega*(1.0 + d_omega_relative_limit);
+ d_omega_mid = 0.5*(d_min_omega+d_max_omega);
}
protected:
@@ -76,7 +78,8 @@ protected:
private:
float d_mu; // fractional sample position [0.0, 1.0]
float d_omega; // nominal frequency
- float d_min_omega; // minimum allowed omega
+ float d_min_omega; // minimum allowed omega
+ float d_omega_mid; // average omega
float d_max_omega; // maximum allowed omega
float d_gain_omega; // gain for adjusting omega
float d_gain_mu; // gain for adjusting mu
diff --git a/gnuradio-core/src/lib/general/gr_math.h b/gnuradio-core/src/lib/general/gr_math.h
index 2cd5b8eb7..e5173eceb 100644
--- a/gnuradio-core/src/lib/general/gr_math.h
+++ b/gnuradio-core/src/lib/general/gr_math.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2003,2005 Free Software Foundation, Inc.
+ * Copyright 2003,2005,2008 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -64,9 +64,7 @@ static inline float gr_fast_atan2f(gr_complex z)
return gr_fast_atan2f(z.imag(), z.real());
}
-
/* This bounds x by +/- clip without a branch */
-
static inline float gr_branchless_clip(float x, float clip)
{
float x1 = fabsf(x+clip);
@@ -75,6 +73,98 @@ static inline float gr_branchless_clip(float x, float clip)
return 0.5*x1;
}
+static inline float gr_clip(float x, float clip)
+{
+ float y;
+ if(x > clip)
+ y = clip;
+ else if(x < clip)
+ y = -clip;
+ return y;
+}
+
+// Slicer Functions
+static inline unsigned int gr_binary_slicer(float x)
+{
+ if(x >= 0)
+ return 1;
+ else
+ return 0;
+}
+
+static inline unsigned int gr_quad_45deg_slicer(float r, float i)
+{
+ unsigned int ret = 0;
+ if((r >= 0) && (i >= 0))
+ ret = 0;
+ else if((r < 0) && (i >= 0))
+ ret = 1;
+ else if((r < 0) && (i < 0))
+ ret = 2;
+ else
+ ret = 3;
+ return ret;
+}
+
+static inline unsigned int gr_quad_0deg_slicer(float r, float i)
+{
+ unsigned int ret = 0;
+ if(fabsf(r) > fabsf(i)) {
+ if(r > 0)
+ ret = 0;
+ else
+ ret = 2;
+ }
+ else {
+ if(i > 0)
+ ret = 1;
+ else
+ ret = 3;
+ }
+
+ return ret;
+}
+static inline unsigned int gr_quad_45deg_slicer(gr_complex x)
+{
+ return gr_quad_45deg_slicer(x.real(), x.imag());
+}
+
+static inline unsigned int gr_quad_0deg_slicer(gr_complex x)
+{
+ return gr_quad_0deg_slicer(x.real(), x.imag());
+}
+
+// Branchless Slicer Functions
+static inline unsigned int gr_branchless_binary_slicer(float x)
+{
+ return (x >= 0);
+}
+
+static inline unsigned int gr_branchless_quad_0deg_slicer(float r, float i)
+{
+ unsigned int ret = 0;
+ ret = (fabsf(r) > fabsf(i)) * (((r < 0) << 0x1)); // either 0 (00) or 2 (10)
+ ret |= (fabsf(i) > fabsf(r)) * (((i < 0) << 0x1) | 0x1); // either 1 (01) or 3 (11)
+
+ return ret;
+}
+
+static inline unsigned int gr_branchless_quad_0deg_slicer(gr_complex x)
+{
+ return gr_branchless_quad_0deg_slicer(x.real(), x.imag());
+}
+
+static inline unsigned int gr_branchless_quad_45deg_slicer(float r, float i)
+{
+ char ret = (r <= 0);
+ ret |= ((i <= 0) << 1);
+ return (ret ^ ((ret & 0x2) >> 0x1));
+}
+
+static inline unsigned int gr_branchless_quad_45deg_slicer(gr_complex x)
+{
+ return gr_branchless_quad_45deg_slicer(x.real(), x.imag());
+}
#endif /* _GR_MATH_H_ */
diff --git a/gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.cc b/gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.cc
index c943e3637..d1a743f14 100644
--- a/gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.cc
+++ b/gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.cc
@@ -91,12 +91,12 @@ gr_mpsk_receiver_cc::gr_mpsk_receiver_cc (unsigned int M, float theta,
switch(d_M) {
case 2: // optimized algorithms for BPSK
d_phase_error_detector = &gr_mpsk_receiver_cc::phase_error_detector_generic; //bpsk;
- d_decision = &gr_mpsk_receiver_cc::decision_generic; //bpsk;
+ d_decision = &gr_mpsk_receiver_cc::decision_bpsk;
break;
case 4: // optimized algorithms for QPSK
d_phase_error_detector = &gr_mpsk_receiver_cc::phase_error_detector_generic; //qpsk;
- d_decision = &gr_mpsk_receiver_cc::decision_generic; //qpsk;
+ d_decision = &gr_mpsk_receiver_cc::decision_qpsk;
break;
default: // generic algorithms for any M (power of 2?) but not pretty
@@ -145,31 +145,20 @@ float gr_mpsk_receiver_cc::phase_error_detector_generic(gr_complex sample) const
return -arg(sample*conj(d_constellation[d_current_const_point]));
}
-// FIXME add these back in an test difference in performance
unsigned int
gr_mpsk_receiver_cc::decision_bpsk(gr_complex sample) const
{
- unsigned int index = 0;
-
- // Implements a 1-demensional slicer
- if(sample.real() > 0)
- index = 1;
- return index;
+ return (gr_branchless_binary_slicer(sample.real()) ^ 1);
+ //return gr_binary_slicer(sample.real()) ^ 1;
}
-// FIXME add these back in an test difference in performance
unsigned int
gr_mpsk_receiver_cc::decision_qpsk(gr_complex sample) const
{
- unsigned int index = 0;
-
- // Implements a simple slicer function
- if((sample.real() < 0) && (sample.imag() > 0))
- index = 1;
- else if((sample.real() < 0) && (sample.imag() < 0))
- index = 2;
- else
- index = 3;
+ unsigned int index;
+
+ //index = gr_branchless_quad_0deg_slicer(sample);
+ index = gr_quad_0deg_slicer(sample);
return index;
}
@@ -211,11 +200,8 @@ gr_mpsk_receiver_cc::mm_sampler(const gr_complex symbol)
d_phase += d_freq; // increment the phase based on the frequency of the rotation
// Keep phase clamped and not walk to infinity
- while(d_phase>M_TWOPI)
- d_phase -= M_TWOPI;
- while(d_phase<-M_TWOPI)
- d_phase += M_TWOPI;
-
+ d_phase = gr_branchless_clip(d_phase, M_TWOPI);
+
nco = gr_expj(d_phase+d_theta); // get the NCO value for derotating the current sample
sample = nco*symbol; // get the downconverted symbol
@@ -247,20 +233,10 @@ gr_mpsk_receiver_cc::mm_error_tracking(gr_complex sample)
y = (d_p_0T - d_p_2T) * conj(d_c_1T);
u = y - x;
mm_error = u.real(); // the error signal is in the real part
-
- // limit mm_val
- if (mm_error > 1.0)
- mm_error = 1.0;
- else if (mm_error < -1.0)
- mm_error = -1.0;
-
+ mm_error = gr_branchless_clip(mm_error, 1.0); // limit mm_val
+
d_omega = d_omega + d_gain_omega * mm_error; // update omega based on loop error
-
- // make sure we don't walk away
- if (d_omega > d_max_omega)
- d_omega = d_max_omega;
- else if (d_omega < d_min_omega)
- d_omega = d_min_omega;
+ d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_rel); // make sure we don't walk away
d_mu += d_omega + d_gain_mu * mm_error; // update mu based on loop error
@@ -280,26 +256,17 @@ gr_mpsk_receiver_cc::phase_error_tracking(gr_complex sample)
// Make phase and frequency corrections based on sampled value
phase_error = (*this.*d_phase_error_detector)(sample);
- if (phase_error > 1)
- phase_error = 1;
- else if (phase_error < -1)
- phase_error = -1;
-
+ phase_error = gr_branchless_clip(phase_error, 1.0);
+
d_freq += d_beta*phase_error; // adjust frequency based on error
d_phase += d_freq + d_alpha*phase_error; // adjust phase based on error
-
+
// Make sure we stay within +-2pi
- while(d_phase>M_TWOPI)
- d_phase -= M_TWOPI;
- while(d_phase<-M_TWOPI)
- d_phase += M_TWOPI;
+ d_phase = gr_branchless_clip(d_phase, M_TWOPI);
// Limit the frequency range
- if (d_freq > d_max_freq)
- d_freq = d_max_freq;
- else if (d_freq < d_min_freq)
- d_freq = d_min_freq;
-
+ d_freq = gr_branchless_clip(d_freq, d_max_freq);
+
#if VERBOSE_COSTAS
printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n",
phase_error, d_phase, d_freq, sample.real(), sample.imag(),
@@ -318,7 +285,6 @@ gr_mpsk_receiver_cc::general_work (int noutput_items,
int i=0, o=0;
- //while(i < ninput_items[0]) {
while((o < noutput_items) && (i < ninput_items[0])) {
while((d_mu > 1) && (i < ninput_items[0])) {
mm_sampler(in[i]); // puts symbols into a buffer and adjusts d_mu
diff --git a/gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.h b/gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.h
index b0ecb7c93..cddb697ac 100644
--- a/gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.h
+++ b/gnuradio-core/src/lib/general/gr_mpsk_receiver_cc.h
@@ -100,6 +100,7 @@ class gr_mpsk_receiver_cc : public gr_block
d_omega = omega;
d_min_omega = omega*(1.0 - d_omega_rel);
d_max_omega = omega*(1.0 + d_omega_rel);
+ d_omega_mid = 0.5*(d_min_omega+d_max_omega);
}
//! (M&M) Sets value for mu gain factor
@@ -275,7 +276,7 @@ protected:
// Members related to symbol timing
float d_mu, d_gain_mu;
- float d_omega, d_gain_omega, d_omega_rel, d_max_omega, d_min_omega;
+ float d_omega, d_gain_omega, d_omega_rel, d_max_omega, d_min_omega, d_omega_mid;
gr_complex d_p_2T, d_p_1T, d_p_0T;
gr_complex d_c_2T, d_c_1T, d_c_0T;
diff --git a/gnuradio-core/src/lib/general/qa_general.cc b/gnuradio-core/src/lib/general/qa_general.cc
index cf00dc763..75d563236 100644
--- a/gnuradio-core/src/lib/general/qa_general.cc
+++ b/gnuradio-core/src/lib/general/qa_general.cc
@@ -31,6 +31,7 @@
#include <qa_gr_fxpt.h>
#include <qa_gr_fxpt_nco.h>
#include <qa_gr_fxpt_vco.h>
+#include <qa_gr_math.h>
CppUnit::TestSuite *
qa_general::suite ()
@@ -42,6 +43,7 @@ qa_general::suite ()
s->addTest (qa_gr_fxpt::suite ());
s->addTest (qa_gr_fxpt_nco::suite ());
s->addTest (qa_gr_fxpt_vco::suite ());
+ s->addTest (qa_gr_math::suite ());
return s;
}
diff --git a/gnuradio-core/src/lib/general/qa_gr_math.cc b/gnuradio-core/src/lib/general/qa_gr_math.cc
new file mode 100644
index 000000000..b3a1b959d
--- /dev/null
+++ b/gnuradio-core/src/lib/general/qa_gr_math.cc
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#include <gr_math.h>
+#include <qa_gr_math.h>
+#include <cppunit/TestAssert.h>
+#include <stdio.h>
+
+void
+qa_gr_math::test_binary_slicer1 ()
+{
+ float x[5] = {-1, -0.5, 0, 0.5, 1.0};
+ unsigned int z[5] = {0, 0, 1, 1, 1};
+ unsigned int y;
+
+ //printf("\nBinary\n");
+ for (unsigned int i = 0; i < 5; i++) {
+ y = gr_binary_slicer(x[i]);
+ //printf("in: %f out: %d desired: %d\n", x[i], y, z[i]);
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9);
+ }
+
+ //printf("\nBranchless Binary\n");
+ for (unsigned int i = 0; i < 5; i++) {
+ y = gr_branchless_binary_slicer(x[i]);
+ //printf("in: %f out: %d desired: %d\n", x[i], y, z[i]);
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9);
+ }
+}
+
+void
+qa_gr_math::test_quad_0deg_slicer1 ()
+{
+ gr_complex x[4] = {gr_complex(1, 0),
+ gr_complex(0, 1),
+ gr_complex(-1, 0),
+ gr_complex(0, -1)};
+
+ unsigned int z[4] = {0, 1, 2, 3};
+ unsigned int y;
+
+ //printf("\nQuad0\n");
+ for (unsigned int i = 0; i < 4; i++) {
+ y = gr_quad_0deg_slicer(x[i]);
+ //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]);
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9);
+ }
+
+ //printf("\nBranchless Quad0\n");
+ for (unsigned int i = 0; i < 4; i++) {
+ y = gr_branchless_quad_0deg_slicer(x[i]);
+ //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]);
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9);
+ }
+}
+
+void
+qa_gr_math::test_quad_45deg_slicer1 ()
+{
+ gr_complex x[4] = {gr_complex(0.707, 0.707),
+ gr_complex(-0.707, 0.707),
+ gr_complex(-0.707, -0.707),
+ gr_complex(0.707, -0.707)};
+
+ unsigned int z[4] = {0, 1, 2, 3};
+ unsigned int y;
+
+ //printf("\nQuad45\n");
+ for (unsigned int i = 0; i < 4; i++) {
+ y = gr_quad_45deg_slicer(x[i]);
+ //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]);
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9);
+ }
+
+ //printf("\nBranchless Quad45\n");
+ for (unsigned int i = 0; i < 4; i++) {
+ y = gr_branchless_quad_45deg_slicer(x[i]);
+ //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]);
+
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9);
+ }
+}
diff --git a/gnuradio-core/src/lib/general/qa_gr_math.h b/gnuradio-core/src/lib/general/qa_gr_math.h
new file mode 100644
index 000000000..bcc3a62d0
--- /dev/null
+++ b/gnuradio-core/src/lib/general/qa_gr_math.h
@@ -0,0 +1,42 @@
+/* -*- 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_MATH_H_
+#define _QA_GR_MATH_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_gr_math : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_gr_math);
+ CPPUNIT_TEST(test_binary_slicer1);
+ CPPUNIT_TEST(test_quad_0deg_slicer1);
+ CPPUNIT_TEST(test_quad_45deg_slicer1);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_binary_slicer1();
+ void test_quad_0deg_slicer1();
+ void test_quad_45deg_slicer1();
+};
+
+#endif /* _QA_GR_MATH_H_ */