Browse Source

FFT: real-complex, packed

pull/445/head
Christoph Ruegg 10 years ago
parent
commit
de9e8d101d
  1. 112
      src/Numerics/IntegralTransforms/Fourier.cs
  2. 2
      src/Numerics/Properties/Resources.Designer.cs
  3. 2
      src/Numerics/Properties/Resources.resx
  4. 12
      src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs
  5. 34
      src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs
  6. 66
      src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs
  7. 15
      src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs
  8. 4
      src/UnitTests/Providers/FourierTransform/FourierTransformProviderTests.cs

112
src/Numerics/IntegralTransforms/Fourier.cs

@ -50,7 +50,7 @@ namespace MathNet.Numerics.IntegralTransforms
/// <param name="samples">Sample vector, where the FFT is evaluated in place.</param>
public static void Forward(Complex[] samples)
{
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.SymmetricScaling);
}
/// <summary>
@ -64,17 +64,17 @@ namespace MathNet.Numerics.IntegralTransforms
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.NoScaling);
Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent:
Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.Backward(samples, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.BackwardInplace(samples, FourierTransformScaling.NoScaling);
Control.FourierTransformProvider.Backward(samples, FourierTransformScaling.NoScaling);
break;
default:
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.SymmetricScaling);
break;
}
}
@ -110,14 +110,38 @@ namespace MathNet.Numerics.IntegralTransforms
}
}
public static void ForwardReal(double[] samples, FourierOptions options = FourierOptions.Default)
/// <summary>
/// Packed Real-Complex forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
/// Since for real-valued time samples the complex spectrum is conjugate-even (symmetry),
/// the spectrum can be fully reconstructed form the positive frequencies only (first half).
/// The data array needs to be N+2 (if N is even) or N+1 (if N is odd) long in order to support such a packed spectrum.
/// </summary>
/// <param name="data">Data array of length N+2 (if N is even) or N+1 (if N is odd).</param>
/// <param name="n">The number of samples.</param>
/// <param name="options">Fourier Transform Convention Options.</param>
public static void ForwardReal(double[] data, int n, FourierOptions options = FourierOptions.Default)
{
if (real.Length != imaginary.Length)
int length = n.IsEven() ? n + 2 : n + 1;
if (data.Length < length)
{
throw new ArgumentException(Resources.ArgumentArraysSameLength);
throw new ArgumentException(string.Format(Resources.ArrayTooSmall, length));
}
int length = real.Length/2;
if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
{
throw new NotSupportedException();
}
switch (options)
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.ForwardReal(data, n, FourierTransformScaling.NoScaling);
break;
default:
Control.FourierTransformProvider.ForwardReal(data, n, FourierTransformScaling.SymmetricScaling);
break;
}
}
/// <summary>
@ -135,17 +159,17 @@ namespace MathNet.Numerics.IntegralTransforms
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.ForwardInplaceMultidim(samples, dimensions, FourierTransformScaling.NoScaling);
Control.FourierTransformProvider.ForwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent:
Control.FourierTransformProvider.BackwardInplaceMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.BackwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.BackwardInplaceMultidim(samples, dimensions, FourierTransformScaling.NoScaling);
Control.FourierTransformProvider.BackwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling);
break;
default:
Control.FourierTransformProvider.ForwardInplaceMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.ForwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling);
break;
}
}
@ -191,7 +215,7 @@ namespace MathNet.Numerics.IntegralTransforms
/// <param name="spectrum">Spectrum data, where the iFFT is evaluated in place.</param>
public static void Inverse(Complex[] spectrum)
{
Control.FourierTransformProvider.BackwardInplace(spectrum, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
}
/// <summary>
@ -204,22 +228,22 @@ namespace MathNet.Numerics.IntegralTransforms
switch (options)
{
case FourierOptions.NoScaling:
Control.FourierTransformProvider.BackwardInplace(spectrum, FourierTransformScaling.NoScaling);
Control.FourierTransformProvider.Backward(spectrum, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.BackwardInplace(spectrum, FourierTransformScaling.BackwardScaling);
Control.FourierTransformProvider.Backward(spectrum, FourierTransformScaling.BackwardScaling);
break;
case FourierOptions.InverseExponent:
Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.Forward(spectrum, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.NoScaling);
Control.FourierTransformProvider.Forward(spectrum, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.ForwardScaling);
Control.FourierTransformProvider.Forward(spectrum, FourierTransformScaling.ForwardScaling);
break;
default:
Control.FourierTransformProvider.BackwardInplace(spectrum, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
break;
}
}
@ -255,6 +279,42 @@ namespace MathNet.Numerics.IntegralTransforms
}
}
/// <summary>
/// Packed Real-Complex inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
/// Since for real-valued time samples the complex spectrum is conjugate-even (symmetry),
/// the spectrum can be fully reconstructed form the positive frequencies only (first half).
/// The data array needs to be N+2 (if N is even) or N+1 (if N is odd) long in order to support such a packed spectrum.
/// </summary>
/// <param name="data">Data array of length N+2 (if N is even) or N+1 (if N is odd).</param>
/// <param name="n">The number of samples.</param>
/// <param name="options">Fourier Transform Convention Options.</param>
public static void InverseReal(double[] data, int n, FourierOptions options = FourierOptions.Default)
{
int length = n.IsEven() ? n + 2 : n + 1;
if (data.Length < length)
{
throw new ArgumentException(string.Format(Resources.ArrayTooSmall, length));
}
if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
{
throw new NotSupportedException();
}
switch (options)
{
case FourierOptions.NoScaling:
Control.FourierTransformProvider.BackwardReal(data, n, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.BackwardReal(data, n, FourierTransformScaling.BackwardScaling);
break;
default:
Control.FourierTransformProvider.BackwardReal(data, n, FourierTransformScaling.SymmetricScaling);
break;
}
}
/// <summary>
/// Applies the inverse Fast Fourier Transform (iFFT) to multiple dimensional sample data.
/// </summary>
@ -269,22 +329,22 @@ namespace MathNet.Numerics.IntegralTransforms
switch (options)
{
case FourierOptions.NoScaling:
Control.FourierTransformProvider.BackwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling);
Control.FourierTransformProvider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.BackwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.BackwardScaling);
Control.FourierTransformProvider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.BackwardScaling);
break;
case FourierOptions.InverseExponent:
Control.FourierTransformProvider.ForwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
Control.FourierTransformProvider.ForwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling);
Control.FourierTransformProvider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
Control.FourierTransformProvider.ForwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.ForwardScaling);
Control.FourierTransformProvider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.ForwardScaling);
break;
default:
Control.FourierTransformProvider.BackwardInplaceMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling);
break;
}
}

