Diskretna furijeova transformacija

Izvor: testwiki
Prijeđi na navigaciju Prijeđi na pretragu

Diskretna Furijeova transformacija ili DFT jeste Furijeova transformacija diskretnog i konačnog (ili periodičnog) signala. Diskretna Furijeova transformacija je time i specijalni oblik Z-transformacije kod koje se z nalazi na jediničnom krugu. Često se koristi pri obradi digitalnih signala, a najpoznatiji algoritam za to je brza furijeova transformacija (FFT, Fast Fourier Transformation, engl.).

Diskretna Furijeova transformacija može da posluži takođe za aproksimaciju (u određenim slučajevima i rekonstrukciju) funkcije koja odgovara signalu ili kao implementacija digitalnih filtera.

Putem inverzne Furijeove transformacije se iz Furijeovih koeficijenata sklapa izlazni signal, a povezivanjem DFT i inverzne DFT možemo da manipulišemo frekvencijama (nalazi primenu pri ekvilajzerima i filterima).

Definicija

Uzmimo da je R komutativan, unitaran prsten, u kojem je broj N jedinica. Dalje, u R je w jedinični koren.

Za vektor c=(c0,,cN1)RN je diskretna furijeova transformacija c^ na sledeći način definisana:

c^k=j=0N1wjkcj za k=0,,N1

A za c^k, inverzna furijeova transformacija je

ck=1Nj=0N1wjkc^j za k=0,,N1

DFT i IDFT u kompleksnom domenu

U kompleksnom domenu koristimo w=e2*π*kn,k=0,1,,n1.

Onda je DFT za cN: c^k=j=0N1e2πijkNcj za k=0,,N1,

a IDFT za c^N: ck=1Nj=0N1e2πijkNc^j za k=0,,N1

DFT i IDFT u realnom domenu

Računica u realnom domenu je:

c^Nk=j=0N1e2πij(Nk)Ncj=j=0N1e2πi(jNNkN)cj=j=0N1e2πi(jNN)e2πi(kN)cj=j=0N1e2πije2πi(kN)cj

Ojlerov identitet glasi: e2πi=1. Takođe važi eiϕ=eiϕ i z1+z2=z1+z2.

Stoga možemo još uprostiti izraz:

c^Nk=j=0N11e2πi(kN)cj=j=0N1e2πikNcj=j=0N1e2πikNcj=c^k

Što će reći, c^N nije realan, ali samo N nezavisnih vrednosti (umesto 2N).

Za IDFT možemo zaključiti sledeće: Ukoliko za c^N važi c^Nk=c^k za sve k=0,,N1, onda je IDFT realan vektor cN.

Pomeranje i skaliranje u vremenu i frekvenciji

Ako je signal periodičan, onda nije bitno da li transformišemo u opsegu 0,,N1 ili k,,N1+k. Indeksna promenljiva j treba da obuhvati N opseg, ali nije bitno gde on počinje odnosno gde se završava (ovo važi samo za slučaj da je signal periodičan, tj. da se vektor k,,N1+k periodično ponavlja). Prisetimo se: za w važi wN=1. Onda wN+k=wNwk=1wk=wk.

U praksi često želimo da razlika u indeksima bude istovremeno i razlika u vremenu ili razdaljini dva merenja

tn=nT,n=1M,,NM, T je perioda našeg merenja.

Često želimo i da koeficijentima dodelimo frekvenciju tako da su centrirane oko 0

ωn:=2πnNT,n=1K,...,NK, K je negde u blizini N2.

Uzmimo neku funkciju f kojoj dodeljujemo xN tako da xn=f(tn).

DFT je onda yn=f^(ωn)=F(ωn).

Iz toga sledi:

F(ωn)=j=1MNMe2πinjTNTxj=j=1MNMeiωntjf(tj)

a IDFT je

f(tn)=xn=1Nj=1KNKe2πinkTNTyj=1Nj=1KNKeiωjtnF(ωj)

Primeri

Primer filtera

Naš cilj je da izbacimo sve frekvencije koje su „tiše“ (tj. koje imaju amplitudu) od 1 V. Prvo pravimo tabelu:

ti= 0.5000 0.6000 0.7000 0.8000 0.9000 1.0000 1.1000 1.2000 1.3000 1.4000
f(ti)= 12.5000 10.0995 7.6644 6.8554 9.7905 13.5000 11.7546 7.4815 8.2905 12.0636

Imamo 10 vrednosti na 1 sekundu, što će reći perioda našeg merenja je T=0.1, a frekvencija freq=1T=10Hz. Stoga mi možemo da rekonstruišemo talas do 5 Hz. Ukoliko u našem originalnom signalu ima frekvencija viših od 5 Hz onda će naša rekonstrukcija imati grešku. Ali, kao i uvek u životu, čovek mora biti optimističan te ćemo mi pretpostaviti da nema viših frekvencija (to je uostalom i jedan od razloga zašto kompakt-disk ima frekvenciju od oko 41 kHz; ljudsko uho može da registruje tek do 20 kHz!).

