Skip to content
This repository has been archived by the owner on Nov 19, 2020. It is now read-only.

Commit

Permalink
Fixing 2D DFT function, adding unit tests and documentation examples.
Browse files Browse the repository at this point in the history
Updates:
- GH-257: DFT functions in AForge.Math.FourierTransform and Accord.Math.Transforms
- GH-500: Add an Example for FourierTransform2.FFT Method (Complex[], FourierTransform.Direction) doc-request
- GH-560: Add an Example for FourierTransform2.FFT Method (Double[], Double[], FourierTransform.Direction) doc-request
- GH-665: Add an Example for FourierTransform.FFT Method doc-request
  • Loading branch information
cesarsouza committed Sep 29, 2017
1 parent a69fe36 commit fd17ca0
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 98 deletions.
23 changes: 18 additions & 5 deletions Sources/Accord.Math/AForge.Math/FourierTransform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,27 @@ namespace Accord.Math
{
using System;
using Accord.Compat;
using System.Numerics;

using System.Numerics;
using Accord.Math.Transforms;

/// <summary>
/// Fourier transformation.
/// Original Fourier transform from AForge.NET. If possible,
/// please use <see cref="FourierTransform2"/> instead.
/// </summary>
///
/// <remarks>The class implements one dimensional and two dimensional
/// Discrete and Fast Fourier Transformation.</remarks>
/// <remarks>
/// <para>
/// The class implements one dimensional and two dimensional Discrete and Fast Fourier
/// Transformation. However, this class works only with square matrices with sizes that
/// are power of 2, and implements a different form of the transform that differs from
/// the implementations in other packages such as Octave and Matlab. For a more general
/// transform that should produce the same results as Octave, see <see cref="FourierTransform2"/>.</para>
///
/// <para>
/// This class may be deprecated (marked as obsolete) in the future.</para>
/// </remarks>
///
/// <seealso cref="FourierTransform2"/>
///
public static class FourierTransform
{
Expand Down
121 changes: 58 additions & 63 deletions Sources/Accord.Math/Matrix/Matrix.Complex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public static Complex[] Abs(this Complex[] x)
///
public static Complex Sum(this Complex[] x)
{
if (x == null) throw new ArgumentNullException("x");
if (x == null)
throw new ArgumentNullException("x");

Complex r = Complex.Zero;
for (int i = 0; i < x.Length; i++)
Expand All @@ -71,8 +72,10 @@ public static Complex Sum(this Complex[] x)
///
public static Complex[] Multiply(this Complex[] a, Complex[] b)
{
if (a == null) throw new ArgumentNullException("a");
if (b == null) throw new ArgumentNullException("b");
if (a == null)
throw new ArgumentNullException("a");
if (b == null)
throw new ArgumentNullException("b");

Complex[] r = new Complex[a.Length];
for (int i = 0; i < a.Length; i++)
Expand All @@ -88,14 +91,7 @@ public static Complex[] Multiply(this Complex[] a, Complex[] b)
///
public static double[] Magnitude(this Complex[] c)
{
if (c == null)
throw new ArgumentNullException("c");

double[] magnitudes = new double[c.Length];
for (int i = 0; i < c.Length; i++)
magnitudes[i] = c[i].Magnitude;

return magnitudes;
return c.Apply((x, i) => x.Magnitude);
}

/// <summary>
Expand All @@ -104,17 +100,16 @@ public static double[] Magnitude(this Complex[] c)
///
public static double[,] Magnitude(this Complex[,] c)
{
if (c == null) throw new ArgumentNullException("c");

int rows = c.GetLength(0);
int cols = c.GetLength(1);

double[,] magnitudes = new double[rows, cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
magnitudes[i, j] = c[i, j].Magnitude;
return c.Apply((x, i, j) => x.Magnitude);
}

return magnitudes;
/// <summary>
/// Gets the magnitude of every complex number in a matrix.
/// </summary>
///
public static double[][] Magnitude(this Complex[][] c)
{
return c.Apply((x, i, j) => x.Magnitude);
}

/// <summary>
Expand All @@ -123,13 +118,25 @@ public static double[] Magnitude(this Complex[] c)
///
public static double[] Phase(this Complex[] c)
{
if (c == null) throw new ArgumentNullException("c");
return c.Apply((x, i) => x.Phase);
}

double[] phases = new double[c.Length];
for (int i = 0; i < c.Length; i++)
phases[i] = c[i].Phase;
/// <summary>
/// Gets the phase of every complex number in a matrix.
/// </summary>
///
public static double[,] Phase(this Complex[,] c)
{
return c.Apply((x, i, j) => x.Phase);
}

return phases;
/// <summary>
/// Gets the phase of every complex number in a matrix.
/// </summary>
///
public static double[][] Phase(this Complex[][] c)
{
return c.Apply((x, i, j) => x.Phase);
}

/// <summary>
Expand All @@ -142,13 +149,7 @@ public static double[] Phase(this Complex[] c)
///
public static double[] Re(this Complex[] c)
{
if (c == null) throw new ArgumentNullException("c");

double[] re = new double[c.Length];
for (int i = 0; i < c.Length; i++)
re[i] = c[i].Real;

return re;
return c.Apply((x, i) => x.Real);
}

/// <summary>
Expand All @@ -161,18 +162,20 @@ public static double[] Re(this Complex[] c)
///
public static double[,] Re(this Complex[,] c)
{
if (c == null)
throw new ArgumentNullException("c");

int rows = c.GetLength(0);
int cols = c.GetLength(1);

var re = new double[rows, cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
re[i, j] = c[i, j].Real;
return c.Apply((x, i, j) => x.Real);
}

return re;
/// <summary>
/// Returns the real matrix part of the complex matrix c.
/// </summary>
///
/// <param name="c">A matrix of complex numbers.</param>
///
/// <returns>A matrix of scalars with the real part of the complex numbers.</returns>
///
public static double[][] Re(this Complex[][] c)
{
return c.Apply((x, i, j) => x.Real);
}

/// <summary>
Expand All @@ -186,14 +189,7 @@ public static double[] Re(this Complex[] c)
// TODO: Rename to Imaginary
public static double[] Im(this Complex[] c)
{
if (c == null)
throw new ArgumentNullException("c");

double[] im = new double[c.Length];
for (int i = 0; i < c.Length; i++)
im[i] = c[i].Imaginary;

return im;
return c.Apply((x, i) => x.Imaginary);
}

/// <summary>
Expand All @@ -203,18 +199,17 @@ public static double[] Im(this Complex[] c)
/// <returns>A matrix of scalars with the imaginary part of the complex numbers.</returns>
public static double[,] Im(this Complex[,] c)
{
if (c == null)
throw new ArgumentNullException("c");

int rows = c.GetLength(0);
int cols = c.GetLength(1);

var im = new double[rows, cols];
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
im[i, j] = c[i, j].Imaginary;
return c.Apply((x, i, j) => x.Imaginary);
}

return im;
/// <summary>
/// Returns the imaginary matrix part of the complex matrix c.
/// </summary>
/// <param name="c">A matrix of complex numbers.</param>
/// <returns>A matrix of scalars with the imaginary part of the complex numbers.</returns>
public static double[][] Im(this Complex[][] c)
{
return c.Apply((x, i, j) => x.Imaginary);
}

/// <summary>
Expand Down
93 changes: 63 additions & 30 deletions Sources/Accord.Math/Transforms/FourierTransform2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,29 @@ namespace Accord.Math.Transforms
/// </summary>
///
/// <remarks>
/// This fourier transform accepts arbitrary-length matrices and is not
/// restricted only to matrices that have dimensions which are powers of
/// two. It also provides results which are more equivalent with other
/// mathematical packages, such as MATLAB and Octave.
/// <para>
/// The transforms in this class accept arbitrary-length matrices and are not restricted to
/// only matrices that have dimensions which are powers of two. It also provides results which
/// are more equivalent with other mathematical packages, such as MATLAB and Octave.</para>
/// <para>
/// This class had been created as an alternative to <see cref="FourierTransform">AForge.NET's
/// original FourierTransform class</see> that would provide more expected results.</para>
/// </remarks>
///
/// <seealso cref="FourierTransform"/>
///
public static class FourierTransform2
{

/// <summary>
/// 1-D Discrete Fourier Transform.
/// </summary>
///
/// <param name="data">The data to transform..</param>
/// <param name="data">The data to transform.</param>
/// <param name="direction">The transformation direction.</param>
///
/// <code source="Unit Tests\Accord.Tests.Math\FourierTransformTest.cs" region="doc_dft" />
///
public static void DFT(Complex[] data, FourierTransform.Direction direction)
{
int n = data.Length;
Expand Down Expand Up @@ -124,41 +131,61 @@ public static void DFT(Complex[] data, FourierTransform.Direction direction)
/// <param name="data">The data to transform.</param>
/// <param name="direction">The transformation direction.</param>
///
/// <code source="Unit Tests\Accord.Tests.Math\FourierTransformTest.cs" region="doc_dft2" />
///
public static void DFT2(Complex[][] data, FourierTransform.Direction direction)
{
int n = data.Rows();
int m = data.Columns();

// process rows
var row = new Complex[m];
for (int i = 0; i < n; i++)
if (direction == FourierTransform.Direction.Forward)
{
// copy row
for (int j = 0; j < row.Length; j++)
row[j] = data[i][j];
// process rows
for (int i = 0; i < data.Length; i++)
{
// transform it
DFT(data[i], FourierTransform.Direction.Forward);
}

// transform it
DFT(row, direction);
// process columns
var col = new Complex[data.Length];
for (int j = 0; j < m; j++)
{
// copy column
for (int i = 0; i < col.Length; i++)
col[i] = data[i][j];

// copy back
for (int j = 0; j < row.Length; j++)
data[i][j] = row[j];
}
// transform it
DFT(col, FourierTransform.Direction.Forward);

// process columns
var col = new Complex[n];
for (int j = 0; j < m; j++)
// copy back
for (int i = 0; i < col.Length; i++)
data[i][j] = col[i];
}
}
else
{
// copy column
for (int i = 0; i < col.Length; i++)
col[i] = data[i][j];
// process columns
var col = new Complex[data.Length];
for (int j = 0; j < m; j++)
{
// copy column
for (int i = 0; i < col.Length; i++)
col[i] = data[i][j];

// transform it
DFT(col, direction);
// transform it
DFT(col, FourierTransform.Direction.Backward);

// copy back
for (int i = 0; i < col.Length; i++)
data[i][j] = col[i];
// copy back
for (int i = 0; i < col.Length; i++)
data[i][j] = col[i];
}

// process rows
for (int i = 0; i < data.Length; i++)
{
// transform it
DFT(data[i], FourierTransform.Direction.Backward);
}
}
}

Expand All @@ -169,6 +196,8 @@ public static void DFT2(Complex[][] data, FourierTransform.Direction direction)
/// <param name="data">The data to transform..</param>
/// <param name="direction">The transformation direction.</param>
///
/// <code source="Unit Tests\Accord.Tests.Math\FourierTransformTest.cs" region="doc_fft" />
///
public static void FFT(Complex[] data, FourierTransform.Direction direction)
{
int n = data.Length;
Expand Down Expand Up @@ -212,6 +241,8 @@ public static void FFT(Complex[] data, FourierTransform.Direction direction)
/// <param name="imag">The imaginary part of the complex numbers to transform.</param>
/// <param name="direction">The transformation direction.</param>
///
/// <code source="Unit Tests\Accord.Tests.Math\FourierTransformTest.cs" region="doc_fft" />
///
public static void FFT(double[] real, double[] imag, FourierTransform.Direction direction)
{
if (direction == FourierTransform.Direction.Forward)
Expand All @@ -237,9 +268,11 @@ public static void FFT(double[] real, double[] imag, FourierTransform.Direction
/// 2-D Fast Fourier Transform.
/// </summary>
///
/// <param name="data">The data to transform..</param>
/// <param name="data">The data to transform.</param>
/// <param name="direction">The Transformation direction.</param>
///
/// <code source="Unit Tests\Accord.Tests.Math\FourierTransformTest.cs" region="doc_fft2" />
///
public static void FFT2(Complex[][] data, FourierTransform.Direction direction)
{
int n = data.Length;
Expand Down
Loading

0 comments on commit fd17ca0

Please sign in to comment.