remezalg.cpp

来自「Digital filter designer s handbook C++ c」· C++ 代码 · 共 402 行

CPP
402
字号
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//  File = remezalg.cpp
//
//  Remez algorithm for design of FIR filters
//

#include <math.h>
#include <stdlib.h>
#include "fs_dsgn.h"
#include "fs_spec.h"
#include "remezalg.h"
extern ofstream DebugFile;


//======================================================
//  constructor
//------------------------------------------------------

RemezAlgorithm::RemezAlgorithm( int filter_length,
                                int grid_density,
                                double ripple_ratio,
                                double passband_edge_freq,
                                double stopband_edge_freq,
                                double *extremal_freqs,
                                double *filter_coeffs)
{
 int m, j;
 
 //--------------------------------
 //  set up frequency grid

 Filter_Length = filter_length;
 PB_Edge_Freq = passband_edge_freq;
 SB_Edge_Freq = stopband_edge_freq;
 Num_Approx_Funcs = (filter_length + 1)/2;
 Grid_Density = grid_density;
 Ripple_Ratio = ripple_ratio;
 
 SetupGrid();
 
 PB_Edge_Freq = PB_Edge_Freq + (PB_Edge_Freq/(2.0*Num_Grid_Pts_PB));
 Max_Grid_Indx = 1 + Grid_Density*(Num_PB_Freqs+Num_SB_Freqs-1);

 //----------------------------------------------
 //  make initial guess of extremal frequencies           

 for(j=0; j<Num_PB_Freqs; j++) Ext_Freq[j] = (j+1)* grid_density;

 for(j=0; j<Num_SB_Freqs; j++) Ext_Freq[j+Num_PB_Freqs] = 
                               Num_Grid_Pts_PB + 1 + j * grid_density;

 //----------------------------------------------------
 //  find optimal locations for extremal frequencies 

 for(m=1;m<=20;m++) 
   {
    RemezError();

    RemezSearch();
  
    RemezStop2();
    if(RemezStop()) break;
    DebugFile << "done iteration " << m << endl;
  }
   
 for(j=0; j<=Num_Approx_Funcs; j++)
   {
    extremal_freqs[j] = GetFrequency(Ext_Freq[j]);
    DebugFile << "extremal_freqs[ " << j << " ] = "
              << extremal_freqs[j] << endl;
   }

 RemezFinish( filter_coeffs);

 return;
};
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++


void RemezAlgorithm::RemezFinish( double *filter_coeffs )
{
 int k;
 double freq, *aa;
  FreqSampFilterSpec *filter_spec;
  FreqSampFilterDesign *filter_design;
  FreqSampFilterResponse *filter_response;
  
 
 aa = new double[Num_Approx_Funcs];
 
 for( k=0; k<Num_Approx_Funcs; k++)
   {
    freq = (double) k/ (double) Filter_Length;
    aa[k] = ComputeRemezAmplitudeResponse (0, freq);
   }
 filter_spec = new FreqSampFilterSpec( 1, 1, Filter_Length, aa); 
 //status = fsDesign( Filter_Length, 1, aa, filter_coeffs);
 filter_design = new FreqSampFilterDesign( *filter_spec);
 filter_design->ComputeCoefficients( filter_spec);
 filter_design->CopyCoefficients( filter_coeffs);
 //cout << "got into RemezFinish" << endl;
 //exit(86);
 
 
 for(k=0; k<Filter_Length; k++)
   {
    DebugFile << "Coeff[ " << k << " ] = "
              << filter_coeffs[k] << endl;
   }
}
    


//======================================================
//
//------------------------------------------------------

void RemezAlgorithm::SetupGrid( void )
{
 double work;
 work = (0.5 + PB_Edge_Freq - SB_Edge_Freq)/Num_Approx_Funcs;
 
 Num_PB_Freqs = (int)floor(0.5 + PB_Edge_Freq/work);
  
 Num_Grid_Pts_PB = Num_PB_Freqs * Grid_Density;

 Num_SB_Freqs = Num_Approx_Funcs + 1 - Num_PB_Freqs;

 PB_Increment = PB_Edge_Freq / Num_Grid_Pts_PB;
 
 SB_Increment = ( 0.5 - SB_Edge_Freq )/((Num_SB_Freqs-1) * Grid_Density);
 return;
} 
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

