public void FourierRadix2MatchesNaive_RealSine(FourierOptions options) { var samples = Generate.PeriodicMap(16, w => new Complex(Math.Sin(w), 0), 16, 1.0, Constants.Pi2); Verify(samples, 12, options, Fourier.NaiveForward, Fourier.Radix2Forward); Verify(samples, 12, options, Fourier.NaiveInverse, Fourier.Radix2Inverse); }
public void FourierRadix2IsReversible(FourierOptions options) { var samples = Generate.RandomComplex(0x8000, GetUniform(1)); var work = new Complex[samples.Length]; samples.CopyTo(work, 0); Fourier.Radix2Forward(work, options); Assert.IsFalse(work.ListAlmostEqual(samples, 6)); Fourier.Radix2Inverse(work, options); AssertHelpers.AlmostEqual(samples, work, 12); }
/// <summary> /// Rescale FFT-the resulting vector according to the provided convention options. /// </summary> /// <param name="options">Fourier Transform Convention Options.</param> /// <param name="samples">Sample Vector.</param> private static void ForwardScaleByOptions(FourierOptions options, Complex[] samples) { if ((options & FourierOptions.NoScaling) == FourierOptions.NoScaling || (options & FourierOptions.AsymmetricScaling) == FourierOptions.AsymmetricScaling) { return; } var scalingFactor = Math.Sqrt(1.0 / samples.Length); for (int i = 0; i < samples.Length; i++) { samples[i] *= scalingFactor; } }
public void FourierBluesteinIsReversible(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = Generate.RandomComplex(0x7FFF, GetUniform(1)); var work = new Complex[samples.Length]; samples.CopyTo(work, 0); dft.BluesteinForward(work, options); Assert.IsFalse(work.ListAlmostEqual(samples, 6)); dft.BluesteinInverse(work, options); AssertHelpers.ListAlmostEqual(samples, work, 10); }
public void FourierRadix2IsReversible(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = SignalGenerator.Random((u, v) => new Complex(u, v), GetUniform(1), 0x8000); var work = new Complex[samples.Length]; samples.CopyTo(work, 0); dft.Radix2Forward(work, options); Assert.IsFalse(work.ListAlmostEqual(samples, 6)); dft.Radix2Inverse(work, options); AssertHelpers.ListAlmostEqual(samples, work, 12); }
static void Verify( Complex[] samples, int maximumErrorDecimalPlaces, FourierOptions options, Func<Complex[], FourierOptions, Complex[]> naive, Action<Complex[], FourierOptions> fast) { var spectrumNaive = naive(samples, options); var spectrumFast = new Complex[samples.Length]; samples.CopyTo(spectrumFast, 0); fast(spectrumFast, options); AssertHelpers.AlmostEqual(spectrumNaive, spectrumFast, maximumErrorDecimalPlaces); }
public void FourierBluesteinMatchesNaiveOnRandomNonPowerOfTwo(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = Generate.RandomComplex(0x7F, GetUniform(1)); VerifyMatchesNaiveComplex( samples, 10, s => dft.NaiveForward(s, options), s => dft.BluesteinForward(s, options)); VerifyMatchesNaiveComplex( samples, 10, s => dft.NaiveInverse(s, options), s => dft.BluesteinInverse(s, options)); }
public void FourierBluesteinMatchesNaiveOnRandomNonPowerOfTwo(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = SignalGenerator.Random((u, v) => new Complex(u, v), GetUniform(1), 0x7F); VerifyMatchesNaiveComplex( samples, 1e-12, s => dft.NaiveForward(s, options), s => dft.BluesteinForward(s, options)); VerifyMatchesNaiveComplex( samples, 1e-12, s => dft.NaiveInverse(s, options), s => dft.BluesteinInverse(s, options)); }
public void FourierBluesteinMatchesNaiveOnRandomPowerOfTwo(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = Sample.Random((u, v) => new Complex(u, v), _uniform, 0x80); VerifyMatchesNaiveComplex( samples, 1e-12, s => dft.NaiveForward(s, options), s => dft.BluesteinForward(s, options)); VerifyMatchesNaiveComplex( samples, 1e-12, s => dft.NaiveInverse(s, options), s => dft.BluesteinInverse(s, options)); }
public void NaiveMatchesDft(HartleyOptions hartleyOptions, FourierOptions fourierOptions) { var samples = Generate.Random(0x80, GetUniform(1)); VerifyMatchesDft( samples, 5, false, s => Fourier.Forward(s, fourierOptions), s => Hartley.NaiveForward(s, hartleyOptions)); VerifyMatchesDft( samples, 5, true, s => Fourier.Inverse(s, fourierOptions), s => Hartley.NaiveInverse(s, hartleyOptions)); }
public void FourierRadix2MatchesNaiveOnRealSine(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = SignalGenerator.EquidistantPeriodic(w => new Complex(Math.Sin(w), 0), Constants.Pi2, 0, 16); VerifyMatchesNaiveComplex( samples, 1e-12, s => dft.NaiveForward(s, options), s => dft.Radix2Forward(s, options)); VerifyMatchesNaiveComplex( samples, 1e-12, s => dft.NaiveInverse(s, options), s => dft.Radix2Inverse(s, options)); }
public void FourierBluesteinIsReversible(FourierOptions options) { var dft = new DiscreteFourierTransform(); VerifyIsReversibleComplex( 0x7FFF, 1e-12, s => { dft.BluesteinForward(s, options); return s; }, s => { dft.BluesteinInverse(s, options); return s; }); }
/// <summary> /// Rescale the iFFT-resulting vector according to the provided convention options. /// </summary> /// <param name="options">Fourier Transform Convention Options.</param> /// <param name="samples">Sample Vector.</param> private static void InverseScaleByOptions(FourierOptions options, Complex[] samples) { if ((options & FourierOptions.NoScaling) == FourierOptions.NoScaling) { return; } var scalingFactor = 1.0 / samples.Length; if ((options & FourierOptions.AsymmetricScaling) != FourierOptions.AsymmetricScaling) { scalingFactor = Math.Sqrt(scalingFactor); } for (int i = 0; i < samples.Length; i++) { samples[i] *= scalingFactor; } }
public void NaiveMatchesDft(HartleyOptions hartleyOptions, FourierOptions fourierOptions) { var dht = new DiscreteHartleyTransform(); var samples = SignalGenerator.Random(x => x, GetUniform(1), 0x80); VerifyMatchesDft( samples, 1e-5, false, s => Transform.FourierForward(s, fourierOptions), s => dht.NaiveForward(s, hartleyOptions)); VerifyMatchesDft( samples, 1e-5, true, s => Transform.FourierInverse(s, fourierOptions), s => dht.NaiveInverse(s, hartleyOptions)); }
public void NaiveMatchesDFT(HartleyOptions hartleyOptions, FourierOptions fourierOptions) { var dht = new DiscreteHartleyTransform(); var samples = Sample.Random(x => x, _uniform, 0x80); VerifyMatchesDFT( samples, 1e-10, false, s => Transform.FourierForward(s, fourierOptions), s => dht.NaiveForward(s, hartleyOptions)); VerifyMatchesDFT( samples, 1e-10, true, s => Transform.FourierInverse(s, fourierOptions), s => dht.NaiveInverse(s, hartleyOptions)); }
/// <summary> /// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors. /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public static void Forward(Complex32[] samples, FourierOptions options) { switch (options) { case FourierOptions.NoScaling: case FourierOptions.AsymmetricScaling: Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling); break; case FourierOptions.InverseExponent: Control.FourierTransformProvider.Backward(samples, FourierTransformScaling.SymmetricScaling); break; case FourierOptions.InverseExponent | FourierOptions.NoScaling: case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling: Control.FourierTransformProvider.Backward(samples, FourierTransformScaling.NoScaling); break; default: Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.SymmetricScaling); break; } }
/// <summary> /// Applies the forward Fast Fourier Transform (FFT) to multiple dimensional sample data. /// </summary> /// <param name="samples">Sample data, where the FFT is evaluated in place.</param> /// <param name="dimensions"> /// The data size per dimension. The first dimension is the major one. /// For example, with two dimensions "rows" and "columns" the samples are assumed to be organized row by row. /// </param> /// <param name="options">Fourier Transform Convention Options.</param> public static void ForwardMultiDim(Complex[] samples, int[] dimensions, FourierOptions options = FourierOptions.Default) { switch (options) { case FourierOptions.NoScaling: case FourierOptions.AsymmetricScaling: Control.FourierTransformProvider.ForwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling); break; case FourierOptions.InverseExponent: Control.FourierTransformProvider.BackwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling); break; case FourierOptions.InverseExponent | FourierOptions.NoScaling: case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling: Control.FourierTransformProvider.BackwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling); break; default: Control.FourierTransformProvider.ForwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling); break; } }
/// <summary> /// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors. /// </summary> /// <param name="real">Real part of the sample vector, where the FFT is evaluated in place.</param> /// <param name="imaginary">Imaginary part of the sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public static void Forward(float[] real, float[] imaginary, FourierOptions options = FourierOptions.Default) { if (real.Length != imaginary.Length) { throw new ArgumentException("The array arguments must have the same length."); } // TODO: consider to support this natively by the provider, without the need for copying // TODO: otherwise, consider ArrayPool Complex32[] data = new Complex32[real.Length]; for (int i = 0; i < data.Length; i++) { data[i] = new Complex32(real[i], imaginary[i]); } Forward(data, options); for (int i = 0; i < data.Length; i++) { real[i] = data[i].Real; imaginary[i] = data[i].Imaginary; } }
/// <summary> /// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors. /// </summary> /// <param name="real">Real part of the sample vector, where the FFT is evaluated in place.</param> /// <param name="imaginary">Imaginary part of the sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public static void Forward(double[] real, double[] imaginary, FourierOptions options = FourierOptions.Default) { if (real.Length != imaginary.Length) { throw new ArgumentException(Resources.ArgumentArraysSameLength); } // TODO: consider to support this natively by the provider, without the need for copying // TODO: otherwise, consider ArrayPool Complex[] data = new Complex[real.Length]; for (int i = 0; i < data.Length; i++) { data[i] = new Complex(real[i], imaginary[i]); } Forward(data, options); for (int i = 0; i < data.Length; i++) { real[i] = data[i].Real; imaginary[i] = data[i].Imaginary; } }
public static void Radix2Inverse(Complex32[] spectrum, FourierOptions options = FourierOptions.Default) { Inverse(spectrum, options); }
/// <summary> /// Applies the inverse Fast Fourier Transform (iFFT) to two dimensional sample data. /// </summary> /// <param name="spectrumRowWise">Sample data, organized row by row, where the iFFT is evaluated in place</param> /// <param name="rows">The number of rows.</param> /// <param name="columns">The number of columns.</param> /// <remarks>Data available organized column by column instead of row by row can be processed directly by swapping the rows and columns arguments.</remarks> /// <param name="options">Fourier Transform Convention Options.</param> public static void Inverse2D(Complex[] spectrumRowWise, int rows, int columns, FourierOptions options = FourierOptions.Default) { InverseMultiDim(spectrumRowWise, new[] { rows, columns }, options); }
/// <summary> /// Bluestein inverse FFT for arbitrary sized sample vectors. /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public void BluesteinInverse(Complex[] samples, FourierOptions options) { Bluestein(samples, -SignByOptions(options)); InverseScaleByOptions(options, samples); }
/// <summary> /// Naive inverse DFT, useful e.g. to verify faster algorithms. /// </summary> /// <param name="frequencySpace">Frequency-space sample vector.</param> /// <param name="options">Fourier Transform Convention Options.</param> /// <returns>Corresponding time-space vector.</returns> public Complex[] NaiveInverse(Complex[] frequencySpace, FourierOptions options) { var timeSpace = Naive(frequencySpace, -SignByOptions(options)); InverseScaleByOptions(options, timeSpace); return timeSpace; }
/// <summary> /// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors. /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public static void Inverse(Complex[] samples, FourierOptions options) { BluesteinInverse(samples, options); }
/// <summary> /// Extract the exponent sign to be used in forward transforms according to the /// provided convention options. /// </summary> /// <param name="options">Fourier Transform Convention Options.</param> /// <returns>Fourier series exponent sign.</returns> static int SignByOptions(FourierOptions options) { return((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent ? 1 : -1); }
/// <summary> /// Radix-2 forward FFT for power-of-two sized sample vectors. /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> /// <exception cref="ArgumentException"/> public static void Radix2Forward(Complex[] samples, FourierOptions options) { Radix2Parallel(samples, SignByOptions(options)); ForwardScaleByOptions(options, samples); }
/// <summary> /// Bluestein forward FFT for arbitrary sized sample vectors. /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public void BluesteinForward(Complex[] samples, FourierOptions options) { Bluestein(samples, SignByOptions(options)); ForwardScaleByOptions(options, samples); }
public void NaiveMatchesDft([Values(HartleyOptions.Default, HartleyOptions.AsymmetricScaling, HartleyOptions.NoScaling)] HartleyOptions hartleyOptions, [Values(FourierOptions.Default, FourierOptions.AsymmetricScaling, FourierOptions.NoScaling)] FourierOptions fourierOptions) { var dht = new DiscreteHartleyTransform(); var samples = SignalGenerator.Random(x => x, _uniform, 0x80); VerifyMatchesDft( samples, 1e-5, false, s => Transform.FourierForward(s, fourierOptions), s => dht.NaiveForward(s, hartleyOptions)); VerifyMatchesDft( samples, 1e-5, true, s => Transform.FourierInverse(s, fourierOptions), s => dht.NaiveInverse(s, hartleyOptions)); }
/// <summary> /// Bluestein forward FFT for arbitrary sized sample vectors. /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public static void BluesteinForward(Complex32[] samples, FourierOptions options = FourierOptions.Default) { Bluestein(samples, SignByOptions(options)); ForwardScaleByOptions(options, samples); }
public void FourierRadix2IsReversible(FourierOptions options) { var dft = new DiscreteFourierTransform(); VerifyIsReversibleComplex( 0x8000, 1e-12, s => { dft.Radix2Forward(s, options); return s; }, s => { dft.Radix2Inverse(s, options); return s; }); }
public void FourierNaiveIsReversible(FourierOptions options) { var dft = new DiscreteFourierTransform(); VerifyIsReversibleComplex( 0x80, 1e-12, s => dft.NaiveForward(s, options), s => dft.NaiveInverse(s, options)); }
public void FourierRadix2MatchesNaiveOnRandom(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = SignalGenerator.Random((u, v) => new Complex(u, v), GetUniform(1), 0x80); VerifyMatchesNaiveComplex( samples, 1e-12, s => dft.NaiveForward(s, options), s => dft.Radix2Forward(s, options)); VerifyMatchesNaiveComplex( samples, 1e-12, s => dft.NaiveInverse(s, options), s => dft.Radix2Inverse(s, options)); }
public void FourierRadix2MatchesNaiveOnRealSine(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = Generate.PeriodicMap(16, w => new Complex(Math.Sin(w), 0), 16, 1.0, Constants.Pi2); VerifyMatchesNaiveComplex( samples, 12, s => dft.NaiveForward(s, options), s => dft.Radix2Forward(s, options)); VerifyMatchesNaiveComplex( samples, 12, s => dft.NaiveInverse(s, options), s => dft.Radix2Inverse(s, options)); }
public static void BluesteinInverse(Complex[] spectrum, FourierOptions options = FourierOptions.Default) { Inverse(spectrum, options); }
public void FourierRadix2MatchesNaiveOnRandom(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = Generate.RandomComplex(0x80, GetUniform(1)); VerifyMatchesNaiveComplex( samples, 10, s => dft.NaiveForward(s, options), s => dft.Radix2Forward(s, options)); VerifyMatchesNaiveComplex( samples, 10, s => dft.NaiveInverse(s, options), s => dft.Radix2Inverse(s, options)); }
/// <summary> /// Naive forward DFT, useful e.g. to verify faster algorithms. /// </summary> public static void Forward(Complex[] samples, FourierOptions options = FourierOptions.Default) { Naive(samples, SignByOptions(options)); ForwardScaleByOptions(options, samples); }
/// <summary> /// Radix-2 inverse FFT for power-of-two sized sample vectors. /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> /// <exception cref="ArgumentException"/> public static void Radix2Inverse(Complex[] samples, FourierOptions options) { Radix2Parallel(samples, -SignByOptions(options)); InverseScaleByOptions(options, samples); }
/// <summary> /// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors. /// </summary> /// <param name="samples">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public static void Forward(Complex[] samples, FourierOptions options) { BluesteinForward(samples, options); }
/// <summary> /// Extract the exponent sign to be used in forward transforms according to the /// provided convention options. /// </summary> /// <param name="options">Fourier Transform Convention Options.</param> /// <returns>Fourier series exponent sign.</returns> static int SignByOptions(FourierOptions options) { return (options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent ? 1 : -1; }
/// <summary> /// Naive forward DFT, useful e.g. to verify faster algorithms. /// </summary> /// <param name="timeSpace">Time-space sample vector.</param> /// <param name="options">Fourier Transform Convention Options.</param> /// <returns>Corresponding frequency-space vector.</returns> public Complex[] NaiveForward(Complex[] timeSpace, FourierOptions options) { var frequencySpace = Naive(timeSpace, SignByOptions(options)); ForwardScaleByOptions(options, frequencySpace); return frequencySpace; }
/// <summary> /// Applies the forward Fast Fourier Transform (FFT) to two dimensional sample data. /// </summary> /// <param name="samplesRowWise">Sample data, organized row by row, where the FFT is evaluated in place</param> /// <param name="rows">The number of rows.</param> /// <param name="columns">The number of columns.</param> /// <remarks>Data available organized column by column instead of row by row can be processed directly by swapping the rows and columns arguments.</remarks> /// <param name="options">Fourier Transform Convention Options.</param> public static void Forward2D(Complex[] samplesRowWise, int rows, int columns, FourierOptions options = FourierOptions.Default) { ForwardMultiDim(samplesRowWise, new[] { rows, columns }, options); }
/// <summary> /// Naive inverse DFT, useful e.g. to verify faster algorithms. /// </summary> public static void Inverse(Complex32[] spectrum, FourierOptions options = FourierOptions.Default) { Naive(spectrum, -SignByOptions(options)); InverseScaleByOptions(options, spectrum); }
public static void Radix2Forward(Complex[] samples, FourierOptions options = FourierOptions.Default) { Forward(samples, options); }
/// <summary> /// Radix-2 inverse FFT for power-of-two sized sample vectors. /// </summary> /// <param name="spectrum">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> /// <exception cref="ArgumentException"/> public static void Radix2Inverse(Complex[] spectrum, FourierOptions options = FourierOptions.Default) { Radix2Parallel(spectrum, -SignByOptions(options)); InverseScaleByOptions(options, spectrum); }
public static void BluesteinForward(Complex[] samples, FourierOptions options = FourierOptions.Default) { Forward(samples, options); }
/// <summary> /// Bluestein inverse FFT for arbitrary sized sample vectors. /// </summary> /// <param name="spectrum">Sample vector, where the FFT is evaluated in place.</param> /// <param name="options">Fourier Transform Convention Options.</param> public static void BluesteinInverse(Complex[] spectrum, FourierOptions options = FourierOptions.Default) { Bluestein(spectrum, -SignByOptions(options)); InverseScaleByOptions(options, spectrum); }
public void FourierBluesteinMatchesNaiveOnRealSineNonPowerOfTwo(FourierOptions options) { var dft = new DiscreteFourierTransform(); var samples = Generate.PeriodicMap(14, w => new Complex(Math.Sin(w), 0), 14, 1.0, Constants.Pi2); VerifyMatchesNaiveComplex( samples, 12, s => dft.NaiveForward(s, options), s => dft.BluesteinForward(s, options)); VerifyMatchesNaiveComplex( samples, 12, s => dft.NaiveInverse(s, options), s => dft.BluesteinInverse(s, options)); }
public FourierEventArgs(System.Numerics.Complex[] Samples, FourierOptions AppliedOptions) { this.Samples = Samples; this.AppliedOptions = AppliedOptions; }