diff options
author | Marcus Müller <mmueller@gnuradio.org> | 2019-08-07 21:45:12 +0200 |
---|---|---|
committer | Marcus Müller <marcus@hostalia.de> | 2019-08-09 23:04:28 +0200 |
commit | f7bbf2c1d8d780294f3e016aff239ca35eb6516e (patch) | |
tree | e09ab6112e02b2215b2d59ac24d3d6ea2edac745 /gr-digital/lib/symbol_sync_cc_impl.cc | |
parent | 78431dc6941e3acc67c858277dfe4a0ed583643c (diff) |
Tree: clang-format without the include sorting
Diffstat (limited to 'gr-digital/lib/symbol_sync_cc_impl.cc')
-rw-r--r-- | gr-digital/lib/symbol_sync_cc_impl.cc | 858 |
1 files changed, 417 insertions, 441 deletions
diff --git a/gr-digital/lib/symbol_sync_cc_impl.cc b/gr-digital/lib/symbol_sync_cc_impl.cc index c9e44c708b..aa5fd3dd4b 100644 --- a/gr-digital/lib/symbol_sync_cc_impl.cc +++ b/gr-digital/lib/symbol_sync_cc_impl.cc @@ -31,454 +31,424 @@ #include <stdexcept> namespace gr { - namespace digital { - - symbol_sync_cc::sptr - symbol_sync_cc::make(enum ted_type detector_type, - float sps, - float loop_bw, - float damping_factor, - float ted_gain, - float max_deviation, - int osps, - constellation_sptr slicer, - ir_type interp_type, - int n_filters, - const std::vector<float> &taps) - { - return gnuradio::get_initial_sptr - (new symbol_sync_cc_impl(detector_type, - sps, - loop_bw, - damping_factor, - ted_gain, - max_deviation, - osps, - slicer, - interp_type, - n_filters, - taps)); - } - - symbol_sync_cc_impl::symbol_sync_cc_impl( - enum ted_type detector_type, - float sps, - float loop_bw, - float damping_factor, - float ted_gain, - float max_deviation, - int osps, - constellation_sptr slicer, - ir_type interp_type, - int n_filters, - const std::vector<float> &taps) - : block("symbol_sync_cc", - io_signature::make(1, 1, sizeof(gr_complex)), - io_signature::makev(1, 4, std::vector<int>(4, sizeof(float)))), - d_ted(NULL), - d_interp(NULL), - d_inst_output_period(sps / static_cast<float>(osps)), - d_inst_clock_period(sps), - d_avg_clock_period(sps), - d_osps(static_cast<float>(osps)), - d_osps_n(osps), - d_tags(), - d_new_tags(), - d_time_est_key(pmt::intern("time_est")), - d_clock_est_key(pmt::intern("clock_est")), - d_noutputs(1), - d_out_error(NULL), - d_out_instantaneous_clock_period(NULL), - d_out_average_clock_period(NULL) - { - // Brute force fix of the output io_signature, because I can't get - // an anonymous std::vector<int>() rvalue, with a const expression - // initializing the vector, to work. Lvalues seem to make everything - // better. - int output_io_sizes[4] = { - sizeof(gr_complex), - sizeof(float), sizeof(float), sizeof(float) - }; - std::vector<int> output_io_sizes_vector(&output_io_sizes[0], - &output_io_sizes[4]); - set_output_signature(io_signature::makev(1, 4, output_io_sizes_vector)); - - if (sps <= 1.0f) +namespace digital { + +symbol_sync_cc::sptr symbol_sync_cc::make(enum ted_type detector_type, + float sps, + float loop_bw, + float damping_factor, + float ted_gain, + float max_deviation, + int osps, + constellation_sptr slicer, + ir_type interp_type, + int n_filters, + const std::vector<float>& taps) +{ + return gnuradio::get_initial_sptr(new symbol_sync_cc_impl(detector_type, + sps, + loop_bw, + damping_factor, + ted_gain, + max_deviation, + osps, + slicer, + interp_type, + n_filters, + taps)); +} + +symbol_sync_cc_impl::symbol_sync_cc_impl(enum ted_type detector_type, + float sps, + float loop_bw, + float damping_factor, + float ted_gain, + float max_deviation, + int osps, + constellation_sptr slicer, + ir_type interp_type, + int n_filters, + const std::vector<float>& taps) + : block("symbol_sync_cc", + io_signature::make(1, 1, sizeof(gr_complex)), + io_signature::makev(1, 4, std::vector<int>(4, sizeof(float)))), + d_ted(NULL), + d_interp(NULL), + d_inst_output_period(sps / static_cast<float>(osps)), + d_inst_clock_period(sps), + d_avg_clock_period(sps), + d_osps(static_cast<float>(osps)), + d_osps_n(osps), + d_tags(), + d_new_tags(), + d_time_est_key(pmt::intern("time_est")), + d_clock_est_key(pmt::intern("clock_est")), + d_noutputs(1), + d_out_error(NULL), + d_out_instantaneous_clock_period(NULL), + d_out_average_clock_period(NULL) +{ + // Brute force fix of the output io_signature, because I can't get + // an anonymous std::vector<int>() rvalue, with a const expression + // initializing the vector, to work. Lvalues seem to make everything + // better. + int output_io_sizes[4] = { + sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float) + }; + std::vector<int> output_io_sizes_vector(&output_io_sizes[0], &output_io_sizes[4]); + set_output_signature(io_signature::makev(1, 4, output_io_sizes_vector)); + + if (sps <= 1.0f) throw std::out_of_range("nominal samples per symbol must be > 1"); - if (osps < 1) + if (osps < 1) throw std::out_of_range("output samples per symbol must be > 0"); - // Timing Error Detector - d_ted = timing_error_detector::make(detector_type, slicer); - if (d_ted == NULL) + // Timing Error Detector + d_ted = timing_error_detector::make(detector_type, slicer); + if (d_ted == NULL) throw std::runtime_error("unable to create timing_error_detector"); - // Interpolating Resampler - d_interp = interpolating_resampler_ccf::make(interp_type, - d_ted->needs_derivative(), - n_filters, taps); - if (d_interp == NULL) - throw std::runtime_error("unable to create interpolating_resampler_ccf"); - - // Block Internal Clocks - d_interps_per_symbol_n = boost::math::lcm(d_ted->inputs_per_symbol(), - d_osps_n); - d_interps_per_ted_input_n = - d_interps_per_symbol_n / d_ted->inputs_per_symbol(); - d_interps_per_output_sample_n = - d_interps_per_symbol_n / d_osps_n; - - d_interps_per_symbol = static_cast<float>(d_interps_per_symbol_n); - d_interps_per_ted_input = static_cast<float>(d_interps_per_ted_input_n); - - d_interp_clock = d_interps_per_symbol_n - 1; - sync_reset_internal_clocks(); - d_inst_interp_period = d_inst_clock_period / d_interps_per_symbol; - - if (d_interps_per_symbol > sps) - GR_LOG_WARN(d_logger, - boost::format("block performing more interopolations per " - "symbol (%3f) than input samples per symbol" - "(%3f). Consider reducing osps or " - "increasing sps") % d_interps_per_symbol - % sps); - - // Symbol Clock Tracking and Estimation - d_clock = new clock_tracking_loop(loop_bw, - sps + max_deviation, - sps - max_deviation, - sps, - damping_factor, - ted_gain); - - // Timing Error Detector - d_ted->sync_reset(); - - // Interpolating Resampler - d_interp->sync_reset(sps); - - // Tag Propagation and Clock Tracking Reset/Resync - set_relative_rate (d_osps / sps); - set_tag_propagation_policy(TPP_DONT); - d_filter_delay = (d_interp->ntaps() + 1) / 2; - - set_output_multiple(d_osps_n); - } - - symbol_sync_cc_impl::~symbol_sync_cc_impl() - { - delete d_ted; - delete d_interp; - delete d_clock; - } + // Interpolating Resampler + d_interp = interpolating_resampler_ccf::make( + interp_type, d_ted->needs_derivative(), n_filters, taps); + if (d_interp == NULL) + throw std::runtime_error("unable to create interpolating_resampler_ccf"); - // // Block Internal Clocks - // - void - symbol_sync_cc_impl::update_internal_clock_outputs() - { - // a d_interp_clock boolean output would always be true. - d_ted_input_clock = (d_interp_clock % d_interps_per_ted_input_n == 0); - d_output_sample_clock = - (d_interp_clock % d_interps_per_output_sample_n == 0); - d_symbol_clock = (d_interp_clock % d_interps_per_symbol_n == 0); - } - - void - symbol_sync_cc_impl::advance_internal_clocks() - { - d_interp_clock = (d_interp_clock + 1) % d_interps_per_symbol_n; - update_internal_clock_outputs(); - } + d_interps_per_symbol_n = boost::math::lcm(d_ted->inputs_per_symbol(), d_osps_n); + d_interps_per_ted_input_n = d_interps_per_symbol_n / d_ted->inputs_per_symbol(); + d_interps_per_output_sample_n = d_interps_per_symbol_n / d_osps_n; - void - symbol_sync_cc_impl::revert_internal_clocks() - { - if (d_interp_clock == 0) - d_interp_clock = d_interps_per_symbol_n - 1; - else - d_interp_clock--; - update_internal_clock_outputs(); - } - - void - symbol_sync_cc_impl::sync_reset_internal_clocks() - { - d_interp_clock = d_interps_per_symbol_n - 1; - update_internal_clock_outputs(); - } + d_interps_per_symbol = static_cast<float>(d_interps_per_symbol_n); + d_interps_per_ted_input = static_cast<float>(d_interps_per_ted_input_n); - // - // Tag Propagation and Clock Tracking Reset/Resync - // - void - symbol_sync_cc_impl::collect_tags(uint64_t nitems_rd, int count) - { - // Get all the tags in offset order - // d_new_tags is used to look for time_est and clock_est tags. - // d_tags is used for manual tag propagation. - d_new_tags.clear(); - get_tags_in_range(d_new_tags, 0, nitems_rd, nitems_rd + count); - std::sort(d_new_tags.begin(), d_new_tags.end(), tag_t::offset_compare); - d_tags.insert(d_tags.end(), d_new_tags.begin(), d_new_tags.end()); - std::sort(d_tags.begin(), d_tags.end(), tag_t::offset_compare); - } + d_interp_clock = d_interps_per_symbol_n - 1; + sync_reset_internal_clocks(); + d_inst_interp_period = d_inst_clock_period / d_interps_per_symbol; - bool - symbol_sync_cc_impl::find_sync_tag(uint64_t nitems_rd, int iidx, - int distance, - uint64_t &tag_offset, - float &timing_offset, - float &clock_period) - { - bool found; - uint64_t soffset, eoffset; - std::vector<tag_t>::iterator t; - std::vector<tag_t>::iterator t2; - - // PLL Reset/Resynchronization to time_est & clock_est tags - // - // Look for a time_est tag between the current interpolated input sample - // and the next predicted interpolated input sample. (both rounded up) - soffset = nitems_rd + d_filter_delay + static_cast<uint64_t>(iidx + 1); - eoffset = soffset + distance; - found = false; - for (t = d_new_tags.begin(); - t != d_new_tags.end(); - t = d_new_tags.erase(t)) { - - if (t->offset > eoffset) // search finished - break; + if (d_interps_per_symbol > sps) + GR_LOG_WARN(d_logger, + boost::format("block performing more interopolations per " + "symbol (%3f) than input samples per symbol" + "(%3f). Consider reducing osps or " + "increasing sps") % + d_interps_per_symbol % sps); - if (t->offset < soffset) // tag is in the past of what we care about - continue; - - if (!pmt::eq(t->key, d_time_est_key) && // not a time_est tag - !pmt::eq(t->key, d_clock_est_key) ) // not a clock_est tag - continue; - - found = true; - tag_offset = t->offset; - if (pmt::eq(t->key, d_time_est_key)) { - // got a time_est tag - timing_offset = static_cast<float>(pmt::to_double(t->value)); - // next instantaneous clock period estimate will be nominal - clock_period = d_clock->get_nom_avg_period(); - - // Look for a clock_est tag at the same offset, - // as we prefer clock_est tags - for (t2 = ++t; t2 != d_new_tags.end(); ++t2) { - if (t2->offset > t->offset) // search finished - break; - if (!pmt::eq(t->key, d_clock_est_key)) // not a clock_est - continue; - // Found a clock_est tag at the same offset - tag_offset = t2->offset; - timing_offset = static_cast<float>( - pmt::to_double(pmt::tuple_ref(t2->value, 0))); - clock_period = static_cast<float>( - pmt::to_double(pmt::tuple_ref(t2->value, 1))); - break; - } - } else { - // got a clock_est tag - timing_offset = static_cast<float>( - pmt::to_double(pmt::tuple_ref(t->value, 0))); - clock_period = static_cast<float>( - pmt::to_double(pmt::tuple_ref(t->value, 1))); - } + // Symbol Clock Tracking and Estimation + d_clock = new clock_tracking_loop( + loop_bw, sps + max_deviation, sps - max_deviation, sps, damping_factor, ted_gain); - if (!(timing_offset >= -1.0f && timing_offset <= 1.0f)) { - // the time_est/clock_est tag's payload is invalid - GR_LOG_WARN(d_logger, - boost::format("ignoring time_est/clock_est tag with" - " value %.2f, outside of allowed " - "range [-1.0, 1.0]") % timing_offset); - found = false; - continue; - } + // Timing Error Detector + d_ted->sync_reset(); - if (t->offset == soffset && timing_offset < 0.0f) { - // already handled times earlier than this previously - found = false; - continue; - } + // Interpolating Resampler + d_interp->sync_reset(sps); - if (t->offset == eoffset && timing_offset >= 0.0f) { - // handle times greater than this later - found = false; + // Tag Propagation and Clock Tracking Reset/Resync + set_relative_rate(d_osps / sps); + set_tag_propagation_policy(TPP_DONT); + d_filter_delay = (d_interp->ntaps() + 1) / 2; + + set_output_multiple(d_osps_n); +} + +symbol_sync_cc_impl::~symbol_sync_cc_impl() +{ + delete d_ted; + delete d_interp; + delete d_clock; +} + +// +// Block Internal Clocks +// +void symbol_sync_cc_impl::update_internal_clock_outputs() +{ + // a d_interp_clock boolean output would always be true. + d_ted_input_clock = (d_interp_clock % d_interps_per_ted_input_n == 0); + d_output_sample_clock = (d_interp_clock % d_interps_per_output_sample_n == 0); + d_symbol_clock = (d_interp_clock % d_interps_per_symbol_n == 0); +} + +void symbol_sync_cc_impl::advance_internal_clocks() +{ + d_interp_clock = (d_interp_clock + 1) % d_interps_per_symbol_n; + update_internal_clock_outputs(); +} + +void symbol_sync_cc_impl::revert_internal_clocks() +{ + if (d_interp_clock == 0) + d_interp_clock = d_interps_per_symbol_n - 1; + else + d_interp_clock--; + update_internal_clock_outputs(); +} + +void symbol_sync_cc_impl::sync_reset_internal_clocks() +{ + d_interp_clock = d_interps_per_symbol_n - 1; + update_internal_clock_outputs(); +} + +// +// Tag Propagation and Clock Tracking Reset/Resync +// +void symbol_sync_cc_impl::collect_tags(uint64_t nitems_rd, int count) +{ + // Get all the tags in offset order + // d_new_tags is used to look for time_est and clock_est tags. + // d_tags is used for manual tag propagation. + d_new_tags.clear(); + get_tags_in_range(d_new_tags, 0, nitems_rd, nitems_rd + count); + std::sort(d_new_tags.begin(), d_new_tags.end(), tag_t::offset_compare); + d_tags.insert(d_tags.end(), d_new_tags.begin(), d_new_tags.end()); + std::sort(d_tags.begin(), d_tags.end(), tag_t::offset_compare); +} + +bool symbol_sync_cc_impl::find_sync_tag(uint64_t nitems_rd, + int iidx, + int distance, + uint64_t& tag_offset, + float& timing_offset, + float& clock_period) +{ + bool found; + uint64_t soffset, eoffset; + std::vector<tag_t>::iterator t; + std::vector<tag_t>::iterator t2; + + // PLL Reset/Resynchronization to time_est & clock_est tags + // + // Look for a time_est tag between the current interpolated input sample + // and the next predicted interpolated input sample. (both rounded up) + soffset = nitems_rd + d_filter_delay + static_cast<uint64_t>(iidx + 1); + eoffset = soffset + distance; + found = false; + for (t = d_new_tags.begin(); t != d_new_tags.end(); t = d_new_tags.erase(t)) { + + if (t->offset > eoffset) // search finished + break; + + if (t->offset < soffset) // tag is in the past of what we care about + continue; + + if (!pmt::eq(t->key, d_time_est_key) && // not a time_est tag + !pmt::eq(t->key, d_clock_est_key)) // not a clock_est tag + continue; + + found = true; + tag_offset = t->offset; + if (pmt::eq(t->key, d_time_est_key)) { + // got a time_est tag + timing_offset = static_cast<float>(pmt::to_double(t->value)); + // next instantaneous clock period estimate will be nominal + clock_period = d_clock->get_nom_avg_period(); + + // Look for a clock_est tag at the same offset, + // as we prefer clock_est tags + for (t2 = ++t; t2 != d_new_tags.end(); ++t2) { + if (t2->offset > t->offset) // search finished + break; + if (!pmt::eq(t->key, d_clock_est_key)) // not a clock_est + continue; + // Found a clock_est tag at the same offset + tag_offset = t2->offset; + timing_offset = + static_cast<float>(pmt::to_double(pmt::tuple_ref(t2->value, 0))); + clock_period = + static_cast<float>(pmt::to_double(pmt::tuple_ref(t2->value, 1))); break; } + } else { + // got a clock_est tag + timing_offset = + static_cast<float>(pmt::to_double(pmt::tuple_ref(t->value, 0))); + clock_period = + static_cast<float>(pmt::to_double(pmt::tuple_ref(t->value, 1))); + } - if (found == true) - break; + if (!(timing_offset >= -1.0f && timing_offset <= 1.0f)) { + // the time_est/clock_est tag's payload is invalid + GR_LOG_WARN(d_logger, + boost::format("ignoring time_est/clock_est tag with" + " value %.2f, outside of allowed " + "range [-1.0, 1.0]") % + timing_offset); + found = false; + continue; } - return found; - } - void - symbol_sync_cc_impl::propagate_tags(uint64_t nitems_rd, int iidx, - float iidx_fraction, - float inst_output_period, - uint64_t nitems_wr, int oidx) - { - // Tag Propagation - // - // Onto this output sample, place all the remaining tags that - // came before the interpolated input sample, and all the tags - // on and after the interpolated input sample, up to half way to - // the next output sample. - - uint64_t mid_period_offset = nitems_rd + d_filter_delay - + static_cast<uint64_t>(iidx) - + static_cast<uint64_t>(llroundf(iidx_fraction - + inst_output_period/2.0f)); - - uint64_t output_offset = nitems_wr + static_cast<uint64_t>(oidx); - - int i; - std::vector<tag_t>::iterator t; - for (t = d_tags.begin(); - t != d_tags.end() && t->offset <= mid_period_offset; - t = d_tags.erase(t)) { - t->offset = output_offset; - for (i = 0; i < d_noutputs; i++) - add_item_tag(i, *t); + if (t->offset == soffset && timing_offset < 0.0f) { + // already handled times earlier than this previously + found = false; + continue; } - } - void - symbol_sync_cc_impl::save_expiring_tags(uint64_t nitems_rd, - int consumed) - { - // Deferred Tag Propagation - // - // Only save away input tags that will not be available - // in the next call to general_work(). Otherwise we would - // create duplicate tags next time around. - // Tags that have already been propagated, have already been erased - // from d_tags. - - uint64_t consumed_offset = nitems_rd + static_cast<uint64_t>(consumed); - std::vector<tag_t>::iterator t; - - for (t = d_tags.begin(); t != d_tags.end(); ) { - if (t->offset < consumed_offset) - ++t; - else - t = d_tags.erase(t); + if (t->offset == eoffset && timing_offset >= 0.0f) { + // handle times greater than this later + found = false; + break; } - } - // - // Optional Diagnostic Outputs - // - void - symbol_sync_cc_impl::setup_optional_outputs( - gr_vector_void_star &output_items) - { - d_noutputs = output_items.size(); - d_out_error = NULL; - d_out_instantaneous_clock_period = NULL; - d_out_average_clock_period = NULL; - - if (d_noutputs < 2) - return; - d_out_error = (float *) output_items[1]; - - if (d_noutputs < 3) - return; - d_out_instantaneous_clock_period = (float *) output_items[2]; - - if (d_noutputs < 4) - return; - d_out_average_clock_period = (float *) output_items[3]; + if (found == true) + break; } - - void - symbol_sync_cc_impl::emit_optional_output(int oidx, - float error, - float inst_clock_period, - float avg_clock_period) - { - if (d_noutputs < 2) - return; - d_out_error[oidx] = error; - - if (d_noutputs < 3) - return; - d_out_instantaneous_clock_period[oidx] = inst_clock_period; - - if (d_noutputs < 4) - return; - d_out_average_clock_period[oidx] = avg_clock_period; + return found; +} + +void symbol_sync_cc_impl::propagate_tags(uint64_t nitems_rd, + int iidx, + float iidx_fraction, + float inst_output_period, + uint64_t nitems_wr, + int oidx) +{ + // Tag Propagation + // + // Onto this output sample, place all the remaining tags that + // came before the interpolated input sample, and all the tags + // on and after the interpolated input sample, up to half way to + // the next output sample. + + uint64_t mid_period_offset = + nitems_rd + d_filter_delay + static_cast<uint64_t>(iidx) + + static_cast<uint64_t>(llroundf(iidx_fraction + inst_output_period / 2.0f)); + + uint64_t output_offset = nitems_wr + static_cast<uint64_t>(oidx); + + int i; + std::vector<tag_t>::iterator t; + for (t = d_tags.begin(); t != d_tags.end() && t->offset <= mid_period_offset; + t = d_tags.erase(t)) { + t->offset = output_offset; + for (i = 0; i < d_noutputs; i++) + add_item_tag(i, *t); } +} - void - symbol_sync_cc_impl::forecast(int noutput_items, - gr_vector_int &ninput_items_required) - { - unsigned ninputs = ninput_items_required.size(); - - // The '+ 2' in the expression below is an effort to always have at - // least one output sample, even if the main loop decides it has to - // revert one computed sample and wait for the next call to - // general_work(). - // The d_clock->get_max_avg_period() is also an effort to do the same, - // in case we have the worst case allowable clock timing deviation on - // input. - int answer = static_cast<int>( - ceilf(static_cast<float>(noutput_items + 2) - * d_clock->get_max_avg_period() / d_osps)) - + static_cast<int>(d_interp->ntaps()); - - for(unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = answer; +void symbol_sync_cc_impl::save_expiring_tags(uint64_t nitems_rd, int consumed) +{ + // Deferred Tag Propagation + // + // Only save away input tags that will not be available + // in the next call to general_work(). Otherwise we would + // create duplicate tags next time around. + // Tags that have already been propagated, have already been erased + // from d_tags. + + uint64_t consumed_offset = nitems_rd + static_cast<uint64_t>(consumed); + std::vector<tag_t>::iterator t; + + for (t = d_tags.begin(); t != d_tags.end();) { + if (t->offset < consumed_offset) + ++t; + else + t = d_tags.erase(t); } - - int - symbol_sync_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) - { - // max input to consume - int ni = ninput_items[0] - static_cast<int>(d_interp->ntaps()); - if (ni <= 0) - return 0; - - const gr_complex *in = (const gr_complex *)input_items[0]; - gr_complex *out = (gr_complex *)output_items[0]; - - setup_optional_outputs(output_items); - - int ii = 0; // input index - int oo = 0; // output index - gr_complex interp_output; - gr_complex interp_derivative = gr_complex(0.0f, 0.0f); - float error; - float look_ahead_phase = 0.0f; - int look_ahead_phase_n = 0; - float look_ahead_phase_wrapped = 0.0f; - - uint64_t nitems_rd = nitems_read(0); - uint64_t nitems_wr = nitems_written(0); - uint64_t sync_tag_offset; - float sync_timing_offset; - float sync_clock_period; - - // Tag Propagation and Symbol Clock Tracking Reset/Resync - collect_tags(nitems_rd, ni); - - while (oo < noutput_items) { +} + +// +// Optional Diagnostic Outputs +// +void symbol_sync_cc_impl::setup_optional_outputs(gr_vector_void_star& output_items) +{ + d_noutputs = output_items.size(); + d_out_error = NULL; + d_out_instantaneous_clock_period = NULL; + d_out_average_clock_period = NULL; + + if (d_noutputs < 2) + return; + d_out_error = (float*)output_items[1]; + + if (d_noutputs < 3) + return; + d_out_instantaneous_clock_period = (float*)output_items[2]; + + if (d_noutputs < 4) + return; + d_out_average_clock_period = (float*)output_items[3]; +} + +void symbol_sync_cc_impl::emit_optional_output(int oidx, + float error, + float inst_clock_period, + float avg_clock_period) +{ + if (d_noutputs < 2) + return; + d_out_error[oidx] = error; + + if (d_noutputs < 3) + return; + d_out_instantaneous_clock_period[oidx] = inst_clock_period; + + if (d_noutputs < 4) + return; + d_out_average_clock_period[oidx] = avg_clock_period; +} + +void symbol_sync_cc_impl::forecast(int noutput_items, + gr_vector_int& ninput_items_required) +{ + unsigned ninputs = ninput_items_required.size(); + + // The '+ 2' in the expression below is an effort to always have at + // least one output sample, even if the main loop decides it has to + // revert one computed sample and wait for the next call to + // general_work(). + // The d_clock->get_max_avg_period() is also an effort to do the same, + // in case we have the worst case allowable clock timing deviation on + // input. + int answer = static_cast<int>(ceilf(static_cast<float>(noutput_items + 2) * + d_clock->get_max_avg_period() / d_osps)) + + static_cast<int>(d_interp->ntaps()); + + for (unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = answer; +} + +int symbol_sync_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) +{ + // max input to consume + int ni = ninput_items[0] - static_cast<int>(d_interp->ntaps()); + if (ni <= 0) + return 0; + + const gr_complex* in = (const gr_complex*)input_items[0]; + gr_complex* out = (gr_complex*)output_items[0]; + + setup_optional_outputs(output_items); + + int ii = 0; // input index + int oo = 0; // output index + gr_complex interp_output; + gr_complex interp_derivative = gr_complex(0.0f, 0.0f); + float error; + float look_ahead_phase = 0.0f; + int look_ahead_phase_n = 0; + float look_ahead_phase_wrapped = 0.0f; + + uint64_t nitems_rd = nitems_read(0); + uint64_t nitems_wr = nitems_written(0); + uint64_t sync_tag_offset; + float sync_timing_offset; + float sync_clock_period; + + // Tag Propagation and Symbol Clock Tracking Reset/Resync + collect_tags(nitems_rd, ni); + + while (oo < noutput_items) { // Block Internal Clocks advance_internal_clocks(); // Symbol Clock and Interpolator Positioning & Alignment - interp_output = d_interp->interpolate(&in[ii], - d_interp->phase_wrapped()); + interp_output = d_interp->interpolate(&in[ii], d_interp->phase_wrapped()); if (output_sample_clock()) out[oo] = interp_output; @@ -495,9 +465,8 @@ namespace gr { // We must interpolate ahead to the *next* ted_input_clock, so the // ted will compute the error for *this* symbol. - d_interp->next_phase(d_interps_per_ted_input - * (d_clock->get_inst_period() - / d_interps_per_symbol), + d_interp->next_phase(d_interps_per_ted_input * + (d_clock->get_inst_period() / d_interps_per_symbol), look_ahead_phase, look_ahead_phase_n, look_ahead_phase_wrapped); @@ -525,9 +494,8 @@ namespace gr { interp_output = d_interp->interpolate(&in[ii + look_ahead_phase_n], look_ahead_phase_wrapped); if (d_ted->needs_derivative()) - interp_derivative = - d_interp->differentiate(&in[ii + look_ahead_phase_n], - look_ahead_phase_wrapped); + interp_derivative = d_interp->differentiate(&in[ii + look_ahead_phase_n], + look_ahead_phase_wrapped); d_ted->input_lookahead(interp_output, interp_derivative); } error = d_ted->error(); @@ -546,7 +514,7 @@ namespace gr { d_inst_output_period = d_inst_clock_period / d_osps; } - // Symbol Clock, Interpolator Positioning & Alignment, and + // Symbol Clock, Interpolator Positioning & Alignment, and // Tag Propagation if (symbol_clock()) { // N.B. symbol_clock() == true implies ted_input_clock() == true @@ -586,8 +554,12 @@ namespace gr { d_interp->advance_phase(d_inst_interp_period); // Symbol Clock Tracking Reset/Resync to time_est and clock_est tags - if (find_sync_tag(nitems_rd, ii, d_interp->phase_n(), sync_tag_offset, - sync_timing_offset, sync_clock_period) == true ) { + if (find_sync_tag(nitems_rd, + ii, + d_interp->phase_n(), + sync_tag_offset, + sync_timing_offset, + sync_clock_period) == true) { // Block Internal Clocks sync_reset_internal_clocks(); @@ -602,9 +574,11 @@ namespace gr { // seem right on paper (maybe rounding in the computation of // d_filter_delay is the culprit). Anyway, experiment trumps // theory *every* time; so + 1 it is. - d_inst_clock_period = static_cast<float>( - static_cast<int>(sync_tag_offset - nitems_rd - d_filter_delay) - - ii + 1) + sync_timing_offset - d_interp->phase_wrapped(); + d_inst_clock_period = + static_cast<float>( + static_cast<int>(sync_tag_offset - nitems_rd - d_filter_delay) - ii + + 1) + + sync_timing_offset - d_interp->phase_wrapped(); d_clock->set_inst_period(d_inst_clock_period); d_clock->set_avg_period(sync_clock_period); @@ -626,12 +600,14 @@ namespace gr { if (output_sample_clock()) { // Diagnostic Output of Symbol Clock Tracking cycle results - emit_optional_output(oo, error, d_inst_clock_period, - d_avg_clock_period); + emit_optional_output(oo, error, d_inst_clock_period, d_avg_clock_period); // Tag Propagation - propagate_tags(nitems_rd, ii, - d_interp->prev_phase_wrapped(), d_inst_output_period, - nitems_wr, oo); + propagate_tags(nitems_rd, + ii, + d_interp->prev_phase_wrapped(), + d_inst_output_period, + nitems_wr, + oo); // Symbol Clock and Interpolator Positioning & Alignment oo++; @@ -639,15 +615,15 @@ namespace gr { // Symbol Clock and Interpolator Positioning & Alignment ii += d_interp->phase_n(); - } + } - // Deferred Tag Propagation - save_expiring_tags(nitems_rd, ii); + // Deferred Tag Propagation + save_expiring_tags(nitems_rd, ii); - // Symbol Clock and Interpolator Positioning & Alignment - consume_each(ii); - return oo; - } + // Symbol Clock and Interpolator Positioning & Alignment + consume_each(ii); + return oo; +} - } /* namespace digital */ +} /* namespace digital */ } /* namespace gr */ |