C# – La Trasformata di Fourier (Libreria in c#)

E’ da tempo che volevo postare la libreria e i relativi sorgenti sulla trasformata di Fourier.

Breve spiegazione presa da Wikipedia :

Fonte “Wikipedia“”
In analisi matematica, la trasformata di Fourier, abbreviata spesso in F-trasformata, è una trasformata integrale con molte applicazioni nella fisica e nell’ingegneria. Fu sviluppata dal matematico francese Jean Baptiste Joseph Fourier nel 1822, nel suo trattato Théorie analytique de la chaleur.

La trasformata di Fourier è uno degli strumenti matematici maggiormente sfruttati nell’ambito delle scienze pure e applicate. Viene utilizzata, ad esempio, per trasformare unafunzione matematica o una distribuzione x(t) definita nel dominio del tempo (spesso chiamata in questo ambito segnale) in una nuova funzione (o distribuzione) \hat x(\omega) = \hat x(2\pi f) il cui argomento è una frequenza angolare o una frequenza (indicata in hertz). Questa funzione viene chiamata spesso spettro delle frequenze della funzione x(t). La trasformata di Fourier è invertibile (vedi teorema di inversione di Fourier), quindi, a partire dalla trasformata di una funzione \hat x è possibile risalire alla funzione x.

Nel caso di funzioni periodiche, la trasformata di Fourier può essere semplificata con il calcolo di un insieme discreto di ampiezze complesse, chiamati coefficienti della serie di Fourier. Inoltre, quando un segnale nel dominio del tempo viene campionato, ad esempio per facilitare l’immagazzinamento o l’elaborazione digitale, è possibile ricreare una versione della trasformata originale utilizzando la formula di sommazione di Poisson.

Formalmente, la trasformata di Fourier \mathcal{F}\left\{x(t)\right\}(\omega) di una funzione x(t) è equivalente al valutare la trasformata di Laplace bilatera \mathcal{L} di x ponendo s = i\omega, e tale definizione è valida se e solo se la regione di convergenza della trasformata di Laplace contiene l’asse immaginario.

Passiamo ora alla creazione di due Classi una che contiene i numeri complessi (Complex) e l’altra la classe principale (Fourier) , il nome del Progetto è “TrasformataDiFourier” e quindi il suo namespace è “TrasformataDiFourier” ma lo potete modificare come lo volete :

Classe Complex.cs

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TrasformataDiFourier
{
public class Complex
{
public double real = 0.0;
public double imag = 0.0;

//Costruttore Vuoto
public Complex()
{
this.real = 0.0;
this.imag = 0.0;
}

public Complex(double real, double imag)
{
this.real = real;
this.imag = imag;
}

public override string ToString()
{
string data = real.ToString() + " " + imag.ToString() + "i";
return data;
}

//Converte i valori polari in rettangolari
public static Complex from_polar(double r, double radians)
{
Complex data = new Complex(r * Math.Cos(radians), r * Math.Sin(radians));
return data;
}

//Override l'operatore di addizione
public static Complex operator +(Complex a, Complex b)
{
Complex data = new Complex(a.real + b.real, a.imag + b.imag);
return data;
}

//Override l'operatore di sottrazione
public static Complex operator -(Complex a, Complex b)
{
Complex data = new Complex(a.real - b.real, a.imag - b.imag);
return data;
}

//Override l'operatore di moltiplicazione
public static Complex operator *(Complex a, Complex b)
{
Complex data = new Complex((a. real * b.real ) - (a.imag * b.imag ),(a. real * b.imag + (a.imag * b.real )));
return data;
}

//Ritorna il valore Complesso di Ampiezza
public double magnitude
{
get
{
return Math.Sqrt(Math.Pow(this.real, 2) + Math.Pow(this.imag, 2));
}
}

//Ritorna la fase
public double phase
{
get
{
return Math.Atan(this.imag / this.real);
}
}

}
}

Classe Fourier.cs :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TrasformataDiFourier
{
public class Fourier
{
public Complex[] DFT(Complex[] x)
{
int N = x.Length;
Complex[] X = new Complex[N];

for (int k = 0; k < N; k++)
{
X[k] = new Complex(0, 0);

for (int n = 0; n < N; n++)
{
Complex temp = Complex.from_polar(1, -2 * Math.PI * n * k / N);
temp *= x[n];
X[k] += temp;
}
}

return X;
}

public Complex[] FFT(Complex[] x)
{
int N = x.Length;
Complex[] X = new Complex[N];

Complex[] d, D, e, E;

if (N == 1)
{
X[0] = x[0];
return X;
}

int k;

e = new Complex[N / 2];
d = new Complex[N / 2];

for (k = 0; k < N / 2; k++)
{
e[k] = x[2 * k];
d[k] = x[2 * k + 1];
}

D = FFT(d);
E = FFT(e);

for (k = 0; k < N / 2; k++)
{
Complex temp = Complex.from_polar(1, -2 * Math.PI * k / N);
D[k] *= temp;
}

for (k = 0; k < N / 2; k++)
{
X[k] = E[k] + D[k];
X[k + N / 2] = E[k] - D[k];
}

return X;
}
}
}

Ora facciamo un Test del suo funzionamento :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TrasformataDiFourier;

namespace TestTrasformataFourier
{
class Program
{
static void Main(string[] args)
{

TrasformataDiFourier.Complex[] tmp=new TrasformataDiFourier.Complex[8];
int n=tmp.Length;

for(int i=0;i<n;++i)
tmp[i]=new TrasformataDiFourier.Complex(i,0);

for(int i=0;i<n;++i)
Console.WriteLine("tmp["+i+"]: " + tmp[i]);

Complex[] f = TrasformataDiFourier.Fourier.DFT(tmp);

for(int i=0;i<n;++i)
Console.WriteLine("f["+i+"]: " + f[i]);

f = TrasformataDiFourier.Fourier.FFT(f);

for(int i=0;i<n;++i)
Console.WriteLine("inversa: f[" + i + "]: " + f[i]);
}
}
}

Lascia un commento