3 * Copyright 2002,2008 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
23 #include <atsci_sssr.h>
28 #include <atsci_diag_output.h>
33 * ----------------------------------------------------------------
34 * Segment Integrator Pre-Processor
36 * Compute weight passed to integrator based on
37 * correlation result and ncorr_gain2
41 sipp (bool digcorr_output)
44 return +2; // positive correlation
46 return -1; // no correlation
50 * ----------------------------------------------------------------
51 * Segment Sync Integrator...
54 static const int SSI_MIN = -16;
55 static const int SSI_MAX = 15;
58 sssr::seg_sync_integrator::reset ()
60 for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++)
61 d_integrator[i] = SSI_MIN;
65 sssr::seg_sync_integrator::update (int weight, int index)
67 int t = d_integrator[index] + weight;
68 t = std::max (t, SSI_MIN);
69 t = std::min (t, SSI_MAX);
70 d_integrator[index] = t;
76 sssr::seg_sync_integrator::find_max (int *v)
78 int best_value = d_integrator[0];
81 for (int i = 1; i < ATSC_DATA_SEGMENT_LENGTH; i++)
82 if (d_integrator[i] > best_value){
83 best_value = d_integrator[i];
92 * ----------------------------------------------------------------
93 * Segment Sync and Symbol recovery
96 static const int SYMBOL_INDEX_OFFSET = 3;
97 static const int MIN_SEG_LOCK_CORRELATION_VALUE = 5;
99 atsci_sssr::atsci_sssr ()
104 if (_SSSR_DIAG_OUTPUT_){
105 const char *file = "sssr.ssout";
106 if ((d_debug_fp = fopen (file, "wb")) == 0){
113 atsci_sssr::~atsci_sssr ()
122 d_correlator.reset ();
123 d_integrator.reset ();
124 d_quad_filter.reset ();
126 for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++)
127 d_quad_output[i] = 0;
132 d_seg_locked = false;
136 atsci_sssr::update (sssr::sample_t sample_in, // input
137 bool *seg_locked, // are we seeing segment syncs?
138 int *symbol_index, // 0..831
139 double *timing_adjust) // how much to adjust timing
141 double qo = d_quad_filter.update (sample_in);
142 d_quad_output[d_counter] = qo;
144 int bit = gr_signbit (sample_in) ^ 1; // slice on sign: + => 1, - => 0
145 int corr_out = d_correlator.update (bit);
146 int weight = sipp (corr_out);
147 int corr_value = d_integrator.update (weight, d_counter);
148 int best_correlation_index = -1;
150 incr_symbol_index ();
151 if (incr_counter ()){ // counter just wrapped...
152 int best_correlation_value;
153 best_correlation_index = d_integrator.find_max (&best_correlation_value);
154 d_seg_locked = best_correlation_value >= MIN_SEG_LOCK_CORRELATION_VALUE;
155 d_timing_adjust = d_quad_output[best_correlation_index];
157 d_symbol_index = SYMBOL_INDEX_OFFSET - 1 - best_correlation_index;
158 if (d_symbol_index < 0)
159 d_symbol_index += ATSC_DATA_SEGMENT_LENGTH;
162 *seg_locked = d_seg_locked;
163 *symbol_index = d_symbol_index;
164 *timing_adjust = d_timing_adjust;
166 if (_SSSR_DIAG_OUTPUT_){
169 iodata[1] = corr_value;
171 iodata[3] = d_counter;
172 iodata[4] = d_symbol_index;
173 iodata[5] = best_correlation_index;
174 iodata[6] = d_timing_adjust;
176 if (fwrite (iodata, sizeof (iodata), 1, d_debug_fp) != 1){
177 perror ("fwrite: sssr");
185 * ----------------------------------------------------------------
186 * Interpolator control for Seg & Symbol Sync Recovery
189 static const double LOOP_FILTER_TAP = 0.00025; // 0.0005 works
190 static const double ADJUSTMENT_GAIN = 1.0e-5 / (10 * ATSC_DATA_SEGMENT_LENGTH);
192 atsci_interpolator::atsci_interpolator (double nominal_ratio_of_rx_clock_to_symbol_freq)
195 // Tweaked ratio from 1.8 to 1.78 to support input rate of 19.2MHz
196 assert (nominal_ratio_of_rx_clock_to_symbol_freq >= 1.78);
197 d_nominal_ratio_of_rx_clock_to_symbol_freq =
198 nominal_ratio_of_rx_clock_to_symbol_freq;
200 d_loop.set_taps (LOOP_FILTER_TAP);
204 if (_SSSR_DIAG_OUTPUT_){
205 const char *file = "interp.ssout";
206 if ((d_debug_fp = fopen (file, "wb")) == 0){
214 atsci_interpolator::~atsci_interpolator ()
221 atsci_interpolator::reset ()
223 d_w = d_nominal_ratio_of_rx_clock_to_symbol_freq;
230 atsci_interpolator::update (
231 const sssr::sample_t input_samples[], // I: vector of samples
232 int nsamples, // I: total number of samples
233 int *index, // I/O: current input index
234 double timing_adjustment, // I: how much to bump timing
235 sssr::sample_t *output_sample)
237 if (*index + (int) ntaps () > nsamples)
240 // FIXME Confirm that this is right. I think it is. It was (1-d_mu)
241 *output_sample = d_interp.interpolate (&input_samples[*index], d_mu);
243 double filter_out = 0;
247 filter_out = d_loop.filter (timing_adjustment);
248 d_w = d_w + ADJUSTMENT_GAIN * filter_out * 1e-3;
252 filter_out = d_loop.filter (timing_adjustment);
253 d_mu = d_mu + ADJUSTMENT_GAIN * 10e3 * filter_out;
257 static const double alpha = 0.01;
258 static const double beta = alpha * alpha / 16;
260 double x = ADJUSTMENT_GAIN * 10e3 * timing_adjustment;
262 d_mu = d_mu + alpha * x; // conceptually "phase"
263 d_w = d_w + beta * x; // conceptually "frequency"
267 double s = d_mu + d_w;
268 double float_incr = floor (s);
269 d_mu = s - float_incr;
270 d_incr = (int) float_incr;
272 assert (d_incr >= 1 && d_incr <= 3);
275 if (_SSSR_DIAG_OUTPUT_){
277 iodata[0] = timing_adjustment;
278 iodata[1] = filter_out;
282 iodata[5] = *output_sample;
283 if (fwrite (iodata, sizeof (iodata), 1, d_debug_fp) != 1){
284 perror ("fwrite: interpolate");