예제 #1
0
        /// <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));
        }
예제 #2
0
        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));
            });
        }
예제 #3
0
        /// <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)));
        }
예제 #4
0
        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));
            });
        }
예제 #5
0
        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;
        }
예제 #6
0
        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;
        }
예제 #7
0
        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));
            });
        }
예제 #8
0
        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);
        }
예제 #9
0
 /// <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)));
 }
예제 #10
0
 /// <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)));
 }
예제 #11
0
 /// <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)));
 }
예제 #12
0
 /// <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)));
 }
예제 #13
0
 /// <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)));
 }
예제 #14
0
 /// <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)));
 }
예제 #15
0
        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}");
        }