Merge branch 'dfsg-orig'
[debian/gnuradio] / gr-atsc / src / lib / atsci_sssr.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2002,2008 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
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)
10  * any later version.
11  * 
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.
16  * 
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.
21  */
22
23 #include <atsci_sssr.h>
24 #include <algorithm>
25 #include <cmath>
26 #include <cstdio>
27 #include <assert.h>
28 #include <atsci_diag_output.h>
29 #include <gr_math.h>
30 #include <stdio.h>
31
32 /*
33  * ----------------------------------------------------------------
34  * Segment Integrator Pre-Processor
35  *
36  * Compute weight passed to integrator based on
37  * correlation result and ncorr_gain2
38  */
39
40 inline static int
41 sipp (bool digcorr_output)
42 {
43   if (digcorr_output)
44     return +2;                  // positive correlation
45   else
46     return -1;                  // no correlation
47 }
48
49 /* 
50  * ----------------------------------------------------------------
51  * Segment Sync Integrator...
52  */
53
54 static const int SSI_MIN = -16;
55 static const int SSI_MAX =  15;
56
57 void
58 sssr::seg_sync_integrator::reset ()
59 {
60   for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++)
61     d_integrator[i] = SSI_MIN;
62 }
63   
64 int
65 sssr::seg_sync_integrator::update (int weight, int index)
66 {
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;
71
72   return t;
73 }
74
75 int
76 sssr::seg_sync_integrator::find_max (int *v)
77 {
78   int   best_value = d_integrator[0];
79   int   best_index = 0;
80   
81   for (int i = 1; i < ATSC_DATA_SEGMENT_LENGTH; i++)
82     if (d_integrator[i] > best_value){
83       best_value = d_integrator[i];
84       best_index = i;
85     }
86
87   *v = best_value;
88   return best_index;
89 }
90
91 /*
92  * ----------------------------------------------------------------
93  * Segment Sync and Symbol recovery
94  */
95
96 static const int        SYMBOL_INDEX_OFFSET = 3;
97 static const int        MIN_SEG_LOCK_CORRELATION_VALUE = 5;
98
99 atsci_sssr::atsci_sssr ()
100   : d_debug_fp(0)
101 {
102   reset ();
103   
104   if (_SSSR_DIAG_OUTPUT_){
105     const char *file = "sssr.ssout";
106     if ((d_debug_fp = fopen (file, "wb")) == 0){
107       perror (file);
108       exit (1);
109     }
110   }
111 }
112
113 atsci_sssr::~atsci_sssr ()
114 {
115   if (d_debug_fp)
116     fclose (d_debug_fp);
117 }
118
119 void
120 atsci_sssr::reset ()
121 {
122   d_correlator.reset ();
123   d_integrator.reset ();
124   d_quad_filter.reset ();
125
126   for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++)
127     d_quad_output[i] = 0;
128   
129   d_timing_adjust = 0;
130   d_counter = 0;
131   d_symbol_index = 0;
132   d_seg_locked = false;
133 }
134
135 void
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
140 {
141   double qo = d_quad_filter.update (sample_in);
142   d_quad_output[d_counter] = qo;
143
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;
149
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];
156
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;
160   }
161
162   *seg_locked = d_seg_locked;
163   *symbol_index = d_symbol_index;
164   *timing_adjust = d_timing_adjust;
165
166   if (_SSSR_DIAG_OUTPUT_){
167     float       iodata[7];
168     iodata[0] = bit;
169     iodata[1] = corr_value;
170     iodata[2] = qo;
171     iodata[3] = d_counter;
172     iodata[4] = d_symbol_index;
173     iodata[5] = best_correlation_index;
174     iodata[6] = d_timing_adjust;
175
176     if (fwrite (iodata, sizeof (iodata), 1, d_debug_fp) != 1){
177       perror ("fwrite: sssr");
178       exit (1);
179     }
180   }
181
182 }
183
184 /*
185  * ----------------------------------------------------------------
186  * Interpolator control for Seg & Symbol Sync Recovery
187  */
188
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);
191   
192 atsci_interpolator::atsci_interpolator (double nominal_ratio_of_rx_clock_to_symbol_freq)
193   : d_debug_fp(0)
194 {
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;
199
200   d_loop.set_taps (LOOP_FILTER_TAP);
201
202   reset ();
203
204   if (_SSSR_DIAG_OUTPUT_){
205     const char *file = "interp.ssout";
206     if ((d_debug_fp = fopen (file, "wb")) == 0){
207       perror (file);
208       exit (1);
209     }
210   }
211
212 }
213
214 atsci_interpolator::~atsci_interpolator ()
215 {
216   if (d_debug_fp)
217     fclose (d_debug_fp);
218 }
219
220 void
221 atsci_interpolator::reset ()
222 {
223   d_w = d_nominal_ratio_of_rx_clock_to_symbol_freq;
224   d_mu = 0.5;
225   d_incr = 0;
226   d_loop.reset ();
227 }
228
229 bool
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)
236 {
237   if (*index + (int) ntaps () > nsamples)
238     return false;
239
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);  
242
243   double filter_out = 0;
244   
245 #if 0
246
247   filter_out = d_loop.filter (timing_adjustment);
248   d_w = d_w + ADJUSTMENT_GAIN * filter_out * 1e-3;
249
250 #elif 1
251
252   filter_out = d_loop.filter (timing_adjustment);
253   d_mu = d_mu + ADJUSTMENT_GAIN * 10e3 * filter_out;
254
255 #else
256
257   static const double alpha = 0.01;
258   static const double beta = alpha * alpha / 16;
259
260   double x = ADJUSTMENT_GAIN * 10e3 * timing_adjustment;
261
262   d_mu = d_mu + alpha * x;      // conceptually "phase"
263   d_w  = d_w  + beta * x;       // conceptually "frequency"
264   
265 #endif
266   
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;
271
272   assert (d_incr >= 1 && d_incr <= 3);
273   *index += d_incr;
274
275   if (_SSSR_DIAG_OUTPUT_){
276     float       iodata[6];
277     iodata[0] = timing_adjustment;
278     iodata[1] = filter_out;
279     iodata[2] = d_w;
280     iodata[3] = d_mu;
281     iodata[4] = d_incr;
282     iodata[5] = *output_sample;
283     if (fwrite (iodata, sizeof (iodata), 1, d_debug_fp) != 1){
284       perror ("fwrite: interpolate");
285       exit (1);
286     }
287   }
288
289   return true;
290 }