double RemezAlgorithm::GetFrequency( int grid_index)
{ 
 if( grid_index <= Num_Grid_Pts_PB )
   {
    // compute freq in passband
    
    return( grid_index * PB_Increment );
   }
 else
   {
    // compute freq in stopband
    
    return( SB_Edge_Freq + 
          ( grid_index - (Num_Grid_Pts_PB+1))*SB_Increment);
   }   
} 
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

void RemezAlgorithm::RemezError( void)
{
 int j;
 double freq;
 double ampl_resp;
 
 ampl_resp = ComputeRemezAmplitudeResponse( 1, 0.0);
 
 for( j=0; j<= Max_Grid_Indx; j++)
   {
    freq = GetFrequency(j);
    
    ampl_resp = ComputeRemezAmplitudeResponse( 0, freq);
    
    Error[j] = WeightFunction(freq) * (DesiredResponse(freq) - ampl_resp);
   } 
 return;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

double RemezAlgorithm::ComputeRemezAmplitudeResponse( 
                                               int init_flag,
                                               double contin_freq)
{
 static int i, j, k, sign;
 static double freq, denom, numer, alpha, delta;
 static double absDelta, xCont, term;
 static double x[50], beta[50], gamma[50];
 double aa;

 if(init_flag)
   {
    for(j=0; j<=Num_Approx_Funcs; j++)
      {
       freq = GetFrequency(Ext_Freq[j]);
       x[j] = cos(TWO_PI * freq);
      }
  
    //  compute delta
    denom = 0.0;
    numer = 0.0;
    sign = -1;
    for( k=0; k<=Num_Approx_Funcs; k++)
      {
       sign = -sign;
       alpha = 1.0;
       for( i=0; i<=(Num_Approx_Funcs-1); i++)
         {
          if(i==k) continue;
            alpha = alpha / (x[k] - x[i]);
         }
       beta[k] = alpha;
       if( k != Num_Approx_Funcs ) 
                         alpha = alpha/(x[k] - x[Num_Approx_Funcs]);
       freq =  GetFrequency(Ext_Freq[k]);
       numer = numer + alpha * DesiredResponse(freq);
                 
       denom = denom + sign*(alpha/WeightFunction(freq));
      } // end of loop over k
    
    delta = numer/denom;
    absDelta = fabs(delta);
  
    sign = -1;
    for( k=0; k<=Num_Approx_Funcs-1; k++)
      {
       sign = -sign;
       freq = GetFrequency(Ext_Freq[k]);
       gamma[k] = DesiredResponse(freq) - sign * delta / 
            WeightFunction(freq);
      }
   } // end of if(init_flag)
 else
   {
    xCont = cos(TWO_PI * contin_freq);
    numer = 0.0;
    denom = 0.0;
    for( k=0; k<Num_Approx_Funcs; k++)
      {
       term = xCont - x[k];
       if(fabs(term)<1.0e-7)
         {
          aa = gamma[k];
          goto done;
         }
       else
         {
          term = beta[k]/(xCont - x[k]);
          denom += term;
          numer += gamma[k]*term;
         }
      }
    aa = numer/denom;
   }
 done:
 return(aa); 
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

void RemezAlgorithm::RemezSearch(void)
{
 int i,j,k,extras,indexOfSmallest;
 double minVal;

 k=0;

 /* test for extremum at f=0  */
 if( ( (Error[0]>0.0) && 
       (Error[0]>Error[1]) && 
       (fabs(Error[0])>=Abs_Delta) ) ||
     ( (Error[0]<0.0) && 
       (Error[0]<Error[1]) && 
       (fabs(Error[0])>=Abs_Delta) ) )
   { 
    Ext_Freq[k]=0;
    k++;
   }

 /*  search for extrema in passband  */
 for(j=1; j<Num_Grid_Pts_PB; j++)
   {
    if( ( (Error[j]>=Error[j-1]) && 
          (Error[j]>Error[j+1]) && 
          (Error[j]>0.0) ) ||
        ( (Error[j]<=Error[j-1]) && 
          (Error[j]<Error[j+1]) && (Error[j]<0.0) ))
      {
       Ext_Freq[k] = j;
       k++;
      }
   }

 /* pick up an extremal frequency at passband edge  */
 Ext_Freq[k]=Num_Grid_Pts_PB;
 k++;

 /* pick up an extremal frequency at stopband edge  */
 j=Num_Grid_Pts_PB+1;
 Ext_Freq[k]=j;
 k++;

 /*  search for extrema in stopband  */
     
 for(j=Num_Grid_Pts_PB+2; j<Max_Grid_Indx; j++)
   {
    if( ( (Error[j]>=Error[j-1]) && 
          (Error[j]>Error[j+1]) && 
          (Error[j]>0.0) ) ||
        ( (Error[j]<=Error[j-1]) && 
          (Error[j]<Error[j+1]) && 
          (Error[j]<0.0) ))
      {
       Ext_Freq[k] = j;
       k++;
      }
   }
 /* test for extremum at f=0.5  */
 j = Max_Grid_Indx;
 if( ( (Error[j]>0.0) && 
       (Error[j]>Error[j-1]) && 
       (fabs(Error[j])>=Abs_Delta) ) ||
     ( (Error[j]<0.0) && 
       (Error[j]<Error[j-1]) && 
       (fabs(Error[j])>=Abs_Delta) ) )
   { 
    Ext_Freq[k]=Max_Grid_Indx;
    k++;
   }
 /*----------------------------------------------------*/
 /*  find and remove superfluous extremal frequencies  */
 if( k>Num_Approx_Funcs+1)
   {
    extras = k - (Num_Approx_Funcs+1);
    for(i=1; i<=extras; i++)
      {
       minVal = fabs(Error[Ext_Freq[0]]);
       indexOfSmallest = 0;
       for(j=1; j< k; j++)
         {
          if(fabs(Error[Ext_Freq[j]]) >= minVal) continue;
            minVal = fabs(Error[Ext_Freq[j]]);
            indexOfSmallest = j;
         }
       k--;
       for(j=indexOfSmallest; j<k; j++) Ext_Freq[j] = Ext_Freq[j+1];
      }
   }
 return;
} 
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

int RemezAlgorithm::RemezStop2()
{
 double maxVal, minVal, qq;
 int j, result;

 result = 0;
 maxVal = fabs(Error[Ext_Freq[0]]);
 minVal = fabs(Error[Ext_Freq[0]]);

 for( j=1; j<= Num_Approx_Funcs; j++)
   {
    if(fabs(Error[Ext_Freq[j]]) < minVal) minVal = fabs(Error[Ext_Freq[j]]);
    if(fabs(Error[Ext_Freq[j]]) > maxVal) maxVal = fabs(Error[Ext_Freq[j]]);
   }                                                                
 qq = (maxVal - minVal)/maxVal;
 if(qq<0.01) result = 1;
 return(result);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

int RemezAlgorithm::RemezStop( void)
{
 static int Old_Ext_Freq[50];
 int j, result;
 
 result = 1;
 
 for(j=0; j<=Num_Approx_Funcs; j++)
   {
    if(Ext_Freq[j] != Old_Ext_Freq[j]) result = 0;
    Old_Ext_Freq[j] = Ext_Freq[j];
   }
 return(result);
}   
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

double RemezAlgorithm::WeightFunction(double freq)
{
 double result;
 
 result = 1.0;
 if(freq <= PB_Edge_Freq) result = 1.0/Ripple_Ratio;
 return(result);
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

double RemezAlgorithm::DesiredResponse(double freq)
{
 double result;
 
 result = 0.0;
 if(freq <= PB_Edge_Freq) result = 1.0;
 return(result);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?