Updated FSF address in all files. Fixes ticket:51
[debian/gnuradio] / gr-atsc / src / lib / atsci_sssr.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2002 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 2, 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
31 /*
32  * ----------------------------------------------------------------
33  * Segment Integrator Pre-Processor
34  *
35  * Compute weight passed to integrator based on
36  * correlation result and ncorr_gain2
37  */
38
39 inline static int
40 sipp (bool digcorr_output)
41 {
42   if (digcorr_output)
43     return +2;                  // positive correlation
44   else
45     return -1;                  // no correlation
46 }
47
48 /* 
49  * ----------------------------------------------------------------
50  * Segment Sync Integrator...
51  */
52
53 static const int SSI_MIN = -16;
54 static const int SSI_MAX =  15;
55
56 void
57 sssr::seg_sync_integrator::reset ()
58 {
59   for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++)
60     d_integrator[i] = SSI_MIN;
61 }
62   
63 int
64 sssr::seg_sync_integrator::update (int weight, int index)
65 {
66   int   t = d_integrator[index] + weight;
67   t = std::max (t, SSI_MIN);
68   t = std::min (t, SSI_MAX);
69   d_integrator[index] = t;
70
71   return t;
72 }
73
74 int
75 sssr::seg_sync_integrator::find_max (int *v)
76 {
77   int   best_value = d_integrator[0];
78   int   best_index = 0;
79   
80   for (int i = 1; i < ATSC_DATA_SEGMENT_LENGTH; i++)
81     if (d_integrator[i] > best_value){
82       best_value = d_integrator[i];
83       best_index = i;
84     }
85
86   *v = best_value;
87   return best_index;
88 }
89
90 /*
91  * ----------------------------------------------------------------
92  * Segment Sync and Symbol recovery
93  */
94
95 static const int        SYMBOL_INDEX_OFFSET = 3;
96 static const int        MIN_SEG_LOCK_CORRELATION_VALUE = 5;
97
98 atsci_sssr::atsci_sssr ()
99 {
100   reset ();
101   
102   if (_SSSR_DIAG_OUTPUT_){
103     const char *file = "sssr.ssout";
104     if ((d_debug_fp = fopen (file, "wb")) == 0){
105       perror (file);
106       exit (1);
107     }
108   }
109 }
110
111 atsci_sssr::~atsci_sssr ()
112 {
113   if (d_debug_fp)
114     fclose (d_debug_fp);
115 }
116
117 void
118 atsci_sssr::reset ()
119 {
120   d_correlator.reset ();
121   d_integrator.reset ();
122   d_quad_filter.reset ();
123
124   for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++)
125     d_quad_output[i] = 0;
126   
127   d_timing_adjust = 0;
128   d_counter = 0;
129   d_symbol_index = 0;
130   d_seg_locked = false;
131 }
132
133 void
134 atsci_sssr::update (sssr::sample_t sample_in,    // input
135                    bool          *seg_locked,    // are we seeing segment syncs?
136                    int           *symbol_index,  // 0..831
137                    double        *timing_adjust) // how much to adjust timing
138 {
139   double qo = d_quad_filter.update (sample_in);
140   d_quad_output[d_counter] = qo;
141
142   int bit = gr_signbit (sample_in) ^ 1; // slice on sign: + => 1, - => 0
143   int corr_out = d_correlator.update (bit);
144   int weight = sipp (corr_out);
145   int corr_value = d_integrator.update (weight, d_counter);
146   int best_correlation_index = -1;
147
148   incr_symbol_index ();
149   if (incr_counter ()){         // counter just wrapped...
150     int best_correlation_value;
151     best_correlation_index = d_integrator.find_max (&best_correlation_value);
152     d_seg_locked = best_correlation_value >= MIN_SEG_LOCK_CORRELATION_VALUE;
153     d_timing_adjust = d_quad_output[best_correlation_index];
154
155     d_symbol_index = SYMBOL_INDEX_OFFSET - 1 - best_correlation_index;
156     if (d_symbol_index < 0)
157       d_symbol_index += ATSC_DATA_SEGMENT_LENGTH;
158   }
159
160   *seg_locked = d_seg_locked;
161   *symbol_index = d_symbol_index;
162   *timing_adjust = d_timing_adjust;
163
164   if (_SSSR_DIAG_OUTPUT_){
165     float       iodata[7];
166     iodata[0] = bit;
167     iodata[1] = corr_value;
168     iodata[2] = qo;
169     iodata[3] = d_counter;
170     iodata[4] = d_symbol_index;
171     iodata[5] = best_correlation_index;
172     iodata[6] = d_timing_adjust;
173
174     if (fwrite (iodata, sizeof (iodata), 1, d_debug_fp) != 1){
175       perror ("fwrite: sssr");
176       exit (1);
177     }
178   }
179
180 }
181
182 /*
183  * ----------------------------------------------------------------
184  * Interpolator control for Seg & Symbol Sync Recovery
185  */
186
187 static const double     LOOP_FILTER_TAP = 0.00025;      // 0.0005 works
188 static const double     ADJUSTMENT_GAIN = 1.0e-5 / (10 * ATSC_DATA_SEGMENT_LENGTH);
189   
190 atsci_interpolator::atsci_interpolator (double nominal_ratio_of_rx_clock_to_symbol_freq)
191 {
192   assert (nominal_ratio_of_rx_clock_to_symbol_freq >= 1.8);
193   d_nominal_ratio_of_rx_clock_to_symbol_freq =
194     nominal_ratio_of_rx_clock_to_symbol_freq;
195
196   d_loop.set_taps (LOOP_FILTER_TAP);
197
198   reset ();
199
200   if (_SSSR_DIAG_OUTPUT_){
201     const char *file = "interp.ssout";
202     if ((d_debug_fp = fopen (file, "wb")) == 0){
203       perror (file);
204       exit (1);
205     }
206   }
207
208 }
209
210 atsci_interpolator::~atsci_interpolator ()
211 {
212   if (d_debug_fp)
213     fclose (d_debug_fp);
214 }
215
216 void
217 atsci_interpolator::reset ()
218 {
219   d_w = d_nominal_ratio_of_rx_clock_to_symbol_freq;
220   d_mu = 0.5;
221   d_incr = 0;
222   d_loop.reset ();
223 }
224
225 bool
226 atsci_interpolator::update (
227            const sssr::sample_t input_samples[],        // I: vector of samples
228            int                  nsamples,               // I: total number of samples
229            int                 *index,                  // I/O: current input index
230            double               timing_adjustment,      // I: how much to bump timing
231            sssr::sample_t      *output_sample)
232 {
233   if (*index + (int) ntaps () > nsamples)
234     return false;
235
236   // FIXME Confirm that this is right.  I think it is.  It was (1-d_mu)
237   *output_sample = d_interp.interpolate (&input_samples[*index], d_mu);  
238
239   double filter_out = 0;
240   
241 #if 0
242
243   filter_out = d_loop.filter (timing_adjustment);
244   d_w = d_w + ADJUSTMENT_GAIN * filter_out * 1e-3;
245
246 #elif 1
247
248   filter_out = d_loop.filter (timing_adjustment);
249   d_mu = d_mu + ADJUSTMENT_GAIN * 10e3 * filter_out;
250
251 #else
252
253   static const double alpha = 0.01;
254   static const double beta = alpha * alpha / 16;
255
256   double x = ADJUSTMENT_GAIN * 10e3 * timing_adjustment;
257
258   d_mu = d_mu + alpha * x;      // conceptually "phase"
259   d_w  = d_w  + beta * x;       // conceptually "frequency"
260   
261 #endif
262   
263   double s = d_mu + d_w;
264   double float_incr = floor (s);
265   d_mu = s - float_incr;
266   d_incr = (int) float_incr;
267
268   assert (d_incr >= 1 && d_incr <= 3);
269   *index += d_incr;
270
271   if (_SSSR_DIAG_OUTPUT_){
272     float       iodata[6];
273     iodata[0] = timing_adjustment;
274     iodata[1] = filter_out;
275     iodata[2] = d_w;
276     iodata[3] = d_mu;
277     iodata[4] = d_incr;
278     iodata[5] = *output_sample;
279     if (fwrite (iodata, sizeof (iodata), 1, d_debug_fp) != 1){
280       perror ("fwrite: interpolate");
281       exit (1);
282     }
283   }
284
285   return true;
286 }