RTXI 1.3
plugins/include/DSP/remezalg.cpp
Go to the documentation of this file.
00001 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00002 //
00003 //  File = remezalg.cpp
00004 //
00005 //  Remez algorithm for design of FIR filters
00006 //
00007 
00008 #include <math.h>
00009 #include <stdlib.h>
00010 #include <ostream.h>
00011 #include "fs_dsgn.h"
00012 #include "fs_spec.h"
00013 #include "remezalg.h"
00014 #ifdef _DEBUG
00015 extern std::ofstream DebugFile;
00016 #endif
00017 
00018 //======================================================
00019 //  constructor
00020 //------------------------------------------------------
00021 
00022 RemezAlgorithm::RemezAlgorithm( istream& uin,
00023                                 ostream& uout,
00024                                 int filter_length,
00025                                 double passband_edge_freq,
00026                                 double stopband_edge_freq,
00027                                 double ripple_ratio,
00028                                 FirFilterDesign **fir_filter)
00029 {
00030  int m, j;
00031  int grid_density;
00032  //--------------------------------
00033  // get user-specified parameters
00034 
00035   uout << "\nparameters for Remez algorithm\n"
00036        << "--------------------------------" << std::endl;
00037   uout << "number of grid points per extremal frequency?\n"
00038        << "( MUST be an integer)" << std::endl;
00039   uin >> grid_density;
00040 
00041   //uout << "ripple ratio?" << std::endl;
00042   //uin >> ripple_ratio;
00043 
00044  //--------------------------------
00045  //  set up frequency grid
00046 
00047  Filter_Length = filter_length;
00048  PB_Edge_Freq = passband_edge_freq;
00049  SB_Edge_Freq = stopband_edge_freq;
00050  Num_Approx_Funcs = (filter_length + 1)/2;
00051  Grid_Density = grid_density;
00052  Ripple_Ratio = ripple_ratio;
00053 
00054  double* extremal_freqs = new double[Num_Approx_Funcs+1];
00055  double* filter_coeffs = new double[filter_length+1];
00056  
00057  SetupGrid();
00058 
00059  Ext_Freq = new int[Num_PB_Freqs+Num_SB_Freqs];
00060  Old_Ext_Freq = new int[Num_PB_Freqs+Num_SB_Freqs];
00061  
00062  PB_Edge_Freq = PB_Edge_Freq + (PB_Edge_Freq/(2.0*Num_Grid_Pts_PB));
00063  Max_Grid_Indx = 1 + Grid_Density*(Num_PB_Freqs+Num_SB_Freqs-1);
00064  Error = new double[Max_Grid_Indx+1];
00065 
00066  //----------------------------------------------
00067  //  make initial guess of extremal frequencies           
00068 
00069  for(j=0; j<Num_PB_Freqs; j++) Ext_Freq[j] = (j+1)* grid_density;
00070 
00071  for(j=0; j<Num_SB_Freqs; j++) Ext_Freq[j+Num_PB_Freqs] = 
00072                                Num_Grid_Pts_PB + 1 + j * grid_density;
00073 
00074  //----------------------------------------------------
00075  //  find optimal locations for extremal frequencies 
00076 
00077  for(m=1;m<=20;m++) 
00078    {
00079     RemezError();
00080 
00081     RemezSearch();
00082   
00083     RemezStop2();
00084     if(RemezStop()) break;
00085     #ifdef _DEBUG
00086     DebugFile << "done iteration " << m << std::endl;
00087     #endif
00088   }
00089    
00090  for(j=0; j<=Num_Approx_Funcs; j++)
00091    {
00092     extremal_freqs[j] = GetFrequency(Ext_Freq[j]);
00093     #ifdef _DEBUG
00094     DebugFile << "extremal_freqs[ " << j << " ] = "
00095               << extremal_freqs[j] << std::endl;
00096     #endif
00097    }
00098 
00099  RemezFinish( filter_coeffs);
00100 
00101  *fir_filter = new FirFilterDesign( filter_length, 
00102                                     FIR_SYM_EVEN_LEFT, 
00103                                     filter_coeffs);
00104  return;
00105 };
00106 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++
00107 
00108 
00109 void RemezAlgorithm::RemezFinish( double *filter_coeffs )
00110 {
00111  int k;
00112  double freq, *aa;
00113   FreqSampFilterSpec *filter_spec;
00114   FreqSampFilterDesign *filter_design; 
00115  
00116  aa = new double[Num_Approx_Funcs];
00117  
00118  for( k=0; k<Num_Approx_Funcs; k++)
00119    {
00120     freq = (double) k/ (double) Filter_Length;
00121     aa[k] = ComputeRemezAmplitudeResponse (0, freq);
00122    }
00123  filter_spec = new FreqSampFilterSpec( 1, 1, Filter_Length, aa); 
00124  filter_design = new FreqSampFilterDesign( *filter_spec);
00125  filter_design->ComputeCoefficients( filter_spec);
00126  filter_design->CopyCoefficients( filter_coeffs);
00127  
00128  
00129  for(k=0; k<Filter_Length; k++)
00130    {
00131     #ifdef _DEBUG
00132     DebugFile << "Coeff[ " << k << " ] = "
00133               << filter_coeffs[k] << std::endl;
00134     #endif
00135    }
00136 }
00137     
00138 
00139 
00140 //======================================================
00141 //
00142 //------------------------------------------------------
00143 
00144 void RemezAlgorithm::SetupGrid( void )
00145 {
00146  double work;
00147  work = (0.5 + PB_Edge_Freq - SB_Edge_Freq)/Num_Approx_Funcs;
00148  
00149  Num_PB_Freqs = (int)floor(0.5 + PB_Edge_Freq/work);
00150   
00151  Num_Grid_Pts_PB = Num_PB_Freqs * Grid_Density;
00152 
00153  Num_SB_Freqs = Num_Approx_Funcs + 1 - Num_PB_Freqs;
00154 
00155  PB_Increment = PB_Edge_Freq / Num_Grid_Pts_PB;
00156  
00157  SB_Increment = ( 0.5 - SB_Edge_Freq )/((Num_SB_Freqs-1) * Grid_Density);
00158  return;
00159 } 
00160 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00161 
00162 double RemezAlgorithm::GetFrequency( int grid_index)
00163 { 
00164  if( grid_index <= Num_Grid_Pts_PB )
00165    {
00166     // compute freq in passband
00167     
00168     return( grid_index * PB_Increment );
00169    }
00170  else
00171    {
00172     // compute freq in stopband
00173     
00174     return( SB_Edge_Freq + 
00175           ( grid_index - (Num_Grid_Pts_PB+1))*SB_Increment);
00176    }   
00177 } 
00178 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
00179 
00180 void RemezAlgorithm::RemezError( void)
00181 {
00182  int j;
00183  double freq;
00184  double ampl_resp;
00185  
00186  ampl_resp = ComputeRemezAmplitudeResponse( 1, 0.0);
00187  
00188  for( j=0; j<= Max_Grid_Indx; j++)
00189    {
00190     freq = GetFrequency(j);
00191     
00192     ampl_resp = ComputeRemezAmplitudeResponse( 0, freq);
00193     
00194     Error[j] = WeightFunction(freq) * (DesiredResponse(freq) - ampl_resp);
00195    } 
00196  return;
00197 }
00198 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00199 
00200 double RemezAlgorithm::ComputeRemezAmplitudeResponse( 
00201                                                int init_flag,
00202                                                double contin_freq)
00203 {
00204  static int i, j, k, sign;
00205  static double freq, denom, numer, alpha, delta;
00206  static double absDelta, xCont, term;
00207  double aa;
00208 
00209  if(init_flag)
00210    {
00211     X_ = new double[Num_Approx_Funcs+1];
00212     Beta_ = new double[Num_Approx_Funcs+1];
00213     Gamma_ = new double[Num_Approx_Funcs+1];
00214     for(j=0; j<=Num_Approx_Funcs; j++)
00215       {
00216        freq = GetFrequency(Ext_Freq[j]);
00217        X_[j] = cos(TWO_PI * freq);
00218       }
00219   
00220     //  compute delta
00221     denom = 0.0;
00222     numer = 0.0;
00223     sign = -1;
00224     for( k=0; k<=Num_Approx_Funcs; k++)
00225       {
00226        sign = -sign;
00227        alpha = 1.0;
00228        for( i=0; i<=(Num_Approx_Funcs-1); i++)
00229          {
00230           if(i==k) continue;
00231             alpha = alpha / (X_[k] - X_[i]);
00232          }
00233        Beta_[k] = alpha;
00234        if( k != Num_Approx_Funcs ) 
00235                          alpha = alpha/(X_[k] - X_[Num_Approx_Funcs]);
00236        freq =  GetFrequency(Ext_Freq[k]);
00237        numer = numer + alpha * DesiredResponse(freq);
00238                  
00239        denom = denom + sign*(alpha/WeightFunction(freq));
00240       } // end of loop over k
00241     
00242     delta = numer/denom;
00243     absDelta = fabs(delta);
00244   
00245     sign = -1;
00246     for( k=0; k<=Num_Approx_Funcs-1; k++)
00247       {
00248        sign = -sign;
00249        freq = GetFrequency(Ext_Freq[k]);
00250        Gamma_[k] = DesiredResponse(freq) - sign * delta / 
00251             WeightFunction(freq);
00252       }
00253    } // end of if(init_flag)
00254  else
00255    {
00256     xCont = cos(TWO_PI * contin_freq);
00257     numer = 0.0;
00258     denom = 0.0;
00259     for( k=0; k<Num_Approx_Funcs; k++)
00260       {
00261        term = xCont - X_[k];
00262        if(fabs(term)<1.0e-7)
00263          {
00264           aa = Gamma_[k];
00265           goto done;
00266          }
00267        else
00268          {
00269           term = Beta_[k]/(xCont - X_[k]);
00270           denom += term;
00271           numer += Gamma_[k]*term;
00272          }
00273       }
00274     aa = numer/denom;
00275    }
00276  done:
00277  return(aa); 
00278 }
00279 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00280 
00281 void RemezAlgorithm::RemezSearch(void)
00282 {
00283  int i,j,k,extras,indexOfSmallest;
00284  double minVal;
00285 
00286  k=0;
00287 
00288  /* test for extremum at f=0  */
00289  if( ( (Error[0]>0.0) && 
00290        (Error[0]>Error[1]) && 
00291        (fabs(Error[0])>=Abs_Delta) ) ||
00292      ( (Error[0]<0.0) && 
00293        (Error[0]<Error[1]) && 
00294        (fabs(Error[0])>=Abs_Delta) ) )
00295    { 
00296     Ext_Freq[k]=0;
00297     k++;
00298    }
00299 
00300  /*  search for extrema in passband  */
00301  for(j=1; j<Num_Grid_Pts_PB; j++)
00302    {
00303     if( ( (Error[j]>=Error[j-1]) && 
00304           (Error[j]>Error[j+1]) && 
00305           (Error[j]>0.0) ) ||
00306         ( (Error[j]<=Error[j-1]) && 
00307           (Error[j]<Error[j+1]) && (Error[j]<0.0) ))
00308       {
00309        Ext_Freq[k] = j;
00310        k++;
00311       }
00312    }
00313 
00314  /* pick up an extremal frequency at passband edge  */
00315  Ext_Freq[k]=Num_Grid_Pts_PB;
00316  k++;
00317 
00318  /* pick up an extremal frequency at stopband edge  */
00319  j=Num_Grid_Pts_PB+1;
00320  Ext_Freq[k]=j;
00321  k++;
00322 
00323  /*  search for extrema in stopband  */
00324      
00325  for(j=Num_Grid_Pts_PB+2; j<Max_Grid_Indx; j++)
00326    {
00327     if( ( (Error[j]>=Error[j-1]) && 
00328           (Error[j]>Error[j+1]) && 
00329           (Error[j]>0.0) ) ||
00330         ( (Error[j]<=Error[j-1]) && 
00331           (Error[j]<Error[j+1]) && 
00332           (Error[j]<0.0) ))
00333       {
00334        Ext_Freq[k] = j;
00335        k++;
00336       }
00337    }
00338  /* test for extremum at f=0.5  */
00339  j = Max_Grid_Indx;
00340  if( ( (Error[j]>0.0) && 
00341        (Error[j]>Error[j-1]) && 
00342        (fabs(Error[j])>=Abs_Delta) ) ||
00343      ( (Error[j]<0.0) && 
00344        (Error[j]<Error[j-1]) && 
00345        (fabs(Error[j])>=Abs_Delta) ) )
00346    { 
00347     Ext_Freq[k]=Max_Grid_Indx;
00348     k++;
00349    }
00350  /*----------------------------------------------------*/
00351  /*  find and remove superfluous extremal frequencies  */
00352  if( k>Num_Approx_Funcs+1)
00353    {
00354     extras = k - (Num_Approx_Funcs+1);
00355     for(i=1; i<=extras; i++)
00356       {
00357        minVal = fabs(Error[Ext_Freq[0]]);
00358        indexOfSmallest = 0;
00359        for(j=1; j< k; j++)
00360          {
00361           if(fabs(Error[Ext_Freq[j]]) >= minVal) continue;
00362             minVal = fabs(Error[Ext_Freq[j]]);
00363             indexOfSmallest = j;
00364          }
00365        k--;
00366        for(j=indexOfSmallest; j<k; j++) Ext_Freq[j] = Ext_Freq[j+1];
00367       }
00368    }
00369  return;
00370 } 
00371 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00372 
00373 int RemezAlgorithm::RemezStop2()
00374 {
00375  double maxVal, minVal, qq;
00376  int j, result;
00377 
00378  result = 0;
00379  maxVal = fabs(Error[Ext_Freq[0]]);
00380  minVal = fabs(Error[Ext_Freq[0]]);
00381 
00382  for( j=1; j<= Num_Approx_Funcs; j++)
00383    {
00384     if(fabs(Error[Ext_Freq[j]]) < minVal) minVal = fabs(Error[Ext_Freq[j]]);
00385     if(fabs(Error[Ext_Freq[j]]) > maxVal) maxVal = fabs(Error[Ext_Freq[j]]);
00386    }                                                                
00387  qq = (maxVal - minVal)/maxVal;
00388  if(qq<0.01) result = 1;
00389  return(result);
00390 }
00391 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00392 
00393 int RemezAlgorithm::RemezStop( void)
00394 {
00395  //static int Old_Ext_Freq[50];
00396  int j, result;
00397  
00398  result = 1;
00399  
00400  for(j=0; j<=Num_Approx_Funcs; j++)
00401    {
00402     if(Ext_Freq[j] != Old_Ext_Freq[j]) result = 0;
00403     Old_Ext_Freq[j] = Ext_Freq[j];
00404    }
00405  return(result);
00406 }   
00407 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00408 
00409 double RemezAlgorithm::WeightFunction(double freq)
00410 {
00411  double result;
00412  
00413  result = 1.0;
00414  if(freq <= PB_Edge_Freq) result = 1.0/Ripple_Ratio;
00415  return(result);
00416 }
00417 
00418 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00419 
00420 double RemezAlgorithm::DesiredResponse(double freq)
00421 {
00422  double result;
00423  
00424  result = 0.0;
00425  if(freq <= PB_Edge_Freq) result = 1.0;
00426  return(result);
00427 }
00428 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines