diff options
author | ghostop14 <ghostop14@gmail.com> | 2020-01-29 17:20:16 -0500 |
---|---|---|
committer | Michael Dickens <michael.dickens@ettus.com> | 2020-02-14 10:05:12 -0500 |
commit | aa0bd44efbf8afdfd93d627e486c1427426b76f9 (patch) | |
tree | dd2acb4ebed83dc5a553678ba46b76424690b90a /gr-digital/lib/costas_loop_cc_impl.h | |
parent | 36680f338e0b7ae7e5bcf7d2a860527ca7b14dfe (diff) |
gr-digital: Improve Performance of Costas Loop
This update is focused on improving the throughput of the Costas
loop, however some changes are more global performance enhancements
as this PR has evolved. Updates include an ENABLE_NATIVE added to
CMake, which is off by default but enables native compiling (including
FMA support) if desired; sincos was inlined in sincos.h and sincos.cc
was removed from the appropriate CMake to improve sincos speed, some
constants were added to math.h, inlined functions in costas loop and
nco.h, used switch instead of function pointer (much faster), and
used fast complex multiply to get around all the range checking in
the standard complex.h complex multiply function on all builds.
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); |