예제 #1
0
 public void TestNextPowerOf2()
 {
     Assert.AreEqual(1024, SignalExtension.NextPowerOf2(1000));
     Assert.AreEqual(2048, SignalExtension.NextPowerOf2(1024));
     Assert.AreEqual(1, SignalExtension.NextPowerOf2(0));
     Assert.AreEqual(0, SignalExtension.NextPowerOf2(-100));
 }
예제 #2
0
        /// <summary>
        /// Compute the forward or inverse Fourier Transform of data, with data
        /// containing complex valued data as alternating real and imaginary
        /// parts. The length must be a power of 2. This method caches values
        /// and should be slightly faster on repeated uses than then FFT method.
        /// It is also slightly more accurate.
        /// </summary>
        /// <param name="data">The complex data stored as alternating real
        /// and imaginary parts</param>
        /// <param name="forward">true for a forward transform, false for
        /// inverse transform</param>
        public void TableFFT(ref double[] data, bool forward)
        {
            var n = data.Length;

            // checks n is a power of 2 in 2's complement format
            if ((n & (n - 1)) != 0)
            {
                data = data.SubArray(SignalExtension.NextPowerOf2(n));
                n    = data.Length;
            }
            n /= 2;               // n is the number of samples

            Reverse(ref data, n); // bit index data reversal

            // make table if needed
            if (_cosTable.Count != n)
            {
                Initialize(n);
            }

            // do transform: so single point transforms, then doubles, etc.
            double sign = forward ? 1 : -1;
            var    mmax = 1;
            var    tptr = 0;

            while (n > mmax)
            {
                var istep = 2 * mmax;
                for (var m = 0; m < istep; m += 2)
                {
                    var wr = _cosTable[tptr];
                    var wi = sign * _sinTable[tptr++];
                    for (var k = m; k < 2 * n; k += 2 * istep)
                    {
                        var j     = k + istep;
                        var tempr = wr * data[j] - wi * data[j + 1];
                        var tempi = wi * data[j] + wr * data[j + 1];
                        data[j]     = data[k] - tempr;
                        data[j + 1] = data[k + 1] - tempi;
                        data[k]     = data[k] + tempr;
                        data[k + 1] = data[k + 1] + tempi;
                    }
                }
                mmax = istep;
            }

            // copy out with optional scaling
            if (forward)
            {
                return;
            }

            var scale = 1.0 / n;

            for (var i = 0; i < 2 * n; ++i)
            {
                data[i] *= scale;
            }
        }
예제 #3
0
        /// <summary>
        /// Compute the forward or inverse Fourier Transform of data, with
        /// data containing complex valued data as alternating real and
        /// imaginary parts. The length must be a power of 2.
        /// </summary>
        /// <param name="data">The complex data stored as alternating real
        /// and imaginary parts</param>
        /// <param name="forward">true for a forward transform, false for
        /// inverse transform</param>
        public void DynamicFFT(ref double[] data, bool forward)
        {
            var n = data.Length;

            // checks n is a power of 2 in 2's complement format
            if ((n & (n - 1)) != 0)
            {
                data = data.SubArray(SignalExtension.NextPowerOf2(n));
                n    = data.Length;
            }
            n /= 2;               // n is the number of samples

            Reverse(ref data, n); // bit index data reversal

            // do transform: so single point transforms, then doubles, etc.
            double sign = forward ? 1 : -1;
            var    mmax = 1;

            while (n > mmax)
            {
                var    istep = 2 * mmax;
                var    theta = sign * Math.PI / mmax;
                double wr = 1, wi = 0;
                var    wpr = Math.Cos(theta);
                var    wpi = Math.Sin(theta);
                for (var m = 0; m < istep; m += 2)
                {
                    for (var k = m; k < 2 * n; k += 2 * istep)
                    {
                        var j     = k + istep;
                        var tempr = wr * data[j] - wi * data[j + 1];
                        var tempi = wi * data[j] + wr * data[j + 1];
                        data[j]     = data[k] - tempr;
                        data[j + 1] = data[k + 1] - tempi;
                        data[k]     = data[k] + tempr;
                        data[k + 1] = data[k + 1] + tempi;
                    }
                    var t = wr; // trig recurrence
                    wr = wr * wpr - wi * wpi;
                    wi = wi * wpr + t * wpi;
                }
                mmax = istep;
            }

            // inverse scaling in the backward case
            if (forward)
            {
                return;
            }
            var scale = 1.0 / n;

            for (var i = 0; i < 2 * n; ++i)
            {
                data[i] *= scale;
            }
        }
