/// <summary> /// Computes an Fast Fourier Transform. /// </summary> /// <param name="data">Array of complex numbers. This array provides the input data and is used to store the result of the FFT.</param> /// <param name="exponent">The exponent n.</param> /// <param name="mode">The <see cref="FftMode"/> to use. Use <see cref="FftMode.Forward"/> as the default value.</param> public static void Fft(Complex[] data, int exponent, FftMode mode = FftMode.Forward) { //count; if exponent = 12 -> c = 2^12 = 4096 int c = (int)Math.Pow(2, exponent); //binary inversion Inverse(data, c); int j0, j1, j2 = 1; float n0, n1, tr, ti, m; float v0 = -1, v1 = 0; //move to outer scope to optimize performance int j, i; for (int l = 0; l < exponent; l++) { n0 = 1; n1 = 0; j1 = j2; j2 <<= 1; //j2 * 2 for (j = 0; j < j1; j++) { for (i = j; i < c; i += j2) { j0 = i + j1; //-- tr = n0 * data[j0].Real - n1 * data[j0].Imaginary; ti = n0 * data[j0].Imaginary + n1 * data[j0].Real; //-- data[j0].Real = data[i].Real - tr; data[j0].Imaginary = data[i].Imaginary - ti; //add data[i].Real += tr; data[i].Imaginary += ti; } //calc coeff m = v0 * n0 - v1 * n1; n1 = v1 * n0 + v0 * n1; n0 = m; } if (mode == FftMode.Forward) { v1 = (float)Math.Sqrt((1f - v0) / 2f); } else { v1 = (float)-Math.Sqrt((1f - v0) / 2f); } v0 = (float)Math.Sqrt((1f + v0) / 2f); } if (mode == FftMode.Forward) { Forward(data, c); } }
/// <summary> /// Performs forward transform to the specified span. /// </summary> /// <param name="span">The span.</param> /// <param name="mode">The FFT's Mode.</param> private static void Perform(Span <ComplexF> span, FftMode mode) { double thetaBase = mode == FftMode.Forward ? -Tau : Tau; if (span.Length < 2) { return; } Perform2(span); if (span.Length < 4) { return; } switch (mode) { case FftMode.Forward: Perform4Forward(span); break; case FftMode.Backward: Perform4Backward(span); break; } var index = 3; for (int m = 8; m <= span.Length; m <<= 1) { ComplexF t, u; Complex omega = 1; int mHalf = m >> 1; var omegaM = GetValueToMultiply(index++); omegaM = mode == FftMode.Forward ? Complex.Conjugate(omegaM) : omegaM; Span <ComplexF> omegas = stackalloc ComplexF[mHalf]; for (int i = 0; i < omegas.Length; i++) { omegas[i] = (ComplexF)omega; omega *= omegaM; } for (int k = 0; k < span.Length; k += m) { //Preset addressing reduces addition and boundary checks. var spanA = span.Slice(k, omegas.Length); var spanB = span.Slice(k + mHalf, spanA.Length); for (int j = 0; j < omegas.Length; j++) { t = omegas[j] * spanB[j]; u = spanA[j]; spanA[j] = u + t; spanB[j] = u - t; } } } }
/// <summary> /// Performs forward transform to the specified span. /// </summary> /// <param name="span">The span.</param> /// <param name="mode">The FFT's Mode.</param> private static void Perform(Span <Complex> span, FftMode mode) { double thetaBase = 2 * Math.PI * (mode == FftMode.Forward ? -1 : 1); Complex omega, omegaM; if (span.Length >= 2) { Perform2(span); if (span.Length >= 4) { switch (mode) { case FftMode.Forward: Perform4Forward(span); break; case FftMode.Backward: Perform4Backward(span); break; } for (int m = 8; m <= span.Length; m <<= 1) { Complex t, u; double theta = thetaBase / m; omegaM = Complex.FromPolarCoordinates(1, theta); for (int k = 0; k < span.Length; k += m) { omega = 1; int mHalf = m >> 1; //Preset addressing reduces addition and boundary checks. var spanA = span.Slice(k, mHalf); var spanB = span.Slice(k + mHalf, spanA.Length); for (int j = 0; j < spanA.Length; j++) { t = omega * spanB[j]; u = spanA[j]; spanA[j] = u + t; spanB[j] = u - t; omega *= omegaM; } } } } } }
public static void FFT1(Complex[] data, int exponent, FftMode mode) { Fft(data, exponent, mode); }