2
src/Numerics/Properties/Resources.Designer.cs

@ -90,7 +90,7 @@ namespace MathNet.Numerics.Properties {
}
/// <summary>
/// Looks up a localized string similar to The given array is the wrong length. Should be {0}..
/// Looks up a localized string similar to The given array has the wrong length. Should be {0}..
/// </summary>
public static string ArgumentArrayWrongLength {
get {

2
src/Numerics/Properties/Resources.resx

@ -370,7 +370,7 @@
<value>The given array is too small. It must be at least {0} long.</value>
</data>
<data name="ArgumentArrayWrongLength" xml:space="preserve">
<value>The given array is the wrong length. Should be {0}.</value>
<value>The given array has the wrong length. Should be {0}.</value>
</data>
<data name="RowsLessThanColumns" xml:space="preserve">
<value>The number of rows must greater than or equal to the number of columns.</value>

12
src/Numerics/Providers/FourierTransform/IFourierTransformProvider.cs

@ -55,13 +55,13 @@ namespace MathNet.Numerics.Providers.FourierTransform
/// </summary>
void InitializeVerify();
void ForwardInplace(Complex[] complex, FourierTransformScaling scaling);
void BackwardInplace(Complex[] complex, FourierTransformScaling scaling);
void Forward(Complex[] samples, FourierTransformScaling scaling);
void Backward(Complex[] spectrum, FourierTransformScaling scaling);
Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling);
Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling);
void ForwardReal(double[] samples, int n, FourierTransformScaling scaling);
void BackwardReal(double[] spectrum, int n, FourierTransformScaling scaling);
void ForwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling);
void BackwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling);
void ForwardMultidim(Complex[] samples, int[] dimensions, FourierTransformScaling scaling);
void BackwardMultidim(Complex[] spectrum, int[] dimensions, FourierTransformScaling scaling);
}
}

