/// <summary> /// Band-limited resampling /// </summary> /// <param name="signal"></param> /// <param name="newSamplingRate"></param> /// <param name="filter"></param> /// <param name="order"></param> /// <returns></returns> public DiscreteSignal Resample(DiscreteSignal signal, int newSamplingRate, FirFilter filter = null, int order = 15) { if (signal.SamplingRate == newSamplingRate) { return(signal.Copy()); } var g = (float)newSamplingRate / signal.SamplingRate; var input = signal.Samples; var output = new float[(int)(input.Length * g)]; if (g < 1 && filter == null) { filter = DesignFilter.FirLp(MinResamplingFilterOrder, g / 2); input = filter.ApplyTo(signal).Samples; } var step = 1 / g; for (var n = 0; n < output.Length; n++) { var x = n * step; for (var i = -order; i < order; i++) { var j = (int)Math.Floor(x) - i; if (j < 0 || j >= input.Length) { continue; } var t = x - j; float w = (float)(0.5 * (1.0 + Math.Cos(t / order * Math.PI))); // Hann window float sinc = (float)MathUtils.Sinc(t); // Sinc function output[n] += w * sinc * input[j]; } } return(new DiscreteSignal(newSamplingRate, output)); }
public void TestSosToTf() { var sos = new TransferFunction[4] { new TransferFunction(new[] { 1, -0.4, 0.85 }, new[] { 1, -0.1, 0 }), new TransferFunction(new[] { 1, -1, 0.29 }, new[] { 1, -0.7, 0.1 }), new TransferFunction(new[] { 1, 0.3, 0 }, new[] { 1, 1.8, 0.85 }), new TransferFunction(new[] { 1, -1, 0.0 }, new[] { 1, -1.6, 0.6 }) }; var tf = DesignFilter.SosToTf(sos); Assert.Multiple(() => { Assert.That(tf.Numerator, Is.EqualTo(new[] { 1, -2.1, 2.22, -1.624, 0.4607, 0.11725, -0.07395, 0, 0 }).Within(1e-10)); Assert.That(tf.Denominator, Is.EqualTo(new[] { 1, -0.6, -1.42, 0.888, 0.4889, -0.4413, 0.0895, -0.0051, 0 }).Within(1e-10)); }); }
/// <summary> /// Resampling based on simple interpolation /// </summary> /// <param name="signal"></param> /// <param name="up"></param> /// <param name="down"></param> /// <returns></returns> private static DiscreteSignal ResampleUpDown(DiscreteSignal signal, int up, int down) { var ratio = (float)up / down; var freq = ratio > 1 ? 0.5f / ratio : 0.5f * ratio; var lpFilter = DesignFilter.FirLp(MinResamplingFilterOrder, freq); var input = signal.Samples; var output = MathUtils.InterpolateLinear( Enumerable.Range(0, input.Length) .Select(s => s * ratio) .ToArray(), input, Enumerable.Range(0, (int)(signal.Length * ratio) + 1) .Select(s => (float)s) .ToArray()); return(lpFilter.ApplyTo(new DiscreteSignal(signal.SamplingRate * up / down, output))); }
public void TestTfToSos() { var zs = new ComplexDiscreteSignal(1, new[] { 1, 0.5, -0.3, 0.2, 0.5, 0.2 }, new[] { 0, 0.2, 0, -0.9, -0.2, 0.9 }); var ps = new ComplexDiscreteSignal(1, new[] { 1, 0.2, 0.5, -0.9, 0.6, 0.1, -0.9 }, new[] { 0, 0, 0, 0.2, 0, 0, -0.2 }); var sos = DesignFilter.TfToSos(new TransferFunction(zs, ps)); Assert.Multiple(() => { Assert.That(sos[0].Numerator, Is.EqualTo(new[] { 1, -0.4, 0.85 }).Within(1e-10)); Assert.That(sos[0].Denominator, Is.EqualTo(new[] { 1, -0.1, 0 }).Within(1e-10)); Assert.That(sos[1].Numerator, Is.EqualTo(new[] { 1, -1, 0.29 }).Within(1e-10)); Assert.That(sos[1].Denominator, Is.EqualTo(new[] { 1, -0.7, 0.1 }).Within(1e-10)); Assert.That(sos[2].Numerator, Is.EqualTo(new[] { 1, 0.3, 0 }).Within(1e-10)); Assert.That(sos[2].Denominator, Is.EqualTo(new[] { 1, 1.8, 0.85 }).Within(1e-10)); Assert.That(sos[3].Numerator, Is.EqualTo(new[] { 1, -1, 0 }).Within(1e-10)); Assert.That(sos[3].Denominator, Is.EqualTo(new[] { 1, -1.6, 0.6 }).Within(1e-10)); Assert.That(sos.Length, Is.EqualTo(4)); }); }
private void AnalyzeCustomLpFilter() { var order = 15; var freq = 0.1; if (filterParamsDataGrid.RowCount > 0) { order = Convert.ToInt32(filterParamsDataGrid.Rows[0].Cells[1].Value); freq = Convert.ToDouble(filterParamsDataGrid.Rows[1].Cells[1].Value); } orderNumeratorTextBox.Text = (order - 1).ToString(); orderDenominatorTextBox.Text = (order - 1).ToString(); _filter = DesignFilter.FirLp(order, freq); filterParamsDataGrid.RowCount = 2; filterParamsDataGrid.Rows[0].Cells[0].Value = "order"; filterParamsDataGrid.Rows[0].Cells[1].Value = order; filterParamsDataGrid.Rows[1].Cells[0].Value = "freq"; filterParamsDataGrid.Rows[1].Cells[1].Value = freq; }
private void AnalyzeEquirippleLpFilter() { var order = 47; var fp = 0.15; var fa = 0.18; var ripplePass = 1.0; // dB var rippleStop = 42.0; // dB if (filterParamsDataGrid.RowCount > 0) { order = Convert.ToInt32(filterParamsDataGrid.Rows[0].Cells[1].Value); fp = Convert.ToDouble(filterParamsDataGrid.Rows[1].Cells[1].Value); fa = Convert.ToDouble(filterParamsDataGrid.Rows[2].Cells[1].Value); ripplePass = Convert.ToDouble(filterParamsDataGrid.Rows[3].Cells[1].Value); rippleStop = Convert.ToDouble(filterParamsDataGrid.Rows[4].Cells[1].Value); } orderNumeratorTextBox.Text = (order - 1).ToString(); orderDenominatorTextBox.Text = (order - 1).ToString(); var wp = Remez.DbToPassbandWeight(ripplePass); var wa = Remez.DbToStopbandWeight(rippleStop); _filter = new FirFilter(DesignFilter.FirEquirippleLp(order, fp, fa, wp, wa)); filterParamsDataGrid.RowCount = 5; filterParamsDataGrid.Rows[0].Cells[0].Value = "order"; filterParamsDataGrid.Rows[0].Cells[1].Value = order; filterParamsDataGrid.Rows[1].Cells[0].Value = "fp"; filterParamsDataGrid.Rows[1].Cells[1].Value = fp; filterParamsDataGrid.Rows[2].Cells[0].Value = "fa"; filterParamsDataGrid.Rows[2].Cells[1].Value = fa; filterParamsDataGrid.Rows[3].Cells[0].Value = "rp"; filterParamsDataGrid.Rows[3].Cells[1].Value = ripplePass; filterParamsDataGrid.Rows[4].Cells[0].Value = "rs"; filterParamsDataGrid.Rows[4].Cells[1].Value = rippleStop; }
public void TestTfToSos() { var zeros = new Complex[6] { new Complex(1, 0), new Complex(0.5, 0.2), new Complex(-0.3, 0), new Complex(0.2, -0.9), new Complex(0.5, -0.2), new Complex(0.2, 0.9) }; var poles = new Complex[7] { new Complex(1, 0), new Complex(0.2, 0), new Complex(0.5, 0), new Complex(-0.9, 0.2), new Complex(0.6, 0), new Complex(0.1, 0), new Complex(-0.9, -0.2) }; var sos = DesignFilter.TfToSos(new TransferFunction(zeros, poles)); Assert.Multiple(() => { Assert.That(sos[0].Numerator, Is.EqualTo(new[] { 1, -0.4, 0.85 }).Within(1e-10)); Assert.That(sos[0].Denominator, Is.EqualTo(new[] { 1, -0.1, 0 }).Within(1e-10)); Assert.That(sos[1].Numerator, Is.EqualTo(new[] { 1, -1, 0.29 }).Within(1e-10)); Assert.That(sos[1].Denominator, Is.EqualTo(new[] { 1, -0.7, 0.1 }).Within(1e-10)); Assert.That(sos[2].Numerator, Is.EqualTo(new[] { 1, 0.3, 0 }).Within(1e-10)); Assert.That(sos[2].Denominator, Is.EqualTo(new[] { 1, 1.8, 0.85 }).Within(1e-10)); Assert.That(sos[3].Numerator, Is.EqualTo(new[] { 1, -1, 0 }).Within(1e-10)); Assert.That(sos[3].Denominator, Is.EqualTo(new[] { 1, -1.6, 0.6 }).Within(1e-10)); Assert.That(sos.Length, Is.EqualTo(4)); }); }
public FirFiltersVsBlockConvolvers() { _signal = new WhiteNoiseBuilder().OfLength(N).Build(); var kernel21 = DesignFilter.FirWinLp(21, 0.1); _filter21 = new FirFilter(kernel21); _ola21 = new OlaBlockConvolver(kernel21, 128); _ols21 = new OlsBlockConvolver(kernel21, 128); var kernel101 = DesignFilter.FirWinLp(101, 0.1); _filter101 = new FirFilter(kernel101); _filter101.KernelSizeForBlockConvolution = 2048; _ola101 = new OlaBlockConvolver(kernel101, 512); _ols101 = new OlsBlockConvolver(kernel101, 512); var kernel315 = DesignFilter.FirWinLp(315, 0.1); _filter315 = new FirFilter(kernel315); _filter315.KernelSizeForBlockConvolution = 2048; _ola315 = new OlaBlockConvolver(kernel315, 2048); _ols315 = new OlsBlockConvolver(kernel315, 2048); }
/// <summary> /// Generates transfer function. /// </summary> /// <param name="frequency">Normalized cutoff frequency in range [0..0.5]</param> /// <param name="order">Filter order</param> /// <param name="ripple">Ripple (in dB)</param> private static TransferFunction MakeTf(double frequency, int order, double ripple = 0.1) { return(DesignFilter.IirLpTf(frequency, PrototypeChebyshevI.Poles(order, ripple))); }
/// <summary> /// TF generator /// </summary> /// <param name="f1"></param> /// <param name="f2"></param> /// <param name="order"></param> /// <returns></returns> private static TransferFunction MakeTf(double f1, double f2, int order) { return(DesignFilter.IirBpTf(f1, f2, PrototypeButterworth.Poles(order))); }
/// <summary> /// Generates transfer function. /// </summary> /// <param name="frequency">Normalized cutoff frequency in range [0..0.5]</param> /// <param name="order">Filter order</param> private static TransferFunction MakeTf(double frequency, int order) { return(DesignFilter.IirHpTf(frequency, PrototypeBessel.Poles(order))); }
/// <summary> /// TF generator /// </summary> /// <param name="freq"></param> /// <param name="order"></param> /// <param name="ripplePass"></param> /// <param name="rippleStop"></param> /// <returns></returns> private static TransferFunction MakeTf(double freq, int order, double ripplePass = 1, double rippleStop = 20) { return(DesignFilter.IirHpTf(freq, PrototypeElliptic.Poles(order, ripplePass, rippleStop), PrototypeElliptic.Zeros(order, ripplePass, rippleStop))); }
/// <summary> /// TF generator /// </summary> /// <param name="f1"></param> /// <param name="f2"></param> /// <param name="order"></param> /// <returns></returns> private static TransferFunction MakeTf(double freq1, double freq2, int order, double ripple = 0.1) { return(DesignFilter.IirBpTf(freq1, freq2, PrototypeChebyshevII.Poles(order, ripple), PrototypeChebyshevII.Zeros(order))); }
/// <summary> /// Generates transfer function. /// </summary> /// <param name="frequencyLow">Normalized low cutoff frequency in range [0..0.5]</param> /// <param name="frequencyHigh">Normalized high cutoff frequency in range [0..0.5]</param> /// <param name="order">Filter order</param> private static TransferFunction MakeTf(double frequencyLow, double frequencyHigh, int order) { return(DesignFilter.IirBpTf(frequencyLow, frequencyHigh, PrototypeButterworth.Poles(order))); }
public void Run() { var output2 = new float[_signal.Length]; var output4 = new float[_signal.Length]; var output5 = new float[_signal.Length]; var outputZi = new float[_signal.Length]; var samples = _signal.Samples; for (var i = 0; i < samples.Length; i++) { output4[i] = _filterV4BiQuad.Process(samples[i]); output5[i] = _filterV5BiQuad.Process(samples[i]); outputZi[i] = _filterZiBiQuad.Process(samples[i]); } var diffAverageV4 = output5.Zip(output4, (o5, o4) => Math.Abs(o5 - o4)).Average(); var diffAverageZi = output5.Zip(outputZi, (o5, zi) => Math.Abs(o5 - zi)).Average(); Console.WriteLine($"Average difference Ver.0.9.5 vs. Ver.0.9.4 : {diffAverageV4}"); Console.WriteLine($"Average difference IirFilter vs. ZiFilter : {diffAverageZi}"); for (var i = 0; i < samples.Length; i++) { output4[i] = _filterV4Butterworth6.Process(samples[i]); output5[i] = _filterV5Butterworth6.Process(samples[i]); outputZi[i] = _filterZiButterworth6.Process(samples[i]); } diffAverageV4 = output5.Zip(output4, (o5, o4) => Math.Abs(o5 - o4)).Average(); diffAverageZi = output5.Zip(outputZi, (o5, zi) => Math.Abs(o5 - zi)).Average(); Console.WriteLine($"Average difference Ver.0.9.5 vs. Ver.0.9.4 : {diffAverageV4}"); Console.WriteLine($"Average difference IirFilter vs. ZiFilter : {diffAverageZi}"); // === MISC ==== var med = new MedianFilter(); var med2 = new MedianFilter2(); var medOut = med.ApplyTo(_signal).Samples; var medOut2 = med2.ApplyTo(_signal).Samples; var diffAverageMed = medOut.Zip(medOut, (m1, m2) => Math.Abs(m1 - m2)).Average(); Console.WriteLine($"Average difference MedianFilter vs. MedianFilter2 : {diffAverageMed}"); var ma = new MovingAverageFilter(); var maRec = new MovingAverageRecursiveFilter(); var maOut = ma.ApplyTo(_signal).Samples; var maRecOut = maRec.ApplyTo(_signal).Samples; var diffAverageMa = maOut.Zip(maRecOut, (m1, m2) => Math.Abs(m1 - m2)).Average(); Console.WriteLine($"Average difference MovingAverageFilter vs. MovingAverageRecursiveFilter : {diffAverageMa}"); // 32bit vs. 64bit var fir32 = new FirFilter(DesignFilter.FirWinLp(7, 0.1)); var fir64 = new FirFilter64(DesignFilter.FirWinLp(7, 0.1)); var fir32Out = fir32.ApplyTo(_signal).Samples; var fir64Out = fir64.ApplyTo(_signal.Samples.ToDoubles()); var diffAverageFir = fir64Out.Zip(fir32Out, (m1, m2) => Math.Abs(m1 - m2)).Average(); Console.WriteLine($"Average difference FirFilter vs. FirFilter64 : {diffAverageFir}"); var iir32 = new IirFilter(_filterV5Butterworth6.Tf); var iir64 = new IirFilter64(_filterV5Butterworth6.Tf); var iir32Out = iir32.ApplyTo(_signal).Samples; var iir64Out = iir64.ApplyTo(_signal.Samples.ToDoubles()); var diffAverageIir = iir64Out.Zip(iir32Out, (m1, m2) => Math.Abs(m1 - m2)).Average(); Console.WriteLine($"Average difference IirFilter vs. IirFilter64 : {diffAverageIir}"); var zi32 = new ZiFilter(_filterV5Butterworth6.Tf); var zi64 = new ZiFilter64(_filterV5Butterworth6.Tf); var zi32Out = zi32.ApplyTo(_signal).Samples; var zi64Out = zi64.ApplyTo(_signal.Samples.ToDoubles()); var diffAverageZis = zi64Out.Zip(zi32Out, (m1, m2) => Math.Abs(m1 - m2)).Average(); Console.WriteLine($"Average difference ZiFilter vs. ZiFilter64 : {diffAverageZis}"); zi32Out = zi32.ZeroPhase(_signal).Samples; zi64Out = zi64.ZeroPhase(_signal.Samples.ToDoubles()); var diffAverageZiZeroPhase = zi64Out.Zip(zi32Out, (m1, m2) => Math.Abs(m1 - m2)).Average(); Console.WriteLine($"Average difference ZiFilter vs. ZiFilter64 (zero-phase): {diffAverageZiZeroPhase}"); }