X-Git-Url: https://git.gag.com/?p=debian%2Fgnuradio;a=blobdiff_plain;f=gr-atsc%2Fsrc%2Flib%2Fatsci_sssr.cc;fp=gr-atsc%2Fsrc%2Flib%2Fatsci_sssr.cc;h=dc5c01b0d28981a48de8cfebd0cd635c2579ac42;hp=0000000000000000000000000000000000000000;hb=fd9980f919b6f05e2fbea404fea322825ce438f0;hpb=2415ccdbf9d97878a0888bbdff30d699ae2326dd diff --git a/gr-atsc/src/lib/atsci_sssr.cc b/gr-atsc/src/lib/atsci_sssr.cc new file mode 100644 index 00000000..dc5c01b0 --- /dev/null +++ b/gr-atsc/src/lib/atsci_sssr.cc @@ -0,0 +1,290 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * ---------------------------------------------------------------- + * Segment Integrator Pre-Processor + * + * Compute weight passed to integrator based on + * correlation result and ncorr_gain2 + */ + +inline static int +sipp (bool digcorr_output) +{ + if (digcorr_output) + return +2; // positive correlation + else + return -1; // no correlation +} + +/* + * ---------------------------------------------------------------- + * Segment Sync Integrator... + */ + +static const int SSI_MIN = -16; +static const int SSI_MAX = 15; + +void +sssr::seg_sync_integrator::reset () +{ + for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++) + d_integrator[i] = SSI_MIN; +} + +int +sssr::seg_sync_integrator::update (int weight, int index) +{ + int t = d_integrator[index] + weight; + t = std::max (t, SSI_MIN); + t = std::min (t, SSI_MAX); + d_integrator[index] = t; + + return t; +} + +int +sssr::seg_sync_integrator::find_max (int *v) +{ + int best_value = d_integrator[0]; + int best_index = 0; + + for (int i = 1; i < ATSC_DATA_SEGMENT_LENGTH; i++) + if (d_integrator[i] > best_value){ + best_value = d_integrator[i]; + best_index = i; + } + + *v = best_value; + return best_index; +} + +/* + * ---------------------------------------------------------------- + * Segment Sync and Symbol recovery + */ + +static const int SYMBOL_INDEX_OFFSET = 3; +static const int MIN_SEG_LOCK_CORRELATION_VALUE = 5; + +atsci_sssr::atsci_sssr () + : d_debug_fp(0) +{ + reset (); + + if (_SSSR_DIAG_OUTPUT_){ + const char *file = "sssr.ssout"; + if ((d_debug_fp = fopen (file, "wb")) == 0){ + perror (file); + exit (1); + } + } +} + +atsci_sssr::~atsci_sssr () +{ + if (d_debug_fp) + fclose (d_debug_fp); +} + +void +atsci_sssr::reset () +{ + d_correlator.reset (); + d_integrator.reset (); + d_quad_filter.reset (); + + for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++) + d_quad_output[i] = 0; + + d_timing_adjust = 0; + d_counter = 0; + d_symbol_index = 0; + d_seg_locked = false; +} + +void +atsci_sssr::update (sssr::sample_t sample_in, // input + bool *seg_locked, // are we seeing segment syncs? + int *symbol_index, // 0..831 + double *timing_adjust) // how much to adjust timing +{ + double qo = d_quad_filter.update (sample_in); + d_quad_output[d_counter] = qo; + + int bit = gr_signbit (sample_in) ^ 1; // slice on sign: + => 1, - => 0 + int corr_out = d_correlator.update (bit); + int weight = sipp (corr_out); + int corr_value = d_integrator.update (weight, d_counter); + int best_correlation_index = -1; + + incr_symbol_index (); + if (incr_counter ()){ // counter just wrapped... + int best_correlation_value; + best_correlation_index = d_integrator.find_max (&best_correlation_value); + d_seg_locked = best_correlation_value >= MIN_SEG_LOCK_CORRELATION_VALUE; + d_timing_adjust = d_quad_output[best_correlation_index]; + + d_symbol_index = SYMBOL_INDEX_OFFSET - 1 - best_correlation_index; + if (d_symbol_index < 0) + d_symbol_index += ATSC_DATA_SEGMENT_LENGTH; + } + + *seg_locked = d_seg_locked; + *symbol_index = d_symbol_index; + *timing_adjust = d_timing_adjust; + + if (_SSSR_DIAG_OUTPUT_){ + float iodata[7]; + iodata[0] = bit; + iodata[1] = corr_value; + iodata[2] = qo; + iodata[3] = d_counter; + iodata[4] = d_symbol_index; + iodata[5] = best_correlation_index; + iodata[6] = d_timing_adjust; + + if (fwrite (iodata, sizeof (iodata), 1, d_debug_fp) != 1){ + perror ("fwrite: sssr"); + exit (1); + } + } + +} + +/* + * ---------------------------------------------------------------- + * Interpolator control for Seg & Symbol Sync Recovery + */ + +static const double LOOP_FILTER_TAP = 0.00025; // 0.0005 works +static const double ADJUSTMENT_GAIN = 1.0e-5 / (10 * ATSC_DATA_SEGMENT_LENGTH); + +atsci_interpolator::atsci_interpolator (double nominal_ratio_of_rx_clock_to_symbol_freq) + : d_debug_fp(0) +{ +// Tweaked ratio from 1.8 to 1.78 to support input rate of 19.2MHz + assert (nominal_ratio_of_rx_clock_to_symbol_freq >= 1.78); + d_nominal_ratio_of_rx_clock_to_symbol_freq = + nominal_ratio_of_rx_clock_to_symbol_freq; + + d_loop.set_taps (LOOP_FILTER_TAP); + + reset (); + + if (_SSSR_DIAG_OUTPUT_){ + const char *file = "interp.ssout"; + if ((d_debug_fp = fopen (file, "wb")) == 0){ + perror (file); + exit (1); + } + } + +} + +atsci_interpolator::~atsci_interpolator () +{ + if (d_debug_fp) + fclose (d_debug_fp); +} + +void +atsci_interpolator::reset () +{ + d_w = d_nominal_ratio_of_rx_clock_to_symbol_freq; + d_mu = 0.5; + d_incr = 0; + d_loop.reset (); +} + +bool +atsci_interpolator::update ( + const sssr::sample_t input_samples[], // I: vector of samples + int nsamples, // I: total number of samples + int *index, // I/O: current input index + double timing_adjustment, // I: how much to bump timing + sssr::sample_t *output_sample) +{ + if (*index + (int) ntaps () > nsamples) + return false; + + // FIXME Confirm that this is right. I think it is. It was (1-d_mu) + *output_sample = d_interp.interpolate (&input_samples[*index], d_mu); + + double filter_out = 0; + +#if 0 + + filter_out = d_loop.filter (timing_adjustment); + d_w = d_w + ADJUSTMENT_GAIN * filter_out * 1e-3; + +#elif 1 + + filter_out = d_loop.filter (timing_adjustment); + d_mu = d_mu + ADJUSTMENT_GAIN * 10e3 * filter_out; + +#else + + static const double alpha = 0.01; + static const double beta = alpha * alpha / 16; + + double x = ADJUSTMENT_GAIN * 10e3 * timing_adjustment; + + d_mu = d_mu + alpha * x; // conceptually "phase" + d_w = d_w + beta * x; // conceptually "frequency" + +#endif + + double s = d_mu + d_w; + double float_incr = floor (s); + d_mu = s - float_incr; + d_incr = (int) float_incr; + + assert (d_incr >= 1 && d_incr <= 3); + *index += d_incr; + + if (_SSSR_DIAG_OUTPUT_){ + float iodata[6]; + iodata[0] = timing_adjustment; + iodata[1] = filter_out; + iodata[2] = d_w; + iodata[3] = d_mu; + iodata[4] = d_incr; + iodata[5] = *output_sample; + if (fwrite (iodata, sizeof (iodata), 1, d_debug_fp) != 1){ + perror ("fwrite: interpolate"); + exit (1); + } + } + + return true; +}