private static void SyncLookupTableLength(int length) { Debug.Assert(length < 1024 * 10); Debug.Assert(length >= 0); if (length > _lookupTabletLength) { int level = (int)Math.Ceiling(Math.Log(length, 2)); Fourier.InitializeReverseBits(level); Fourier.InitializeComplexRotations(level); //_cFFTData = new Complex[ Math2.CeilingBase( length, 2 ) ]; //_cFFTDataF = new ComplexF[ Math2.CeilingBase( length, 2 ) ]; _lookupTabletLength = length; } }
/// <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 (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); } } }
static private void ReorderArray(double[] data) { Debug.Assert(data != null); int length = data.Length / 2; Debug.Assert(Fourier.IsPowerOf2(length) == true); Debug.Assert(length >= cMinLength); Debug.Assert(length <= cMaxLength); int[] reversedBits = Fourier.GetReversedBits(Fourier.Log2(length)); for (int i = 0; i < length; i++) { int swap = reversedBits[i]; if (swap > i) { Fourier.Swap(ref data[i << 1], ref data[swap << 1]); Fourier.Swap(ref data[i << 1 + 1], ref data[swap << 1 + 1]); } } }
static private int[] GetReversedBits(int numberOfBits) { Debug.Assert(numberOfBits >= cMinBits); Debug.Assert(numberOfBits <= cMaxBits); if (_reversedBits[numberOfBits - 1] == null) { int maxBits = Fourier.Pow2(numberOfBits); int[] reversedBits = new int[maxBits]; for (int i = 0; i < maxBits; i++) { int oldBits = i; int newBits = 0; for (int j = 0; j < numberOfBits; j++) { newBits = (newBits << 1) | (oldBits & 1); oldBits = (oldBits >> 1); } reversedBits[i] = newBits; } _reversedBits[numberOfBits - 1] = reversedBits; } return(_reversedBits[numberOfBits - 1]); }
/// <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); } }