예제 #4
0
        static bool Test(FFTAction fftFunction, double[] test, IList <double> answer)
        {
            // Test the given function on the given data and see if the result is the given answer.

            var returnValue = true;
            var copy        = test.ToArray(); // make a copy

            if ((test.Length & (test.Length - 1)) != 0)
            {
                test = test.SubArray(SignalExtension.NextPowerOf2(test.Length));
            }
            fftFunction(ref copy, true);          // forward transform
            returnValue &= Compare(copy, answer); // check it
            fftFunction(ref copy, false);         // backward transform
            returnValue &= Compare(copy, test);   // check it
            return(returnValue);
        }
예제 #5
0
        /// <summary>
        /// Executes the block
        /// </summary>
        public override void Execute()
        {
            var connectingNode = InputNodes[0].ConnectingNode as BlockOutputNode;

            if (connectingNode == null || connectingNode.Object == null)
            {
                return;
            }

            int beforeSize = 0, afterSize = 0;

            if (ExtensionSize > 0)
            {
                beforeSize = ExtensionSize;
                afterSize  = ExtensionSize;
            }
            OutputNodes[0].Object.Clear();
            foreach (var signal in connectingNode.Object)
            {
                if (ExtensionSize <= 0)
                {
                    var size = SignalExtension.NextPowerOf2(signal.Samples.Length);
                    beforeSize = afterSize = (size - signal.Samples.Length) / 2;
                    while (beforeSize + afterSize + signal.Samples.Length < size)
                    {
                        afterSize++;
                    }
                }

                var output = signal.Clone();
                SignalExtension.Extend(ref output, ExtensionMode, beforeSize, afterSize);
                OutputNodes[0].Object.Add(output);
            }

            if (Cascade && OutputNodes[0].ConnectingNode != null)
            {
                OutputNodes[0].ConnectingNode.Root.Execute();
            }
        }
예제 #6
0
        /// <summary>
        /// Compute the forward or inverse Fourier Transform of data, with
        /// data containing real valued data only. The output is complex
        /// valued after the first two entries, stored in alternating real
        /// and imaginary parts. The first two returned entries are the real
        /// parts of the first and last value from the conjugate symmetric
        /// output, which are necessarily real. The length must be a power
        /// of 2.
        /// </summary>
        /// <param name="data">The complex data stored as alternating real
        /// and imaginary parts</param>
        /// <param name="forward">true for a forward transform, false for
        /// inverse transform</param>
        public void RealFFT(ref double[] data, bool forward)
        {
            var n = data.Length; // # of real inputs, 1/2 the complex length

            // checks n is a power of 2 in 2's complement format
            if ((n & (n - 1)) != 0)
            {
                data = data.SubArray(SignalExtension.NextPowerOf2(n));
                n    = data.Length;
            }

            double sign = -1;

            if (forward)
            {
                // do packed FFT. This can be changed to FFT to save memory
                TableFFT(ref data, true);
                sign = 1;
            }

            var theta = sign * 2 * Math.PI / n;
            var wpr   = Math.Cos(theta);
            var wpi   = Math.Sin(theta);
            var wjr   = wpr;
            var wji   = wpi;

            for (var j = 1; j <= n / 4; ++j)
            {
                var k   = n / 2 - j;
                var tnr = data[2 * k];
                var tni = data[2 * k + 1];
                var tjr = data[2 * j];
                var tji = data[2 * j + 1];

                var e = (tjr + tnr);
                var f = (tji - tni);
                var a = (tjr - tnr) * wji;
                var d = (tji + tni) * wji;
                var b = (tji + tni) * wjr;
                var c = (tjr - tnr) * wjr;

                // compute entry y[j]
                data[2 * j]     = 0.5 * (e + sign * (a + b));
                data[2 * j + 1] = 0.5 * (f - sign * (c - d));

                // compute entry y[k]
                data[2 * k]     = 0.5 * (e - sign * (a + b));
                data[2 * k + 1] = 0.5 * (sign * (-c + d) - f);

                var temp = wjr;
                // todo - allow more accurate version here? make option?
                wjr = wjr * wpr - wji * wpi;
                wji = temp * wpi + wji * wpr;
            }

            if (forward)
            {
                // compute final y0 and y_{N/2}, store data[0], data[1]
                var temp = data[0];
                data[0] += data[1];
                data[1]  = temp - data[1];
            }
            else
            {
                var temp = data[0]; // unpack the y[j], then invert FFT
                data[0] = 0.5 * (temp + data[1]);
                data[1] = 0.5 * (temp - data[1]);
                // do packed FFT. This can be changed to FFT to save memory
                TableFFT(ref data, false);
            }
        }
