/// <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 void FFT2(ComplexNumber[,] data, Direction 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("Incorrect data length."); } // process rows ComplexNumber[] row = new ComplexNumber[n]; for (int i = 0; i < k; i++) { // copy row for (int j = 0; j < n; j++) row[j] = data[i, j]; // transform it FFT(row, direction); // copy back for (int j = 0; j < n; j++) data[i, j] = row[j]; } // process columns ComplexNumber[] col = new ComplexNumber[k]; for (int j = 0; j < n; j++) { // copy column for (int i = 0; i < k; i++) col[i] = data[i, j]; // transform it FFT(col, direction); // copy back for (int i = 0; i < k; i++) data[i, j] = col[i]; } }
/// <summary> /// Two dimensional Discrete Fourier Transform. /// </summary> /// /// <param name="data">Data to transform.</param> /// <param name="direction">Transformation direction.</param> /// public void DFT2(ComplexNumber[,] data, Direction direction) { int n = data.GetLength(0); // rows int m = data.GetLength(1); // columns double arg, cos, sin; ComplexNumber[] dst = new ComplexNumber[System.Math.Max(n, m)]; // process rows for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { dst[j] = ComplexNumberConstants.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 += (data[i, k].Re * cos - data[i, k].Im * sin); dst[j].Im += (data[i, k].Re * sin + data[i, k].Im * cos); } } // copy elements if (direction == Direction.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] = ComplexNumberConstants.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 += (data[k, j].Re * cos - data[k, j].Im * sin); dst[i].Im += (data[k, j].Re * sin + data[k, j].Im * cos); } } // copy elements if (direction == Direction.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; } } } }