diff options
Diffstat (limited to 'gr-digital/lib/costas_loop_cc_impl.h')
-rw-r--r-- | gr-digital/lib/costas_loop_cc_impl.h | 72 |
1 files changed, 60 insertions, 12 deletions
diff --git a/gr-digital/lib/costas_loop_cc_impl.h b/gr-digital/lib/costas_loop_cc_impl.h index 7d90f9fc12..fa33bbec8a 100644 --- a/gr-digital/lib/costas_loop_cc_impl.h +++ b/gr-digital/lib/costas_loop_cc_impl.h @@ -22,28 +22,60 @@ class costas_loop_cc_impl : public costas_loop_cc private: float d_error; float d_noise; + bool d_use_snr; + int d_order; /*! \brief the phase detector circuit for 8th-order PSK loops. * * \param sample complex sample * \return the phase error */ - float phase_detector_8(gr_complex sample) const; // for 8PSK + float phase_detector_8(gr_complex sample) const // for 8PSK + { + /* 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. + */ + + const float K = (sqrtf(2.0) - 1); + if (fabsf(sample.real()) >= fabsf(sample.imag())) { + return ((sample.real() > 0.0f ? 1.0f : -1.0f) * sample.imag() - + (sample.imag() > 0.0f ? 1.0f : -1.0f) * sample.real() * K); + } else { + return ((sample.real() > 0.0f ? 1.0f : -1.0f) * sample.imag() * K - + (sample.imag() > 0.0f ? 1.0f : -1.0f) * sample.real()); + } + }; /*! \brief the phase detector circuit for fourth-order loops. * * \param sample complex sample * \return the phase error */ - float phase_detector_4(gr_complex sample) const; // for QPSK + float phase_detector_4(gr_complex sample) const // for QPSK + { + return ((sample.real() > 0.0f ? 1.0f : -1.0f) * sample.imag() - + (sample.imag() > 0.0f ? 1.0f : -1.0f) * sample.real()); + }; /*! \brief the phase detector circuit for second-order loops. * * \param sample a complex sample * \return the phase error */ - float phase_detector_2(gr_complex sample) const; // for BPSK - + float phase_detector_2(gr_complex sample) const // for BPSK + { + return (sample.real() * sample.imag()); + } /*! \brief the phase detector circuit for 8th-order PSK * loops. Uses tanh instead of slicing and the noise estimate @@ -52,7 +84,18 @@ private: * \param sample complex sample * \return the phase error */ - float phase_detector_snr_8(gr_complex sample) const; // for 8PSK + float phase_detector_snr_8(gr_complex sample) const // for 8PSK + { + const float K = (sqrtf(2.0) - 1.0); + const float snr = std::norm(sample) / d_noise; + if (fabsf(sample.real()) >= fabsf(sample.imag())) { + return ((blocks::tanhf_lut(snr * sample.real()) * sample.imag()) - + (blocks::tanhf_lut(snr * sample.imag()) * sample.real() * K)); + } else { + return ((blocks::tanhf_lut(snr * sample.real()) * sample.imag() * K) - + (blocks::tanhf_lut(snr * sample.imag()) * sample.real())); + } + }; /*! \brief the phase detector circuit for fourth-order * loops. Uses tanh instead of slicing and the noise estimate @@ -61,7 +104,12 @@ private: * \param sample complex sample * \return the phase error */ - float phase_detector_snr_4(gr_complex sample) const; // for QPSK + float phase_detector_snr_4(gr_complex sample) const // for QPSK + { + const float snr = std::norm(sample) / d_noise; + return ((blocks::tanhf_lut(snr * sample.real()) * sample.imag()) - + (blocks::tanhf_lut(snr * sample.imag()) * sample.real())); + }; /*! \brief the phase detector circuit for second-order * loops. Uses tanh instead of slicing and the noise estimate @@ -70,17 +118,17 @@ private: * \param sample a complex sample * \return the phase error */ - float phase_detector_snr_2(gr_complex sample) const; // for BPSK - - typedef float (costas_loop_cc_impl::*d_phase_detector_t)(gr_complex sample) const; - static d_phase_detector_t choose_phase_detector(unsigned int order, bool use_snr); - const d_phase_detector_t d_phase_detector; + float phase_detector_snr_2(gr_complex sample) const // for BPSK + { + const float snr = std::norm(sample) / d_noise; + return blocks::tanhf_lut(snr * sample.real()) * sample.imag(); + }; public: costas_loop_cc_impl(float loop_bw, unsigned int order, bool use_snr = false); ~costas_loop_cc_impl(); - float error() const; + float error() const { return d_error; }; void handle_set_noise(pmt::pmt_t msg); |