Пример #1
0
        public void TestExtendAntisymmetricWholePoint()
        {
            var points   = new double[] { 2, 6, 1, 6, 5, 4, 5, 3, 4 };
            var extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.AntisymmetricWholePoint, 3);
            var expected = new double[] { -2, 3, -2, 2, 6, 1, 6, 5, 4, 5, 3, 4, 5, 3, 4 };

            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 2, 6, 1 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.AntisymmetricWholePoint, 1);
            expected = new double[] { -2, 2, 6, 1, -4 };
            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 2 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.AntisymmetricWholePoint, 1);
            expected = new double[] { -2, 2, -2 };
            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.AntisymmetricWholePoint, 1);
            expected = new double[] { 0, 0 };
            Assert.IsTrue(extended.SequenceEqual(expected));

            points = new double[] { 2, 6, 1, 6, 5, 0 };
            SignalExtension.Extend(points, SignalExtension.ExtensionMode.AntisymmetricWholePoint, 8);
        }
Пример #2
0
        private static Signal RescaleSignal(Signal decomposition, Signal signal, DecompositionLevel level)
        {
            var rescaled = WaveMath.InterpolateCubic(decomposition, (uint)Math.Pow(2, level.Index + 1));

            if (rescaled.SamplesCount < signal.SamplesCount)
            {
                var extensionSize = signal.SamplesCount - rescaled.SamplesCount;
                int right;
                var left = right = extensionSize / 2;
                if (left + right != extensionSize)
                {
                    left++;
                }

                SignalExtension.Extend(ref rescaled, SignalExtension.ExtensionMode.SmoothPadding0, left, right);
            }
            else
            {
                rescaled.Samples = SignalExtension.Deextend(rescaled.Samples, signal.SamplesCount);
            }
            rescaled.CustomPlot       = null;
            rescaled.Finish           = signal.Finish;
            rescaled.SamplingRate     = signal.SamplingRate;
            rescaled.SamplingInterval = signal.SamplingInterval;
            return(rescaled);
        }
Пример #3
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));
 }
Пример #4
0
        /// <summary>
        /// Multilevel 1-D Discreete Wavelet Transform
        /// </summary>
        /// <param name="signal">The signal. Example: new Signal(5, 6, 7, 8, 1, 2, 3, 4)</param>
        /// <param name="motherWavelet">The mother wavelet to be used. Example: CommonMotherWavelets.GetWaveletFromName("DB4")</param>
        /// <param name="level">The depth-level to perform the DWT</param>
        /// <param name="extensionMode">Signal extension mode</param>
        /// <param name="convolutionMode">Defines what convolution function should be used</param>
        /// <returns></returns>
        public static List <DecompositionLevel> ExecuteDWT(Signal signal, MotherWavelet motherWavelet, int level, SignalExtension.ExtensionMode extensionMode = SignalExtension.ExtensionMode.SymmetricHalfPoint, ConvolutionModeEnum convolutionMode = ConvolutionModeEnum.ManagedFFT)
        {
            var levels = new List <DecompositionLevel>();

            var approximation = (double[])signal.Samples.Clone();
            var details       = (double[])signal.Samples.Clone();

            var realLength = signal.Samples.Length;

            for (var i = 1; i <= level; i++)
            {
                var extensionSize = motherWavelet.Filters.DecompositionLowPassFilter.Length - 1;

                approximation = SignalExtension.Extend(approximation, extensionMode, extensionSize);
                details       = SignalExtension.Extend(details, extensionMode, extensionSize);

                approximation = WaveMath.Convolve(convolutionMode, approximation, motherWavelet.Filters.DecompositionLowPassFilter);
                approximation = WaveMath.DownSample(approximation);

                details = WaveMath.Convolve(convolutionMode, details, motherWavelet.Filters.DecompositionHighPassFilter);
                details = WaveMath.DownSample(details);

                realLength = realLength / 2;

                levels.Add(new DecompositionLevel
                {
                    Signal        = signal,
                    Index         = i - 1,
                    Approximation = approximation,
                    Details       = details
                });
                details = (double[])approximation.Clone();
            }
            return(levels);
        }
Пример #5
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;
            }
        }
Пример #6
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;
            }
        }
Пример #7
0
        public void TestDeextend()
        {
            var points     = new double[] { 2, 6, 1, 6, 5, 0, 4, 5, 3, 4 };
            var extended   = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SymmetricHalfPoint, 100);
            var deextended = SignalExtension.Deextend(extended, points.Length);

            Assert.IsTrue(deextended.SequenceEqual(points));

            points     = new double[] { 1, 2 };
            deextended = SignalExtension.Deextend(points, 1);
            Assert.IsTrue(deextended.SequenceEqual(points));
        }
Пример #8
0
        public void TestExtendAntisymmetricHalfPoint()
        {
            var points   = new double[] { 2, 6, 1, 6, 5, 0, 4, 5, 3, 4 };
            var extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.AntisymmetricHalfPoint, 3);
            var expected = new double[] { -1, -6, -2, 2, 6, 1, 6, 5, 0, 4, 5, 3, 4, -4, -3, -5 };

            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 2, 6, 1 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.AntisymmetricHalfPoint, 1);
            expected = new double[] { -2, 2, 6, 1, -1 };
            Assert.IsTrue(extended.SequenceEqual(expected));
        }