34
src/Numerics/Providers/FourierTransform/ManagedFourierTransformProvider.cs

@ -58,61 +58,55 @@ namespace MathNet.Numerics.Providers.FourierTransform
return "Managed";
}
public void ForwardInplace(Complex[] complex, FourierTransformScaling scaling)
public void Forward(Complex[] samples, FourierTransformScaling scaling)
{
switch (scaling)
{
case FourierTransformScaling.SymmetricScaling:
Fourier.BluesteinForward(complex, FourierOptions.Default);
Fourier.BluesteinForward(samples, FourierOptions.Default);
break;
case FourierTransformScaling.ForwardScaling:
// Only backward scaling can be expressed with options, hence the double-inverse
Fourier.BluesteinInverse(complex, FourierOptions.AsymmetricScaling | FourierOptions.InverseExponent);
Fourier.BluesteinInverse(samples, FourierOptions.AsymmetricScaling | FourierOptions.InverseExponent);
break;
default:
Fourier.BluesteinForward(complex, FourierOptions.NoScaling);
Fourier.BluesteinForward(samples, FourierOptions.NoScaling);
break;
}
}
public void BackwardInplace(Complex[] complex, FourierTransformScaling scaling)
public void Backward(Complex[] spectrum, FourierTransformScaling scaling)
{
switch (scaling)
{
case FourierTransformScaling.SymmetricScaling:
Fourier.BluesteinInverse(complex, FourierOptions.Default);
Fourier.BluesteinInverse(spectrum, FourierOptions.Default);
break;
case FourierTransformScaling.BackwardScaling:
Fourier.BluesteinInverse(complex, FourierOptions.AsymmetricScaling);
Fourier.BluesteinInverse(spectrum, FourierOptions.AsymmetricScaling);
break;
default:
Fourier.BluesteinInverse(complex, FourierOptions.NoScaling);
Fourier.BluesteinInverse(spectrum, FourierOptions.NoScaling);
break;
}
}
public Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling)
public void ForwardReal(double[] samples, int n, FourierTransformScaling scaling)
{
Complex[] work = new Complex[complexTimeSpace.Length];
complexTimeSpace.Copy(work);
ForwardInplace(work, scaling);
return work;
throw new NotImplementedException();
}
public Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling)
public void BackwardReal(double[] spectrum, int n, FourierTransformScaling scaling)
{
Complex[] work = new Complex[complexFrequenceSpace.Length];
complexFrequenceSpace.Copy(work);
BackwardInplace(work, scaling);
return work;
throw new NotImplementedException();
}
public void ForwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling)
public void ForwardMultidim(Complex[] samples, int[] dimensions, FourierTransformScaling scaling)
{
throw new NotImplementedException();
}
public void BackwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling)
public void BackwardMultidim(Complex[] spectrum, int[] dimensions, FourierTransformScaling scaling)
{
throw new NotImplementedException();
}

66
src/Numerics/Providers/FourierTransform/Mkl/MklFourierTransformProvider.cs

