// Get rotation of complex number private static Complex[] GetComplexRotation(int numberOfBits, FourierDirection direction) { int directionIndex = (direction == FourierDirection.Forward) ? 0 : 1; // check if the array is already calculated if (complexRotation[numberOfBits - 1, directionIndex] == null) { int n = 1 << (numberOfBits - 1); float uR = 1.0f; float uI = 0.0f; double angle = System.Math.PI / n * (int)direction; float wR = (float)System.Math.Cos(angle); float wI = (float)System.Math.Sin(angle); float t; Complex[] rotation = new Complex[n]; for (int i = 0; i < n; i++) { rotation[i] = new Complex(uR, uI); t = uR * wI + uI * wR; uR = uR * wR - uI * wI; uI = t; } complexRotation[numberOfBits - 1, directionIndex] = rotation; } return(complexRotation[numberOfBits - 1, directionIndex]); }
public static void DFT(Complex[] data, FourierDirection direction) { int length = data.Length; Complex[] complexArray = new Complex[length]; for (int i = 0; i < length; i++) { complexArray[i] = Complex.Zero; double num2 = (((((double)-((int)direction)) * 2.0) * 3.1415926535897931) * i) / ((double)length); for (int j = 0; j < length; j++) { double num3 = Math.Cos(j * num2); double num4 = Math.Sin(j * num2); complexArray[i].Re += (float)((data[j].Re * num3) - (data[j].Im * num4)); complexArray[i].Im += (float)((data[j].Re * num4) + (data[j].Im * num3)); } } if (direction == FourierDirection.Forward) { for (int k = 0; k < length; k++) { data[k].Re = complexArray[k].Re / ((float)length); data[k].Im = complexArray[k].Im / ((float)length); } } else { for (int m = 0; m < length; m++) { data[m].Re = complexArray[m].Re; data[m].Im = complexArray[m].Im; } } }
private static void LinearFFT(float[] data, int start, int inc, int length, FourierDirection direction) { Debug.Assert(data != null); Debug.Assert(start >= 0); Debug.Assert(inc >= 1); Debug.Assert(length >= 1); Debug.Assert((start + inc * (length - 1)) * 2 < data.Length); // copy to buffer float[] buffer = null; LockBufferF(length * 2, ref buffer); int j = start; for (int i = 0; i < length * 2; i++) { buffer[i] = data[j]; j += inc; } FFT(buffer, length, direction); // copy from buffer j = start; for (int i = 0; i < length; i++) { data[j] = buffer[i]; j += inc; } UnlockBufferF(ref buffer); }
FFT(double[] x, double[] y, uint n, FourierDirection direction, ref object temporaryStorage) { ChirpNativeFFTStorage s = temporaryStorage as ChirpNativeFFTStorage; chirpnativefft(x, y, x, y, (int)n, direction, ref s); temporaryStorage = s; }
/// <summary> /// Compute a 2D fast fourier transform on a data set of complex numbers /// </summary> /// <param name="data"></param> /// <param name="xLength"></param> /// <param name="yLength"></param> /// <param name="direction"></param> public static void FFT2(ComplexF[] data, int xLength, int yLength, FourierDirection direction) { int xInc = 1; int yInc = xLength; if (xLength > 1) { SyncLookupTableLength(xLength); for (int y = 0; y < yLength; y++) { int xStart = y * yInc; LinearFFT_Quick(data, xStart, xInc, xLength, direction); } } if (yLength > 1) { SyncLookupTableLength(yLength); for (int x = 0; x < xLength; x++) { int yStart = x * xInc; LinearFFT_Quick(data, yStart, yInc, yLength, direction); } } }
/// <summary> /// Compute a 1D real-symmetric fast fourier transform. /// </summary> /// <param name="data"></param> /// <param name="direction"></param> public static void RFFT(float[] data, FourierDirection direction) { if (data == null) { throw new ArgumentNullException("data"); } Fourier.RFFT(data, data.Length, direction); }
public static void FFT(ComplexF[] data, FourierDirection direction) { if (data == null) { throw new ArgumentNullException("data"); } FFT(data, data.Length, direction); }
/// <summary> /// Compute a 1D fast Fourier transform of a dataset of complex numbers. /// </summary> /// <param name="data"></param> /// <param name="length"></param> /// <param name="direction"></param> public static void FFT_Quick(ComplexF[] data, int length, FourierDirection direction) { /*if( data == null ) { * throw new ArgumentNullException( "data" ); * } * if( data.Length < length ) { * throw new ArgumentOutOfRangeException( "length", length, "must be at least as large as 'data.Length' parameter" ); * } * if( Fourier.IsPowerOf2( length ) == false ) { * throw new ArgumentOutOfRangeException( "length", length, "must be a power of 2" ); * } * * Fourier.SyncLookupTableLength( length );*/ int ln = Fourier.Log2(length); // reorder array Fourier.ReorderArray(data); // successive doubling int N = 1; int signIndex = (direction == FourierDirection.Forward) ? 0 : 1; for (int level = 1; level <= ln; level++) { int M = N; N <<= 1; float[] uRLookup = _uRLookupF[level, signIndex]; float[] uILookup = _uILookupF[level, signIndex]; for (int j = 0; j < M; j++) { float uR = uRLookup[j]; float uI = uILookup[j]; for (int even = j; even < length; even += N) { int odd = even + M; float r = data[odd].Re; float i = data[odd].Im; float odduR = r * uR - i * uI; float odduI = r * uI + i * uR; r = data[even].Re; i = data[even].Im; data[even].Re = r + odduR; data[even].Im = i + odduI; data[odd].Re = r - odduR; data[odd].Im = i - odduI; } } } }
/// <summary> /// Performs a inline native fouriertransformation of real and imaginary part arrays. /// </summary> /// <param name="real">The real part of the array to transform.</param> /// <param name="imag">The real part of the array to transform.</param> /// <param name="direction">Direction of the Fourier transform.</param> public static void FFT(double[] real, double[] imag, FourierDirection direction) { if (real.Length != imag.Length) { throw new ArgumentException("Length of real and imaginary array do not match!"); } FFT(real, imag, real, imag, real.Length, direction); }
/// <summary> /// Performs a out-of-place fourier transformation. The original values are kept. /// </summary> /// <param name="inputarr">The data to transform.</param> /// <param name="direction">Specify forward or reverse transformation here.</param> /// <param name="outputarr">. On output, contains the fourier transformed data.</param> public void Transform(double[] inputarr, FourierDirection direction, double[] outputarr) { if(inputarr.Length!=_numberOfData) throw new ArgumentException(string.Format("Length of array inputarr ({0}) is different from the length specified at construction ({1})",inputarr.Length,_numberOfData),"inputarr"); if(outputarr.Length!=_numberOfData) throw new ArgumentException(string.Format("Length of array outputarr ({0}) is different from the length specified at construction ({1})",outputarr.Length,_numberOfData),"outputarr"); Array.Copy(inputarr,0,outputarr,0,inputarr.Length); Transform(outputarr,direction); }
//====================================================================================== /// <summary> /// Compute a 1D fast Fourier transform of a dataset of complex numbers (as pairs of float's). /// </summary> /// <param name="data"></param> /// <param name="direction"></param> public static void FFT(float[] data, FourierDirection direction) { int length = data.Length; Debug.Assert(data != null); Debug.Assert(data.Length >= length * 2); Debug.Assert(Fourier.IsPowerOf2(length) == true); Fourier.SyncLookupTableLength(length); int ln = Fourier.Log2(length); // reorder array Fourier.ReorderArray(data); // successive doubling int N = 1; int signIndex = (direction == FourierDirection.Forward) ? 0 : 1; for (int level = 1; level <= ln; level++) { int M = N; N <<= 1; float[] uRLookup = _uRLookupF[level, signIndex]; float[] uILookup = _uILookupF[level, signIndex]; for (int j = 0; j < M; j++) { float uR = uRLookup[j]; float uI = uILookup[j]; for (int evenT = j; evenT < length; evenT += N) { int even = evenT << 1; int odd = (evenT + M) << 1; float r = data[odd]; float i = data[odd + 1]; float odduR = r * uR - i * uI; float odduI = r * uI + i * uR; r = data[even]; i = data[even + 1]; data[even] = r + odduR; data[even + 1] = i + odduI; data[odd] = r - odduR; data[odd + 1] = i - odduI; } } } }
private static void chirpnativefft( double[] resultreal, double[] resultimag, double[] inputreal, double[] inputimag, int arrsize, FourierDirection direction, ref ChirpNativeFFTStorage s) { if (arrsize <= 2) { throw new ArgumentException("This algorithm works for array sizes > 2 only."); } int msize = GetNecessaryTransformationSize(arrsize); if (s == null || arrsize != s._arrSize || direction != s._direction) { s = new ChirpNativeFFTStorage(msize, arrsize, direction); } else // if the temp storage is not fresh, we have to clear the arrays first { Array.Clear(s._xjfj_real, 0, msize); Array.Clear(s._xjfj_imag, 0, msize); } // make the arrays local variables double[] xjfj_real = s._xjfj_real; double[] xjfj_imag = s._xjfj_imag; double[] fserp_real = s._fserp_real; double[] fserp_imag = s._fserp_imag; double[] resarray_real = s._resarray_real; double[] resarray_imag = s._resarray_imag; var chirpfactor_real = s._chirpfactors_real; var chirpfactor_imag = s._chirpfactors_imag; // multiply the input array with the chirpfactors for (int i = 0; i < arrsize; ++i) { xjfj_real[i] = inputreal[i] * chirpfactor_real[i] - inputimag[i] * chirpfactor_imag[i]; xjfj_imag[i] = inputreal[i] * chirpfactor_imag[i] + inputimag[i] * chirpfactor_real[i]; } // convolute xjfj with precomputed fourier-transformation of fserp fhtconvolutionWithFouriertransformed2ndArgument(resarray_real, resarray_imag, xjfj_real, xjfj_imag, fserp_real, fserp_imag, msize); // multiply the result with the chirpfactors for (int i = 0; i < arrsize; ++i) { resultreal[i] = resarray_real[i] * chirpfactor_real[i] - resarray_imag[i] * chirpfactor_imag[i]; resultimag[i] = resarray_real[i] * chirpfactor_imag[i] + resarray_imag[i] * chirpfactor_real[i]; } }
public static void DFT2(Complex[,] data, FourierDirection direction) { double num3; double num4; double num5; int length = data.GetLength(0); int num2 = data.GetLength(1); Complex[] complexArray = new Complex[Math.Max(length, num2)]; for (int i = 0; i < length; i++) { for (int k = 0; k < num2; k++) { complexArray[k] = Complex.Zero; num3 = (((((double)-((int)direction)) * 2.0) * 3.1415926535897931) * k) / ((double)num2); for (int m = 0; m < num2; m++) { num4 = Math.Cos(m * num3); num5 = Math.Sin(m * num3); complexArray[k].Re += (float)((data[i, m].Re * num4) - (data[i, m].Im * num5)); complexArray[k].Im += (float)((data[i, m].Re * num5) + (data[i, m].Im * num4)); } } if (direction == FourierDirection.Forward) { for (int n = 0; n < num2; n++) { data[i, n].Re = complexArray[n].Re / ((float)num2); data[i, n].Im = complexArray[n].Im / ((float)num2); } } else { for (int num10 = 0; num10 < num2; num10++) { data[i, num10].Re = complexArray[num10].Re; data[i, num10].Im = complexArray[num10].Im; } } } for (int j = 0; j < num2; j++) { for (int num12 = 0; num12 < length; num12++) { complexArray[num12] = Complex.Zero; num3 = (((((double)-((int)direction)) * 2.0) * 3.1415926535897931) * num12) / ((double)length); for (int num13 = 0; num13 < length; num13++) { num4 = Math.Cos(num13 * num3); num5 = Math.Sin(num13 * num3); complexArray[num12].Re += (float)((data[num13, j].Re * num4) - (data[num13, j].Im * num5)); complexArray[num12].Im += (float)((data[num13, j].Re * num5) + (data[num13, j].Im * num4)); } } if (direction == FourierDirection.Forward) { for (int num14 = 0; num14 < length; num14++) { data[num14, j].Re = complexArray[num14].Re / ((float)length); data[num14, j].Im = complexArray[num14].Im / ((float)length); } } else { for (int num15 = 0; num15 < length; num15++) { data[num15, j].Re = complexArray[num15].Re; data[num15, j].Im = complexArray[num15].Im; } } } }
// Two dimensional Fast Fourier Transform public static void FFT2(Complex[,] data, FourierDirection direction) { int k = data.GetLength(0); int n = data.GetLength(1); // check data size if ( (!Tools.IsPowerOf2(k)) || (!Tools.IsPowerOf2(n)) || (k < minLength) || (k > maxLength) || (n < minLength) || (n > maxLength) ) { throw new ArgumentException( ); } // process rows Complex[] row = new Complex[n]; for (int i = 0; i < k; i++) { // copy row for (int j = 0; j < n; j++) { row[j] = data[i, j]; } // transform it FourierTransform.FFT(row, direction); // copy back for (int j = 0; j < n; j++) { data[i, j] = row[j]; } } // process columns Complex[] col = new Complex[k]; for (int j = 0; j < n; j++) { // copy column for (int i = 0; i < k; i++) { col[i] = data[i, j]; } // transform it FourierTransform.FFT(col, direction); // copy back for (int i = 0; i < k; i++) { data[i, j] = col[i]; } } }
FFT(double[] x, double[] y, FourierDirection direction, ref object temporaryStorage) { if (x.Length != y.Length) { throw new ArgumentException("Length of real and imaginary array do not match!"); } var s = temporaryStorage as ChirpNativeFFTStorage; chirpnativefft(x, y, x, y, x.Length, direction, ref s); temporaryStorage = s; }
//====================================================================================== //====================================================================================== /// <summary> /// Compute a 1D fast Fourier transform of a dataset of complex numbers (as pairs of float's). /// </summary> /// <param name = "data"></param> /// <param name = "length"></param> /// <param name = "direction"></param> public static void FFT(float[] data, int length, FourierDirection direction) { Debug.Assert(data != null); Debug.Assert(data.Length >= length*2); Debug.Assert(IsPowerOf2(length)); SyncLookupTableLength(length); int ln = Log2(length); // reorder array ReorderArray(data); // successive doubling int N = 1; int signIndex = (direction == FourierDirection.Forward) ? 0 : 1; for (int level = 1; level <= ln; level++) { int M = N; N <<= 1; float[] uRLookup = _uRLookupF[level, signIndex]; float[] uILookup = _uILookupF[level, signIndex]; for (int j = 0; j < M; j++) { float uR = uRLookup[j]; float uI = uILookup[j]; for (int evenT = j; evenT < length; evenT += N) { int even = evenT << 1; int odd = (evenT + M) << 1; float r = data[odd]; float i = data[odd + 1]; float odduR = r*uR - i*uI; float odduI = r*uI + i*uR; r = data[even]; i = data[even + 1]; data[even] = r + odduR; data[even + 1] = i + odduI; data[odd] = r - odduR; data[odd + 1] = i - odduI; } } } }
/// <summary> /// Fourier transform /// </summary> /// <param name="array">Array</param> /// <param name="direction">Fourier direction</param> public static void Fourier(Array array, FourierDirection direction) { var handle = GCHandle.Alloc(array, GCHandleType.Pinned); FftwLock.WaitOne(); var plan = dft(array.Rank, Enumerable.Range(0, array.Rank).Select(array.GetLength).ToArray(), handle.AddrOfPinnedObject(), handle.AddrOfPinnedObject(), (fftw_direction) direction, fftw_flags.Estimate); execute(plan); destroy_plan(plan); FftwLock.ReleaseMutex(); handle.Free(); }
/// <summary> /// Fourier transform /// </summary> /// <param name="n0">Array size</param> /// <param name="n1">Array size</param> /// <param name="array">Array</param> /// <param name="direction">Fourier direction</param> public static void Fourier(int n0, int n1, Array array, FourierDirection direction) { var handle = GCHandle.Alloc(array, GCHandleType.Pinned); FftwLock.WaitOne(); var plan = dft_2d(n0, n1, handle.AddrOfPinnedObject(), handle.AddrOfPinnedObject(), (fftw_direction) direction, fftw_flags.Estimate); execute(plan); destroy_plan(plan); FftwLock.ReleaseMutex(); handle.Free(); }
/// <summary> /// Voert een 2 dimensionale Fourier analyse uit op een afbeelding /// </summary> /// <param name="invoer">De complexe waarden van de afbeelding</param> /// <param name="dir">FourierDirection.Forward or FourierDirection.Backward</param> /// <returns>Fourier resultset</returns> private static ComplexGetal[,] FFT2D(ComplexGetal[,] invoer, FourierDirection dir) { float[] reëel = new float[invoer.GetLength(1)]; float[] imaginair = new float[invoer.GetLength(1)]; ComplexGetal[,] resultaat = invoer; //rijen for (int i = 0; i < invoer.GetLength(0); i++) { // Plaats de waarden in een 1 dimensionale array for (int j = 0; j < invoer.GetLength(1); j++) { reëel[j] = invoer[i, j].Reëel; imaginair[j] = invoer[i, j].Imaginair; } // Voer een 1 dimensionale fourier analyse uit op de huidige rij FFT1D(dir, reëel, imaginair); // Plaats de waarden in het resultaat object for (int j = 0; j < resultaat.GetLength(1); j++) { resultaat[i, j].Reëel = reëel[j]; resultaat[i, j].Imaginair = imaginair[j]; } } //kolommen - gebruik nu het resultaat object, anders gaan de berekeningen van de rijen verloren for (int i = 0; i < resultaat.GetLength(1); i++) { // Plaats de waarden in een 1 dimensionale array for (int j = 0; j < resultaat.GetLength(0); j++) { reëel[j] = resultaat[j, i].Reëel; imaginair[j] = resultaat[j, i].Imaginair; } // Voer een 1 dimensionale fourier analyse uit op de huidige kolom FFT1D(dir, reëel, imaginair); // Plaats de waarden in het resultaat object for (int j = 0; j < resultaat.GetLength(0); j++) { resultaat[j, i].Reëel = reëel[j]; resultaat[j, i].Imaginair = imaginair[j]; } } return(resultaat); }
/// <summary> /// Performs a out-of-place fourier transformation. The original values are kept. /// </summary> /// <param name="inputarr">The data to transform.</param> /// <param name="direction">Specify forward or reverse transformation here.</param> /// <param name="outputarr">. On output, contains the fourier transformed data.</param> public void Transform(double[] inputarr, FourierDirection direction, double[] outputarr) { if (inputarr.Length != _numberOfData) { throw new ArgumentException(string.Format("Length of array inputarr ({0}) is different from the length specified at construction ({1})", inputarr.Length, _numberOfData), "inputarr"); } if (outputarr.Length != _numberOfData) { throw new ArgumentException(string.Format("Length of array outputarr ({0}) is different from the length specified at construction ({1})", outputarr.Length, _numberOfData), "outputarr"); } Array.Copy(inputarr, 0, outputarr, 0, inputarr.Length); Transform(outputarr, direction); }
/// <summary> /// Performs a native fouriertransformation of a real value array. /// </summary> /// <param name="arr">The double valued array to transform.</param> /// <param name="resultarr">Used to store the result of the transformation.</param> /// <param name="count">Number of points to transform.</param> /// <param name="direction">Direction of the Fourier transform.</param> public static void FFT(double[] arr, Complex[] resultarr, int count, FourierDirection direction) { int iss = direction == FourierDirection.Forward ? 1 : -1; for (int k = 0; k < count; k++) { resultarr[k] = new Complex(0, 0); for (int i = 0; i < count; i++) { double phi = iss * 2 * Math.PI * ((i * k) % count) / count; resultarr[k] += new Complex(arr[i] * Math.Cos(phi), arr[i] * Math.Sin(phi)); } } }
// One dimensional Fast Fourier Transform public static void FFT(Complex[] data, FourierDirection direction) { int n = data.Length; int m = Tools.Log2(n); // reorder data first ReorderData(data); // compute FFT int tn = 1, tm; for (int k = 1; k <= m; k++) { Complex[] rotation = FourierTransform.GetComplexRotation(k, direction); tm = tn; tn <<= 1; for (int i = 0; i < tm; i++) { Complex t = rotation[i]; for (int even = i; even < n; even += tn) { int odd = even + tm; Complex ce = data[even]; Complex co = data[odd]; float tr = co.Re * t.Re - co.Im * t.Im; float ti = co.Re * t.Im + co.Im * t.Re; data[even].Re += tr; data[even].Im += ti; data[odd].Re = ce.Re - tr; data[odd].Im = ce.Im - ti; } } } if (direction == FourierDirection.Forward) { for (int i = 0; i < n; i++) { data[i].Re /= (float)n; data[i].Im /= (float)n; } } }
private void MyRoutine2(double[] real1, FourierDirection dir) { int n = real1.Length; var rnd = new System.Random(); double[] real2 = new double[n]; for (int i = 0; i < n; i++) { real2[i] = rnd.NextDouble() / n; } var fft = new Pfa235FFT(n); fft.RealFFT(real2, real1, dir); }
/// <summary> /// Fourier transform /// </summary> /// <param name="array">Array</param> /// <param name="direction">Fourier direction</param> public static void Fourier(Array array, FourierDirection direction) { var handle = GCHandle.Alloc(array, GCHandleType.Pinned); FftwLock.WaitOne(); var plan = dft(array.Rank, Enumerable.Range(0, array.Rank).Select(array.GetLength).ToArray(), handle.AddrOfPinnedObject(), handle.AddrOfPinnedObject(), (fftw_direction)direction, fftw_flags.Estimate); execute(plan); destroy_plan(plan); FftwLock.ReleaseMutex(); handle.Free(); }
/// <summary> /// Fourier transform /// </summary> /// <param name="n0">Array size</param> /// <param name="n1">Array size</param> /// <param name="n2">Array size</param> /// <param name="array">Array</param> /// <param name="direction">Fourier direction</param> public static void Fourier(int n0, int n1, int n2, Complex[] array, FourierDirection direction) { GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned); FftwLock.WaitOne(); IntPtr plan = dft_3d(n0, n1, n2, handle.AddrOfPinnedObject(), handle.AddrOfPinnedObject(), (fftw_direction)direction, fftw_flags.Estimate); execute(plan); destroy_plan(plan); FftwLock.ReleaseMutex(); handle.Free(); }
/*------------------------------------------------------------------------- * Perform a 2D FFT inplace given a complex 2D array. * The dimensions of c must be powers of 2 */ public static Complex[,] FFT2D(Complex[,] c, FourierDirection dir) { int rows = c.GetLength(0), cols = c.GetLength(1); Complex[,] result = new Complex[rows, cols]; double[] real = new double[cols]; double[] imag = new double[cols]; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { real[j] = c[i, j].real; imag[j] = c[i, j].imag; } // Calling 1D FFT Function for Rows FFT1D(ref real, ref imag, dir); for (int j = 0; j < cols; j++) { result[i, j].real = real[j]; result[i, j].imag = imag[j]; } } real = new double[rows]; imag = new double[rows]; for (int i = 0; i < cols; i++) { for (int j = 0; j < rows; j++) { real[j] = result[j, i].real; imag[j] = result[j, i].imag; } // Calling 1D FFT Function for Columns FFT1D(ref real, ref imag, dir); for (int j = 0; j < rows; j++) { result[j, i].real = real[j]; result[j, i].imag = imag[j]; } } return(result); }
//====================================================================================== /// <summary> /// Compute a 1D fast Fourier transform of a dataset of complex numbers. /// </summary> /// <param name="data"></param> /// <param name="length"></param> /// <param name="direction"></param> public static void FFT(ComplexF[] data, int length, FourierDirection direction) { SyncLookupTableLength(length); int ln = Log2(length); // reorder array ReorderArray(data); // successive doubling int N = 1; int signIndex = (direction == FourierDirection.Forward) ? 0 : 1; for (int level = 1; level <= ln; level++) { int M = N; N <<= 1; float[] uRLookup = _uRLookupF[level, signIndex]; float[] uILookup = _uILookupF[level, signIndex]; for (int j = 0; j < M; j++) { float uR = uRLookup[j]; float uI = uILookup[j]; for (int even = j; even < length; even += N) { int odd = even + M; float r = data[odd].Re; float i = data[odd].Im; float odduR = r * uR - i * uI; float odduI = r * uI + i * uR; r = data[even].Re; i = data[even].Im; data[even].Re = r + odduR; data[even].Im = i + odduI; data[odd].Re = r - odduR; data[odd].Im = i - odduI; } } } }
/// <summary> /// Fourier transform /// </summary> /// <param name="array">Array</param> /// <param name="direction">Fourier direction</param> public static void Fourier(Complex[,] array, FourierDirection direction) { int n0 = array.GetLength(0); int n1 = array.GetLength(1); GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned); FftwLock.WaitOne(); IntPtr plan = dft_2d(n0, n1, handle.AddrOfPinnedObject(), handle.AddrOfPinnedObject(), (fftw_direction)direction, fftw_flags.Estimate); execute(plan); destroy_plan(plan); FftwLock.ReleaseMutex(); handle.Free(); }
public ChirpNativeFFTStorage(int msize, int arrsize, FourierDirection direction) { _msize = msize; _arrSize = arrsize; _direction = direction; _xjfj_real = new double[msize]; _xjfj_imag = new double[msize]; _fserp_real = new double[msize]; _fserp_imag = new double[msize]; _resarray_real = new double[msize]; _resarray_imag = new double[msize]; _chirpfactors_real = new double[arrsize]; _chirpfactors_imag = new double[arrsize]; PreCompute_ChirpFactors(); // Precompute the factors for An: Exp(sign * I * Pi * i^2/N) Precompute_Fouriertransformed_ChirpFactorsConjugate(); // Pre-compute fserp using Pre-computed chirp-factors }
// One dimensional Discrete Fourier Transform public static void DFT(Complex[] data, FourierDirection direction) { int n = data.Length; double arg, cos, sin; Complex[] dst = new Complex[n]; // for each destination element for (int i = 0; i < n; i++) { dst[i] = Complex.Zero; arg = -(int)direction * 2.0 * System.Math.PI * (double)i / (double)n; // sum source elements for (int j = 0; j < n; j++) { cos = System.Math.Cos(j * arg); sin = System.Math.Sin(j * arg); dst[i].Re += (float)(data[j].Re * cos - data[j].Im * sin); dst[i].Im += (float)(data[j].Re * sin + data[j].Im * cos); } } // copy elements if (direction == FourierDirection.Forward) { // devide also for forward transform for (int i = 0; i < n; i++) { data[i].Re = dst[i].Re / n; data[i].Im = dst[i].Im / n; } } else { for (int i = 0; i < n; i++) { data[i].Re = dst[i].Re; data[i].Im = dst[i].Im; } } }
// One dimensional Discrete Fourier Transform public static void DFT( Complex[] data, FourierDirection direction ) { int n = data.Length; double arg, cos, sin; Complex[] dst = new Complex[n]; // for each destination element for ( int i = 0; i < n; i++ ) { dst[i] = Complex.Zero; arg = - (int) direction * 2.0 * System.Math.PI * (double) i / (double) n; // sum source elements for ( int j = 0; j < n; j++ ) { cos = System.Math.Cos( j * arg ); sin = System.Math.Sin( j * arg ); dst[i].Re += (float) ( data[j].Re * cos - data[j].Im * sin ); dst[i].Im += (float) ( data[j].Re * sin + data[j].Im * cos ); } } // copy elements if ( direction == FourierDirection.Forward ) { // devide also for forward transform for ( int i = 0; i < n; i++ ) { data[i].Re = dst[i].Re / n; data[i].Im = dst[i].Im / n; } } else { for ( int i = 0; i < n; i++ ) { data[i].Re = dst[i].Re; data[i].Im = dst[i].Im; } } }
/// <summary> /// Compute a 2D fast fourier transform on a data set of complex numbers /// </summary> /// <param name="data"></param> /// <param name="xLength"></param> /// <param name="yLength"></param> /// <param name="direction"></param> public static void FFT2(Complex[] data, int xLength, int yLength, FourierDirection direction) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length < xLength * yLength) { throw new ArgumentOutOfRangeException("data.Length", data.Length, "must be at least as large as 'xLength * yLength' parameter"); } if (Fourier.IsPowerOf2(xLength) == false) { throw new ArgumentOutOfRangeException("xLength", xLength, "must be a power of 2"); } if (Fourier.IsPowerOf2(yLength) == false) { throw new ArgumentOutOfRangeException("yLength", yLength, "must be a power of 2"); } int xInc = 1; int yInc = xLength; if (xLength > 1) { Fourier.SyncLookupTableLength(xLength); for (int y = 0; y < yLength; y++) { int xStart = y * yInc; Fourier.LinearFFT_Quick(data, xStart, xInc, xLength, direction); } } if (yLength > 1) { Fourier.SyncLookupTableLength(yLength); for (int x = 0; x < xLength; x++) { int yStart = x * xInc; Fourier.LinearFFT_Quick(data, yStart, yInc, yLength, direction); } } }
private static void LinearFFT(float[] data, int start, int inc, int length, FourierDirection direction) { float[] buffer = null; LockBufferF(length * 2, ref buffer); int num = start; for (int i = 0; i < length * 2; i++) { buffer[i] = data[num]; num += inc; } FFT(buffer, length, direction); num = start; for (int j = 0; j < length; j++) { data[num] = buffer[j]; num += inc; } UnlockBufferF(ref buffer); }
public static void FFT2(float[] data, int xLength, int yLength, FourierDirection direction) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length < xLength * yLength * 2) { throw new ArgumentOutOfRangeException("data.Length", data.Length, "must be at least as large as 'xLength * yLength * 2' parameter"); } if (!IsPowerOf2(xLength)) { throw new ArgumentOutOfRangeException("xLength", xLength, "must be a power of 2"); } if (!IsPowerOf2(yLength)) { throw new ArgumentOutOfRangeException("yLength", yLength, "must be a power of 2"); } int num = 1; if (xLength > 1) { SyncLookupTableLength(xLength); for (int i = 0; i < yLength; i++) { int start = i * xLength; LinearFFT_Quick(data, start, num, xLength, direction); } } if (yLength > 1) { SyncLookupTableLength(yLength); for (int j = 0; j < xLength; j++) { int start2 = j * num; LinearFFT_Quick(data, start2, xLength, yLength, direction); } } }
public static void FFT(Complex[] data, FourierDirection direction) { int length = data.Length; int num2 = Tools.Log2(length); ReorderData(data); int num3 = 1; for (int i = 1; i <= num2; i++) { Complex[] complexRotation = GetComplexRotation(i, direction); int num4 = num3; num3 = num3 << 1; for (int j = 0; j < num4; j++) { Complex complex = complexRotation[j]; for (int k = j; k < length; k += num3) { int index = k + num4; Complex complex2 = data[k]; Complex complex3 = data[index]; float num9 = (complex3.Re * complex.Re) - (complex3.Im * complex.Im); float num10 = (complex3.Re * complex.Im) + (complex3.Im * complex.Re); data[k].Re += num9; data[k].Im += num10; data[index].Re = complex2.Re - num9; data[index].Im = complex2.Im - num10; } } } if (direction == FourierDirection.Forward) { for (int m = 0; m < length; m++) { data[m].Re /= (float)length; data[m].Im /= (float)length; } } }
/// <summary> /// 傅里叶转换 /// </summary> /// <param name="data"></param> /// <param name="length"></param> /// <param name="direction"></param> public static void FFT(float[] data, int length, FourierDirection direction) { SyncLookupTableLength(length); int num = Log2(length); ReorderArray(data); int num2 = 1; int num3 = ((direction != FourierDirection.Forward) ? 1 : 0); for (int i = 1; i <= num; i++) { int num4 = num2; num2 <<= 1; float[] array = _uRLookupF[i, num3]; float[] array2 = _uILookupF[i, num3]; for (int j = 0; j < num4; j++) { float num5 = array[j]; float num6 = array2[j]; for (int k = j; k < length; k += num2) { int num7 = k << 1; int num8 = k + num4 << 1; float num9 = data[num8]; float num10 = data[num8 + 1]; float num11 = num9 * num5 - num10 * num6; float num12 = num9 * num6 + num10 * num5; num9 = data[num7]; num10 = data[num7 + 1]; data[num7] = num9 + num11; data[num7 + 1] = num10 + num12; data[num8] = num9 - num11; data[num8 + 1] = num10 - num12; } } } }
/// <summary> /// Compute a 1D fast Fourier transform of a dataset of complex numbers. /// </summary> /// <param name="data"></param> /// <param name="length"></param> /// <param name="direction"></param> public static void FFT_Quick( Complex[] data, int length, FourierDirection direction ) { /*if( data == null ) { throw new ArgumentNullException( "data" ); } if( data.Length < length ) { throw new ArgumentOutOfRangeException( "length", length, "must be at least as large as 'data.Length' parameter" ); } if( Fourier.IsPowerOf2( length ) == false ) { throw new ArgumentOutOfRangeException( "length", length, "must be a power of 2" ); } Fourier.SyncLookupTableLength( length ); */ int ln = Fourier.Log2( length ); // reorder array Fourier.ReorderArray( data ); // successive doubling int N = 1; int signIndex = ( direction == FourierDirection.Forward ) ? 0 : 1; for( int level = 1; level <= ln; level ++ ) { int M = N; N <<= 1; double[] uRLookup = _uRLookup[ level, signIndex ]; double[] uILookup = _uILookup[ level, signIndex ]; for( int j = 0; j < M; j ++ ) { double uR = uRLookup[j]; double uI = uILookup[j]; for( int even = j; even < length; even += N ) { int odd = even + M; double r = data[ odd ].Re; double i = data[ odd ].Im; double odduR = r * uR - i * uI; double odduI = r * uI + i * uR; r = data[ even ].Re; i = data[ even ].Im; data[ even ].Re = r + odduR; data[ even ].Im = i + odduI; data[ odd ].Re = r - odduR; data[ odd ].Im = i - odduI; } } } }
// Two dimensional Fast Fourier Transform public static void FFT2( Complex[,] data, FourierDirection direction ) { int k = data.GetLength( 0 ); int n = data.GetLength( 1 ); // check data size if ( ( !Tools.IsPowerOf2( k ) ) || ( !Tools.IsPowerOf2( n ) ) || ( k < minLength ) || ( k > maxLength ) || ( n < minLength ) || ( n > maxLength ) ) { throw new ArgumentException( ); } // process rows Complex[] row = new Complex[n]; for ( int i = 0; i < k; i++ ) { // copy row for ( int j = 0; j < n; j++ ) row[j] = data[i, j]; // transform it FourierTransform.FFT( row, direction ); // copy back for ( int j = 0; j < n; j++ ) data[i, j] = row[j]; } // process columns Complex[] col = new Complex[k]; for ( int j = 0; j < n; j++ ) { // copy column for ( int i = 0; i < k; i++ ) col[i] = data[i, j]; // transform it FourierTransform.FFT( col, direction ); // copy back for ( int i = 0; i < k; i++ ) data[i, j] = col[i]; } }
// Two dimensional Discrete Fourier Transform public static void DFT2( Complex[,] data, FourierDirection direction ) { int n = data.GetLength( 0 ); // rows int m = data.GetLength( 1 ); // columns double arg, cos, sin; Complex[] dst = new Complex[System.Math.Max( n, m )]; // process rows for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < m; j++ ) { dst[j] = Complex.Zero; arg = - (int) direction * 2.0 * System.Math.PI * (double) j / (double) m; // sum source elements for ( int k = 0; k < m; k++ ) { cos = System.Math.Cos( k * arg ); sin = System.Math.Sin( k * arg ); dst[j].Re += (float) ( data[i, k].Re * cos - data[i, k].Im * sin ); dst[j].Im += (float) ( data[i, k].Re * sin + data[i, k].Im * cos ); } } // copy elements if ( direction == FourierDirection.Forward ) { // devide also for forward transform for ( int j = 0; j < m; j++ ) { data[i, j].Re = dst[j].Re / m; data[i, j].Im = dst[j].Im / m; } } else { for ( int j = 0; j < m; j++ ) { data[i, j].Re = dst[j].Re; data[i, j].Im = dst[j].Im; } } } // process columns for ( int j = 0; j < m; j++ ) { for ( int i = 0; i < n; i++ ) { dst[i] = Complex.Zero; arg = - (int) direction * 2.0 * System.Math.PI * (double) i / (double) n; // sum source elements for ( int k = 0; k < n; k++ ) { cos = System.Math.Cos( k * arg ); sin = System.Math.Sin( k * arg ); dst[i].Re += (float) ( data[k, j].Re * cos - data[k, j].Im * sin ); dst[i].Im += (float) ( data[k, j].Re * sin + data[k, j].Im * cos ); } } // copy elements if ( direction == FourierDirection.Forward ) { // devide also for forward transform for ( int i = 0; i < n; i++ ) { data[i, j].Re = dst[i].Re / n; data[i, j].Im = dst[i].Im / n; } } else { for ( int i = 0; i < n; i++ ) { data[i, j].Re = dst[i].Re; data[i, j].Im = dst[i].Im; } } } }
/// <summary> /// Voert een 2 dimensionale Fourier analyse uit op een afbeelding /// </summary> /// <param name="invoer">De complexe waarden van de afbeelding</param> /// <param name="dir">FourierDirection.Forward or FourierDirection.Backward</param> /// <returns>Fourier resultset</returns> private static ComplexGetal[,] FFT2D(ComplexGetal[,] invoer, FourierDirection dir) { float[] reëel = new float[invoer.GetLength(1)]; float[] imaginair = new float[invoer.GetLength(1)]; ComplexGetal[,] resultaat = invoer; //rijen for (int i = 0; i < invoer.GetLength(0); i++) { // Plaats de waarden in een 1 dimensionale array for (int j = 0; j < invoer.GetLength(1); j++) { reëel[j] = invoer[i, j].Reëel; imaginair[j] = invoer[i, j].Imaginair; } // Voer een 1 dimensionale fourier analyse uit op de huidige rij FFT1D(dir, reëel, imaginair); // Plaats de waarden in het resultaat object for (int j = 0; j < resultaat.GetLength(1); j++) { resultaat[i, j].Reëel = reëel[j]; resultaat[i, j].Imaginair = imaginair[j]; } } //kolommen - gebruik nu het resultaat object, anders gaan de berekeningen van de rijen verloren for (int i = 0; i < resultaat.GetLength(1); i++) { // Plaats de waarden in een 1 dimensionale array for (int j = 0; j < resultaat.GetLength(0); j++) { reëel[j] = resultaat[j, i].Reëel; imaginair[j] = resultaat[j, i].Imaginair; } // Voer een 1 dimensionale fourier analyse uit op de huidige kolom FFT1D(dir, reëel, imaginair); // Plaats de waarden in het resultaat object for (int j = 0; j < resultaat.GetLength(0); j++) { resultaat[j, i].Reëel = reëel[j]; resultaat[j, i].Imaginair = imaginair[j]; } } return resultaat; }
public static void FFT2(Complex[,] data, FourierDirection direction) { int length = data.GetLength(0); int x = data.GetLength(1); if (((!Tools.IsPowerOf2(length) || !Tools.IsPowerOf2(x)) || ((length < 2) || (length > 0x4000))) || ((x < 2) || (x > 0x4000))) { throw new ArgumentException(); } Complex[] complexArray = new Complex[x]; for (int i = 0; i < length; i++) { for (int k = 0; k < x; k++) { complexArray[k] = data[i, k]; } FFT(complexArray, direction); for (int m = 0; m < x; m++) { data[i, m] = complexArray[m]; } } Complex[] complexArray2 = new Complex[length]; for (int j = 0; j < x; j++) { for (int n = 0; n < length; n++) { complexArray2[n] = data[n, j]; } FFT(complexArray2, direction); for (int num8 = 0; num8 < length; num8++) { data[num8, j] = complexArray2[num8]; } } }
private static Complex[] GetComplexRotation(int numberOfBits, FourierDirection direction) { int num = (direction == FourierDirection.Forward) ? 0 : 1; if (complexRotation[numberOfBits - 1, num] == null) { int num2 = ((int)1) << (numberOfBits - 1); float re = 1f; float im = 0f; double d = (3.1415926535897931 / ((double)num2)) * ((double)direction); float num6 = (float)Math.Cos(d); float num7 = (float)Math.Sin(d); Complex[] complexArray = new Complex[num2]; for (int i = 0; i < num2; i++) { complexArray[i] = new Complex(re, im); float num8 = (re * num7) + (im * num6); re = (re * num6) - (im * num7); im = num8; } complexRotation[numberOfBits - 1, num] = complexArray; } return complexRotation[numberOfBits - 1, num]; }
/// <summary> /// This function computes an in-place complex-to-complex FFT /// x and y are the real and imaginary arrays of 2^m points. /// Both arrays must have equal size and must be a power of 2. /// dir = 1 gives forward transform /// dir = -1 gives reverse transform /// Formula: forward /// N-1 /// --- /// 1 \ - j k 2 pi n / N /// X(K) = --- > x(n) e = Forward transform /// N / n=0..N-1 /// --- /// n=0 /// Formula: reverse /// N-1 /// --- /// \ j k 2 pi n / N /// X(n) = > x(k) e = Inverse transform /// / k=0..N-1 /// --- /// k=0 /// The result is found in the arrays x and y. /// </summary> /// <param name="dir">FourierDirection.Forward or FourierDirection.Backward</param> /// <param name="x">real values</param> /// <param name="y">imaginary values</param> private static void FFT1D(FourierDirection dir, float[] x, float[] y) { long nn, i, i1, j, k, i2, l, l1, l2; float c1, c2, tx, ty, t1, t2, u1, u2, z; if (x.Length != y.Length) throw new FormatException("Real values and imaginary values arrays lengths do not match"); int m = (int)Math.Log(x.Length, 2); if (m != Math.Log(x.Length, 2)) throw new FormatException("Data arrays lenght is no power of two"); /* Calculate the number of points */ nn = 1; for (i = 0; i < m; i++) nn *= 2; /* Do the bit reversal */ i2 = nn >> 1; j = 0; for (i = 0; i < nn - 1; i++) { if (i < j) { tx = x[i]; ty = y[i]; x[i] = x[j]; y[i] = y[j]; x[j] = tx; y[j] = ty; } k = i2; while (k <= j) { j -= k; k >>= 1; } j += k; } /* Compute the FFT */ c1 = -1f; c2 = 0f; l2 = 1; for (l = 0; l < m; l++) { l1 = l2; l2 <<= 1; u1 = 1; u2 = 0; for (j = 0; j < l1; j++) { for (i = j; i < nn; i += l2) { i1 = i + l1; t1 = u1 * x[i1] - u2 * y[i1]; t2 = u1 * y[i1] + u2 * x[i1]; x[i1] = x[i] - t1; y[i1] = y[i] - t2; x[i] += t1; y[i] += t2; } z = u1 * c1 - u2 * c2; u2 = u1 * c2 + u2 * c1; u1 = z; } c2 = (float)Math.Sqrt((1f - c1) / 2f); if (dir == FourierDirection.Forward) c2 = -c2; c1 = (float)Math.Sqrt((1f + c1) / 2f); } /* Scaling for forward transform */ if (dir == FourierDirection.Forward) { for (i = 0; i < nn; i++) { x[i] /= nn; y[i] /= nn; } } }
/// <summary> /// Compute a 2D fast fourier transform on a data set of complex numbers /// </summary> /// <param name="data"></param> /// <param name="xLength"></param> /// <param name="yLength"></param> /// <param name="direction"></param> public static void FFT2( ComplexF[] data, int xLength, int yLength, FourierDirection direction ) { int xInc = 1; int yInc = xLength; if( xLength > 1 ) { SyncLookupTableLength( xLength ); for( int y = 0; y < yLength; y ++ ) { int xStart = y * yInc; LinearFFT_Quick( data, xStart, xInc, xLength, direction ); } } if( yLength > 1 ) { SyncLookupTableLength( yLength ); for( int x = 0; x < xLength; x ++ ) { int yStart = x * xInc; LinearFFT_Quick( data, yStart, yInc, yLength, direction ); } } }
/// <summary> /// Compute a 1D real-symmetric fast fourier transform. /// </summary> /// <param name="data"></param> /// <param name="length"></param> /// <param name="direction"></param> public static void RFFT( float[] data, int length, FourierDirection direction ) { if( data == null ) { throw new ArgumentNullException( "data" ); } if( data.Length < length ) { throw new ArgumentOutOfRangeException( "length", length, "must be at least as large as 'data.Length' parameter" ); } if( Fourier.IsPowerOf2( length ) == false ) { throw new ArgumentOutOfRangeException( "length", length, "must be a power of 2" ); } float c1 = 0.5f, c2; float theta = (float) Math.PI / (length/2); if( direction == FourierDirection.Forward ) { c2 = -0.5f; FFT( data, length/2, direction ); } else { c2 = 0.5f; theta = - theta; } float wtemp = (float) Math.Sin( 0.5*theta ); float wpr = -2 * wtemp*wtemp; float wpi =(float) Math.Sin( theta ); float wr = 1 + wpr; float wi = wpi; // do / undo packing for( int i = 1; i < length/4; i ++ ) { int a = 2*i; int b = length - 2*i; float h1r = c1 * ( data[ a ] + data[ b ] ); float h1i = c1 * ( data[ a+1 ] - data[ b+1 ] ); float h2r = -c2 * ( data[ a+1 ] + data[ b+1 ] ); float h2i = c2 * ( data[ a ] - data[ b ] ); data[ a ] = h1r + wr*h2r - wi*h2i; data[ a+1 ] = h1i + wr*h2i + wi*h2r; data[ b ] = h1r - wr*h2r + wi*h2i; data[ b+1 ] = -h1i + wr*h2i + wi*h2r; wr = (wtemp = wr) * wpr - wi * wpi + wr; wi = wi * wpr + wtemp * wpi + wi; } if( direction == FourierDirection.Forward ) { float hir = data[0]; data[0] = hir + data[1]; data[1] = hir - data[1]; } else { float hir = data[0]; data[0] = c1 * ( hir + data[1] ); data[1] = c1 * ( hir - data[1] ); Fourier.FFT( data, length/2, direction ); } }
// Get rotation of complex number private static Complex[] GetComplexRotation( int numberOfBits, FourierDirection direction ) { int directionIndex = ( direction == FourierDirection.Forward ) ? 0 : 1; // check if the array is already calculated if ( complexRotation[numberOfBits - 1, directionIndex] == null ) { int n = 1 << (numberOfBits - 1); float uR = 1.0f; float uI = 0.0f; double angle = System.Math.PI / n * (int) direction; float wR = (float) System.Math.Cos( angle ); float wI = (float) System.Math.Sin( angle ); float t; Complex[] rotation = new Complex[n]; for ( int i = 0; i < n; i++ ) { rotation[i] = new Complex(uR, uI); t = uR * wI + uI * wR; uR = uR * wR - uI * wI; uI = t; } complexRotation[numberOfBits - 1, directionIndex] = rotation; } return complexRotation[numberOfBits - 1, directionIndex]; }
private static void LinearFFT_Quick( float[] data, int start, int inc, int length, FourierDirection direction ) { /*Debug.Assert( data != null ); Debug.Assert( start >= 0 ); Debug.Assert( inc >= 1 ); Debug.Assert( length >= 1 ); Debug.Assert( ( start + inc * ( length - 1 ) ) * 2 < data.Length );*/ // copy to buffer float[] buffer = null; LockBufferF( length * 2, ref buffer ); int j = start; for( int i = 0; i < length * 2; i ++ ) { buffer[ i ] = data[ j ]; j += inc; } FFT_Quick( buffer, length, direction ); // copy from buffer j = start; for( int i = 0; i < length; i ++ ) { data[ j ] = buffer[ i ]; j += inc; } UnlockBufferF( ref buffer ); }
/// <summary> /// Convolves or deconvolves a real-valued data set data[] (including any /// user supplied zero padding) with a response function response[]. /// The result is returned in the array result[]. All arrays including /// the scratch[] array must have the same dimensions (or larger). /// The data set (and of course the other arrays) can be either one-dimensional, /// two-dimensional, or three-dimensional, d = 1,2,3. Each dimension must be /// of the form n = (2**p) * (3**q) * (5**r), because of the underlying FFT. /// The d-dimensional data can be either single precision (FLOAT := float) /// or double precision (FLOAT := double). /// </summary> /// <param name="data"> ///The real-valued data set. Note, that you have to /// care for end effects by zero padding. This means, /// that you have to pad the data with a number of zeros /// on one end equal to the maximal positive duration /// or maximal negative duration of the response function, /// whichever is larger!! /// </param> /// <param name="response"> /// The response function must be stored in wrap-around /// order. This means that the first half of the array /// response[] (in each dimension) contains the impulse /// response function at positive times, while the second /// half of the array contains the impulse response /// function at negative times, counting down from the /// element with the highest index. The array must have /// at least the size of the data array. /// </param> /// <param name="result"> /// The result array. It must have /// at least the size of the data array. /// </param> /// <param name="scratch"> /// A work array. If a NULL pointer is passed the /// work array is allocated and freed auotomatically. /// If the array is given by the user it must have /// at least the size of the data array. /// </param> /// <param name="isign"> /// If isign == forward a convolution is performed. /// If isign == inverse then a deconvolution is performed. /// </param> /// <returns> /// In the case of a convolution (isign == forward) the value "true" is returned /// always. In the case of deconvolution (isign == inverse) the value "false" is /// returned if the FFT transform of the response function is exactly zero for /// some value. This indicates that the original convolution has lost all /// information at this particular frequency, so that a reconstruction is not /// possible. If the transform of the response function is non-zero everywhere /// the deconvolution can be performed and the value "true" is returned. ///</returns> ///<remarks> /// Implementation notes /// -------------------- /// The FFT of the real-valued data array and the real-valued response array is /// calculated in one step. This is done by regarding the two arrays /// as the real part and the imaginary part of one complex-valued array. /// /// Possible improvements /// --------------------- /// * When doing the backtransform only a real transform is necessary. /// The upper half of the result/scratch arrays is redundant. /// (comment: "symmetry"). This should be used to speed-up the backtransform. /// /// * 2D and 3D versions are not yet available !!! ///</remarks> public bool Convolute (double[] data, double[] response, double[] result, double[] scratch, FourierDirection isign) { // return status bool status = true; // get total size of data array int size = 0; if (ndim == 0) { throw new ArithmeticException("MpConvolution::Convolute no dimensions have been specified"); } else if (ndim == 1) { size = dim[0]; } else if (ndim == 2) { size = row_order ? (dim[0] * id) : (id * dim[1]); } else if (ndim == 3) { size = row_order ? (dim[0] * dim[1] * id) : (id * dim[1] * dim[2]); } // allocate the scratch array //bool auto_scratch = false; if ( null==scratch ) { scratch = new double[size]; //auto_scratch = true; } //---------------------------------------------------------------------------// // 1-dimensional convolution (original data not are overwritten) //---------------------------------------------------------------------------// if (ndim == 1) { // First copy the arrays data and response to result and scratch, // respectively, to prevent overwriting of the original data. Array.Copy(data,result,size); Array.Copy(response,scratch, size); // transform both arrays simultaneously - this is a forward FFT base.FFT(result,scratch, FourierDirection.Forward); // multiply FFTs to convolve int n = dim[0], n2 = n/2; if (isign == FourierDirection.Forward) { double scale = 0.25/n; result[0] *= scratch[0] / n; scratch[0] = 0; for (int i = 1; i <= n2; i++) { double rr = result[i] + result[n-i], ri = result[i] - result[n-i], sr = scratch[i] + scratch[n-i], si = scratch[i] - scratch[n-i]; result[i] = scale * (rr*sr + ri*si); // real part scratch[i] = scale * (si*sr - ri*rr); // imaginary part result[n-i] = result[i]; // symmetry scratch[n-i] = -scratch[i]; // symmetry } } else /* isign == inverse */ { double mag; if ((mag = Square(scratch[0])) == 0.0) { // check for zero divide status = false; goto ErrorExit; } result[0] *= scratch[0] / mag / n; scratch[0] = 0; for (int i = 1; i <= n2; i++) { double rr = result[i] + result[n-i], ri = result[i] - result[n-i], sr = scratch[i] + scratch[n-i], si = scratch[i] - scratch[n-i]; if ((mag = sr*sr + ri*ri) == 0.0) { // check for zero divide status = false; goto ErrorExit; } result[i] = (rr*sr - ri*si) / (n*mag); // real part scratch[i] = (si*sr + ri*rr) / (n*mag); // imaginary part result[n-i] = result[i]; // symmetry scratch[n-i] = -scratch[i]; // symmetry } } // transform back - this is an inverse FFT base.FFT(result,scratch, FourierDirection.Inverse); //---------------------------------------------------------------------------// // 2-dimensional convolution //---------------------------------------------------------------------------// } else if (ndim == 2) { int n = dim[0], m = dim[1]; // set imaginary parts to zero FillZero(result); // imaginary part of data FillZero(scratch); // imaginary part of response // transform both arrays - this is a forward FFT base.FFT(data,result, FourierDirection.Forward); base.FFT(response,scratch,FourierDirection.Forward); if (isign == FourierDirection.Forward) { double scale = 1.0/n/m; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) { int l = row_order ? i*id+j : j*id+i; // do complex multiplication with three real multiplications // (a+ib)(c+id) = ( ac-bd ) + i( (a+b)(c+d)-ac-bd ) double ac = data[l]*response[l], bd = result[l]*scratch[l]; scratch[l] = scale*((data[l]+result[l])*(response[l]+scratch[l])-ac-bd); result[l] = scale*(ac-bd); } } else /* isign == inverse */ { double mag, scale = 1.0/n/m; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) { int l = row_order ? i*id+j : j*id+i; // do complex division (a+ib)/(c+id) = // (a+ib)(c-id)/(cc+dd) = [(ac+bd) + i((a+b)(c-d)-ac+bd)]/(cc+dd) if ((mag = Square(response[l])+Square(scratch[l])) == 0.0) { status = false; goto ErrorExit; } mag = scale/mag; double ac = data[l]*response[l], bd = result[l]*scratch[l]; scratch[l] = mag*((data[l]+result[l])*(response[l]-scratch[l])-ac+bd); result[l] = mag*(ac+bd); } } // transform back - this is an inverse FFT base.FFT(result,scratch,FourierDirection.Inverse); //---------------------------------------------------------------------------// // 3-dimensional convolution //---------------------------------------------------------------------------// } else if (ndim == 3) { int n = dim[0], m = dim[1], p = dim[2]; // set imaginary parts to zero FillZero(result); // imaginary part of data FillZero(scratch); // imaginary part of response // transform both arrays - this is a forward FFT base.FFT(data,result,FourierDirection.Forward); base.FFT(response,scratch,FourierDirection.Forward); if (isign == FourierDirection.Forward) { double scale = 1.0/n/m/p; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) for (int k = 0; k < p; k++) { int l = row_order ? (i*m+j)*id+k : (k*m+j)*id+i; // do complex multiplication with three real multiplications // (a+ib)(c+id) = ( ac-bd ) + i( (a+b)(c+d)-ac-bd ) double ac = data[l]*response[l], bd = result[l]*scratch[l]; scratch[l] = scale*((data[l]+result[l])*(response[l]+scratch[l])-ac-bd); result[l] = scale*(ac-bd); } } else /* isign == inverse */ { double mag, scale = 1.0/n/m/p; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) for (int k = 0; k < p; k++) { int l = row_order ? (i*m+j)*id+k : (k*m+j)*id+i; // do complex division (a+ib)/(c+id) = // (a+ib)(c-id)/(cc+dd) = [(ac+bd) + i((a+b)(c-d)-ac+bd)]/(cc+dd) if ((mag = Square(response[l])+Square(scratch[l])) == 0.0) { status = false; goto ErrorExit; } mag = scale/mag; double ac = data[l]*response[l], bd = result[l]*scratch[l]; scratch[l] = mag*((data[l]+result[l])*(response[l]-scratch[l])-ac+bd); result[l] = mag*(ac+bd); } } // transform back - this is an inverse FFT base.FFT(result,scratch,FourierDirection.Inverse); } ErrorExit: return status; }
/// <summary> /// Convolves or deconvolves a splitted complex-valued data set data[] (including any /// user supplied zero padding) with a response function response[]. /// The result is returned in the splitted complex arrays resultre[] and resultim[]. All arrays including /// the scratch[] arrays must have the same dimensions (or larger). /// The data set (and of course the other arrays) can be either one-dimensional, /// two-dimensional, or three-dimensional, d = 1,2,3. Each dimension must be /// of the form n = (2**p) * (3**q) * (5**r), because of the underlying FFT. /// </summary> /// <param name="datare"> /// The splitted complex-valued data set. Note, that you have to /// care for end effects by zero padding. This means, /// that you have to pad the data with a number of zeros /// on one end equal to the maximal positive duration /// or maximal negative duration of the response function, /// whichever is larger!!</param> /// <param name="dataim">The imaginary part of the data array.</param> /// <param name="responsere"> /// The response function must be stored in wrap-around /// order. This means that the first half of the array /// response[] (in each dimension) contains the impulse /// response function at positive times, while the second /// half of the array contains the impulse response /// function at negative times, counting down from the /// element with the highest index. The array must have /// at least the size of the data array. /// </param> /// <param name="responseim">The imaginary part of the response array.</param> /// <param name="resultre"> /// The real part of the result array. It must have /// at least the size of the data array. /// </param> /// <param name="resultim">The imaginary part of the result array.</param> /// <param name="scratchre"> /// A work array. If a NULL pointer is passed the /// work array is allocated and freed auotomatically. /// If the array is given by the user it must have /// at least the size of the data array. /// </param> /// <param name="scratchim"> /// A work array. If a NULL pointer is passed the /// work array is allocated and freed auotomatically. /// If the array is given by the user it must have /// at least the size of the data array. /// </param> /// <param name="isign"> /// If isign == forward a convolution is performed. /// If isign == inverse then a deconvolution is performed. /// </param> /// <returns> /// In the case of a convolution (isign == forward) the value "true" is returned /// always. In the case of deconvolution (isign == inverse) the value "false" is /// returned if the FFT transform of the response function is exactly zero for /// some value. This indicates that the original convolution has lost all /// information at this particular frequency, so that a reconstruction is not /// possible. If the transform of the response function is non-zero everywhere /// the deconvolution can be performed and the value "true" is returned. /// </returns> public bool Convolute ( double[] datare, double[] dataim, double[] responsere, double[] responseim, double[] resultre, double[] resultim, double[] scratchre, double[] scratchim, FourierDirection isign) { // return status bool status = true; // get total size of data array int size = 0; if (ndim == 0) { throw new ArithmeticException("Convolute: no dimensions have been specified"); } else if (ndim == 1) { size = dim[0]; } else if (ndim == 2) { size = row_order ? (dim[0] * id) : (id * dim[1]); } else if (ndim == 3) { size = row_order ? (dim[0] * dim[1] * id) : (id * dim[1] * dim[2]); } // allocate the scratch array //bool auto_scratch = false; if ( null==scratchre ) scratchre = new double[size]; if ( null==scratchim ) scratchim = new double[size]; //---------------------------------------------------------------------------// // 1-dimensional convolution (original data not are overwritten) //---------------------------------------------------------------------------// if (ndim == 1) { // First copy the arrays data and response to result and scratch, // respectively, to prevent overwriting of the original data. Array.Copy(datare,resultre,size); Array.Copy(dataim,resultim,size); Array.Copy(responsere,scratchre, size); Array.Copy(responseim,scratchim, size); // transform both arrays simultaneously - this is a forward FFT base.FFT(resultre,resultim, FourierDirection.Forward); base.FFT(scratchre,scratchim, FourierDirection.Forward); // multiply FFTs to convolve int n = dim[0]; if (isign == FourierDirection.Forward) { double scale = 1.0/n; for (int i = 0; i < n; i++) { double re = resultre[i]*scratchre[i] - resultim[i]*scratchim[i]; double im = resultre[i]*scratchim[i] + resultim[i]*scratchre[i]; resultre[i] = re*scale; resultim[i] = im*scale; } } else /* isign == inverse */ { double mag; if ((mag = Square(scratchre[0])+Square(scratchim[0])) == 0.0) { // check for zero divide status = false; goto ErrorExit; } for (int i = 0; i < n; i++) { double rr = resultre[i]; double ri = resultim[i]; double sr = scratchre[i]; double si = scratchim[i]; if ((mag = sr*sr + ri*ri) == 0.0) { // check for zero divide status = false; goto ErrorExit; } resultre[i] = (rr*sr - ri*si) / (n*mag); // real part resultim[i] = (si*sr + ri*rr) / (n*mag); // imaginary part } } // transform back - this is an inverse FFT base.FFT(resultre,resultim, FourierDirection.Inverse); } else { throw new NotImplementedException("Sorry, convolution of dimension 2 or 3 is not implemented yet. Will you do it?"); } ErrorExit: return status; }
/// <summary> /// Compute a 3D fast fourier transform on a data set of complex numbers /// </summary> /// <param name="data"></param> /// <param name="xLength"></param> /// <param name="yLength"></param> /// <param name="zLength"></param> /// <param name="direction"></param> public static void FFT3( Complex[] data, int xLength, int yLength, int zLength, FourierDirection direction ) { if( data == null ) { throw new ArgumentNullException( "data" ); } if( data.Length < xLength*yLength*zLength ) { throw new ArgumentOutOfRangeException( "data.Length", data.Length, "must be at least as large as 'xLength * yLength * zLength' parameter" ); } if( Fourier.IsPowerOf2( xLength ) == false ) { throw new ArgumentOutOfRangeException( "xLength", xLength, "must be a power of 2" ); } if( Fourier.IsPowerOf2( yLength ) == false ) { throw new ArgumentOutOfRangeException( "yLength", yLength, "must be a power of 2" ); } if( Fourier.IsPowerOf2( zLength ) == false ) { throw new ArgumentOutOfRangeException( "zLength", zLength, "must be a power of 2" ); } int xInc = 1; int yInc = xLength; int zInc = xLength * yLength; if( xLength > 1 ) { Fourier.SyncLookupTableLength( xLength ); for( int z = 0; z < zLength; z ++ ) { for( int y = 0; y < yLength; y ++ ) { int xStart = y * yInc + z * zInc; Fourier.LinearFFT_Quick( data, xStart, xInc, xLength, direction ); } } } if( yLength > 1 ) { Fourier.SyncLookupTableLength( yLength ); for( int z = 0; z < zLength; z ++ ) { for( int x = 0; x < xLength; x ++ ) { int yStart = z * zInc + x * xInc; Fourier.LinearFFT_Quick( data, yStart, yInc, yLength, direction ); } } } if( zLength > 1 ) { Fourier.SyncLookupTableLength( zLength ); for( int y = 0; y < yLength; y ++ ) { for( int x = 0; x < xLength; x ++ ) { int zStart = y * yInc + x * xInc; Fourier.LinearFFT_Quick( data, zStart, zInc, zLength, direction ); } } } }
private static void LinearFFT_Quick( ComplexF[] data, int start, int inc, int length, FourierDirection direction ) { // copy to buffer ComplexF[] buffer = null; LockBufferCF( length, ref buffer ); int j = start; for( int i = 0; i < length; i ++ ) { buffer[ i ] = data[ j ]; j += inc; } FFT( buffer, length, direction ); // copy from buffer j = start; for( int i = 0; i < length; i ++ ) { data[ j ] = buffer[ i ]; j += inc; } UnlockBufferCF( ref buffer ); }
/// <summary> /// Compute a 1D real-symmetric fast fourier transform. /// </summary> /// <param name="data"></param> /// <param name="direction"></param> public static void RFFT( float[] data, FourierDirection direction ) { if( data == null ) { throw new ArgumentNullException( "data" ); } Fourier.RFFT( data, data.Length, direction ); }
//====================================================================================== /// <summary> /// Compute a 1D fast Fourier transform of a dataset of complex numbers. /// </summary> /// <param name="data"></param> /// <param name="length"></param> /// <param name="direction"></param> public static void FFT( ComplexF[] data, int length, FourierDirection direction ) { SyncLookupTableLength( length ); int ln = Log2( length ); // reorder array ReorderArray( data ); // successive doubling int N = 1; int signIndex = ( direction == FourierDirection.Forward ) ? 0 : 1; for( int level = 1; level <= ln; level ++ ) { int M = N; N <<= 1; float[] uRLookup = _uRLookupF[ level, signIndex ]; float[] uILookup = _uILookupF[ level, signIndex ]; for( int j = 0; j < M; j ++ ) { float uR = uRLookup[j]; float uI = uILookup[j]; for( int even = j; even < length; even += N ) { int odd = even + M; float r = data[ odd ].Re; float i = data[ odd ].Im; float odduR = r * uR - i * uI; float odduI = r * uI + i * uR; r = data[ even ].Re; i = data[ even ].Im; data[ even ].Re = r + odduR; data[ even ].Im = i + odduI; data[ odd ].Re = r - odduR; data[ odd ].Im = i - odduI; } } } }
private static void LinearFFT( Complex[] data, int start, int inc, int length, FourierDirection direction ) { Debug.Assert( data != null ); Debug.Assert( start >= 0 ); Debug.Assert( inc >= 1 ); Debug.Assert( length >= 1 ); Debug.Assert( ( start + inc * ( length - 1 ) ) < data.Length ); // copy to buffer Complex[] buffer = null; LockBufferC( length, ref buffer ); int j = start; for( int i = 0; i < length; i ++ ) { buffer[ i ] = data[ j ]; j += inc; } FFT( buffer, length, direction ); // copy from buffer j = start; for( int i = 0; i < length; i ++ ) { data[ j ] = buffer[ i ]; j += inc; } UnlockBufferC( ref buffer ); }
/// <summary> /// Compute a 1D fast Fourier transform of a dataset of complex numbers. /// </summary> /// <param name="data"></param> /// <param name="direction"></param> public static void FFT( ComplexF[] data, FourierDirection direction ) { if( data == null ) { throw new ArgumentNullException( "data" ); } FourierBase.FFT(data, data.Length, direction); }
/// <summary> /// Performs a inplace fourier transformation. The original values are overwritten by the fourier transformed values. /// </summary> /// <param name="arr">The data to transform. On output, the fourier transformed data.</param> /// <param name="direction">Specify forward or reverse transformation here.</param> public void Transform(double[] arr, FourierDirection direction) { if(arr.Length!=_numberOfData) throw new ArgumentException(string.Format("Length of array arr ({0}) is different from the length specified at construction ({1})",arr.Length,_numberOfData),"arr"); switch(_method) { case Method.Trivial: { if(_numberOfData==2) { double a0=arr[0],a1=arr[1]; arr[0]=a0+a1; arr[1]=a0-a1; } } break; case Method.Hartley: { FastHartleyTransform.RealFFT(arr,direction); } break; case Method.Pfa235: { NullifyTempArrN1(); _pfa235.RealFFT(arr,_tempArr1N,direction); } break; case Method.Chirp: { if(direction==FourierDirection.Forward) { NullifyTempArrN1(); } else { if(null==this._tempArr1N) _tempArr1N = new double[_numberOfData]; _tempArr1N[0]=0; for(int k=1;k<=_numberOfData/2;k++) { double sumreal = arr[k]; double sumimag = arr[_numberOfData-k]; _tempArr1N[k] = sumimag; _tempArr1N[_numberOfData-k] = -sumimag; arr[_numberOfData-k] = sumreal; } } ChirpFFT.FFT(arr, _tempArr1N, direction, ref _fftTempStorage); if(direction==FourierDirection.Forward) { for(int k=0;k<=_numberOfData/2;k++) { double sumreal = arr[k]; double sumimag = _tempArr1N[k]; if(k!=0 && (k+k)!=_numberOfData) arr[_numberOfData-k] = sumimag; arr[k] = sumreal; } } } break; } }
/// <summary> /// Compute a 2D fast fourier transform on a data set of complex numbers (represented as pairs of floats) /// </summary> /// <param name="data"></param> /// <param name="xLength"></param> /// <param name="yLength"></param> /// <param name="direction"></param> public static void FFT2( float[] data, int xLength, int yLength, FourierDirection direction ) { if( data == null ) { throw new ArgumentNullException( "data" ); } if( data.Length < xLength*yLength*2 ) { throw new ArgumentOutOfRangeException( "data.Length", data.Length, "must be at least as large as 'xLength * yLength * 2' parameter" ); } if (Misc.IsPowerOf2(xLength) == false) { throw new ArgumentOutOfRangeException( "xLength", xLength, "must be a power of 2" ); } if (Misc.IsPowerOf2(yLength) == false) { throw new ArgumentOutOfRangeException( "yLength", yLength, "must be a power of 2" ); } int xInc = 1; int yInc = xLength; if( xLength > 1 ) { FourierBase.SyncLookupTableLength(xLength); for( int y = 0; y < yLength; y ++ ) { int xStart = y * yInc; FourierBase.LinearFFT_Quick(data, xStart, xInc, xLength, direction); } } if( yLength > 1 ) { FourierBase.SyncLookupTableLength(yLength); for( int x = 0; x < xLength; x ++ ) { int yStart = x * xInc; FourierBase.LinearFFT_Quick(data, yStart, yInc, yLength, direction); } } }