Sledi izračunavanje ωi. Nas zanimaju samo vrednosti vezane za pozitivne indekse:

n=1K,,NK;K=N/2=5;
n=4,,5
NT=10.1=1
ω0=2π0NT=0,ω1=2π,ω2=4π,,ω5=10π

Sada imamo sve vrednosti i možemo da počnemo sa računanjem:

F(ω0=0)=j=0N1=9ei0tjf(tj)=j=09f(tj)=100=y0=c^0
F(ω1=2π)=j=0N1=9ei2πtjf(tj)==03.5i=y1=c^1
F(ω2=4π)=j=0N1=9ei4πtjf(tj)==15+0i=y2=c^2

Izračunavanje ostalih koeficijenata ide analogno, te ćemo ih ovde samo navesti kao rezultate:

F(ω3=6π)=2.53i=y3=c^3
F(ω4=8π)=6.7586e14+2.8240e14i=y4=c^4

Imamo c^, sada želimo da izbacimo sve previše „tihe“ tonove. Trebaju nam ck:

c=c^/Nci=c^i/10

ci: 10 -0.35i 1.5 - 0i 0.25 - 0.3i 0 + 0i

Znamo da važi: c0=a0,ci>0=12(aibii). Na taj način možemo da izračunamo ai i bi:

a0=10
a1b1i=0.7ia1=0,b1=0.7

Ostale amplitude:

a2=3
a3=0.5
b3=0.6
a4=b4=0

Iz a4=b4=0 možemo da zaključimo da frekvencija od 4 Hz nema u našem signalu. Često je vrlo zgodno navesti sve amplitude u grafikonu. Amplituda Ak za neku frekvenciju k je Ak=(ak2+bk2).

Sve ai i bi za koje važi (ai2+bi2)<1 izbacujemo i na kraju dobijamo rekonstruisanu i obrađenu funkciju:

f(t)=10+3cos(2ωt)

Sada možemo da ponovo da izračunamo f(ti) ili da se poslužimo IDFT i tako prerađen signal snimimo u memoriju.

Primer u C-u

#include <stdio.h>
#include <math.h>
#include <complex.h>

#define pi 3.14159265
#define N 1000
#define T 0.001
#define FREQ 25

double my_function (double t )
{
	 /* violina svira ton od 25 Hz */
	 double ugaona_brzina = 2 * pi * FREQ;
	 return 5 + 10 * cos(ugaona_brzina * t) + 15 * cos(2 * (ugaona_brzina * t) ) 
			+ 20 * sin (3 * (ugaona_brzina * t) );

}

complex double get_fourier_coef (double omega_n, double* t, double* f  )
{
	 complex double coeff = 0;

	int k = 0;

	for (k = 0; k < N; k ++ )
	{
		// f[k] == f(t[k] );
		coeff += cexp (- I * omega_n * t[k]) * f[ k] ;
	}
	return coeff;
}

int main()
{
	double t[N];
	double omega[N];
	double f[N];

	double a[N/2+1];
	double phi[N/2+1];
	int n = 0;

	complex double coeff[N];
	
	/* pripremi vektore t i f_t -> nas signal je f_t !*/
	t[0] = 0;
	f[0] = my_function (t[0] );
	omega[0] = 0;

	for (n = 1; n < N; n ++ )
	{
		omega[n] = 2 * pi * n / (N * T );
		t[n] = n * T;
		f[n] = my_function (t[n] );	
	}

 
	/* izracunavanje koeficijenata */
	for (n = 0; n < N/2+1; n ++ )
	{
		coeff[n] = get_fourier_coef (omega[n], t, f );
		if (cabs(coeff[n]) > 0.1 ){
			printf ("# Koeficijent %d:  %e * e^i*%e\n", n, cabs(coeff[n]), carg(coeff[n]) ); 
		}
	}
	
	

	/* krece inverzija: */		
	a[0] = cabs(coeff[0]) / N;
	phi[0] = 0;
	for (n = 1; n < N/2+1; n++ )
	{
		if (cabs(coeff[n]) > 0.1 )
		{
			// c = 1/2 (a + ib ), zato a = 2 * |c|, b == 0 
			a[n] = 2  * cabs(coeff[n]) / N; 

			if (abs (carg(coeff[n])) > 0.001 )
			{
				phi[n] = carg(coeff[n] );
			}
			 else 
			{
				phi[n] = 0;
			}
		} 
		else 
		{
			a[n] = 0;
			phi[n] = 0;
		}
	}


	/* predstavljanje rezultata: */
	printf ("Nasa rekonstrukcija:\n f (t) = %e", a[0] );
	for (n = 1; n < N/2+1; n++ )
	{

		if (a[n] )
		{
			if (phi[n] )
			{
				printf (" + %e * cos (%d * (2 * pi * t + %e) )", a[n], n, phi[n] );
			}
			else
			{
				printf ("+ %e * cos (%d * 2 * pi * t )", a[n], n );
			}
		}
	}
	printf ("\n" );
	

	return 0;
}

Literatura

Šablon:Refbegin

Šablon:Refend

Povezano