@ -42,6 +42,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl
public IntPtr Handle;
public int[] Dimensions;
public FourierTransformScaling Scaling;
public bool Real;
}
Kernel _kernel;
@ -142,7 +143,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl
return MklProvider.Describe();
}
Kernel Configure(int length, FourierTransformScaling scaling)
Kernel Configure(int length, FourierTransformScaling scaling, bool real)
{
Kernel kernel = Interlocked.Exchange(ref _kernel, null);
@ -151,20 +152,26 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl
kernel = new Kernel
{
Dimensions = new[] {length},
Scaling = scaling
Scaling = scaling,
Real = real
};
SafeNativeMethods.z_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length));
if (real) SafeNativeMethods.d_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length));
else SafeNativeMethods.z_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length));
return kernel;
}
if (kernel.Dimensions.Length != 1 || kernel.Dimensions[0] != length || kernel.Scaling != scaling)
if (kernel.Dimensions.Length != 1 || kernel.Dimensions[0] != length || kernel.Scaling != scaling || kernel.Real != real)
{
SafeNativeMethods.x_fft_free(ref kernel.Handle);
SafeNativeMethods.z_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length));
if (real) SafeNativeMethods.d_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length));
else SafeNativeMethods.z_fft_create(out kernel.Handle, length, ForwardScaling(scaling, length), BackwardScaling(scaling, length));
kernel.Dimensions = new[] {length};
kernel.Scaling = scaling;
kernel.Real = real;
return kernel;
}
@ -175,7 +182,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl
{
if (dimensions.Length == 1)
{
return Configure(dimensions[0], scaling);
return Configure(dimensions[0], scaling, false);
}
Kernel kernel = Interlocked.Exchange(ref _kernel, null);
@ -185,7 +192,8 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl
kernel = new Kernel
{
Dimensions = dimensions,
Scaling = scaling
Scaling = scaling,
Real = false
};
long length = 1;
@ -198,7 +206,7 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl
return kernel;
}
bool mismatch = kernel.Dimensions.Length != dimensions.Length || kernel.Scaling != scaling;
bool mismatch = kernel.Dimensions.Length != dimensions.Length || kernel.Scaling != scaling || kernel.Real != false;
if (!mismatch)
{
for (int i = 0; i < dimensions.Length; i++)
@ -221,8 +229,10 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl
SafeNativeMethods.x_fft_free(ref kernel.Handle);
SafeNativeMethods.z_fft_create_multidim(out kernel.Handle, dimensions.Length, dimensions, ForwardScaling(scaling, length), BackwardScaling(scaling, length));
kernel.Dimensions = dimensions;
kernel.Scaling = scaling;
kernel.Real = false;
return kernel;
}
@ -238,47 +248,47 @@ namespace MathNet.Numerics.Providers.FourierTransform.Mkl
}
}
public void ForwardInplace(Complex[] complex, FourierTransformScaling scaling)
public void Forward(Complex[] samples, FourierTransformScaling scaling)
{
Kernel kernel = Configure(complex.Length, scaling);
SafeNativeMethods.z_fft_forward(kernel.Handle, complex);
Kernel kernel = Configure(samples.Length, scaling, false);
SafeNativeMethods.z_fft_forward(kernel.Handle, samples);
Release(kernel);
}
public void BackwardInplace(Complex[] complex, FourierTransformScaling scaling)
public void Backward(Complex[] spectrum, FourierTransformScaling scaling)
{
Kernel kernel = Configure(complex.Length, scaling);
SafeNativeMethods.z_fft_backward(kernel.Handle, complex);
Kernel kernel = Configure(spectrum.Length, scaling, false);
SafeNativeMethods.z_fft_backward(kernel.Handle, spectrum);
Release(kernel);
}
public Complex[] Forward(Complex[] complexTimeSpace, FourierTransformScaling scaling)
public void ForwardReal(double[] samples, int n, FourierTransformScaling scaling)
{
Complex[] work = new Complex[complexTimeSpace.Length];
complexTimeSpace.Copy(work);
ForwardInplace(work, scaling);
return work;
Kernel kernel = Configure(n, scaling, true);
SafeNativeMethods.d_fft_forward(kernel.Handle, samples);
Release(kernel);
}
public Complex[] Backward(Complex[] complexFrequenceSpace, FourierTransformScaling scaling)
public void BackwardReal(double[] spectrum, int n, FourierTransformScaling scaling)
{
Complex[] work = new Complex[complexFrequenceSpace.Length];
complexFrequenceSpace.Copy(work);
BackwardInplace(work, scaling);
return work;
Kernel kernel = Configure(n, scaling, true);
SafeNativeMethods.d_fft_backward(kernel.Handle, spectrum);
Release(kernel);
spectrum[n] = 0d;
}
public void ForwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling)
public void ForwardMultidim(Complex[] samples, int[] dimensions, FourierTransformScaling scaling)
{
Kernel kernel = Configure(dimensions, scaling);
SafeNativeMethods.z_fft_forward(kernel.Handle, complex);
SafeNativeMethods.z_fft_forward(kernel.Handle, samples);
Release(kernel);
}
public void BackwardInplaceMultidim(Complex[] complex, int[] dimensions, FourierTransformScaling scaling)
public void BackwardMultidim(Complex[] spectrum, int[] dimensions, FourierTransformScaling scaling)
{
Kernel kernel = Configure(dimensions, scaling);
SafeNativeMethods.z_fft_backward(kernel.Handle, complex);
SafeNativeMethods.z_fft_backward(kernel.Handle, spectrum);
Release(kernel);
}

