Ejemplo n.º 1
0
        /// <summary>
        /// Fast convolution via FFT for general complex-valued case
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="kernel"></param>
        /// <returns></returns>
        public ComplexDiscreteSignal Convolve(ComplexDiscreteSignal signal, ComplexDiscreteSignal kernel)
        {
            var length = signal.Length + kernel.Length - 1;

            var fftSize = MathUtils.NextPowerOfTwo(length);
            var fft     = new Fft64(fftSize);

            signal = signal.ZeroPadded(fftSize);
            kernel = kernel.ZeroPadded(fftSize);

            // 1) do FFT of both signals

            fft.Direct(signal.Real, signal.Imag);
            fft.Direct(kernel.Real, kernel.Imag);

            // 2) do complex multiplication of spectra

            var spectrum = signal.Multiply(kernel);

            // 3) do inverse FFT of resulting spectrum

            fft.Inverse(spectrum.Real, spectrum.Imag);

            // 3a) normalize

            for (var i = 0; i < spectrum.Length; i++)
            {
                spectrum.Real[i] /= fftSize;
                spectrum.Imag[i] /= fftSize;
            }

            // 4) return resulting meaningful part of the signal (truncate size to N + M - 1)

            return(new ComplexDiscreteSignal(signal.SamplingRate, spectrum.Real, spectrum.Imag).First(length));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Fast deconvolution via FFT for general complex-valued case.
        ///
        /// NOTE!
        ///
        /// Deconvolution is an experimental feature.
        /// It's problematic due to division by zero.
        ///
        /// </summary>
        /// <param name="signal"></param>
        /// <param name="kernel"></param>
        /// <param name="fftSize"></param>
        /// <returns></returns>
        public ComplexDiscreteSignal Deconvolve(ComplexDiscreteSignal signal, ComplexDiscreteSignal kernel, int fftSize = 0)
        {
            // first, try to divide polynomials

            var div = MathUtils.DividePolynomial(signal.Real.Zip(signal.Imag, (r, i) => new Complex(r, i)).ToArray(),
                                                 kernel.Real.Zip(kernel.Imag, (r, i) => new Complex(r, i)).ToArray());

            var quotient  = div[0];
            var remainder = div[1];

            if (remainder.All(d => Math.Abs(d.Real) < 1e-10) &&
                remainder.All(d => Math.Abs(d.Imaginary) < 1e-10))
            {
                return(new ComplexDiscreteSignal(signal.SamplingRate,
                                                 quotient.Select(q => q.Real),
                                                 quotient.Select(q => q.Imaginary)));
            }

            // ... deconvolve via FFT

            var length = signal.Length - kernel.Length + 1;

            if (fftSize == 0)
            {
                fftSize = MathUtils.NextPowerOfTwo(signal.Length);
            }

            var fft = new Fft64(fftSize);

            signal = signal.ZeroPadded(fftSize);
            kernel = kernel.ZeroPadded(fftSize);

            // 1) do FFT of both signals

            fft.Direct(signal.Real, signal.Imag);
            fft.Direct(kernel.Real, kernel.Imag);

            for (var i = 0; i < fftSize; i++)
            {
                signal.Real[i] += 1e-10;
                signal.Imag[i] += 1e-10;
                kernel.Real[i] += 1e-10;
                kernel.Imag[i] += 1e-10;
            }

            // 2) do complex division of spectra

            var spectrum = signal.Divide(kernel);

            // 3) do inverse FFT of resulting spectrum

            fft.Inverse(spectrum.Real, spectrum.Imag);

            // 4) return resulting meaningful part of the signal (truncate to N - M + 1)

            return(new ComplexDiscreteSignal(signal.SamplingRate,
                                             spectrum.Real.FastCopyFragment(length),
                                             spectrum.Imag.FastCopyFragment(length)));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// FIR filter design using frequency sampling method
        /// </summary>
        /// <param name="order">Filter order</param>
        /// <param name="magnitudeResponse">Magnitude response</param>
        /// <param name="phaseResponse">Phase response</param>
        /// <param name="window">Window</param>
        /// <returns>FIR filter kernel</returns>
        public static double[] Fir(int order,
                                   double[] magnitudeResponse,
                                   double[] phaseResponse = null,
                                   WindowTypes window     = WindowTypes.Blackman)
        {
            Guard.AgainstEvenNumber(order, "The order of the filter");

            var fftSize = MathUtils.NextPowerOfTwo(magnitudeResponse.Length);

            var real = phaseResponse == null?
                       magnitudeResponse.PadZeros(fftSize) :
                           magnitudeResponse.Zip(phaseResponse, (m, p) => m * Math.Cos(p)).ToArray();

            var imag = phaseResponse == null ?
                       new double[fftSize] :
                       magnitudeResponse.Zip(phaseResponse, (m, p) => m * Math.Sin(p)).ToArray();

            var fft = new Fft64(fftSize);

            fft.Inverse(real, imag);

            var kernel = new double[order];

            var compensation = 2.0 / fftSize;
            var middle       = order / 2;

            for (var i = 0; i <= middle; i++)
            {
                kernel[i]          = real[middle - i] * compensation;
                kernel[i + middle] = real[i] * compensation;
            }

            kernel.ApplyWindow(window);

            return(kernel);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Method for FIR filter design using window method
        /// </summary>
        /// <param name="order"></param>
        /// <param name="magnitudeResponse"></param>
        /// <param name="phaseResponse"></param>
        /// <param name="window"></param>
        /// <returns></returns>
        public static FirFilter Fir(int order, double[] magnitudeResponse, double[] phaseResponse = null, WindowTypes window = WindowTypes.Blackman)
        {
            if (order % 2 == 0)
            {
                throw new ArgumentException("The order of a filter must be an odd number!");
            }

            var fftSize = MathUtils.NextPowerOfTwo(magnitudeResponse.Length);

            var real = phaseResponse == null?
                       magnitudeResponse.PadZeros(fftSize) :
                           magnitudeResponse.Zip(phaseResponse, (m, p) => m * Math.Cos(p)).ToArray();

            var imag = phaseResponse == null ?
                       new double[fftSize] :
                       magnitudeResponse.Zip(phaseResponse, (m, p) => m * Math.Sin(p)).ToArray();

            var fft = new Fft64(fftSize);

            fft.Inverse(real, imag);

            var kernel = new double[order];

            var compensation = 2.0 / fftSize;
            var middle       = order / 2;

            for (var i = 0; i <= middle; i++)
            {
                kernel[i]          = real[middle - i] * compensation;
                kernel[i + middle] = real[i] * compensation;
            }

            kernel.ApplyWindow(window);

            return(new FirFilter(kernel));
        }