Exemplo n.º 1
0
 public void TestFilterAppliedDirectly()
 {
     AssertFilterOutput(_filter.ApplyTo(_signal, FilteringMethod.DifferenceEquation));
 }
Exemplo n.º 2
0
        /// <summary>
        /// Method creates overlapping ERB filters (ported from Malcolm Slaney's MATLAB code).
        /// </summary>
        /// <param name="erbFilterCount">Number of ERB filters</param>
        /// <param name="fftSize">Assumed size of FFT</param>
        /// <param name="samplingRate">Assumed sampling rate</param>
        /// <param name="lowFreq">Lower bound of the frequency range</param>
        /// <param name="highFreq">Upper bound of the frequency range</param>
        /// <param name="normalizeGain">True if gain should be normalized; false if all filters should have same height 1.0</param>
        /// <returns>Array of ERB filters</returns>
        public static float[][] Erb(
            int erbFilterCount, int fftSize, int samplingRate, double lowFreq = 0, double highFreq = 0, bool normalizeGain = true)
        {
            if (lowFreq < 0)
            {
                lowFreq = 0;
            }
            if (highFreq <= lowFreq)
            {
                highFreq = samplingRate / 2.0;
            }

            const double earQ  = 9.26449;
            const double minBw = 24.7;
            const double bw    = earQ * minBw;
            const int    order = 1;

            var t = 1.0 / samplingRate;

            var frequencies = new double[erbFilterCount];

            for (var i = 1; i <= erbFilterCount; i++)
            {
                frequencies[erbFilterCount - i] =
                    -bw + Math.Exp(i * (-Math.Log(highFreq + bw) + Math.Log(lowFreq + bw)) / erbFilterCount) * (highFreq + bw);
            }

            var ucirc = new Complex[fftSize / 2 + 1];

            for (var i = 0; i < ucirc.Length; i++)
            {
                ucirc[i] = Complex.Exp((2 * Complex.ImaginaryOne * i * Math.PI) / fftSize);
            }

            var rootPos = Math.Sqrt(3 + Math.Pow(2, 1.5));
            var rootNeg = Math.Sqrt(3 - Math.Pow(2, 1.5));

            var fft = new Fft(fftSize);

            var erbFilterBank = new float[erbFilterCount][];

            for (var i = 0; i < erbFilterCount; i++)
            {
                var cf  = frequencies[i];
                var erb = Math.Pow(Math.Pow(cf / earQ, order) + Math.Pow(minBw, order), 1.0 / order);
                var b   = 1.019 * 2 * Math.PI * erb;

                var theta  = 2 * cf * Math.PI * t;
                var itheta = Complex.Exp(2 * Complex.ImaginaryOne * theta);

                var a0 = t;
                var a2 = 0.0;
                var b0 = 1.0;
                var b1 = -2 * Math.Cos(theta) / Math.Exp(b * t);
                var b2 = Math.Exp(-2 * b * t);

                var common = -t *Math.Exp(-b *t);

                var k1 = Math.Cos(theta) + rootPos * Math.Sin(theta);
                var k2 = Math.Cos(theta) - rootPos * Math.Sin(theta);
                var k3 = Math.Cos(theta) + rootNeg * Math.Sin(theta);
                var k4 = Math.Cos(theta) - rootNeg * Math.Sin(theta);

                var a11 = common * k1;
                var a12 = common * k2;
                var a13 = common * k3;
                var a14 = common * k4;

                var gainArg = Complex.Exp(Complex.ImaginaryOne * theta - b * t);

                var gain = Complex.Abs(
                    (itheta - gainArg * k1) *
                    (itheta - gainArg * k2) *
                    (itheta - gainArg * k3) *
                    (itheta - gainArg * k4) *
                    Complex.Pow(t * Math.Exp(b * t) / (-1.0 / Math.Exp(b * t) + 1 + itheta * (1 - Math.Exp(b * t))), 4.0));

                var filter1 = new IirFilter(new[] { a0, a11, a2 }, new[] { b0, b1, b2 });
                var filter2 = new IirFilter(new[] { a0, a12, a2 }, new[] { b0, b1, b2 });
                var filter3 = new IirFilter(new[] { a0, a13, a2 }, new[] { b0, b1, b2 });
                var filter4 = new IirFilter(new[] { a0, a14, a2 }, new[] { b0, b1, b2 });

                var ir = new double[fftSize];
                ir[0] = 1.0;

                // for doubles the following code will work ok
                // (however there's a crucial lost of precision in case of floats):

                //var filter = filter1 * filter2 * filter3 * filter4;
                //ir = filter.ApplyTo(ir);

                // this code is ok both for floats and for doubles:

                ir = filter1.ApplyTo(ir);
                ir = filter2.ApplyTo(ir);
                ir = filter3.ApplyTo(ir);
                ir = filter4.ApplyTo(ir);

                var kernel = new DiscreteSignal(1, ir.Select(s => (float)(s / gain)));

                erbFilterBank[i] = fft.PowerSpectrum(kernel, false).Samples;
            }

            // normalize gain (by default)

            if (!normalizeGain)
            {
                return(erbFilterBank);
            }

            foreach (var filter in erbFilterBank)
            {
                var sum = 0.0;
                for (var j = 0; j < filter.Length; j++)
                {
                    sum += Math.Abs(filter[j] * filter[j]);
                }

                var weight = Math.Sqrt(sum * samplingRate / fftSize);

                for (var j = 0; j < filter.Length; j++)
                {
                    filter[j] = (float)(filter[j] / weight);
                }
            }

            return(erbFilterBank);
        }
Exemplo n.º 3
0
 public void OfflineFilterForLoop()
 {
     var output = _filter.ApplyTo(_signal);
 }
Exemplo n.º 4
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}");
        }