예제 #7
0
        /// <summary>
        /// Convolves vectors input and filter using a managed FFT algorithm.
        /// </summary>
        /// <param name="input">The input signal</param>
        /// <param name="filter">The filter</param>
        /// <param name="returnOnlyValid">True to return only the middle of the array</param>
        /// <param name="margin">Margin to be used if returnOnlyValid is set to true</param>
        /// <param name="mode">Mode</param>
        /// <returns></returns>
        public static double[] ConvolveManagedFFT(double[] input, double[] filter, bool returnOnlyValid = true, int margin = 0, ManagedFFTModeEnum mode = ManagedFFTModeEnum.UseLookupTable)
        {
            if (input == null || filter == null)
            {
                return(null);
            }
            if (input.Length < filter.Length)
            {
                var auxSignal = input;
                input  = filter;
                filter = auxSignal;
            }
            var realSize  = input.Length + filter.Length - 1;
            var size      = ((realSize > 0) && ((realSize & (realSize - 1)) == 0) ? realSize : SignalExtension.NextPowerOf2(realSize));
            var inputFFT  = MemoryPool.Pool.New <double>(size * 2);
            var filterFFT = MemoryPool.Pool.New <double>(size * 2);
            var ifft      = MemoryPool.Pool.New <double>(size * 2);

            for (var i = 0; i < input.Length; i++)
            {
                inputFFT[i * 2] = input[i];
            }
            for (var i = 0; i < filter.Length; i++)
            {
                filterFFT[i * 2] = filter[i];
            }

            ManagedFFT.Instance.FFT(ref inputFFT, true, mode);
            ManagedFFT.Instance.FFT(ref filterFFT, true, mode);
            for (var i = 0; i < ifft.Length; i = i + 2)
            {
                ifft[i]     = inputFFT[i] * filterFFT[i] - inputFFT[i + 1] * filterFFT[i + 1];
                ifft[i + 1] = (inputFFT[i] * filterFFT[i + 1] + inputFFT[i + 1] * filterFFT[i]) * -1;
            }
            ManagedFFT.Instance.FFT(ref ifft, false, mode);

            var ifft2 = MemoryPool.Pool.New <double>(size);

            ifft2[0] = ifft[0];
            for (var i = 0; i < ifft2.Length - 2; i = i + 1)
            {
                ifft2[i + 1] = ifft[ifft.Length - 2 - i * 2];
            }
            int start;

            if (returnOnlyValid)
            {
                size = input.Length - filter.Length + 1;
                var padding = (realSize - size) / 2;
                start = padding + margin;
                size  = input.Length - filter.Length - margin * 2 + 1;
            }
            else
            {
                start = 0;
                size  = realSize;
            }
            var result = MemoryPool.Pool.New <double>(size);

            Array.Copy(ifft2, start, result, 0, size);
            return(result);
        }