GNU Radio 3.4.0 C++ API
atsci_sssr.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /*
00003  * Copyright 2002 Free Software Foundation, Inc.
00004  * 
00005  * This file is part of GNU Radio
00006  * 
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3, or (at your option)
00010  * any later version.
00011  * 
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with GNU Radio; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 51 Franklin Street,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022 
00023 /*
00024  *   --- ATSC Segment and Symbol Sync Recovery ---
00025  */
00026 
00027 #ifndef _ATSC_SSSR_H_
00028 #define _ATSC_SSSR_H_
00029 
00030 #include <atsc_consts.h>
00031 #include <gri_mmse_fir_interpolator.h>
00032 #include <gr_single_pole_iir.h>
00033 #include <cstdio>
00034 
00035 /*
00036  *   --- support classes for atsci_sssr ---
00037  */
00038 
00039 namespace sssr {
00040 
00041   typedef float sample_t;
00042 
00043   // ----------------------------------------------------------------
00044   //! digital correlator for 1001 and 0110 patterns
00045 
00046   class digital_correlator {
00047     int         d_sr;   // 4 bit shift register
00048 
00049   public:
00050     
00051     // Constructor
00052     digital_correlator () { reset (); }
00053 
00054     // Manipulators
00055 
00056     //! called on channel change
00057     void reset () { d_sr = 0; }
00058 
00059     //! clock bit in and return true if we've seen 1001
00060 
00061     bool update (int bit) {
00062       d_sr = ((bit & 1) << 3) | (d_sr >> 1);
00063 
00064       return (d_sr == 0x9);     // 1001
00065     }
00066 
00067   };
00068 
00069 
00070   // ----------------------------------------------------------------
00071   //! segment sync integrator
00072 
00073   class seg_sync_integrator {
00074     signed char d_integrator[ATSC_DATA_SEGMENT_LENGTH];
00075     
00076   public:
00077 
00078     // Constructor
00079     seg_sync_integrator () { reset (); }
00080 
00081     // Manipulators
00082 
00083     //! called on channel change
00084     void reset ();
00085     
00086     //! update current tap with weight and return integrated correlation value
00087     int update (int weight, int index);
00088 
00089     //! return index of maximum correlation value
00090     int find_max (int *value);
00091 
00092   };
00093   
00094   // ----------------------------------------------------------------
00095   //! quad filter (used to compute timing error)
00096 
00097   class quad_filter {
00098     sample_t    d_delay[4];
00099 
00100   public:
00101     // Constructor
00102     quad_filter () { reset (); }
00103 
00104     // Manipulators
00105 
00106     //! called on channel change
00107     void reset () { d_delay[0] = d_delay[1] = d_delay[2] = d_delay[3] = 0; }
00108 
00109     double update (sample_t sample){
00110       d_delay[3] = d_delay[2];
00111       d_delay[2] = d_delay[1];
00112       d_delay[1] = d_delay[0];
00113       d_delay[0] = sample;
00114 
00115       // the coefficients are -1,-1,+1,+1
00116       return d_delay[3] + d_delay[2] - d_delay[1] - d_delay[0];
00117     }
00118   };
00119 }
00120 
00121 // ----------------------------------------------------------------
00122 
00123 /*!
00124  * \brief ATSC Segment and Symbol Sync Recovery
00125  *
00126  * This class implements data segment sync tracking and symbol timing
00127  * using the method described in "ATSC/VSB Tutorial - Receiver Technology"
00128  * by Wayne E. Bretl of Zenith, pgs 41-45.
00129  */
00130 
00131 class atsci_sssr {
00132   sssr::digital_correlator      d_correlator;
00133   sssr::seg_sync_integrator     d_integrator;
00134   sssr::quad_filter             d_quad_filter;
00135   double                        d_quad_output[ATSC_DATA_SEGMENT_LENGTH];
00136   double                        d_timing_adjust;
00137   int                           d_counter;      // free running mod 832 counter
00138   int                           d_symbol_index;
00139   bool                          d_seg_locked;
00140   FILE                         *d_debug_fp;
00141 
00142   
00143   bool incr_counter () {
00144     d_counter++;
00145     if (d_counter >= ATSC_DATA_SEGMENT_LENGTH){
00146       d_counter = 0;
00147       return true;
00148     }
00149     return false;
00150   }
00151     
00152   void incr_symbol_index () {
00153     d_symbol_index++;
00154     if (d_symbol_index >= ATSC_DATA_SEGMENT_LENGTH)
00155       d_symbol_index = 0;
00156   }
00157 
00158 public:
00159 
00160   // Constructor
00161   atsci_sssr ();
00162   ~atsci_sssr ();
00163 
00164   // Manipulators
00165 
00166   //! call on channel change
00167   void reset ();
00168 
00169 
00170   /*!
00171    * \brief process a single sample at the ATSC symbol rate (~10.76 MSPS)
00172    *
00173    * This block computes an indication of our timing error and keeps
00174    * track of where the segment sync's occur.  \p timing_adjust is
00175    * returned to indicate how the interpolator timing needs to be
00176    * adjusted to track the transmitter's symbol timing.  If \p seg_locked
00177    * is true, then \p symbol_index is the index of this sample in 
00178    * the current segment.  The symbols are numbered from 0 to 831, where 
00179    * symbols 0, 1, 2 and 3 correspond to the data segment sync pattern, 
00180    * nominally +5, -5, -5, +5.
00181    */
00182 
00183   void update (sssr::sample_t  sample_in,       // input
00184                bool           *seg_locked,      // are we seeing segment syncs?
00185                int            *symbol_index,    // 0..831
00186                double         *timing_adjust);  // how much to adjust timing
00187 
00188 };
00189 
00190 // ----------------------------------------------------------------
00191 
00192 /*!
00193  * \brief interpolator control for segment and symbol sync recovery
00194  */
00195  
00196 class atsci_interpolator {
00197   gri_mmse_fir_interpolator     d_interp;
00198   gr_single_pole_iir<float,float,float> d_loop; // ``VCO'' loop filter
00199   double                        d_nominal_ratio_of_rx_clock_to_symbol_freq; // FREQ
00200   double                        d_w;    // ratio of PERIOD of Tx to Rx clocks
00201   double                        d_mu;   // fractional delay [0,1]
00202   int                           d_incr;         // diagnostic only
00203   FILE                         *d_debug_fp;     // diagnostic only
00204 
00205 public:
00206   //! \p nominal_ratio_of_rx_clock_to_symbol_freq must be >= 1.8
00207   atsci_interpolator (double nominal_ratio_of_rx_clock_to_symbol_freq);
00208   ~atsci_interpolator ();
00209 
00210   // Manipulators
00211 
00212   //! call on channel change
00213   void reset ();
00214 
00215   /*!
00216    * \brief produce next sample referenced to Tx clock
00217    *
00218    * If there aren't enough input_samples left to produce
00219    * an output, return false, else true.
00220    */
00221 
00222   bool update (const sssr::sample_t input_samples[],    // I: vector of samples
00223                int                  nsamples,           // I: total number of samples
00224                int                 *index,              // I/O: current input index
00225                double               timing_adjustment,  // I: how much to bump timing
00226                sssr::sample_t      *output_sample);     // O: the output sample
00227 
00228   // Accessors
00229 
00230   // how much history we require on our input
00231   unsigned ntaps () const { return d_interp.ntaps (); }
00232 
00233   // diagnostic accessors
00234   double mu ()   const { return d_mu; }
00235   double w ()    const { return d_w;  }
00236   int    incr () const { return d_incr; }
00237   
00238 };
00239 
00240 #endif /* _ATSC_SSSR_H_ */