You are here: Symbol Reference > Dew Namespace > Dew.Signal Namespace > Dew.Signal.Units Namespace > Classes > OptimalFir Class > OptimalFir Methods > OptimalFir.remez Method
Dew Signal for .NET
ContentsIndexHome
PreviousUpNext
OptimalFir.remez Method

Design an optimal equiripple FIR filter with Parks-McClellan algorithm.

Syntax
C#
Visual Basic
public static int remez([In] TVec h, [In] double[] bands, [In] double[] gains, [In] double[] Weights, TRemezType FilterType, out double err, double FS, bool ConstantRipple);
Parameters 
Description 
[In] TVec h 
An array of length h.Length on entry and contains the filter impulse response on exit. 
[In] double[] bands 
Defines the frequency bands.  
[In] double[] gains 
Defines, if the band is a stopband or a passband. 
[In] double[] Weights 
Array contains the ratios between required ripples for different bands. 
TRemezType FilterType 
Choose between bandpass, hilbert, differentator and integrator. 
out double err 
Contains the maximum ripple error upon return. 
double FS 
Specifies the sampling frequency. 
bool ConstantRipple 
If True, the ripple will be constant and not weighted to give constant percentage error in case of the following filter types: rmtDifferentiator, rmtIntegrator, rmtDoubleDifferentiator, rmtDoubleIntegrator  

Designs an equiripple (optimal) FIR filter. The routine will not always converge. Parameters have to be specified, for which the filter exists. Most common causes for trouble are:

  • too wide transition bands
  • transition bands not of equal width.
  • too strong attenuation (of the stopband) or to small ripple (of the passband) specified.
  • wrong filter length (odd/even).

 

The length of the filter can be estimated with the RemezLength routine. RemezLength routine will also properly adjust the error weights. An extensive explanation of the algorithm can be found in [1] Ch. 7.6, p. 462.  

A few need to know things about FIR filters:

  • The length of the filter is defined as: n = Order-1. (Order is the order of the polynomial and n is the number of coefficients.)
  • highpass or a bandstop filter or any filter with the passband at FS/2 has to have odd length (even order). RemezLength routine automatically adjusts filter length.
  • a filter with negative symmetry also shifts the phase by 90 degrees. The routine automatically assumes negative symmetry, if the FilterType is different from rmtBandpass.
  • Required stopband attenuation is usually specified in dB. To obtain the required ripple, the following formula can be used: Ripple = Exp10(Att/-20);
  • Passband ripple can also be specified in dB. To obtain the required linear ripple, the following formula can be used: Ripple = (1-Exp10(PassRippldB/-20))/2
  • The passband ripple "rp" specified for the passband is a +/-rp specification. Total ripple is 2*rp.
  • the amount of ripple is a function of filter length. (longer filters give less ripple).
  • if different bands have different required ripple, this can be addressed by adjusting the error weights array.

The Fortran source code can be found in [2] p. 198. 

 

References:  

 

 

 

KaiserImpulse, SavGolayImpulse, RemezImpulse, RemezLength

A sample lowpass filter design with sampling frequency 8000Hz, transition band between at 1500Hz and 2000Hz with 60 dB attenuation (20 * Log10(0.001)) and 0.001 ripple in the passband. To try out other setups comment out the lowpass and comment in the desired filter. 

 

