//
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2018 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using IStation.Numerics.LinearAlgebra;
using IStation.Numerics.LinearAlgebra.Storage;
using IStation.Numerics.Providers.FourierTransform;
using Complex = System.Numerics.Complex;
namespace IStation.Numerics.IntegralTransforms
{
///
/// Complex Fast (FFT) Implementation of the Discrete Fourier Transform (DFT).
///
public static partial class Fourier
{
///
/// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
public static void Forward(Complex32[] samples)
{
FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.SymmetricScaling);
}
///
/// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
public static void Forward(Complex[] samples)
{
FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.SymmetricScaling);
}
///
/// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
public static void Forward(Complex32[] samples, FourierOptions options)
{
switch (options)
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent:
FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.NoScaling);
break;
default:
FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
public static void Forward(Complex[] samples, FourierOptions options)
{
switch (options)
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent:
FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.Backward(samples, FourierTransformScaling.NoScaling);
break;
default:
FourierTransformControl.Provider.Forward(samples, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
///
/// Real part of the sample vector, where the FFT is evaluated in place.
/// Imaginary part of the sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
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;
}
}
///
/// Applies the forward Fast Fourier Transform (FFT) to arbitrary-length sample vectors.
///
/// Real part of the sample vector, where the FFT is evaluated in place.
/// Imaginary part of the sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
public static void Forward(double[] real, double[] 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
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;
}
}
///
/// 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 from 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.
///
/// Data array of length N+2 (if N is even) or N+1 (if N is odd).
/// The number of samples.
/// Fourier Transform Convention Options.
public static void ForwardReal(float[] data, int n, FourierOptions options = FourierOptions.Default)
{
int length = n.IsEven() ? n + 2 : n + 1;
if (data.Length < length)
{
throw new ArgumentException($"The given array is too small. It must be at least {length} long.");
}
if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
{
throw new NotSupportedException();
}
switch (options)
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.ForwardReal(data, n, FourierTransformScaling.NoScaling);
break;
default:
FourierTransformControl.Provider.ForwardReal(data, n, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// 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.
///
/// Data array of length N+2 (if N is even) or N+1 (if N is odd).
/// The number of samples.
/// Fourier Transform Convention Options.
public static void ForwardReal(double[] data, int n, FourierOptions options = FourierOptions.Default)
{
int length = n.IsEven() ? n + 2 : n + 1;
if (data.Length < length)
{
throw new ArgumentException($"The given array is too small. It must be at least {length} long.");
}
if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
{
throw new NotSupportedException();
}
switch (options)
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.ForwardReal(data, n, FourierTransformScaling.NoScaling);
break;
default:
FourierTransformControl.Provider.ForwardReal(data, n, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the forward Fast Fourier Transform (FFT) to multiple dimensional sample data.
///
/// Sample data, where the FFT is evaluated in place.
///
/// 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.
///
/// Fourier Transform Convention Options.
public static void ForwardMultiDim(Complex32[] samples, int[] dimensions, FourierOptions options = FourierOptions.Default)
{
switch (options)
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.ForwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent:
FourierTransformControl.Provider.BackwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.BackwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling);
break;
default:
FourierTransformControl.Provider.ForwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the forward Fast Fourier Transform (FFT) to multiple dimensional sample data.
///
/// Sample data, where the FFT is evaluated in place.
///
/// 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.
///
/// Fourier Transform Convention Options.
public static void ForwardMultiDim(Complex[] samples, int[] dimensions, FourierOptions options = FourierOptions.Default)
{
switch (options)
{
case FourierOptions.NoScaling:
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.ForwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent:
FourierTransformControl.Provider.BackwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.BackwardMultidim(samples, dimensions, FourierTransformScaling.NoScaling);
break;
default:
FourierTransformControl.Provider.ForwardMultidim(samples, dimensions, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the forward Fast Fourier Transform (FFT) to two dimensional sample data.
///
/// Sample data, organized row by row, where the FFT is evaluated in place
/// The number of rows.
/// The number of columns.
/// Data available organized column by column instead of row by row can be processed directly by swapping the rows and columns arguments.
/// Fourier Transform Convention Options.
public static void Forward2D(Complex32[] samplesRowWise, int rows, int columns, FourierOptions options = FourierOptions.Default)
{
ForwardMultiDim(samplesRowWise, new[] { rows, columns }, options);
}
///
/// Applies the forward Fast Fourier Transform (FFT) to two dimensional sample data.
///
/// Sample data, organized row by row, where the FFT is evaluated in place
/// The number of rows.
/// The number of columns.
/// Data available organized column by column instead of row by row can be processed directly by swapping the rows and columns arguments.
/// Fourier Transform Convention Options.
public static void Forward2D(Complex[] samplesRowWise, int rows, int columns, FourierOptions options = FourierOptions.Default)
{
ForwardMultiDim(samplesRowWise, new[] { rows, columns }, options);
}
///
/// Applies the forward Fast Fourier Transform (FFT) to a two dimensional data in form of a matrix.
///
/// Sample matrix, where the FFT is evaluated in place
/// Fourier Transform Convention Options.
public static void Forward2D(Matrix samples, FourierOptions options = FourierOptions.Default)
{
var rowMajorArray = samples.AsRowMajorArray();
if (rowMajorArray != null)
{
ForwardMultiDim(rowMajorArray, new[] { samples.RowCount, samples.ColumnCount }, options);
return;
}
var columnMajorArray = samples.AsColumnMajorArray();
if (columnMajorArray != null)
{
ForwardMultiDim(columnMajorArray, new[] { samples.ColumnCount, samples.RowCount }, options);
return;
}
// Fall Back
columnMajorArray = samples.ToColumnMajorArray();
ForwardMultiDim(columnMajorArray, new[] { samples.ColumnCount, samples.RowCount }, options);
var denseStorage = new DenseColumnMajorMatrixStorage(samples.RowCount, samples.ColumnCount, columnMajorArray);
denseStorage.CopyToUnchecked(samples.Storage, ExistingData.Clear);
}
///
/// Applies the forward Fast Fourier Transform (FFT) to a two dimensional data in form of a matrix.
///
/// Sample matrix, where the FFT is evaluated in place
/// Fourier Transform Convention Options.
public static void Forward2D(Matrix samples, FourierOptions options = FourierOptions.Default)
{
var rowMajorArray = samples.AsRowMajorArray();
if (rowMajorArray != null)
{
ForwardMultiDim(rowMajorArray, new[] { samples.RowCount, samples.ColumnCount }, options);
return;
}
var columnMajorArray = samples.AsColumnMajorArray();
if (columnMajorArray != null)
{
ForwardMultiDim(columnMajorArray, new[] { samples.ColumnCount, samples.RowCount }, options);
return;
}
// Fall Back
columnMajorArray = samples.ToColumnMajorArray();
ForwardMultiDim(columnMajorArray, new[] { samples.ColumnCount, samples.RowCount }, options);
var denseStorage = new DenseColumnMajorMatrixStorage(samples.RowCount, samples.ColumnCount, columnMajorArray);
denseStorage.CopyToUnchecked(samples.Storage, ExistingData.Clear);
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
///
/// Spectrum data, where the iFFT is evaluated in place.
public static void Inverse(Complex32[] spectrum)
{
FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
///
/// Spectrum data, where the iFFT is evaluated in place.
public static void Inverse(Complex[] spectrum)
{
FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
///
/// Spectrum data, where the iFFT is evaluated in place.
/// Fourier Transform Convention Options.
public static void Inverse(Complex32[] spectrum, FourierOptions options)
{
switch (options)
{
case FourierOptions.NoScaling:
FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.BackwardScaling);
break;
case FourierOptions.InverseExponent:
FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.ForwardScaling);
break;
default:
FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
///
/// Spectrum data, where the iFFT is evaluated in place.
/// Fourier Transform Convention Options.
public static void Inverse(Complex[] spectrum, FourierOptions options)
{
switch (options)
{
case FourierOptions.NoScaling:
FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.BackwardScaling);
break;
case FourierOptions.InverseExponent:
FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.Forward(spectrum, FourierTransformScaling.ForwardScaling);
break;
default:
FourierTransformControl.Provider.Backward(spectrum, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
///
/// Real part of the sample vector, where the iFFT is evaluated in place.
/// Imaginary part of the sample vector, where the iFFT is evaluated in place.
/// Fourier Transform Convention Options.
public static void Inverse(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]);
}
Inverse(data, options);
for (int i = 0; i < data.Length; i++)
{
real[i] = data[i].Real;
imaginary[i] = data[i].Imaginary;
}
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to arbitrary-length sample vectors.
///
/// Real part of the sample vector, where the iFFT is evaluated in place.
/// Imaginary part of the sample vector, where the iFFT is evaluated in place.
/// Fourier Transform Convention Options.
public static void Inverse(double[] real, double[] 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
Complex[] data = new Complex[real.Length];
for (int i = 0; i < data.Length; i++)
{
data[i] = new Complex(real[i], imaginary[i]);
}
Inverse(data, options);
for (int i = 0; i < data.Length; i++)
{
real[i] = data[i].Real;
imaginary[i] = data[i].Imaginary;
}
}
///
/// 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.
///
/// Data array of length N+2 (if N is even) or N+1 (if N is odd).
/// The number of samples.
/// Fourier Transform Convention Options.
public static void InverseReal(float[] data, int n, FourierOptions options = FourierOptions.Default)
{
int length = n.IsEven() ? n + 2 : n + 1;
if (data.Length < length)
{
throw new ArgumentException($"The given array is too small. It must be at least {length} long.");
}
if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
{
throw new NotSupportedException();
}
switch (options)
{
case FourierOptions.NoScaling:
FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.BackwardScaling);
break;
default:
FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// 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.
///
/// Data array of length N+2 (if N is even) or N+1 (if N is odd).
/// The number of samples.
/// Fourier Transform Convention Options.
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($"The given array is too small. It must be at least {length} long.");
}
if ((options & FourierOptions.InverseExponent) == FourierOptions.InverseExponent)
{
throw new NotSupportedException();
}
switch (options)
{
case FourierOptions.NoScaling:
FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.BackwardScaling);
break;
default:
FourierTransformControl.Provider.BackwardReal(data, n, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to multiple dimensional sample data.
///
/// Spectrum data, where the iFFT is evaluated in place.
///
/// 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.
///
/// Fourier Transform Convention Options.
public static void InverseMultiDim(Complex32[] spectrum, int[] dimensions, FourierOptions options = FourierOptions.Default)
{
switch (options)
{
case FourierOptions.NoScaling:
FourierTransformControl.Provider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.BackwardScaling);
break;
case FourierOptions.InverseExponent:
FourierTransformControl.Provider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
FourierTransformControl.Provider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.ForwardScaling);
break;
default:
FourierTransformControl.Provider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to multiple dimensional sample data.
///
/// Spectrum data, where the iFFT is evaluated in place.
///
/// 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.
///
/// Fourier Transform Convention Options.
public static void InverseMultiDim(Complex[] spectrum, int[] dimensions, FourierOptions options = FourierOptions.Default)
{
switch (options)
{
case FourierOptions.NoScaling:
FourierTransformControl.Provider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.BackwardScaling);
break;
case FourierOptions.InverseExponent:
FourierTransformControl.Provider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.NoScaling:
FourierTransformControl.Provider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.NoScaling);
break;
case FourierOptions.InverseExponent | FourierOptions.AsymmetricScaling:
FourierTransformControl.Provider.ForwardMultidim(spectrum, dimensions, FourierTransformScaling.ForwardScaling);
break;
default:
FourierTransformControl.Provider.BackwardMultidim(spectrum, dimensions, FourierTransformScaling.SymmetricScaling);
break;
}
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to two dimensional sample data.
///
/// Sample data, organized row by row, where the iFFT is evaluated in place
/// The number of rows.
/// The number of columns.
/// Data available organized column by column instead of row by row can be processed directly by swapping the rows and columns arguments.
/// Fourier Transform Convention Options.
public static void Inverse2D(Complex32[] spectrumRowWise, int rows, int columns, FourierOptions options = FourierOptions.Default)
{
InverseMultiDim(spectrumRowWise, new[] { rows, columns }, options);
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to two dimensional sample data.
///
/// Sample data, organized row by row, where the iFFT is evaluated in place
/// The number of rows.
/// The number of columns.
/// Data available organized column by column instead of row by row can be processed directly by swapping the rows and columns arguments.
/// Fourier Transform Convention Options.
public static void Inverse2D(Complex[] spectrumRowWise, int rows, int columns, FourierOptions options = FourierOptions.Default)
{
InverseMultiDim(spectrumRowWise, new[] { rows, columns }, options);
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to a two dimensional data in form of a matrix.
///
/// Sample matrix, where the iFFT is evaluated in place
/// Fourier Transform Convention Options.
public static void Inverse2D(Matrix spectrum, FourierOptions options = FourierOptions.Default)
{
var rowMajorArray = spectrum.AsRowMajorArray();
if (rowMajorArray != null)
{
InverseMultiDim(rowMajorArray, new[] { spectrum.RowCount, spectrum.ColumnCount }, options);
return;
}
var columnMajorArray = spectrum.AsColumnMajorArray();
if (columnMajorArray != null)
{
InverseMultiDim(columnMajorArray, new[] { spectrum.ColumnCount, spectrum.RowCount }, options);
return;
}
// Fall Back
columnMajorArray = spectrum.ToColumnMajorArray();
InverseMultiDim(columnMajorArray, new[] { spectrum.ColumnCount, spectrum.RowCount }, options);
var denseStorage = new DenseColumnMajorMatrixStorage(spectrum.RowCount, spectrum.ColumnCount, columnMajorArray);
denseStorage.CopyToUnchecked(spectrum.Storage, ExistingData.Clear);
}
///
/// Applies the inverse Fast Fourier Transform (iFFT) to a two dimensional data in form of a matrix.
///
/// Sample matrix, where the iFFT is evaluated in place
/// Fourier Transform Convention Options.
public static void Inverse2D(Matrix spectrum, FourierOptions options = FourierOptions.Default)
{
var rowMajorArray = spectrum.AsRowMajorArray();
if (rowMajorArray != null)
{
InverseMultiDim(rowMajorArray, new[] { spectrum.RowCount, spectrum.ColumnCount }, options);
return;
}
var columnMajorArray = spectrum.AsColumnMajorArray();
if (columnMajorArray != null)
{
InverseMultiDim(columnMajorArray, new[] { spectrum.ColumnCount, spectrum.RowCount }, options);
return;
}
// Fall Back
columnMajorArray = spectrum.ToColumnMajorArray();
InverseMultiDim(columnMajorArray, new[] { spectrum.ColumnCount, spectrum.RowCount }, options);
var denseStorage = new DenseColumnMajorMatrixStorage(spectrum.RowCount, spectrum.ColumnCount, columnMajorArray);
denseStorage.CopyToUnchecked(spectrum.Storage, ExistingData.Clear);
}
///
/// Naive forward DFT, useful e.g. to verify faster algorithms.
///
/// Time-space sample vector.
/// Fourier Transform Convention Options.
/// Corresponding frequency-space vector.
[Obsolete("Use Forward instead. Will be dropped in version 5.0 and behave like Forward until then.")]
public static Complex32[] NaiveForward(Complex32[] samples, FourierOptions options = FourierOptions.Default)
{
var result = new Complex32[samples.Length];
samples.Copy(result);
Forward(result, options);
return result;
}
///
/// Naive forward DFT, useful e.g. to verify faster algorithms.
///
/// Time-space sample vector.
/// Fourier Transform Convention Options.
/// Corresponding frequency-space vector.
[Obsolete("Use Forward instead. Will be dropped in version 5.0 and behave like Forward until then.")]
public static Complex[] NaiveForward(Complex[] samples, FourierOptions options = FourierOptions.Default)
{
var result = new Complex[samples.Length];
samples.Copy(result);
Forward(result, options);
return result;
}
///
/// Naive inverse DFT, useful e.g. to verify faster algorithms.
///
/// Frequency-space sample vector.
/// Fourier Transform Convention Options.
/// Corresponding time-space vector.
[Obsolete("Use Inverse instead. Will be dropped in version 5.0 and behave like Inverse until then.")]
public static Complex32[] NaiveInverse(Complex32[] spectrum, FourierOptions options = FourierOptions.Default)
{
var result = new Complex32[spectrum.Length];
spectrum.Copy(result);
Inverse(result, options);
return result;
}
///
/// Naive inverse DFT, useful e.g. to verify faster algorithms.
///
/// Frequency-space sample vector.
/// Fourier Transform Convention Options.
/// Corresponding time-space vector.
[Obsolete("Use Inverse instead. Will be dropped in version 5.0 and behave like Inverse until then.")]
public static Complex[] NaiveInverse(Complex[] spectrum, FourierOptions options = FourierOptions.Default)
{
var result = new Complex[spectrum.Length];
spectrum.Copy(result);
Inverse(result, options);
return result;
}
///
/// Radix-2 forward FFT for power-of-two sized sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
///
[Obsolete("Use Forward instead. Will be dropped in version 5.0 and behave like Forward until then.")]
public static void Radix2Forward(Complex32[] samples, FourierOptions options = FourierOptions.Default)
{
Forward(samples, options);
}
///
/// Radix-2 forward FFT for power-of-two sized sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
///
[Obsolete("Use Forward instead. Will be dropped in version 5.0 and behave like Forward until then.")]
public static void Radix2Forward(Complex[] samples, FourierOptions options = FourierOptions.Default)
{
Forward(samples, options);
}
///
/// Radix-2 inverse FFT for power-of-two sized sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
///
[Obsolete("Use Inverse instead. Will be dropped in version 5.0 and behave like Inverse until then.")]
public static void Radix2Inverse(Complex32[] spectrum, FourierOptions options = FourierOptions.Default)
{
Inverse(spectrum, options);
}
///
/// Radix-2 inverse FFT for power-of-two sized sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
///
[Obsolete("Use Inverse instead. Will be dropped in version 5.0 and behave like Inverse until then.")]
public static void Radix2Inverse(Complex[] spectrum, FourierOptions options = FourierOptions.Default)
{
Inverse(spectrum, options);
}
///
/// Bluestein forward FFT for arbitrary sized sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
[Obsolete("Use Forward instead. Will be dropped in version 5.0 and behave like Forward until then.")]
public static void BluesteinForward(Complex32[] samples, FourierOptions options = FourierOptions.Default)
{
Forward(samples, options);
}
///
/// Bluestein forward FFT for arbitrary sized sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
[Obsolete("Use Forward instead. Will be dropped in version 5.0 and behave like Forward until then.")]
public static void BluesteinForward(Complex[] samples, FourierOptions options = FourierOptions.Default)
{
Forward(samples, options);
}
///
/// Bluestein inverse FFT for arbitrary sized sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
[Obsolete("Use Inverse instead. Will be dropped in version 5.0 and behave like Inverse until then.")]
public static void BluesteinInverse(Complex32[] spectrum, FourierOptions options = FourierOptions.Default)
{
Inverse(spectrum, options);
}
///
/// Bluestein inverse FFT for arbitrary sized sample vectors.
///
/// Sample vector, where the FFT is evaluated in place.
/// Fourier Transform Convention Options.
[Obsolete("Use Inverse instead. Will be dropped in version 5.0 and behave like Inverse until then.")]
public static void BluesteinInverse(Complex[] spectrum, FourierOptions options = FourierOptions.Default)
{
Inverse(spectrum, options);
}
///
/// Generate the frequencies corresponding to each index in frequency space.
/// The frequency space has a resolution of sampleRate/N.
/// Index 0 corresponds to the DC part, the following indices correspond to
/// the positive frequencies up to the Nyquist frequency (sampleRate/2),
/// followed by the negative frequencies wrapped around.
///
/// Number of samples.
/// The sampling rate of the time-space data.
public static double[] FrequencyScale(int length, double sampleRate)
{
double[] scale = new double[length];
double f = 0, step = sampleRate / length;
int secondHalf = (length >> 1) + 1;
for (int i = 0; i < secondHalf; i++)
{
scale[i] = f;
f += step;
}
f = -step * (secondHalf - 2);
for (int i = secondHalf; i < length; i++)
{
scale[i] = f;
f += step;
}
return scale;
}
}
}