Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

VrPulseCorrelator.h

Go to the documentation of this file.
00001 /* -*- Mode: c++ -*- 
00002  *
00003  *  Copyright 1997 Massachusetts Institute of Technology
00004  * 
00005  *  Permission to use, copy, modify, distribute, and sell this software and its
00006  *  documentation for any purpose is hereby granted without fee, provided that
00007  *  the above copyright notice appear in all copies and that both that
00008  *  copyright notice and this permission notice appear in supporting
00009  *  documentation, and that the name of M.I.T. not be used in advertising or
00010  *  publicity pertaining to distribution of the software without specific,
00011  *  written prior permission.  M.I.T. makes no representations about the
00012  *  suitability of this software for any purpose.  It is provided "as is"
00013  *  without express or implied warranty.
00014  * 
00015  */
00016 
00017 
00018 #ifndef _VRPULSECORRELATOR_H_
00019 #define _VRPULSECORRELATOR_H_
00020 
00021 #include <VrDecimatingSigProc.h>
00022 
00023 #if defined (ENABLE_MMX)
00024 #include <VrMMX.h>
00025 #endif
00026 
00027 /* 
00028   This filter is a version of the complex FIR filter that is designed
00029   to be "digital aware". It tracks the symbol boundaries and
00030   (eventually) will be able to provide any pattern of output samples
00031   in each symbol period.
00032 
00033   The "digital aware" portions only support a single output stream
00034   now, but it seems feasible to make this filter supoort multiple
00035   outputs.  
00036   */
00037 // ********************************************************
00038 
00039 #define   PRECISION_BITS    12
00040 
00041 template<class iType> 
00042 class VrPulseCorrelator : public VrDecimatingSigProc<iType,VrComplex> {
00043 protected:
00044   int num_taps, bump;
00045   int shift_bits, max_sample_count, sample_count, high_res, middle_offset, samples_per_symbol;
00046   int *all_done, high_res_start, high_res_waiting;
00047   VrComplex* taps;
00048   VrComplex phase_correction, phase_corr_incr, *over_sampled_result, small_corr_incr;
00049   long time;
00050   int symbol_boundary, symbol_period, pointer_incr, old_output_loc, new_output_loc; 
00051   float center_freq, gain;
00052   void buildFilter_complex();
00053 #if defined (ENABLE_MMX)
00054   mmxTaps* processedTaps; //Precomputed constants, shifted four times
00055 #endif
00056 public: 
00057   virtual const char *name() { return "VrPulseCorrelator"; }
00058   virtual int work(VrSampleRange output, VrComplex *o[],
00059                    VrSampleRange inputs[], iType *i[]);
00060   virtual void initialize();
00061   int setCenter_Freq(float);
00062   int setNumber_Taps(int);
00063 
00064   float getSymbol_Period();
00065   int setSymbol_Period(float);
00066   int setSymbol_Timing(float);
00067   void start_oversampling(int, int,int,VrComplex*,int*);
00068   VrPulseCorrelator(int n, float d, const int t[], const float f[], 
00069                      const float g[]);
00070   VrPulseCorrelator(float d, int t,float f, float g);
00071   ~VrPulseCorrelator();
00072   int version() { return 0; };
00073 };
00074 
00075 template<class iType> int
00076 VrPulseCorrelator<iType>::work(VrSampleRange output, VrComplex *o[],
00077                                 VrSampleRange inputs[], iType *i[])
00078 {
00079   unsigned int size = output.size;
00080   VrComplex result = 0;
00081   int output_offset = 0;
00082 
00083   cout << "    enter Work in filter" << endl;
00084   for (int i=0;i<size;) {
00085 
00086     //cout << pointer_incr << endl;
00087     //    symbol_boundary += symbol_period;
00088 
00089     if (high_res_waiting & (high_res_start-- == 0)) {
00090       high_res = 1;
00091       high_res_waiting = 0;
00092     }
00093     if (high_res) {
00094       if (sample_count == 1)  symbol_boundary += symbol_period;
00095       if (sample_count % (1 << shift_bits) == 0)  symbol_boundary += symbol_period;
00096       output_offset = (sample_count % (1 << shift_bits)) * (symbol_period >> shift_bits);
00097       new_output_loc = (symbol_boundary + output_offset) >> PRECISION_BITS;
00098     } else {
00099       symbol_boundary += symbol_period;
00100       new_output_loc = (symbol_boundary + (symbol_period/2)) >> PRECISION_BITS;
00101     }
00102 
00103     pointer_incr = new_output_loc - old_output_loc;
00104     if (pointer_incr <0) {
00105       //      cout << pointer_incr << endl;
00106       pointer_incr += (1 << (32-PRECISION_BITS));
00107     }
00108     //cout << "i: " << i << "  sample_count: " << sample_count << " incr: " << pointer_incr << endl;
00109     old_output_loc = new_output_loc;
00110     
00111     if (bump != 0) {
00112       symbol_boundary += bump;
00113       cout << "Bumping pointer " << (float) (bump) / (float)(1<<PRECISION_BITS)  << endl;
00114       bump =0;
00115     }
00116     
00117     result = 0;
00118     
00119     //make input pointer local
00120     iType *inputArray = i[0]+history+(-num_taps+1);
00121 
00122 #if defined (ENABLE_MMX)
00123     if(processedTaps->mmxReady())
00124       result = processedTaps->mmxCVDProduct(inputArray);
00125     else { 
00126       VrComplex *taps_tmp = taps;
00127       for (int j=0; j < num_taps; j++)
00128         result += taps_tmp[j] * inputArray[j];
00129     }
00130 #else
00131     VrComplex *taps_tmp = taps;
00132     for (int j=0; j < num_taps; j++)
00133       result += taps_tmp[j] * inputArray[j];     
00134 #endif
00135    
00136     // Perform phase correction (non-trivial only for freq-xlating filter)
00137     if (center_freq != 0.0) {
00138       if (high_res){
00139         phase_correction *= small_corr_incr;
00140       } else {
00141         phase_correction *= phase_corr_incr;
00142       }
00143       result *= phase_correction;
00144     }
00145     if (high_res) {
00146       over_sampled_result[sample_count-1] = result;
00147       if ((sample_count - middle_offset) % samples_per_symbol == 0) {
00148         i++;
00149       *o[0]++ = result;
00150       }
00151       sample_count++;
00152       if (sample_count == max_sample_count) {
00153         sample_count = 1;
00154         high_res = 0;
00155         *all_done = 1;
00156       }  
00157     } else /* not HIGH_RES */ {
00158       i++;
00159       *o[0]++ = result;
00160     }
00161         i[0] += pointer_incr;
00162   }
00163   cout << "    leave Work in filter" << endl;
00164   return output.size;
00165 }
00166 
00167 template<class iType> void
00168 VrPulseCorrelator<iType>::buildFilter_complex(){
00169   int inSampFreq;
00170   int index;
00171   float N = num_taps, a=0.0;
00172   float M = N-1; /* filter Order */
00173 
00174   inSampFreq = getInputSamplingFrequencyN(0); 
00175   
00176   if (center_freq == 0.0){
00177 
00178       // Build Complex Filter => 
00179       //            produces a low-pass filter using a real Hamming window
00180 
00181       for ( index=0 ; index < num_taps ; index++) {
00182        taps[index] = gain*VrComplex((0.54-0.46*cos(2*M_PI*index/(M))));
00183     }    
00184   } else {
00185     // Build composite Complex Filter => adds freq-shifting part
00186     a = 2*M_PI*center_freq / (float)inSampFreq;
00187     for ( index=0 ; index < num_taps ; index++) {
00188 
00189       taps[index] = VrComplex(gain*cos(a*index)*(0.54-0.46*cos(2*M_PI*index/(M))),
00190          gain*(-1)*sin(a*index)*(0.54-0.46*cos(2*M_PI*index/(M))));
00191 
00192     }
00193     phase_corr_incr = VrComplex(cos(a*(float)decimation),
00194                                 (-1)*sin(a*(float)decimation));
00195   }
00196 
00197   a = a * ((float)(symbol_period) / (float)((int)1 << PRECISION_BITS));
00198   VrComplex temp = VrComplex(cos(a),(-1)*sin(a));
00199   phase_corr_incr = temp;
00200 
00201 #if defined (ENABLE_MMX)
00202   if(processedTaps!=NULL)
00203     delete processedTaps;
00204   processedTaps=new mmxTaps(taps,num_taps);
00205 #endif
00206 }
00207 
00208 template<class iType> 
00209 VrPulseCorrelator<iType>::VrPulseCorrelator(float per,int t,float freq, float g)
00210   :VrDecimatingSigProc<iType,VrComplex>(1,(int) per)
00211 {
00212 
00213   symbol_period = (int) (per * (float)(1 << PRECISION_BITS));
00214   symbol_boundary = 0;
00215   old_output_loc = (symbol_period >>1) >> PRECISION_BITS;
00216   bump = 0;
00217 
00218   
00219   num_taps = t;
00220   phase_correction = VrComplex(1,0);
00221   phase_corr_incr = VrComplex(1,0);
00222   center_freq = freq;
00223   gain = g;
00224 #if defined (ENABLE_MMX)
00225   processedTaps=NULL;
00226 #endif
00227 }
00228 
00229 template<class iType> 
00230 void VrPulseCorrelator<iType>::initialize()
00231 {
00232   taps=new VrComplex[num_taps];
00233   buildFilter_complex();
00234 
00235   //Set history
00236   int max_num_taps = num_taps;
00237   setHistory(max_num_taps);
00238   high_res_waiting = 0;
00239 }
00240 
00241 template<class iType> 
00242 int VrPulseCorrelator<iType>::setCenter_Freq(float cf)
00243 {
00244   center_freq = cf;
00245   buildFilter_complex();
00246   return 1;
00247 }
00248 
00249 template<class iType> 
00250 int VrPulseCorrelator<iType>::setNumber_Taps(int numT)
00251 {
00252   num_taps = numT;
00253   delete taps;
00254   taps=new VrComplex[num_taps];
00255 
00256   //set history
00257   setHistory(num_taps);
00258   buildFilter_complex();
00259   return 1;
00260 }
00261 
00262 template<class iType> 
00263 float VrPulseCorrelator<iType>::getSymbol_Period() 
00264 {
00265   /* returns symbol period in seconds */
00266   return (float)symbol_period /(float)(1 << PRECISION_BITS)  /  (float)getInputSamplingFrequencyN(0);
00267 }
00268 
00269 template<class iType> 
00270 int VrPulseCorrelator<iType>::setSymbol_Period(float period)
00271 {
00272   /* input symbol period in seconds -> converts to fractional number of samples*/
00273   symbol_period = (int)(period * (float)(1 << PRECISION_BITS) * (float)getInputSamplingFrequencyN(0));
00274   cout << " Set period to " << (double) symbol_period / (double)(1 << PRECISION_BITS) << endl;
00275   return 1;
00276 }
00277 
00278 template<class iType> 
00279 int VrPulseCorrelator<iType>::setSymbol_Timing(float fraction)
00280 {
00281   /* input fraction (FP) of symbol period for offset adjustment: (+) =
00282      advance boundary relative to sample stream, (-)= retard boundary */
00283   bump  =  (int)( fraction * (float) symbol_period);
00284   return 1;
00285 }
00286 
00287 template<class iType> 
00288 void VrPulseCorrelator<iType>::start_oversampling(int N, int B, int wait, VrComplex *output_ptr,
00289                                                  int *done_flag)
00290 {
00291 
00292   /* this method sets up the filter to begin producing multiple
00293      outputs per symbol to allow the controlling (downstream) module
00294      to perform correlation to find a sync pulse to recover symbol
00295      timing
00296 
00297      start in 'wait' symbols (wait = 0  => start with next symbol)
00298      2^B output samples per symbol period, N symbol periods
00299   */
00300 
00301   shift_bits = B;
00302   max_sample_count = N * (1 << shift_bits);
00303   high_res_start = wait;
00304   high_res_waiting = 1;
00305   sample_count = 1;
00306   high_res = 0;
00307 
00308   over_sampled_result = output_ptr;
00309   middle_offset = (1 << (shift_bits-1))+1;
00310   samples_per_symbol = (1 << shift_bits);
00311   all_done = done_flag;
00312   *all_done = 0;
00313 
00314   float arg = 2*M_PI*center_freq / (float)getInputSamplingFrequencyN(0);
00315   small_corr_incr = VrComplex(cos(arg*(float)symbol_period / (float)(1 << (PRECISION_BITS+B))),
00316                                 (-1)*sin(arg*(float)symbol_period / (float)(1 << PRECISION_BITS+B)));
00317 }
00318 
00319 template<class iType> 
00320 VrPulseCorrelator<iType>::~VrPulseCorrelator()
00321 {
00322   delete taps;
00323 #if defined (ENABLE_MMX)
00324   delete processedTaps;
00325 #endif
00326 }
00327 #endif

Generated on Tue Mar 15 23:47:08 2005 for GNU Radio by  doxygen 1.4.0