using Dew.Math; using Dew.Math.Editors; using Dew.Math.Units; using Dew.Signal; using Dew.Signal.Units; using Dew.Math.Tee; using Dew.Signal.Tee; private void button1_Click(object sender, EventArgs e) { Vector z = new Vector(0); Vector Response = new Vector(0); Vector Weights = new Vector(0); int n; double err; double FS = 2; //Sampling frequency //Design a lowpass n = OptimalFir.RemezLength(new double[4] {0, 1500, 2000, 4000}, new double[2] {1, 0}, new double[2] {0.001, 0.001} ,Weights, 8000); z.Size(n); OptimalFir.remez( z, new double[4] { 0, 1500, 2000, 4000 }, new double[2] { 1, 0 }, (double []) Weights, TRemezType.rmtBandPass, out err, 8000, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Lowpass", false); //Design a highpass n = OptimalFir.RemezLength(new double[4] { 0, 1500, 2000, 4000 }, new double[2] { 0, 1 }, new double[2] { 0.001, 0.001 }, Weights, 8000); z.Size(n); OptimalFir.remez(z, new double[4] { 0, 1500, 2000, 4000 }, new double[2] { 0, 1 }, (double[])Weights, TRemezType.rmtBandPass, out err, 8000, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Highpass", false); //Design a bandpass (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] {0, 0.15, 0.25, 0.45, 0.55, 1}, new double[3] {0, 1, 0},new double[3] {0.001, 0.001, 0.001},Weights,FS); z.Size(n); OptimalFir.remez(z,new double[6] {0, 0.15, 0.25, 0.45, 0.55, 1}, new double[3] {0, 1, 0}, (double []) Weights, TRemezType.rmtBandPass, out err, FS, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Bandpass", false); //Design a bandstop (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] { 0, 0.15, 0.25, 0.45, 0.55, 1 }, new double[3] { 1, 0, 1 }, new double[3] { 0.001, 0.001, 0.001 }, Weights,FS) ; z.Size(n); OptimalFir.remez(z, new double[6] { 0, 0.15, 0.25, 0.45, 0.55, 1 }, new double[3] { 1, 0, 1 }, (double[]) Weights, TRemezType.rmtBandPass, out err, FS, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Bandstop", false); //Design a multiband (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[10] {0.00, 0.10, 0.20, 0.30, 0.40, 0.45, 0.55, 0.60, 0.70, 1.00}, new double[5] { 1, 0, 1, 0, 1 }, new double[5] { 0.001, 0.001, 0.001, 0.001, 0.001 }, Weights, FS); z.Size(n); OptimalFir.remez(z, new double[10] {0.00, 0.10, 0.20, 0.30, 0.40,0.45, 0.55, 0.60, 0.70, 1.00}, new double[5] { 1, 0, 1, 0, 1 }, (double[]) Weights, TRemezType.rmtBandPass, out err, FS, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Multibandpass", false); // Design a hilbert (type III) transformer (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] {0, 0, 0.1, 0.9, 1, 1}, new double[3] {0,1,0},new double[3] {0.01,0.01,0.01},Weights,FS); if (n % 2 == 0) n++; //odd length type III filter z.Size(n); OptimalFir.remez(z,new double[2] {0.1, 0.9}, new double[1] {1}, new double[1] {1}, TRemezType.rmtHilbert,out err, FS, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Hilbert III", false); //Design a hilbert (type IV) transformer (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] {0, 0, 0.1, 0.9, 1, 1}, new double[3] {0,1,0},new double[3] {0.01,0.01,0.01},Weights,FS); if (n % 2 != 0) n++; //even length type IV filter z.Size(n); OptimalFir.remez(z, new double[2] {0.1, 1}, new double[1] {1},new double[1] {1}, TRemezType.rmtHilbert,out err, 2, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Hilbert IV", false); //Design a differentiator (type III) (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] {0, 0, 0.1, 0.9, 1, 1}, new double[3] {0,1,0}, new double[3] {0.01,0.01,0.01},Weights,FS); if (n % 2 == 0) n++; //odd length type III filter z.Size(n); OptimalFir.remez(z,new double[2] {0.1, 0.9}, new double[1] {1},new double[1] {1}, TRemezType.rmtDifferentiator,out err, 2, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Differentiator III", false); //Design a differentiator (type IV) (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] {0, 0, 0.1, 0.9, 1, 1}, new double[3] {0,1,0},new double[3] {0.01,0.01,0.01},Weights, FS); if (n % 2 != 0) n++; //even length type IV filter z.Size(n); OptimalFir.remez(z,new double[2] {0.1, 1}, new double[1] {1},new double[1] {1}, TRemezType.rmtDifferentiator,out err, FS, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Differentiator IV", false); //Design a double differentiator (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] {0, 0, 0.05, 0.95, 1, 1}, new double[3] {0,1,0},new double[3] {0.01,0.01,0.01},Weights, FS); if (n %2 != 0) n++; //even length type IV filter z.Size(n); OptimalFir.remez(z,new double[2] {0.05, 1}, new double[1] {1},new double[1] {1}, TRemezType.rmtDoubleDifferentiator,out err, FS, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Double differentiator IV", false); //Design an integrator (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] {0, 0, 0.05, 0.95, 1, 1}, new double[3] {0,1,0},new double[3] {0.01,0.01,0.01}, Weights, FS); if (n %2 != 0) n++; //even length type IV filter z.Size(n); OptimalFir.remez(z,new double[2] {0.05, 1}, new double[1] {1},new double[1] {1}, TRemezType.rmtIntegrator,out err, FS, false); SignalUtils.FrequencyResponse(z, null, Response, 8, false, TSignalWindowType.wtRectangular, 0); MtxVecTee.DrawIt(Response, "Integrator IV", false); //Design a double integrator (Sampling frequency = 2) n = OptimalFir.RemezLength(new double[6] {0, 0, 0.05, 0.95, 1, 1}, new double[3] {0,1,0}, new double[3] {0.01,0.01,0.01},Weights,FS); if (n %2 != 0) n++; //even length type IV filter z.Size(n); OptimalFir.remez(z,new double[2] {0.05, 1}, new double[1] {1}, new double[1] {1}, TRemezType.rmtDoubleIntegrator,out err, FS, false); SignalUtils.FrequencyResponse(z,null,Response,8,false,TSignalWindowType.wtRectangular,0); MtxVecTee.DrawIt(Response,"Double integrator IV",false); }
Copyright (c) 1999-2024 by Dew Research. All rights reserved.
What do you think about this topic? Send feedback!