public InverseChebyshevDesign(double h0, double hc, double hs, double ωc, double ωs, ApproximationBase.BetaType bt) { if (h0 <= 0) { throw new System.ArgumentOutOfRangeException("h0"); } if (hc <= 0 || h0 <= hc) { throw new System.ArgumentOutOfRangeException("hc"); } if (hs <= 0 || hc <= hs) { throw new System.ArgumentOutOfRangeException("hs"); } if (ωs <= ωc) { throw new System.ArgumentOutOfRangeException("ωs"); } mH0 = h0; mHc = hc; mHs = hs; mωc = ωc; mΩs = ωs / ωc; mN = CalcOrder(); // H. G. Dimopoulos, Analog Electronic Filters: theory, design and synthesis, Springer, 2012. pp.118 // pp.126のFig 3.17参照。 // calc ε switch (bt) { case ApproximationBase.BetaType.BetaMin: mε = 1.0 / Math.Sqrt(h0 * h0 / hs / hs - 1); break; case ApproximationBase.BetaType.BetaMax: { // Calc cn(Ωs) var cn = ChebyshevDesign.ChebyshevPolynomialCoefficients(mN); double cnΩs = 0; double Ω = 1; for (int i = 0; i < cn.Length; ++i) { cnΩs += Ω * cn[i]; Ω *= mΩs; } mε = 1.0 / cnΩs / Math.Sqrt(h0 * h0 / hc / hc - 1); } break; } }
/// <summary> /// ローパスフィルターの設計。 /// </summary> /// <param name="mG0">0Hzのゲイン (dB)</param> /// <param name="mGc">カットオフ周波数のゲイン (dB)</param> /// <param name="mGs">ストップバンドのゲイン (dB)</param> /// <param name="mFc">カットオフ周波数(Hz)</param> /// <param name="mFs">ストップバンドの下限周波数(Hz)</param> /// <returns></returns> public bool DesignLowpass(double g0, double gc, double gs, double fc, double fs, FilterType ft, ApproximationBase.BetaType betaType) { // Hz → rad/s double ωc = fc * 2.0 * Math.PI; double ωs = fs * 2.0 * Math.PI; // dB → linear double h0 = Math.Pow(10, g0 / 20); double hc = Math.Pow(10, gc / 20); double hs = Math.Pow(10, gs / 20); ApproximationBase filter; switch (ft) { case FilterType.Butterworth: filter = new ButterworthDesign(h0, hc, hs, ωc, ωs, betaType); break; case FilterType.Chebyshev: filter = new ChebyshevDesign(h0, hc, hs, ωc, ωs, betaType); break; case FilterType.Pascal: filter = new PascalDesign(h0, hc, hs, ωc, ωs, betaType); break; case FilterType.InverseChebyshev: filter = new InverseChebyshevDesign(h0, hc, hs, ωc, ωs, betaType); break; case FilterType.Cauer: filter = new CauerDesign(h0, hc, hs, ωc, ωs, betaType); break; default: throw new NotImplementedException(); } mOrder = filter.Order; mNumeratorConstant = filter.TransferFunctionConstant(); // 伝達関数のポールの位置。 mPoleList.Clear(); for (int i = 0; i < filter.NumOfPoles(); ++i) { mPoleList.Add(filter.PoleNth(i)); } // 伝達関数の零の位置。 mZeroList.Clear(); for (int i = 0; i < filter.NumOfZeroes(); ++i) { mZeroList.Add(filter.ZeroNth(i)); } TransferFunction = (WWComplex s) => { return(TransferFunctionValue(WWComplex.Div(s, ωc))); }; PoleZeroPlotTransferFunction = (WWComplex s) => { return(TransferFunctionValue(s)); }; { // Unit Step Function WWPolynomial.PolynomialAndRationalPolynomial H_s; { var unitStepRoots = new WWComplex[filter.NumOfPoles() + 1]; for (int i = 0; i < filter.NumOfPoles(); ++i) { var p = filter.PoleNth(i); unitStepRoots[i] = p; } unitStepRoots[unitStepRoots.Length - 1] = WWComplex.Zero(); var numerCoeffs = new List <WWComplex>(); if (filter.NumOfZeroes() == 0) { numerCoeffs.Add(new WWComplex(mNumeratorConstant, 0)); } else { numerCoeffs.AddRange(WWPolynomial.RootListToCoeffList(mZeroList.ToArray(), new WWComplex(mNumeratorConstant, 0))); } H_s = WWPolynomial.Reduction(numerCoeffs.ToArray(), unitStepRoots); } var H_fraction = WWPolynomial.PartialFractionDecomposition(H_s.numerCoeffList, H_s.denomRootList); var H_integer = FirstOrderComplexRationalPolynomial.CreateFromCoeffList(H_s.coeffList); UnitStepResponseFunction = (double t) => { return(InverseLaplaceTransformValue(H_fraction, H_integer, t)); }; } { // 伝達関数 Transfer function WWPolynomial.PolynomialAndRationalPolynomial H_s; { var H_Roots = new WWComplex[filter.NumOfPoles()]; for (int i = 0; i < filter.NumOfPoles(); ++i) { var p = filter.PoleNth(i); H_Roots[i] = p; } var numerCoeffs = new List <WWComplex>(); if (filter.NumOfZeroes() == 0) { numerCoeffs.Add(new WWComplex(mNumeratorConstant, 0)); } else { numerCoeffs.AddRange(WWPolynomial.RootListToCoeffList(mZeroList.ToArray(), new WWComplex(mNumeratorConstant, 0))); } H_s = WWPolynomial.Reduction(numerCoeffs.ToArray(), H_Roots); } var H_fraction = WWPolynomial.PartialFractionDecomposition(H_s.numerCoeffList, H_s.denomRootList); var H_integer = FirstOrderComplexRationalPolynomial.CreateFromCoeffList(H_s.coeffList); ImpulseResponseFunction = (double t) => { return(InverseLaplaceTransformValue(H_fraction, H_integer, t)); }; #if true mH_PFD = new List <FirstOrderComplexRationalPolynomial>(); for (int i = 0; i < H_fraction.Count; ++i) { mH_PFD.Add(H_fraction[i]); if (1 == H_integer.Count && i == H_fraction.Count / 2 - 1) { mH_PFD.Add(H_integer[0]); } } #else mH_PFD = FirstOrderComplexRationalPolynomial.Add(H_fraction, H_integer); #endif TimeDomainFunctionTimeScale = 1.0 / filter.CutoffFrequencyHz(); if (NumOfZeroes() == 0) { // 共役複素数のペアを組み合わせて伝達関数の係数を全て実数にする。 // s平面のjω軸から遠い項から並べる。 mRealPolynomialList.Clear(); if ((H_fraction.Count() & 1) == 1) { // 奇数。 int center = H_fraction.Count() / 2; mRealPolynomialList.Add(H_fraction[center]); for (int i = 0; i < H_fraction.Count() / 2; ++i) { mRealPolynomialList.Add(WWPolynomial.Mul( H_fraction[center - i - 1], H_fraction[center + i + 1])); } } else { // 偶数。 int center = H_fraction.Count() / 2; for (int i = 0; i < H_fraction.Count() / 2; ++i) { mRealPolynomialList.Add(WWPolynomial.Mul( H_fraction[center - i - 1], H_fraction[center + i])); } } #if true System.Diagnostics.Debug.Assert(H_integer.Count == 0); #else { // integral polynomialは全て実数係数の多項式。単に足す。 foreach (var p in H_integer) { mRealPolynomialList.Add(p); } } #endif } else { // 共役複素数のペアを組み合わせて伝達関数の係数を全て実数にする。 // s平面のjω軸から遠い項から並べる。 // zeroListとPoleListを使って、実係数の2次多項式を作り、 // 伝達関数をこういう感じに実係数2次有理多項式の積の形にする。 // (s^2+c1)(s^2+c2) (s^2+c1) (s^2+c2) // H(s) = ──────────────────────── ⇒ ──────────── * ──────────── // (s^2+a1s+b1)(s^2+a2s+b2) (s^2+a1s+b1) (s^2+a2s+b2) mRealPolynomialList.Clear(); if ((mPoleList.Count & 1) == 1) { // 奇数。 int center = mPoleList.Count / 2; mRealPolynomialList.Add(new FirstOrderComplexRationalPolynomial( WWComplex.Zero(), WWComplex.Unity(), WWComplex.Unity(), WWComplex.Minus(mPoleList[center]))); for (int i = 0; i < mPoleList.Count / 2; ++i) { var p0 = new FirstOrderComplexRationalPolynomial( WWComplex.Unity(), WWComplex.Minus(mZeroList[center - i - 1]), WWComplex.Unity(), WWComplex.Minus(mPoleList[center - i - 1])); var p1 = new FirstOrderComplexRationalPolynomial( WWComplex.Unity(), WWComplex.Minus(mZeroList[center + i]), WWComplex.Unity(), WWComplex.Minus(mPoleList[center + i + 1])); var p = WWPolynomial.Mul(p0, p1); mRealPolynomialList.Add(p); } } else { // 偶数。 int center = mPoleList.Count / 2; for (int i = 0; i < mPoleList.Count / 2; ++i) { var p0 = new FirstOrderComplexRationalPolynomial( WWComplex.Unity(), WWComplex.Minus(mZeroList[center - i - 1]), WWComplex.Unity(), WWComplex.Minus(mPoleList[center - i - 1])); var p1 = new FirstOrderComplexRationalPolynomial( WWComplex.Unity(), WWComplex.Minus(mZeroList[center + i]), WWComplex.Unity(), WWComplex.Minus(mPoleList[center + i])); var p = WWPolynomial.Mul(p0, p1); mRealPolynomialList.Add(p); } } } return(true); } }