From 1a43b1c6d705710a58b4bbd3bcb4000766425091 Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 30 Mar 2011 00:01:01 -0400 Subject: gr-digital: cleaning up and commenting. --- gr-digital/lib/digital_costas_loop_cc.cc | 39 +++++++++++++++++++------------- gr-digital/lib/digital_costas_loop_cc.h | 2 +- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/gr-digital/lib/digital_costas_loop_cc.cc b/gr-digital/lib/digital_costas_loop_cc.cc index d7f98e142..b18b83aeb 100644 --- a/gr-digital/lib/digital_costas_loop_cc.cc +++ b/gr-digital/lib/digital_costas_loop_cc.cc @@ -28,7 +28,7 @@ #include #include #include -#include +#include #define M_TWOPI (2*M_PI) @@ -49,9 +49,9 @@ digital_costas_loop_cc::digital_costas_loop_cc (float damping, float nat_freq, gr_make_io_signature (1, 1, sizeof (gr_complex)), gr_make_io_signature2 (1, 2, sizeof (gr_complex), sizeof(float))), - d_max_freq(1.0), d_min_freq(-1.0), d_freq(0.0), - d_damping(damping), d_nat_freq(nat_freq), - d_phase(0), d_order(order), d_phase_detector(NULL) + d_max_freq(1.0), d_min_freq(-1.0), d_phase(0.0), d_freq(0.0), + d_damping(damping), d_nat_freq(nat_freq), d_order(order), + d_phase_detector(NULL) { // initialize gains from the natural freq and damping factors update_gains(); @@ -78,8 +78,21 @@ digital_costas_loop_cc::digital_costas_loop_cc (float damping, float nat_freq, float digital_costas_loop_cc::phase_detector_8(gr_complex sample) const { - float K = sqrt(2.0) - 1; - if(abs(sample.real()) >= abs(sample.imag())) { + /* This technique splits the 8PSK constellation into 2 squashed + QPSK constellations, one when I is larger than Q and one where + Q is larger than I. The error is then calculated proportionally + to these squashed constellations by the const K = sqrt(2)-1. + + The signal magnitude must be > 1 or K will incorrectly bias + the error value. + + Ref: Z. Huang, Z. Yi, M. Zhang, K. Wang, "8PSK demodulation for + new generation DVB-S2", IEEE Proc. Int. Conf. Communications, + Circuits and Systems, Vol. 2, pp. 1447 - 1450, 2004. + */ + + float K = (sqrt(2.0) - 1); + if(fabsf(sample.real()) >= fabsf(sample.imag())) { return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() - (sample.imag()>0 ? 1.0 : -1.0) * sample.real() * K); } @@ -145,10 +158,7 @@ digital_costas_loop_cc::work (int noutput_items, optr[i] = iptr[i] * nco_out; error = (*this.*d_phase_detector)(optr[i]); - if (error > 1) - error = 1; - else if (error < -1) - error = -1; + error = gr_branchless_clip(error, 1.0); d_freq = d_freq + d_beta * error; d_phase = d_phase + d_freq + d_alpha * error; @@ -171,10 +181,7 @@ digital_costas_loop_cc::work (int noutput_items, optr[i] = iptr[i] * nco_out; error = (*this.*d_phase_detector)(optr[i]); - if (error > 1) - error = 1; - else if (error < -1) - error = -1; + error = gr_branchless_clip(error, 1.0); d_freq = d_freq + d_beta * error; d_phase = d_phase + d_freq + d_alpha * error; @@ -185,9 +192,9 @@ digital_costas_loop_cc::work (int noutput_items, d_phase += M_TWOPI; if (d_freq > d_max_freq) - d_freq = d_max_freq; - else if (d_freq < d_min_freq) d_freq = d_min_freq; + else if (d_freq < d_min_freq) + d_freq = d_max_freq; } } diff --git a/gr-digital/lib/digital_costas_loop_cc.h b/gr-digital/lib/digital_costas_loop_cc.h index 9c112d328..2c4c38e8b 100644 --- a/gr-digital/lib/digital_costas_loop_cc.h +++ b/gr-digital/lib/digital_costas_loop_cc.h @@ -81,7 +81,7 @@ class digital_costas_loop_cc : public gr_sync_block ) throw (std::invalid_argument); float d_alpha, d_beta, d_max_freq, d_min_freq, d_phase, d_freq; - float d_nat_freq, d_damping; + float d_damping, d_nat_freq; int d_order; digital_costas_loop_cc (float damping, float nat_freq, -- cgit From 918d53d764736fe2be79e1a6e08aba7d2e75f56d Mon Sep 17 00:00:00 2001 From: Tom Rondeau Date: Wed, 30 Mar 2011 00:06:55 -0400 Subject: gr-digital: updatign QA code to new interface of Costas Loop. --- gr-digital/python/qa_costas_loop_cc.py | 60 ++++++++++++---------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/gr-digital/python/qa_costas_loop_cc.py b/gr-digital/python/qa_costas_loop_cc.py index 464534723..d310c4278 100644 --- a/gr-digital/python/qa_costas_loop_cc.py +++ b/gr-digital/python/qa_costas_loop_cc.py @@ -34,11 +34,9 @@ class test_digital(gr_unittest.TestCase): def test01 (self): # test basic functionality by setting all gains to 0 - alpha = beta = max_freq = min_freq = 0.0 + damp = nfreq = max_freq = min_freq = 0.0 order = 2 - self.test = digital_swig.costas_loop_cc(alpha, beta, - max_freq, min_freq, - order) + self.test = digital_swig.costas_loop_cc(damp, nfreq, order) data = 100*[complex(1,0),] self.src = gr.vector_source_c(data, False) self.snk = gr.vector_sink_c() @@ -52,14 +50,10 @@ class test_digital(gr_unittest.TestCase): def test02 (self): # Make sure it doesn't diverge given perfect data - alpha = 0.1 - beta = 0.25*alpha*alpha - max_freq = 0.25 - min_freq = -0.25 + damp = 0.4 + nfreq = 0.4 order = 2 - self.test = digital_swig.costas_loop_cc(alpha, beta, - max_freq, min_freq, - order) + self.test = digital_swig.costas_loop_cc(damp, nfreq, order) data = [complex(2*random.randint(0,1)-1, 0) for i in xrange(100)] self.src = gr.vector_source_c(data, False) self.snk = gr.vector_sink_c() @@ -74,14 +68,10 @@ class test_digital(gr_unittest.TestCase): def test03 (self): # BPSK Convergence test with static rotation - alpha = 0.25 - beta = 0.25*alpha*alpha - max_freq = 0.25 - min_freq = -0.25 + damp = 0.4 + nfreq = 0.4 order = 2 - self.test = digital_swig.costas_loop_cc(alpha, beta, - max_freq, min_freq, - order) + self.test = digital_swig.costas_loop_cc(damp, nfreq, order) rot = cmath.exp(0.2j) # some small rotation data = [complex(2*random.randint(0,1)-1, 0) for i in xrange(100)] @@ -103,14 +93,10 @@ class test_digital(gr_unittest.TestCase): def test04 (self): # QPSK Convergence test with static rotation - alpha = 0.25 - beta = 0.25*alpha*alpha - max_freq = 0.25 - min_freq = -0.25 + damp = 0.25 + nfreq = 0.25 order = 4 - self.test = digital_swig.costas_loop_cc(alpha, beta, - max_freq, min_freq, - order) + self.test = digital_swig.costas_loop_cc(damp, nfreq, order) rot = cmath.exp(0.2j) # some small rotation data = [complex(2*random.randint(0,1)-1, 2*random.randint(0,1)-1) for i in xrange(100)] @@ -133,22 +119,21 @@ class test_digital(gr_unittest.TestCase): def test05 (self): # 8PSK Convergence test with static rotation - alpha = 0.25 - beta = 0.25*alpha*alpha - max_freq = 0.25 - min_freq = -0.25 + damp = 0.5 + nfreq = 0.5 order = 8 - self.test = digital_swig.costas_loop_cc(alpha, beta, - max_freq, min_freq, - order) - rot = cmath.exp(cmath.pi/16.0j) # some small rotation + self.test = digital_swig.costas_loop_cc(damp, nfreq, order) + rot1 = 1.41*cmath.exp(1j*cmath.pi/8.0) # rotate and scale to align in and out + rot2 = cmath.exp(0.2j) # some small phase rotation const = blks2.psk.make_constellation(order) data = [random.randint(0,7) for i in xrange(100)] - data = [rot*const[d] for d in data] - + N = 40 # settling time + data = [rot1*const[d] for d in data] # rotate to align with sync expected_result = data[N:] - data = [rot*d for d in data] + + # apply "channel" rotation to input data + data = [rot2*d for d in data] self.src = gr.vector_source_c(data, False) self.snk = gr.vector_sink_c() @@ -158,9 +143,6 @@ class test_digital(gr_unittest.TestCase): dst_data = self.snk.data()[N:] - print expected_result - print dst_data - # generously compare results; the loop will converge near to, but # not exactly on, the target data self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 2) -- cgit