public void Creation() { // http://www.dsplib.ru/content/filters/ch8/ch8.html const double fd = 10; // Частота дискретизации const double dt = 1 / fd; // Период дискретизации const double Rp = 1; // Неоднородность АЧХ в интервале пропускания не более 1 дБ const double Rs = 40; // Уровень подавления более 40 дБ var Gp = (-Rp).From_dB(); // Значения АЧХ в интервале пропускания var Gs = (-Rs).From_dB(); // Значения АЧХ в интервале подавления const double fsl = 4 / Consts.pi2; const double fpl = 5 / Consts.pi2; const double fph = 15 / Consts.pi2; const double fsh = 18 / Consts.pi2; const double wsl = fsl * Consts.pi2; const double wpl = fpl * Consts.pi2; const double wph = fph * Consts.pi2; const double wsh = fsh * Consts.pi2; const double wc = wpl * wph; const double dw = wph - wpl; const double f0 = 1 / Consts.pi2; var ws = wc / wsh > wsl ? wsh : wsl; var f1 = Abs((wc - ws.Pow2()) / (dw * ws)) / Consts.pi2; var eps_p = Sqrt(10.Power(Rp / 10) - 1); var eps_s = Sqrt(10.Power(Rs / 10) - 1); var kw = f0 / f1; var k_eps = eps_p / eps_s; var Kw = FullEllipticIntegral(kw); var Tw = FullEllipticIntegralComplimentary(kw); var K_eps = FullEllipticIntegral(k_eps); var T_eps = FullEllipticIntegralComplimentary(k_eps); var double_N = T_eps * Kw / (K_eps * Tw); var N = (int)Ceiling(double_N); var Fp = DigitalFilter.ToAnalogFrequency(f0, dt); var Fs = DigitalFilter.ToAnalogFrequency(f1, dt); var L = N / 2; var r = N % 2; var u = Range(1, L).ToArray(i => (2 * i - 1d) / N); var m = (1 - k_eps * k_eps).Sqrt(); var kp = m.Power(N) * u.Aggregate(1d, (P, ui) => P * sn_uk(ui, m).Power(4)); var k_W = Sqrt(1 - kp * kp); var im_pz = Range(0, L).ToArray(i => 1 / (k_W * cd_uk(u[i], k_W))); var v0_complex = sn_inverse((0, 1 / eps_p), k_eps) / N; var zeros = new Complex[N - r]; var poles = new Complex[N]; if (r != 0) { poles[0] = Complex.i * sn_uk(v0_complex, k_W); } for (var i = 0; i < L; i++) { var(p_im, p_re) = cd_uk(u[i] - v0_complex, k_W); poles[r + 2 * i] = (-p_re, p_im); poles[r + 2 * i + 1] = poles[r + 2 * i].ComplexConjugate; var p0_im = 1 / (k_W * cd_uk(u[i], k_W)); zeros[2 * i] = (0, p0_im); zeros[2 * i + 1] = zeros[2 * i].ComplexConjugate; } var filter = new DSP.Filters.EllipticBandPass(dt, fsl, fpl, fph, fsh, Gp, Gs); var h_f0 = filter.GetTransmissionCoefficient(0).Power.In_dB_byPower(); var h_sl = filter.GetTransmissionCoefficient(fsl).Power.In_dB_byPower(); var h_pl = filter.GetTransmissionCoefficient(fpl).Power.In_dB_byPower(); var h_c0 = filter.GetTransmissionCoefficient((fpl * fph).Sqrt()).Power.In_dB_byPower(); var h_ph = filter.GetTransmissionCoefficient(fph).Power.In_dB_byPower(); var h_sh = filter.GetTransmissionCoefficient(fsh).Power.In_dB_byPower(); var h_fd = filter.GetTransmissionCoefficient(fd / 2).Power.In_dB_byPower(); h_f0.AssertThanValue().LessThan(-Rs); h_sl.AssertThanValue().LessThan(-Rs); h_pl.AssertThanValue().GreaterThan(-Rp, 1.1); h_c0.AssertThanValue().GreaterThan(-Rp); h_ph.AssertThanValue().GreaterThan(-Rp); h_sh.AssertThanValue().LessThan(-Rs); h_fd.AssertThanValue().LessThan(-Rs); }
public void Creation() { const double fd = 0.5; // Гц // Частота дискретизации const double dt = 1 / fd; // 2с // Период дискретизации const double fp = 0.05; // Гц // Граничная частота полосы пропускания const double fs = 0.15; // Гц // Граничная частота полосы запирания Assert.IsTrue(fp < fs); Assert.IsTrue(fp < fd / 2); //const double wp = Consts.pi2 * fp * dt; // 0.628318530717959 рад/с //const double ws = Consts.pi2 * fs * dt; // 1.884955592153876 рад/с const double Rp = 1; // Неравномерность в полосе пропускания (дБ) const double Rs = 30; // Неравномерность в полосе пропускания (дБ) var eps_p = (10d.Pow(Rp / 10) - 1).Sqrt(); var eps_s = (10d.Pow(Rs / 10) - 1).Sqrt(); Assert.That.Value(eps_p).IsEqual(0.50884713990958752); Assert.That.Value(eps_s).IsEqual(31.606961258558215); var Gp = (-Rp).From_dB(); var Gs = (-Rs).From_dB(); Assert.That.Value(Gp).IsEqual(0.89125093813374556); Assert.That.Value(Gs).IsEqual(0.031622776601683791); Assert.That.Value(Gp.In_dB()).IsEqual(-1, 4.67e-15); Assert.That.Value(Gs.In_dB()).IsEqual(-30); var Fp = DigitalFilter.ToAnalogFrequency(fp, dt); // Частота пропускания аналогового прототипа var Fs = DigitalFilter.ToAnalogFrequency(fs, dt); // Частота подавления аналогового прототипа Assert.That.Value(Fp).IsEqual(0.051712575763384123); Assert.That.Value(Fs).IsEqual(0.2190579862253032); var Wp = Consts.pi2 * Fp; var Ws = Consts.pi2 * Fs; var k_eps = eps_s / eps_p; var k_W = Ws / Wp; Assert.That.Value(k_eps).GreaterThan(0); Assert.That.Value(k_W).GreaterThan(0); var double_n = Log(k_eps) / Log(k_W); // Порядок фильтра var N = (int)double_n; if (double_n - N > 0) { N += 1; } Assert.That.Value(N).IsEqual(3); var L = N / 2; var r = N % 2; Assert.That.Value(L).IsEqual(1); Assert.That.Value(r).IsEqual(1); Assert.That.Value(2 * L + r).IsEqual(N); var alpha = eps_p.Pow(-1d / N); Assert.That.Value(alpha).IsEqual(1.2525763881810263); var th0 = PI / N; var poles = new Complex[N]; if (r != 0) { poles[0] = -alpha; } for (var i = r; i < poles.Length; i += 2) { var w = th0 * (i + 1 - r - 0.5); poles[i] = (-alpha * Sin(w), alpha *Cos(w)); poles[i + 1] = poles[i].ComplexConjugate; } Assert.That.Collection(poles).IsEqualTo( -1.2525763881810263, (-0.62628819409051306, 1.0847629723453271), (-0.62628819409051306, -1.0847629723453271) ); var translated_poles = poles.ToArray(p => p * Wp) .AssertThatCollection() .IsEqualTo( -0.40698673955629, (-0.20349336977814494, 0.35246085545914824), (-0.20349336977814494, -0.35246085545914824)) .ActualValue; var z_poles = translated_poles.ToArray(p => DigitalFilter.ToZ(p, dt)) .AssertThatCollection() .IsEqualTo( 0.42147750491999925, (0.53055357928176117, 0.44824528113449957), (0.53055357928176117, -0.44824528113449957)) .AllItems(z_pole => z_pole.Where(z => z.Abs < 1)) .ActualValue; var kz = DigitalFilter.GetNormalizeCoefficient(translated_poles, dt) .AssertThanValue() .IsEqual(0.45194421873401691) .ActualValue; var WpN = Wp.Pow(N) .AssertThanValue() .IsEqual(0.034302685030761955) .ActualValue; var k = WpN * kz / eps_p; Assert.That.Value(k).IsEqual(0.030466713814017582); var b = Range(0, N + 1).ToArray(i => k * BinomialCoefficient(N, i)); Assert.That.Collection(b).IsEqualTo(new[] { 1 * k, 3 * k, 3 * k, 1 * k }); var a_complex = Polynom.Array.GetCoefficientsInverted((Complex[])z_poles); Assert.That.Collection(a_complex) .CountEquals(4) .AllItems(a_value => a_value.Where(z => z.Im).IsEqual(0, 1e-16)); var a = a_complex.ToRe() ?? throw new AssertFailedException("Отсутствует ссылка на массив вещественных значений"); Assert.That.Collection(a).ValuesAreEqual( 1, -1.4825846634835216, 0.92964373019213786, -0.20332535619647568 ); var filter = new DSP.Filters.ButterworthLowPass(dt, fp, fs, Gp, Gs); Assert.That.Collection(filter.A).IsEqualTo(a, 1e-15); Assert.That.Collection(filter.B).IsEqualTo(b, 1e-16); }
public void Creation() { //https://ru.dsplib.org/content/filter_ellip_ap/filter_ellip_ap.html const double pi2 = 2 * PI; const double fd = 5000; // Частота дискретизации const double dt = 1 / fd; // Период дискретизации const double fp = fd / pi2; // Граничная частота конца интервала пропускания const double fs = 1.5 * fp; // Граничная частота начала интервала подавления const double Rp = 1; // Неоднородность АЧХ в интервале пропускания не более 1 дБ const double Rs = 45; // Уровень подавления более 45 дБ var Gp = (-Rp).From_dB(); // Значения АЧХ в интервале пропускания var Gs = (-Rs).From_dB(); // Значения АЧХ в интервале подавления #region Аналитический расчёт фильтра //const double wp = 2 * Math.PI * fp / fd; // 1 //const double ws = 2 * Math.PI * fs / fd; // 1.5 // Рассчитываем частоты цифрового фильтра var Fp = DigitalFilter.ToAnalogFrequency(fp, dt).AssertThanValue().IsEqual(869.46741682049208).ActualValue; var Fs = DigitalFilter.ToAnalogFrequency(fs, dt).AssertThanValue().IsEqual(1482.6818156701001).ActualValue; // Круговые частоты var Wp = Consts.pi2 * Fp; //var Ws = Consts.pi2 * Fs; // Допуск на АЧХ в интервале пропускания var eps_p = (Pow(10, Rp / 10) - 1).Sqrt().AssertThanValue().IsEqual(0.50884713990958752).ActualValue; // Допуск на АЧХ в интервале подавления var eps_s = (Pow(10, Rs / 10) - 1).Sqrt().AssertThanValue().IsEqual(177.82512927503748).ActualValue; //var k_eps = eps_s / eps_p; //var k_W = Fs / Fp; //Assert.That.Value(k_eps).IsEqual(349.46669702542425); //Assert.That.Value(k_W).IsEqual(1.705275881518411, 2.23e-16); var k_W = fp / fs; var k_eps = eps_p / eps_s; Assert.That.Value(k_W).IsEqual(0.66666666666666663); Assert.That.Value(k_eps).IsEqual(0.0028615029944534269); var K_w = FullEllipticIntegral(k_W) .AssertThanValue().IsEqual(1.8096674954865886) .ActualValue; var T_w = FullEllipticIntegralComplimentary(k_W) .AssertThanValue().IsEqual(1.9042414169449993) .ActualValue; var K_eps = FullEllipticIntegral(k_eps) .AssertThanValue().IsEqual(1.5707995423080867) .ActualValue; var T_eps = FullEllipticIntegralComplimentary(k_eps) .AssertThanValue().IsEqual(7.2427154099443083) .ActualValue; // Оценка снизу порядка фильтра var double_N = T_eps * K_w / (K_eps * T_w); Assert.That.Value(double_N).IsEqual(4.381849263936846); var N = (int)Ceiling(double_N); // Порядок фильтра Assert.That.Value(N).IsEqual(5); var L = N / 2; // Число комплексно сопряжённых полюсов var r = N % 2; // Число (0 или 1) действительных полюсов - (чётность фильтра) Assert.That.Value(L).IsEqual(2); // Число чётных (парных) полюсов Assert.That.Value(r).IsEqual(1); // Есть один нечётный полюс // Эллиптический модуль var u = Enumerable.Range(1, L).ToArray(i => (2 * i - 1d) / N); Assert.That.Collection(u).ValuesAreEqual(0.2, 0.6); var m = (1 - k_eps * k_eps).Sqrt().AssertThanValue().IsEqual(0.99999590589192544).ActualValue; var kp = m.Power(N) * u.Aggregate(1d, (P, ui) => P * sn_uk(ui, m).Power(4)); Assert.That.Value(kp).IsEqual(0.64193363450270813); k_W = (1 - kp * kp).Sqrt().AssertThanValue().IsEqual(0.7667602029931806).ActualValue; var im_pz = Enumerable.Range(0, L).ToArray(i => 1 / (k_W * cd_uk(u[i], k_W))); Assert.That.Collection(im_pz) .ValuesAreEqual( 1.3468197668176745, 1.9455219056033073); var v0_complex = sn_inverse((0, 1 / eps_p), k_eps) / N; Assert.That.Value(v0_complex).IsEqual((0, 0.18181434014993489)); var zeros = new Complex[N - r]; // Массив нулей (на r меньше числа полюсов) var poles = new Complex[N]; // Массив полюсов // Если фильтр нечётный, то первым полюсом будет действительный полюс if (r != 0) { poles[0] = Complex.i * sn_uk(v0_complex, k_W); } for (var i = 0; i < L; i++) { // Меняем местами действительную и мнимую часть вместо домножения на комплексную единицу var(p_im, p_re) = cd_uk(u[i] - v0_complex, k_W); poles[r + 2 * i] = (-p_re, p_im); poles[r + 2 * i + 1] = poles[r + 2 * i].ComplexConjugate; var p0_im = 1 / (k_W * cd_uk(u[i], k_W)); zeros[2 * i] = (0, p0_im); zeros[2 * i + 1] = zeros[2 * i].ComplexConjugate; } // Полюса Assert.That.Collection(poles).IsEqualTo( (-0.36412934994456797), (-0.05673598848637736, +0.9970769704594055), (-0.05673598848637736, -0.9970769704594055), (-0.2239296815274167, +0.7156285075410361), (-0.2239296815274167, -0.7156285075410361) ); // Нули Assert.That.Collection(zeros).IsEqualTo( (0, +1.3468197668176745), (0, -1.3468197668176745), (0, +1.9455219056033073), (0, -1.9455219056033073) ); // Рассчитываем коэффициенты полиномов числителя и знаменателя передаточной функции // аналогового прототипа H(p) = Q(p) / P(p) var analog_numerator_coefficients = GetCoefficientsInverted(zeros); // Q(p) var analog_denominator_coefficients = GetCoefficientsInverted(poles); // P(p) var(analog_b, numerator_coefficients_im) = analog_numerator_coefficients; var(analog_a, denominator_coefficients_im) = analog_denominator_coefficients; CollectionAssert.That.Collection(numerator_coefficients_im).ElementsAreEqualTo(0); CollectionAssert.That.Collection(denominator_coefficients_im).ElementsAreEqualTo(0, 5.56e-17); Assert.That.Collection(analog_b) .ValuesAreEqual( 1, 0, 5.598978969473139, 0, 6.865801033915982); Assert.That.Collection(analog_a) .ValuesAreEqual( 1, 0.925460689972156, 1.8148668237637633, 1.0969076124267614, 0.7466801336882324, 0.2042024062377706); var norm_k = analog_b[^ 1] / analog_a[^ 1];
public void Creation_fp500_ps1500_fd_5000() { const double fp = 500; // Гц // Граничная частота полосы пропускания const double fs = 1500; // Гц // Граничная частота полосы запирания const double fd = 5000; // Гц // Частота дискретизации const double dt = 1 / fd; // 2с // Период дискретизации const double Rp = 1; // Неравномерность в полосе пропускания (дБ) const double Rs = 30; // Неравномерность в полосе пропускания (дБ) var Gp = (-Rp).From_dB(); var Gs = (-Rs).From_dB(); var eps_p = (10d.Pow(Rp / 10) - 1).Sqrt(); var eps_s = (10d.Pow(Rs / 10) - 1).Sqrt(); var Fp = DigitalFilter.ToAnalogFrequency(fp, dt); // Частота пропускания аналогового прототипа var Fs = DigitalFilter.ToAnalogFrequency(fs, dt); // Частота подавления аналогового прототипа var k_eps = eps_s / eps_p; var k_W = Fs / Fp; var double_n = Log(k_eps) / Log(k_W); var N = (int)double_n; if (double_n - N > 0) { N += 1; } var L = N / 2; var r = N % 2; var alpha = eps_p.Pow(-1d / N); var th0 = PI / N; var poles = new Complex[N]; if (r != 0) { poles[0] = -alpha; } for (var i = r; i < poles.Length; i += 2) { var w = th0 * (i + 1 - r - 0.5); poles[i] = (-alpha * Sin(w), alpha *Cos(w)); poles[i + 1] = poles[i].ComplexConjugate; } var translated_poles = poles.ToArray(p => p * Consts.pi2 * Fp); var z_poles = translated_poles.ToArray(p => DigitalFilter.ToZ(p, dt)); var kz = DigitalFilter.GetNormalizeCoefficient(translated_poles, dt); var WpN = (Consts.pi2 * Fp).Pow(N); var k = WpN * kz / eps_p; var b = Range(0, N + 1).ToArray(i => k * BinomialCoefficient(N, i)); var a_complex = Polynom.Array.GetCoefficientsInverted(z_poles); var a = a_complex.ToRe() ?? throw new AssertFailedException("Отсутствует ссылка на массив вещественных значений"); var filter = new DSP.Filters.ButterworthLowPass(dt, fp, fs, Gp, Gs); Assert.That.Value(filter.Order).IsEqual(N); var tr_k = filter.GetTransmissionCoefficient(fs, dt).Abs.In_dB(); Assert.That.Collection(filter.A).IsEqualTo(a, 3e-12); Assert.That.Collection(filter.B).IsEqualTo(b, 1e-16); }