*
* 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 2, or (at your option)
+ * 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,
// 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 = &gr_mpsk_receiver_cc::phase_error_detector_generic; //bpsk;
- d_decision = &gr_mpsk_receiver_cc::decision_generic; //bpsk;
+ d_phase_error_detector = &gr_mpsk_receiver_cc::phase_error_detector_bpsk; //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_phase_error_detector = &gr_mpsk_receiver_cc::phase_error_detector_qpsk; //qpsk;
+ d_decision = &gr_mpsk_receiver_cc::decision_qpsk;
break;
default: // generic algorithms for any M (power of 2?) but not pretty
d_decision = &gr_mpsk_receiver_cc::decision_generic;
break;
}
-
- set_history(3); // ensure 2 extra input sample is available
}
gr_mpsk_receiver_cc::~gr_mpsk_receiver_cc ()
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());
- //ninput_items_required[i] = (int)(d_omega);
-
}
// FIXME add these back in an test difference in performance
float
gr_mpsk_receiver_cc::phase_error_detector_qpsk(gr_complex sample) const
{
- float phase_error = ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() -
- (sample.imag()>0 ? 1.0 : -1.0) * sample.real());
- return -phase_error;
+ 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;
}
-// FIXME add these back in an test difference in performance
float
gr_mpsk_receiver_cc::phase_error_detector_bpsk(gr_complex sample) const
{
- return (sample.real()*sample.imag());
+ return -(sample.real()*sample.imag());
}
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;
}
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)
+ while(d_phase > M_TWOPI)
d_phase -= M_TWOPI;
- while(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
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
// 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;
-
+
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)
+ while(d_phase > M_TWOPI)
d_phase -= M_TWOPI;
- while(d_phase<-M_TWOPI)
+ while(d_phase < -M_TWOPI)
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(),
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