Merge commit 'v3.3.0' into upstream
[debian/gnuradio] / gr-atsc / src / lib / atsci_sssr.h
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 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 /*
24  *   --- ATSC Segment and Symbol Sync Recovery ---
25  */
26
27 #ifndef _ATSC_SSSR_H_
28 #define _ATSC_SSSR_H_
29
30 #include <atsc_consts.h>
31 #include <gri_mmse_fir_interpolator.h>
32 #include <gr_single_pole_iir.h>
33 #include <cstdio>
34
35 /*
36  *   --- support classes for atsci_sssr ---
37  */
38
39 namespace sssr {
40
41   typedef float sample_t;
42
43   // ----------------------------------------------------------------
44   //! digital correlator for 1001 and 0110 patterns
45
46   class digital_correlator {
47     int         d_sr;   // 4 bit shift register
48
49   public:
50     
51     // Constructor
52     digital_correlator () { reset (); }
53
54     // Manipulators
55
56     //! called on channel change
57     void reset () { d_sr = 0; }
58
59     //! clock bit in and return true if we've seen 1001
60
61     bool update (int bit) {
62       d_sr = ((bit & 1) << 3) | (d_sr >> 1);
63
64       return (d_sr == 0x9);     // 1001
65     }
66
67   };
68
69
70   // ----------------------------------------------------------------
71   //! segment sync integrator
72
73   class seg_sync_integrator {
74     signed char d_integrator[ATSC_DATA_SEGMENT_LENGTH];
75     
76   public:
77
78     // Constructor
79     seg_sync_integrator () { reset (); }
80
81     // Manipulators
82
83     //! called on channel change
84     void reset ();
85     
86     //! update current tap with weight and return integrated correlation value
87     int update (int weight, int index);
88
89     //! return index of maximum correlation value
90     int find_max (int *value);
91
92   };
93   
94   // ----------------------------------------------------------------
95   //! quad filter (used to compute timing error)
96
97   class quad_filter {
98     sample_t    d_delay[4];
99
100   public:
101     // Constructor
102     quad_filter () { reset (); }
103
104     // Manipulators
105
106     //! called on channel change
107     void reset () { d_delay[0] = d_delay[1] = d_delay[2] = d_delay[3] = 0; }
108
109     double update (sample_t sample){
110       d_delay[3] = d_delay[2];
111       d_delay[2] = d_delay[1];
112       d_delay[1] = d_delay[0];
113       d_delay[0] = sample;
114
115       // the coefficients are -1,-1,+1,+1
116       return d_delay[3] + d_delay[2] - d_delay[1] - d_delay[0];
117     }
118   };
119 }
120
121 // ----------------------------------------------------------------
122
123 /*!
124  * \brief ATSC Segment and Symbol Sync Recovery
125  *
126  * This class implements data segment sync tracking and symbol timing
127  * using the method described in "ATSC/VSB Tutorial - Receiver Technology"
128  * by Wayne E. Bretl of Zenith, pgs 41-45.
129  */
130
131 class atsci_sssr {
132   sssr::digital_correlator      d_correlator;
133   sssr::seg_sync_integrator     d_integrator;
134   sssr::quad_filter             d_quad_filter;
135   double                        d_quad_output[ATSC_DATA_SEGMENT_LENGTH];
136   double                        d_timing_adjust;
137   int                           d_counter;      // free running mod 832 counter
138   int                           d_symbol_index;
139   bool                          d_seg_locked;
140   FILE                         *d_debug_fp;
141
142   
143   bool incr_counter () {
144     d_counter++;
145     if (d_counter >= ATSC_DATA_SEGMENT_LENGTH){
146       d_counter = 0;
147       return true;
148     }
149     return false;
150   }
151     
152   void incr_symbol_index () {
153     d_symbol_index++;
154     if (d_symbol_index >= ATSC_DATA_SEGMENT_LENGTH)
155       d_symbol_index = 0;
156   }
157
158 public:
159
160   // Constructor
161   atsci_sssr ();
162   ~atsci_sssr ();
163
164   // Manipulators
165
166   //! call on channel change
167   void reset ();
168
169
170   /*!
171    * \brief process a single sample at the ATSC symbol rate (~10.76 MSPS)
172    *
173    * This block computes an indication of our timing error and keeps
174    * track of where the segment sync's occur.  \p timing_adjust is
175    * returned to indicate how the interpolator timing needs to be
176    * adjusted to track the transmitter's symbol timing.  If \p seg_locked
177    * is true, then \p symbol_index is the index of this sample in 
178    * the current segment.  The symbols are numbered from 0 to 831, where 
179    * symbols 0, 1, 2 and 3 correspond to the data segment sync pattern, 
180    * nominally +5, -5, -5, +5.
181    */
182
183   void update (sssr::sample_t  sample_in,       // input
184                bool           *seg_locked,      // are we seeing segment syncs?
185                int            *symbol_index,    // 0..831
186                double         *timing_adjust);  // how much to adjust timing
187
188 };
189
190 // ----------------------------------------------------------------
191
192 /*!
193  * \brief interpolator control for segment and symbol sync recovery
194  */
195  
196 class atsci_interpolator {
197   gri_mmse_fir_interpolator     d_interp;
198   gr_single_pole_iir<float,float,float> d_loop; // ``VCO'' loop filter
199   double                        d_nominal_ratio_of_rx_clock_to_symbol_freq; // FREQ
200   double                        d_w;    // ratio of PERIOD of Tx to Rx clocks
201   double                        d_mu;   // fractional delay [0,1]
202   int                           d_incr;         // diagnostic only
203   FILE                         *d_debug_fp;     // diagnostic only
204
205 public:
206   //! \p nominal_ratio_of_rx_clock_to_symbol_freq must be >= 1.8
207   atsci_interpolator (double nominal_ratio_of_rx_clock_to_symbol_freq);
208   ~atsci_interpolator ();
209
210   // Manipulators
211
212   //! call on channel change
213   void reset ();
214
215   /*!
216    * \brief produce next sample referenced to Tx clock
217    *
218    * If there aren't enough input_samples left to produce
219    * an output, return false, else true.
220    */
221
222   bool update (const sssr::sample_t input_samples[],    // I: vector of samples
223                int                  nsamples,           // I: total number of samples
224                int                 *index,              // I/O: current input index
225                double               timing_adjustment,  // I: how much to bump timing
226                sssr::sample_t      *output_sample);     // O: the output sample
227
228   // Accessors
229
230   // how much history we require on our input
231   unsigned ntaps () const { return d_interp.ntaps (); }
232
233   // diagnostic accessors
234   double mu ()   const { return d_mu; }
235   double w ()    const { return d_w;  }
236   int    incr () const { return d_incr; }
237   
238 };
239
240 #endif /* _ATSC_SSSR_H_ */