diff options
Diffstat (limited to 'gr-digital/lib/costas_loop_cc_impl.cc')
-rw-r--r-- | gr-digital/lib/costas_loop_cc_impl.cc | 68 |
1 files changed, 61 insertions, 7 deletions
diff --git a/gr-digital/lib/costas_loop_cc_impl.cc b/gr-digital/lib/costas_loop_cc_impl.cc index 36f95ac022..a53045ac55 100644 --- a/gr-digital/lib/costas_loop_cc_impl.cc +++ b/gr-digital/lib/costas_loop_cc_impl.cc @@ -35,37 +35,52 @@ namespace gr { namespace digital { costas_loop_cc::sptr - costas_loop_cc::make(float loop_bw, int order) + costas_loop_cc::make(float loop_bw, int order, bool use_snr) { return gnuradio::get_initial_sptr - (new costas_loop_cc_impl(loop_bw, order)); + (new costas_loop_cc_impl(loop_bw, order, use_snr)); } - costas_loop_cc_impl::costas_loop_cc_impl(float loop_bw, int order) + costas_loop_cc_impl::costas_loop_cc_impl(float loop_bw, int order, bool use_snr) : sync_block("costas_loop_cc", io_signature::make(1, 1, sizeof(gr_complex)), io_signature::make2(1, 2, sizeof(gr_complex), sizeof(float))), blocks::control_loop(loop_bw, 1.0, -1.0), - d_order(order), d_error(0), d_phase_detector(NULL) + d_order(order), d_error(0), d_noise(1.0), d_phase_detector(NULL) { // Set up the phase detector to use based on the constellation order switch(d_order) { case 2: - d_phase_detector = &costas_loop_cc_impl::phase_detector_2; + if(use_snr) + d_phase_detector = &costas_loop_cc_impl::phase_detector_snr_2; + else + d_phase_detector = &costas_loop_cc_impl::phase_detector_2; break; case 4: - d_phase_detector = &costas_loop_cc_impl::phase_detector_4; + if(use_snr) + d_phase_detector = &costas_loop_cc_impl::phase_detector_snr_4; + else + d_phase_detector = &costas_loop_cc_impl::phase_detector_4; break; case 8: - d_phase_detector = &costas_loop_cc_impl::phase_detector_8; + if(use_snr) + d_phase_detector = &costas_loop_cc_impl::phase_detector_snr_8; + else + d_phase_detector = &costas_loop_cc_impl::phase_detector_8; break; default: throw std::invalid_argument("order must be 2, 4, or 8"); break; } + + message_port_register_in(pmt::mp("noise")); + set_msg_handler( + pmt::mp("noise"), + boost::bind(&costas_loop_cc_impl::handle_set_noise, + this, _1)); } costas_loop_cc_impl::~costas_loop_cc_impl() @@ -114,11 +129,50 @@ namespace gr { } float + costas_loop_cc_impl::phase_detector_snr_8(gr_complex sample) const + { + float K = (sqrt(2.0) - 1); + float snr = abs(sample)*abs(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())); + } + } + + float + costas_loop_cc_impl::phase_detector_snr_4(gr_complex sample) const + { + float snr = abs(sample)*abs(sample) / d_noise; + return ((blocks::tanhf_lut(snr*sample.real()) * sample.imag()) - + (blocks::tanhf_lut(snr*sample.imag()) * sample.real())); + } + + float + costas_loop_cc_impl::phase_detector_snr_2(gr_complex sample) const + { + float snr = abs(sample)*abs(sample) / d_noise; + return blocks::tanhf_lut(snr*sample.real()) * sample.imag(); + } + + float costas_loop_cc_impl::error() const { return d_error; } + void + costas_loop_cc_impl::handle_set_noise(pmt::pmt_t msg) + { + if(pmt::is_real(msg)) { + d_noise = pmt::to_double(msg); + d_noise = powf(10.0f, d_noise/10.0f); + } + } + int costas_loop_cc_impl::work(int noutput_items, gr_vector_const_void_star &input_items, |