15
src/UnitTests/IntegralTransformsTests/MatchingNaiveTransformTest.cs

@ -187,7 +187,10 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
// 65536 = 2^16
const FourierOptions options = FourierOptions.NoScaling;
var samples = Generate.RandomComplex(65536, GetUniform(1));
var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling);
var provider = new Complex[samples.Length];
samples.Copy(provider);
Control.FourierTransformProvider.Forward(provider, FourierTransformScaling.NoScaling);
Verify(samples, 10, options, (a, b) => provider, Fourier.Radix2Forward);
Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward);
@ -199,7 +202,10 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
// 30870 = 2*3*3*5*7*7*7
const FourierOptions options = FourierOptions.NoScaling;
var samples = Generate.RandomComplex(30870, GetUniform(1));
var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling);
var provider = new Complex[samples.Length];
samples.Copy(provider);
Control.FourierTransformProvider.Forward(provider, FourierTransformScaling.NoScaling);
Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward);
}
@ -209,7 +215,10 @@ namespace MathNet.Numerics.UnitTests.IntegralTransformsTests
{
const FourierOptions options = FourierOptions.NoScaling;
var samples = Generate.RandomComplex(46500, GetUniform(1));
var provider = Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.NoScaling);
var provider = new Complex[samples.Length];
samples.Copy(provider);
Control.FourierTransformProvider.Forward(provider, FourierTransformScaling.NoScaling);
Verify(samples, 10, options, (a, b) => provider, Fourier.BluesteinForward);
}

4
src/UnitTests/Providers/FourierTransform/FourierTransformProviderTests.cs

@ -55,7 +55,7 @@ namespace MathNet.Numerics.UnitTests.Providers.FourierTransform
// real-odd transforms to imaginary odd
samples.Copy(spectrum);
Control.FourierTransformProvider.ForwardInplace(spectrum, FourierTransformScaling.BackwardScaling);
Control.FourierTransformProvider.Forward(spectrum, FourierTransformScaling.BackwardScaling);
// all real components must be zero
foreach (var c in spectrum)
@ -88,7 +88,7 @@ namespace MathNet.Numerics.UnitTests.Providers.FourierTransform
var samples = Generate.RandomComplex(count, GetUniform(1));
var timeSpaceEnergy = Generate.Map(samples, s => s.MagnitudeSquared()).Mean();
Control.FourierTransformProvider.ForwardInplace(samples, FourierTransformScaling.SymmetricScaling);
Control.FourierTransformProvider.Forward(samples, FourierTransformScaling.SymmetricScaling);
var frequencySpaceEnergy = Generate.Map(samples, s => s.MagnitudeSquared()).Mean();
Assert.AreEqual(timeSpaceEnergy, frequencySpaceEnergy, 1e-12);

Loading…
Cancel
Save