summaryrefslogtreecommitdiff
path: root/gr-digital/lib/symbol_sync_cc_impl.cc
diff options
context:
space:
mode:
authorMarcus Müller <mmueller@gnuradio.org>2019-08-07 21:45:12 +0200
committerMarcus Müller <marcus@hostalia.de>2019-08-09 23:04:28 +0200
commitf7bbf2c1d8d780294f3e016aff239ca35eb6516e (patch)
treee09ab6112e02b2215b2d59ac24d3d6ea2edac745 /gr-digital/lib/symbol_sync_cc_impl.cc
parent78431dc6941e3acc67c858277dfe4a0ed583643c (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.cc858
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 */