/// <summary> /// Two dimensional Fast Fourier Transform. /// </summary> /// /// <param name="data">Data to transform.</param> /// <param name="direction">Transformation direction.</param> /// /// <remarks><para><note>The method accepts <paramref name="data"/> array of 2<sup>n</sup> size /// only in each dimension, where <b>n</b> may vary in the [1, 14] range. For example, 16x16 array /// is valid, but 15x15 is not.</note></para></remarks> /// /// <exception cref="ArgumentException">Incorrect data length.</exception> /// public static void FFT2(Complex[,] data, Direction direction) { int k = data.GetLength(0); int n = data.GetLength(1); // check data size if (!Tools.IsPowerOf2(k) || !Tools.IsPowerOf2(n)) { throw new ArgumentException("The matrix rows and columns must be a power of 2."); } if (k < minLength || k > maxLength || n < minLength || n > maxLength) { throw new ArgumentException("Incorrect data length."); } // process rows var row = new Complex[n]; for (var i = 0; i < k; i++) { // copy row for (var j = 0; j < row.Length; j++) { row[j] = data[i, j]; } // transform it FourierTransform.FFT(row, direction); // copy back for (var j = 0; j < row.Length; j++) { data[i, j] = row[j]; } } // process columns var col = new Complex[k]; for (var j = 0; j < n; j++) { // copy column for (var i = 0; i < k; i++) { col[i] = data[i, j]; } // transform it FourierTransform.FFT(col, direction); // copy back for (var i = 0; i < k; i++) { data[i, j] = col[i]; } } }
/// <summary> /// Performs the Fast Hilbert Transform over a complex[] array. /// </summary> public static void FHT(Complex[] data, FourierTransform.Direction direction) { int N = data.Length; // Forward operation if (direction == FourierTransform.Direction.Forward) { // Makes a copy of the data so we don't lose the // original information to build our final signal Complex[] shift = (Complex[])data.Clone(); // Perform FFT FourierTransform.FFT(shift, FourierTransform.Direction.Backward); //double positive frequencies for (var i = 1; i < (N / 2); i++) { shift[i] *= 2.0; } // zero out negative frequencies // (leaving out the dc component) for (var i = (N / 2) + 1; i < N; i++) { shift[i] = Complex.Zero; } // Reverse the FFT FourierTransform.FFT(shift, FourierTransform.Direction.Forward); // Put the Hilbert transform in the Imaginary part // of the input signal, creating a Analytic Signal for (var i = 0; i < N; i++) { data[i] = new Complex(data[i].Real, shift[i].Imaginary); } } else // Backward operation { // Just discard the imaginary part for (var i = 0; i < data.Length; i++) { data[i] = new Complex(data[i].Real, 0.0); } } }
/// <summary> /// Gets the power Cepstrum for a complex signal. /// </summary> public static double[] GetPowerCepstrum(Complex[] signal) { if (signal is null) { throw new ArgumentNullException("signal"); } FourierTransform.FFT(signal, FourierTransform.Direction.Backward); var logabs = new Complex[signal.Length]; for (var i = 0; i < logabs.Length; i++) { logabs[i] = new Complex(Math.Log(signal[i].Magnitude), 0); } FourierTransform.FFT(logabs, FourierTransform.Direction.Forward); return(logabs.Re()); }