Пример #9
0
        public void TestExtendSmoothPadding0()
        {
            var points   = new double[] { 2, 6, 1, 6, 5, 0, 4, 5, 3, 4 };
            var extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SmoothPadding0, 3);
            var expected = new double[] { 2, 2, 2, 2, 6, 1, 6, 5, 0, 4, 5, 3, 4, 4, 4, 4 };

            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 2, 6, 1 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SmoothPadding0, 1);
            expected = new double[] { 2, 2, 6, 1, 1 };
            Assert.IsTrue(extended.SequenceEqual(expected));
        }
Пример #10
0
        public void TestExtendZeroPadding()
        {
            var points   = new double[] { 2, 6, 1, 6, 5, 0, 4, 5, 3, 4 };
            var extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.ZeroPadding, 3);
            var expected = new double[] { 0, 0, 0, 2, 6, 1, 6, 5, 0, 4, 5, 3, 4, 0, 0, 0 };

            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 2, 6, 1 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.ZeroPadding, 1);
            expected = new double[] { 0, 2, 6, 1, 0 };
            Assert.IsTrue(extended.SequenceEqual(expected));
        }
Пример #11
0
        public void TestExtendSignal()
        {
            var points = new double[] { 2, 6, 1, 6, 5, 0, 4, 5, 3, 4 };
            var signal = new Signal(points)
            {
                Start = 0, Finish = 9, SamplingRate = 1, SamplingInterval = 1
            };
            var expected = new double[] { 2, 2, 2, 2, 6, 1, 6, 5, 0, 4, 5, 3, 4, 4, 4, 4 };

            SignalExtension.Extend(ref signal, SignalExtension.ExtensionMode.SmoothPadding0, 3, 3);
            Assert.IsTrue(signal.Samples.SequenceEqual(expected));
            Assert.AreEqual(-3, signal.Start);
            Assert.AreEqual(12, signal.Finish);
        }
Пример #12
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);
        }
Пример #13
0
        public void TestExtendSymmetricHalfPoint()
        {
            var points   = new double[] { 2, 6, 1, 6, 5, 0, 4, 5, 3, 4 };
            var extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SymmetricHalfPoint, 3);
            var expected = new double[] { 1, 6, 2, 2, 6, 1, 6, 5, 0, 4, 5, 3, 4, 4, 3, 5 };

            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 2, 6, 1 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SymmetricHalfPoint, 1);
            expected = new double[] { 2, 2, 6, 1, 1 };
            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 2, 6, 1, 6, 5, 0 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SymmetricHalfPoint, 1);
            expected = new double[] { 2, 2, 6, 1, 6, 5, 0, 0 };
            Assert.IsTrue(extended.SequenceEqual(expected));
        }
Пример #14
0
        public void TestExtendSmoothPadding1()
        {
            var points   = new double[] { 2, 6, 1, 6, 5, 0, 4, 5, 3, 4 };
            var extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SmoothPadding1, 3);
            var expected = new double[] { -10, -6, -2, 2, 6, 1, 6, 5, 0, 4, 5, 3, 4, 5, 6, 7 };

            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 7, 6, 1, 6, 5, 0, 4, 5, 3, 1 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SmoothPadding1, 3);
            expected = new double[] { 10, 9, 8, 7, 6, 1, 6, 5, 0, 4, 5, 3, 1, -1, -3, -5 };
            Assert.IsTrue(extended.SequenceEqual(expected));

            points   = new double[] { 2, 6, 1 };
            extended = SignalExtension.Extend(points, SignalExtension.ExtensionMode.SmoothPadding1, 1);
            expected = new double[] { -2, 2, 6, 1, -4 };
            Assert.IsTrue(extended.SequenceEqual(expected));
        }
Пример #15
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();
            }
        }
Пример #16
0
        /// <summary>
        /// Multilevel inverse discrete 1-D wavelet transform
        /// </summary>
        /// <param name="decompositionLevels">The decomposition levels of the DWT</param>
        /// <param name="motherWavelet">The mother wavelet to be used. Example: CommonMotherWavelets.GetWaveletFromName("DB4") </param>
        /// <param name="level">The depth-level to perform the DWT</param>
        /// <param name="convolutionMode">Defines what convolution function should be used</param>
        /// <returns></returns>
        public static double[] ExecuteIDWT(List <DecompositionLevel> decompositionLevels, MotherWavelet motherWavelet, int level = 0, ConvolutionModeEnum convolutionMode = ConvolutionModeEnum.ManagedFFT)
        {
            if (level == 0 || level > decompositionLevels.Count)
            {
                level = decompositionLevels.Count;
            }
            if (level <= 0)
            {
                return(null);
            }
            var approximation = (double[])decompositionLevels[level - 1].Approximation.Clone();
            var details       = (double[])decompositionLevels[level - 1].Details.Clone();

            for (var i = level - 1; i >= 0; i--)
            {
                approximation = WaveMath.UpSample(approximation);
                approximation = WaveMath.Convolve(convolutionMode, approximation, motherWavelet.Filters.ReconstructionLowPassFilter, true, -1);

                details = WaveMath.UpSample(details);
                details = WaveMath.Convolve(convolutionMode, details, motherWavelet.Filters.ReconstructionHighPassFilter, true, -1);

                //sum approximation with details
                approximation = WaveMath.Add(approximation, details);

                if (i <= 0)
                {
                    continue;
                }
                if (approximation.Length > decompositionLevels[i - 1].Details.Length)
                {
                    approximation = SignalExtension.Deextend(approximation, decompositionLevels[i - 1].Details.Length);
                }

                details = (double[])decompositionLevels[i - 1].Details.Clone();
            }

            return(approximation);
        }
Пример #17
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);
            }
        }
Пример #18
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);
        }