78 using namespace RTPROCESSINGLIB;
79 using namespace Eigen;
85 #define BIG 4096 // Used to define array sizes. Must be somewhat larger than 8 * MaxNumTaps
87 #define M_2PI 6.28318530717958647692
88 #define ITRMAX 50 // Max Number of Iterations. Some filters require as many as 45 iterations.
89 #define MIN_TEST_VAL 1.0E-6 // Min value used in LeGrangeInterp and GEE
95 ParksMcClellan::ParksMcClellan()
97 , ExchangeIndex(SMALL)
115 ParksMcClellan::ParksMcClellan(
int NumTaps,
double OmegaC,
double BW,
double ParksWidth, TPassType PassType)
117 , ExchangeIndex(SMALL)
131 FirCoeff = RowVectorXd::Zero(NumTaps);
132 init(NumTaps, OmegaC, BW, ParksWidth, PassType);
137 ParksMcClellan::~ParksMcClellan()
143 void ParksMcClellan::init(
int NumTaps,
double OmegaC,
double BW,
double ParksWidth, TPassType PassType)
147 if(NumTaps > 256) NumTaps = 256;
148 if(NumTaps < 9) NumTaps = 9;
149 if( (PassType == HPF || PassType == NOTCH) && NumTaps % 2 == 0) NumTaps--;
158 if(Edge[2] < 0.01)Edge[2] = 0.01;
159 if(Edge[2] > 0.98)Edge[2] = 0.98;
160 Edge[3] = Edge[2] + ParksWidth;
161 if(Edge[3] > 0.99)Edge[3] = 0.99;
167 InitWeight[2] = 10.0;
175 if(Edge[3] > 0.99)Edge[3] = 0.99;
176 if(Edge[3] < 0.02)Edge[3] = 0.02;
177 Edge[2] = Edge[3] - ParksWidth;
178 if(Edge[2] < 0.01)Edge[2] = 0.01;
183 InitWeight[1] = 10.0;
191 Edge[3] = OmegaC - BW/2.0;
192 if(Edge[3] < 0.02)Edge[3] = 0.02;
193 Edge[2] = Edge[3] - ParksWidth;
194 if(Edge[2] < 0.01)Edge[2] = 0.01;
195 Edge[4] = OmegaC + BW/2.0;
196 if(Edge[4] > 0.98)Edge[4] = 0.98;
197 Edge[5] = Edge[4] + ParksWidth;
198 if(Edge[5] > 0.99)Edge[5] = 0.99;
204 InitWeight[1] = 10.0;
206 InitWeight[3] = 10.0;
209 if(PassType == NOTCH)
213 Edge[3] = OmegaC - BW/2.0;
214 if(Edge[3] < 0.02)Edge[3] = 0.02;
215 Edge[2] = Edge[3] - ParksWidth;
216 if(Edge[2] < 0.01)Edge[2] = 0.01;
217 Edge[4] = OmegaC + BW/2.0;
218 if(Edge[4] > 0.98)Edge[4] = 0.98;
219 Edge[5] = Edge[4] + ParksWidth;
220 if(Edge[5] > 0.99)Edge[5] = 0.99;
227 InitWeight[2] = 10.0;
232 for(j=1; j<=2*NumBands; j++) Edge[j] /= 2.0;
234 CalcParkCoeff2(NumBands, NumTaps);
239 void ParksMcClellan::CalcParkCoeff2(
int NumBands,
int TapCount)
241 int j,
k, GridCount, GridIndex, BandIndex, NumIterations;
242 double LowFreqEdge, UpperFreq, TempVar, Change;
246 if(TapCount % 2)OddNumTaps =
true;
247 else OddNumTaps =
false;
249 HalfTapCount = TapCount/2;
250 if(OddNumTaps) HalfTapCount++;
253 LowFreqEdge = GridCount * HalfTapCount;
254 LowFreqEdge = 0.5 / LowFreqEdge;
258 while(BandIndex <= NumBands)
260 UpperFreq = Edge[
k+1];
261 while(Grid[j] <= UpperFreq)
264 DesiredMag[j] = BandMag[BandIndex];
265 Weight[j] = InitWeight[BandIndex];
267 Grid[j] = TempVar + LowFreqEdge;
270 Grid[j-1] = UpperFreq;
271 DesiredMag[j-1] = BandMag[BandIndex];
272 Weight[j-1] = InitWeight[BandIndex];
275 if(BandIndex <= NumBands)Grid[j] = Edge[
k];
279 if(!OddNumTaps && Grid[GridIndex] > (0.5-LowFreqEdge)) GridIndex--;
283 for(j=1; j<=GridIndex; j++)
285 Change = cos(M_PI * Grid[j] );
286 DesiredMag[j] = DesiredMag[j] / Change;
287 Weight[j] = Weight[j] * Change;
291 TempVar = (double)(GridIndex-1)/(double)HalfTapCount;
292 for(j=1; j<=HalfTapCount; j++)
294 ExchangeIndex[j] = (double)(j-1) * TempVar + 1.0;
296 ExchangeIndex[HalfTapCount+1] = GridIndex;
298 NumIterations = Remez2(GridIndex);
304 for(j=1; j<=HalfTapCount-1; j++)
306 Coeff[j] = 0.5 * Alpha[HalfTapCount+1-j];
308 Coeff[HalfTapCount] = Alpha[1];
312 Coeff[1] = 0.25 * Alpha[HalfTapCount];
313 for(j=2; j<=HalfTapCount-1; j++)
315 Coeff[j] = 0.25 * (Alpha[HalfTapCount+1-j] + Alpha[HalfTapCount+2-j]);
317 Coeff[HalfTapCount] = 0.5 * Alpha[1] + 0.25 * Alpha[2];
321 for(j=1; j<=HalfTapCount; j++) FirCoeff[j-1] = Coeff[j];
323 for(j=1; j<HalfTapCount; j++) FirCoeff[HalfTapCount+j-1] = Coeff[HalfTapCount-j];
325 for(j=1; j<=HalfTapCount; j++ )FirCoeff[HalfTapCount+j-1] = Coeff[HalfTapCount-j+1];
327 FirCoeff.conservativeResize(TapCount);
331 if(NumIterations <= 3)
345 int ParksMcClellan::Remez2(
int GridIndex)
347 int j, JET, K,
k, NU, JCHNGE, K1, KNZ, KLOW, NUT, KUP;
348 int NUT1, LUCK, KN, NITER;
349 double Deviation, DNUM, DDEN, TempVar;
350 double DEVL, COMP, YNZ, Y1, ERR;
358 ExchangeIndex[HalfTapCount+2] = GridIndex + 1;
360 for(j=1; j<=HalfTapCount+1; j++)
362 TempVar = Grid[ ExchangeIndex[j] ];
363 CosOfGrid[j] = cos(TempVar * M_2PI);
366 JET = (HalfTapCount-1)/15 + 1;
367 for(j=1; j<=HalfTapCount+1; j++)
369 LeGrangeD[j] = LeGrangeInterp2(j,HalfTapCount+1,JET);
375 for(j=1; j<=HalfTapCount+1; j++)
377 k = ExchangeIndex[j];
378 DNUM += LeGrangeD[j] * DesiredMag[
k];
379 DDEN += (double)K * LeGrangeD[j]/Weight[
k];
382 Deviation = DNUM / DDEN;
385 if(Deviation > 0.0) NU = -1;
386 Deviation = -(double)NU * Deviation;
388 for(j=1; j<=HalfTapCount+1; j++)
390 k = ExchangeIndex[j];
391 TempVar = (double)K * Deviation/Weight[
k];
392 DesPlus[j] = DesiredMag[
k] + TempVar;
396 if(Deviation <= DEVL)
return(NITER);
400 K1 = ExchangeIndex[1];
401 KNZ = ExchangeIndex[HalfTapCount+1];
409 while(j<HalfTapCount+2)
411 KUP = ExchangeIndex[j+1];
412 k = ExchangeIndex[j] + 1;
414 if(j == 2) Y1 = COMP;
417 if(
k < KUP && !ErrTest(
k, NUT, COMP, &ERR))
420 COMP = (double)NUT * ERR;
423 if( ErrTest(
k, NUT, COMP, &ERR) )
break;
424 COMP = (double)NUT * ERR;
427 ExchangeIndex[j] =
k-1;
439 k = ExchangeIndex[j] + 1;
442 ExchangeIndex[j] =
k-1;
452 if( ErrTest(
k, NUT, COMP, &ERR) )
continue;
456 KLOW = ExchangeIndex[j];
462 if( ErrTest(
k, NUT, COMP, &ERR) && JCHNGE <= 0)
goto L225;
464 if( ErrTest(
k, NUT, COMP, &ERR) )
466 KLOW = ExchangeIndex[j];
471 COMP = (double)NUT * ERR;
474 for(
k--;
k>KLOW;
k--)
476 if( ErrTest(
k, NUT, COMP, &ERR) )
break;
477 COMP = (double)NUT * ERR;
480 KLOW = ExchangeIndex[j];
481 ExchangeIndex[j] =
k + 1;
486 if(j == HalfTapCount+2) YNZ = COMP;
488 while(j <= HalfTapCount+2)
490 if(K1 > ExchangeIndex[1]) K1 = ExchangeIndex[1];
491 if(KNZ < ExchangeIndex[HalfTapCount+1]) KNZ = ExchangeIndex[HalfTapCount+1];
496 COMP = YNZ * 1.00001;
501 if( ErrTest(
k, NUT, COMP, &ERR) )
continue;
509 if(LUCK == 1 || LUCK == 2)
513 if(COMP > Y1) Y1 = COMP;
514 K1 = ExchangeIndex[HalfTapCount+2];
522 for(
k--;
k>KLOW;
k--)
524 if( ErrTest(
k, NUT, COMP, &ERR) )
continue;
526 COMP = (double)NUT * ERR;
533 if(JCHNGE > 0 && NITER++ < ITRMAX)
goto TOP_LINE;
537 for(j=1; j<=HalfTapCount; j++)
539 ExchangeIndex[HalfTapCount+2 - j] = ExchangeIndex[HalfTapCount+1 - j];
541 ExchangeIndex[1] = K1;
542 if(NITER++ < ITRMAX)
goto TOP_LINE;
545 KN = ExchangeIndex[HalfTapCount+2];
546 for(j=1; j<=HalfTapCount; j++)
548 ExchangeIndex[j] = ExchangeIndex[j+1];
550 ExchangeIndex[HalfTapCount+1] = KN;
551 if(NITER++ < ITRMAX)
goto TOP_LINE;
558 double ParksMcClellan::LeGrangeInterp2(
int K,
int N,
int M)
567 if(j != K)Dee = 2.0 * Dee * (Q - CosOfGrid[j]);
569 if(std::fabs(Dee) < MIN_TEST_VAL )
571 if(Dee < 0.0)Dee = -MIN_TEST_VAL;
572 else Dee = MIN_TEST_VAL;
579 double ParksMcClellan::GEE2(
int K,
int N)
585 XF = cos(M_2PI * XF);
589 C = XF - CosOfGrid[j];
590 if(std::fabs(C) < MIN_TEST_VAL )
592 if(C < 0.0)C = -MIN_TEST_VAL;
593 else C = MIN_TEST_VAL;
595 C = LeGrangeD[j] / C;
597 P = P + C*DesPlus[j];
599 if(std::fabs(Dee) < MIN_TEST_VAL )
601 if(Dee < 0.0)Dee = -MIN_TEST_VAL;
602 else Dee = MIN_TEST_VAL;
609 bool ParksMcClellan::ErrTest(
int k,
int Nut,
double Comp,
double *Err)
611 *Err = GEE2(
k, HalfTapCount+1);
612 *Err = (*Err - DesiredMag[
k]) * Weight[
k];
613 if((
double)Nut * *Err - Comp <= 0.0)
return(
true);
619 void ParksMcClellan::CalcCoefficients()
622 double GTempVar, OneOverNumTaps;
623 double Omega, TempVar, FreqN, TempX, GridCos;
624 double GeeArray[SMALL];
627 CosOfGrid[HalfTapCount+2] = -2.0;
628 OneOverNumTaps = 1.0 /(double)(2*HalfTapCount-1);
631 for(j=1; j<=HalfTapCount; j++)
633 FreqN = (double)(j-1) * OneOverNumTaps;
634 TempX = cos(M_2PI * FreqN);
636 GridCos = CosOfGrid[
k];
639 while(TempX <= GridCos && (GridCos-TempX) >= MIN_TEST_VAL)
642 GridCos = CosOfGrid[
k];
645 if(TempX <= GridCos || (TempX-GridCos) < MIN_TEST_VAL)
647 GeeArray[j] = DesPlus[
k];
652 GeeArray[j] = GEE2(1, HalfTapCount+1);
658 for(j=1; j<=HalfTapCount; j++)
661 Omega = (double)(j-1) * M_2PI * OneOverNumTaps;
662 for(n=1; n<=HalfTapCount-1; n++)
664 TempVar += GeeArray[n+1] * cos(Omega * (
double)n);
666 TempVar = 2.0 * TempVar + GeeArray[1];
670 Alpha[1] = Alpha[1] * OneOverNumTaps;
671 for(j=2; j<=HalfTapCount; j++)
673 Alpha[j] = 2.0 * Alpha[j] * OneOverNumTaps;