summaryrefslogtreecommitdiff
path: root/gr-digital/lib/mpsk_receiver_cc_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-digital/lib/mpsk_receiver_cc_impl.cc')
-rw-r--r--gr-digital/lib/mpsk_receiver_cc_impl.cc332
1 files changed, 0 insertions, 332 deletions
diff --git a/gr-digital/lib/mpsk_receiver_cc_impl.cc b/gr-digital/lib/mpsk_receiver_cc_impl.cc
deleted file mode 100644
index 68aae2cd91..0000000000
--- a/gr-digital/lib/mpsk_receiver_cc_impl.cc
+++ /dev/null
@@ -1,332 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2005-2007,2010-2012 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 "mpsk_receiver_cc_impl.h"
-#include <gnuradio/io_signature.h>
-#include <gnuradio/math.h>
-#include <gnuradio/expj.h>
-#include <stdexcept>
-
-namespace gr {
- namespace digital {
-
-#define M_TWOPI (2*M_PI)
-#define VERBOSE_MM 0 // Used for debugging symbol timing loop
-#define VERBOSE_COSTAS 0 // Used for debugging phase and frequency tracking
-
- mpsk_receiver_cc::sptr
- mpsk_receiver_cc::make(unsigned int M, float theta,
- float loop_bw,
- float fmin, float fmax,
- float mu, float gain_mu,
- float omega, float gain_omega, float omega_rel)
- {
- return gnuradio::get_initial_sptr
- (new mpsk_receiver_cc_impl(M, theta,
- loop_bw,
- fmin, fmax,
- mu, gain_mu,
- omega, gain_omega,
- omega_rel));
- }
-
- mpsk_receiver_cc_impl::mpsk_receiver_cc_impl(unsigned int M, float theta,
- float loop_bw,
- float fmin, float fmax,
- float mu, float gain_mu,
- float omega, float gain_omega,
- float omega_rel)
- : block("mpsk_receiver_cc",
- io_signature::make(1, 1, sizeof(gr_complex)),
- io_signature::make(1, 1, sizeof(gr_complex))),
- blocks::control_loop(loop_bw, fmax, fmin),
- d_M(M), d_theta(theta),
- d_current_const_point(0),
- d_mu(mu), d_gain_mu(gain_mu), d_gain_omega(gain_omega),
- d_omega_rel(omega_rel), d_max_omega(0), d_min_omega(0),
- d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0)
- {
- GR_LOG_WARN(d_logger, "The gr::digital::mpsk_receiver_cc block is deprecated.");
-
- d_interp = new gr::filter::mmse_fir_interpolator_cc();
- d_dl_idx = 0;
-
- set_omega(omega);
-
- if(omega <= 0.0)
- throw std::out_of_range("clock rate must be > 0");
- if(gain_mu < 0 || gain_omega < 0)
- throw std::out_of_range("Gains must be non-negative");
-
- assert(d_interp->ntaps() <= DLLEN);
-
- // zero double length delay line.
- for(unsigned int i = 0; i < 2 * DLLEN; i++)
- d_dl[i] = gr_complex(0.0,0.0);
-
- set_modulation_order(d_M);
- }
-
- mpsk_receiver_cc_impl::~mpsk_receiver_cc_impl()
- {
- delete d_interp;
- }
-
- void
- mpsk_receiver_cc_impl::set_modulation_order(unsigned int M)
- {
- // build the constellation vector from M
- make_constellation();
-
- // Select a phase detector and a decision maker for the modulation order
- switch(d_M) {
- case 2: // optimized algorithms for BPSK
- d_phase_error_detector = &mpsk_receiver_cc_impl::phase_error_detector_bpsk; //bpsk;
- d_decision = &mpsk_receiver_cc_impl::decision_bpsk;
- break;
-
- case 4: // optimized algorithms for QPSK
- d_phase_error_detector = &mpsk_receiver_cc_impl::phase_error_detector_qpsk; //qpsk;
- d_decision = &mpsk_receiver_cc_impl::decision_qpsk;
- break;
-
- default: // generic algorithms for any M (power of 2?) but not pretty
- d_phase_error_detector = &mpsk_receiver_cc_impl::phase_error_detector_generic;
- d_decision = &mpsk_receiver_cc_impl::decision_generic;
- break;
- }
- }
-
- void
- mpsk_receiver_cc_impl::set_gain_omega_rel(float omega_rel)
- {
- d_omega_rel = omega_rel;
- set_omega(d_omega);
- }
-
- void
- mpsk_receiver_cc_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
- {
- unsigned ninputs = ninput_items_required.size();
- for(unsigned i=0; i < ninputs; i++)
- ninput_items_required[i] = (int) ceil((noutput_items * d_omega) + d_interp->ntaps());
- }
-
- // FIXME add these back in an test difference in performance
- float
- mpsk_receiver_cc_impl::phase_error_detector_qpsk(gr_complex sample) const
- {
- float phase_error = 0;
- if(fabsf(sample.real()) > fabsf(sample.imag())) {
- if(sample.real() > 0)
- phase_error = -sample.imag();
- else
- phase_error = sample.imag();
- }
- else {
- if(sample.imag() > 0)
- phase_error = sample.real();
- else
- phase_error = -sample.real();
- }
-
- return phase_error;
- }
-
- float
- mpsk_receiver_cc_impl::phase_error_detector_bpsk(gr_complex sample) const
- {
- return -(sample.real()*sample.imag());
- }
-
- float mpsk_receiver_cc_impl::phase_error_detector_generic(gr_complex sample) const
- {
- //return gr::fast_atan2f(sample*conj(d_constellation[d_current_const_point]));
- return -arg(sample*conj(d_constellation[d_current_const_point]));
- }
-
- unsigned int
- mpsk_receiver_cc_impl::decision_bpsk(gr_complex sample) const
- {
- return (gr::branchless_binary_slicer(sample.real()) ^ 1);
- //return gr_binary_slicer(sample.real()) ^ 1;
- }
-
- unsigned int
- mpsk_receiver_cc_impl::decision_qpsk(gr_complex sample) const
- {
- unsigned int index;
-
- //index = gr::branchless_quad_0deg_slicer(sample);
- index = gr::quad_0deg_slicer(sample);
- return index;
- }
-
- unsigned int
- mpsk_receiver_cc_impl::decision_generic(gr_complex sample) const
- {
- unsigned int min_m = 0;
- float min_s = 65535;
-
- // Develop all possible constellation points and find the one that minimizes
- // the Euclidean distance (error) with the sample
- for(unsigned int m = 0; m < d_M; m++) {
- gr_complex diff = norm(d_constellation[m] - sample);
-
- if(fabs(diff.real()) < min_s) {
- min_s = fabs(diff.real());
- min_m = m;
- }
- }
- // Return the index of the constellation point that minimizes the error
- return min_m;
- }
-
- void
- mpsk_receiver_cc_impl::make_constellation()
- {
- for(unsigned int m = 0; m < d_M; m++) {
- d_constellation.push_back(gr_expj((M_TWOPI/d_M)*m));
- }
- }
-
- void
- mpsk_receiver_cc_impl::mm_sampler(const gr_complex symbol)
- {
- gr_complex sample, nco;
-
- d_mu--; // skip a number of symbols between sampling
- 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;
-
- nco = gr_expj(d_phase+d_theta); // get the NCO value for derotating the current sample
- sample = nco*symbol; // get the downconverted symbol
-
- // Fill up the delay line for the interpolator
- d_dl[d_dl_idx] = sample;
- d_dl[(d_dl_idx + DLLEN)] = sample; // put this in the second half of the buffer for overflows
- d_dl_idx = (d_dl_idx+1) % DLLEN; // Keep the delay line index in bounds
- }
-
- void
- mpsk_receiver_cc_impl::mm_error_tracking(gr_complex sample)
- {
- gr_complex u, x, y;
- float mm_error = 0;
-
- // Make sample timing corrections
-
- // set the delayed samples
- d_p_2T = d_p_1T;
- d_p_1T = d_p_0T;
- d_p_0T = sample;
- d_c_2T = d_c_1T;
- d_c_1T = d_c_0T;
-
- d_current_const_point = (*this.*d_decision)(d_p_0T); // make a decision on the sample value
- d_c_0T = d_constellation[d_current_const_point];
-
- x = (d_c_0T - d_c_2T) * conj(d_p_1T);
- 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
- 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
- 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
-
-#if VERBOSE_MM
- printf("mm: mu: %f omega: %f mm_error: %f sample: %f+j%f constellation: %f+j%f\n",
- d_mu, d_omega, mm_error, sample.real(), sample.imag(),
- d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag());
-#endif
- }
-
-
- void
- mpsk_receiver_cc_impl::phase_error_tracking(gr_complex sample)
- {
- float phase_error = 0;
-
- // Make phase and frequency corrections based on sampled value
- phase_error = (*this.*d_phase_error_detector)(sample);
-
- advance_loop(phase_error);
- phase_wrap();
- frequency_limit();
-
-#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(),
- d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag());
-#endif
-}
-
- int
- mpsk_receiver_cc_impl::general_work(int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
- {
- const gr_complex *in = (const gr_complex*)input_items[0];
- gr_complex *out = (gr_complex*)output_items[0];
-
- int i=0, o=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
- i++;
- }
-
- if(i < ninput_items[0]) {
- gr_complex interp_sample = d_interp->interpolate(&d_dl[d_dl_idx], d_mu);
-
- mm_error_tracking(interp_sample); // corrects M&M sample time
- phase_error_tracking(interp_sample); // corrects phase and frequency offsets
-
- out[o++] = interp_sample;
- }
- }
-
-#if 0
- printf("ninput_items: %d noutput_items: %d consuming: %d returning: %d\n",
- ninput_items[0], noutput_items, i, o);
-#endif
-
- consume_each(i);
- return o;
- }
-
- } /* namespace digital */
-} /* namespace gr */