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; } }
public static double [] SyncCoefficients(double [] Signal) { Complex [] CompSignal; double Sync; double [] ReturnValue; CompSignal = ConvertToComplex(HanningWindow(Signal)); Fourier.FFT(CompSignal, FourierDirection.Forward); Sync = CompSignal[0].Magnitude; ReturnValue = new double [CompSignal.Length / 2]; for (int i = 0; i < ReturnValue.Length; i++) { ReturnValue[i] = CompSignal[i].Magnitude / Sync; } ReturnValue[0] = 0; return(ReturnValue); }
public static double [] Autocorrelation(double [] Signal) { Complex [] InputSignal; Complex [] Correlation; InputSignal = ConvertToComplex(HanningWindow(Signal)); Fourier.FFT(InputSignal, FourierDirection.Forward); InputSignal[0].Re = 0; InputSignal[0].Im = 0; Correlation = new Complex[InputSignal.Length]; for (int i = 0; i < InputSignal.Length; i++) { InputSignal[i] = InputSignal[i] / InputSignal.Length; Correlation[i] = InputSignal[i] * InputSignal[i].Conjugate; } Fourier.FFT(Correlation, FourierDirection.Backward); // Normalize by the value in the zeroth element of the array return(MagnitudeAndSign(Correlation)); }
/// <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); } } }
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]); } } }
public static double [] Crosscorrelation(Complex [] SignalConjugate, double [] Signal) { Complex [] InputSignal; Complex [] Correlation; InputSignal = ConvertToComplex(HanningWindow(Signal)); Fourier.FFT(InputSignal, FourierDirection.Forward); InputSignal[0].Re = 0; InputSignal[0].Im = 0; SignalConjugate[0].Re = 0; SignalConjugate[0].Im = 0; Correlation = new Complex[InputSignal.Length]; for (int i = 0; i < InputSignal.Length; i++) { InputSignal[i] = InputSignal[i] / InputSignal.Length; Correlation[i] = InputSignal[i] * SignalConjugate[i]; } Fourier.FFT(Correlation, FourierDirection.Backward); // Normalize by the product of the standard deviations of the signal return(MagnitudeAndSign(Correlation)); }
static private void ReorderArray(Complex[] data) { Debug.Assert(data != null); int length = data.Length; 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) { Complex temp = data[i]; data[i] = data[swap]; data[swap] = temp; } } }
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 fast Fourier transform of a dataset of complex numbers. /// </summary> /// <param name="data"></param> /// <param name="direction"></param> public static void FFT(Complex[] data, FourierDirection direction) { int length = data.Length; 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; } } } }