• Aucun résultat trouvé

transfo_fourier_cor December 2, 2020

N/A
N/A
Protected

Academic year: 2022

Partager "transfo_fourier_cor December 2, 2020"

Copied!
12
0
0

Texte intégral

(1)

transfo_fourier_cor

December 2, 2020

1 Présentation :

Ce TP est à rendre en devoir maison pour le mardi 17 novembre sous forme de fichier électronique au format python.

Les réponses aux questions de complexité sont écrites dans des commentaires.

Exemple de présentation :

# Q.FFT.1 : def FFT(y):

some code

# Q.FFT.2 :

"""

la complexité est cubique en nombre d'appels à l'exponentielle car l'âge du capitaine et bla et bli....

"""

2 Quelques observations

Commençons par importernumpyet quelques fonctions et constantes [3]: import numpy as np

from numpy import cos,sin,exp,pi#pour ne pas s'embêter avec des préfixes Un calcul utile pour la suite :

[4]: np.exp(2*pi*1j/3),cos(2*pi/3)+1j*sin(2*pi/3) [4]: ((-0.4999999999999998+0.8660254037844387j),

(-0.4999999999999998+0.8660254037844387j)) Les deux parties entières du cours de maths :

[5]: np.floor(5/2), np.ceil(5/2) [5]: (2.0, 3.0)

(2)

3 Spectre d’un signal périodique

D’après un travail similaire de mon collègue du lycée Bertran de Born.

Un signalf continue, de période T, se développe en série de Fourier sous la forme

f(t) =

n=−∞

cne2iπnTt

où lescndésignent les coefficients de Fourier qui se calculent sous la forme intégrale :

cn= 1 T

T

0

f(t)e2iπnTt dt

Le spectre def est l’ensemble des couples(n

T, cn)n∈Z. La détermination du spectre est un élément important de l’étude d’un signal périodique.

On suppose connue la périodeT du signal ainsi qu’un nombre finiN de valeurs du signal régulière- ment espacés sur une période :

yk =f (

kT N

)

pour k= 0, . . . , N1

Les yk sont donc les images des N premiers points d’une subdivision régulière de[0, T] en N + 1 points. L’écart entre deux points de cette subdivision (la largeur des rectangles) est alors 1/N. Par la méthode des rectangles bords gauches on trouve pour n∈Z

cn 1 N

N1 k=0

yke2iπ nNk

On peut établir que l’approximation est plutôt correcte pour −⌊N/2⌋ ≤ n≤ ⌈N/2⌉ −1. Dans le cas oùN est pair, cela donne −N/2≤n≤N/21 et dans le cas impair−⌊N/2⌋ ≤n≤ ⌊N/2. Ce sont ces coefficients que nous étudions ci-dessous.

4 Transformée de Fourier discrète

La transformée de Fourier discrète est un outil majeur en traitement du signal et intervient dans des domaines très variés.

4.1 Présentation

Soit un entierN >0 etωN =e2iπN .

L’application qui à l’image (yk)0kN1 d’une subdivision régulière par la fonction périodique f associe la famille (Yn)0nN1 telle que

Yn=

N1 k=0

ykωNnk

(3)

s’appelle transformée de Fourrier discrète.

On a :

N cn

{ Yn si 0≤n <⌈N/2⌉

Yn+N si − ⌊N/2⌋ ≤n <0

En effet, si −⌊N/2⌋ ≤n <0, comme⌊N/2+⌈N/2=N, on an+N [⌈N/2⌉;N 1[ et Yn+N =

N1 k=0

yke−(n+N)2iπN =

N1 k=0

yke2inπN −2π =

N1 k=0

yke−2inπN ≃N cn

Une conséquence est que, lorsqu’on calcule le tableau des Yn, les premiers termes sont des approx- imations proportionnelles auxcnpour n≥0et les derniers termes pour n≤0.

4.2 Des tableaux de nombres complexes

Il est courant de traiter les problèmes d’analyse numérique (comme pour Euler) en créant des tableaux de la bonne longueur initialement remplis de zéros.

Si les valeurs à approcher sont des nombres réels, la commande suivante suffit : [6]: n = 5

x = np.zeros(5) x[0]=0

x

[6]: array([0., 0., 0., 0., 0.])

Mais si on prévoit d’obtenir un tableau de complexes, on a un problème avec notre initialisation.

En effet les méthodes d’analyse numérique consistent souvent à remplir la case i+ 1 d’un tableau en ajoutant une certaine quantité à la casei. Or, observons ce comportement :

[7]: N=5

omega = exp(-2*1j*pi/N) for i in range(1,len(x)):

x[i] = x[i-1]+i*omega x

/home/ivan/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:4:

ComplexWarning: Casting complex values to real discards the imaginary part after removing the cwd from sys.path.

[7]: array([0. , 0.30901699, 0.92705098, 1.85410197, 3.09016994])

Comme leWarningnous l’a laissé entendre, la partie imaginaire n’a pas été prise en compte. Pour éviter cela on crée dès le départ un tableau de complexes :

[8]: n = 5

x = np.zeros(5,dtype=complex) x[0]=0

(4)

omega = exp(-2*1j*pi/N) for i in range(1,len(x)):

x[i] = x[i-1]+i*omega x

[8]: array([0. +0.j , 0.30901699-0.95105652j, 0.92705098-2.85316955j, 1.85410197-5.7063391j , 3.09016994-9.51056516j])

Le problème a disparu.

4.2.1 Exo 1

• Q.TFD.1 : Ecrire la fonctionimage_subdivision(f,T,N)qui prend en paramètres une fonc- tion continue f, une périodeT et un nombre de pointsN. La fonction retourne un tableau numpy contenant les images parf desN premiers points de la subdivision régulière à N+ 1 points de[0, T](il manque donc le dernier point).

• Q.TFD.2 : Ecrire la fonctionTFD(y)qui prend en paramètres un tableau(yk)0≤k≤N−1(censé être constitué d’images de points d’une subdivision par une certaine fonction) et retourne sa transformée de Fourier discrète(Yn)0nN1 sous forme de tableau numpy.

• Q.TDF.3 : Donner la complexité en nombre d’appels à l’exponentielle.

[9]: #**************

def image_subdivision(f,T,N):

t = np.linspace(0,T,N+1)[:-1]

return f(t)

#***********

[10]: f = lambda x : 2*(cos(2*x/3)+sin(2*x/3)) T, N = 3*pi/2, 4

y = image_subdivision(f,T,N) y

[10]: array([2.00000000e+00, 2.82842712e+00, 2.00000000e+00, 2.22044605e-16]) [25]: #**********************

def TFD(y):

"""

y est un tableau numpy de longueur N représentant les valeurs f(kT/N) pour f continue T-périodique

Retourne la liste des Y_n.

Complexité quadratique en nombres d'appels à l'exponentielle.

"""

N = len(y)

(5)

Y = np.zeros(N,dtype=complex)

k = np.array([k for k in range(N)])#k = 0,1,..,N-1 for n in range(N):

f = lambda x : exp(-2*1j*pi*n* x /N)

Y[n] = np.sum((f(k)*y))#2 boucles successives sur N termes return Y

#***************************

#**************

Pour chaquen entre 0 etN 1, on applique l’exponentielle à tout kentre 0 etN 1. Il y a donc N2 appels à l’exponentielle.

#**************

[26]: TFD(y)

[26]: array([ 6.82842712e+00+0.00000000e+00j, 0.00000000e+00-2.82842712e+00j, 1.17157288e+00+1.43476297e-16j, -4.44089210e-16+2.82842712e+00j]) [32]: TFD([1+3j])

[32]: array([1.+3.j])

[23]: #********* Code (correct) d'une camarade **********

def TFD2(y):# V2 N = len(y)

Y = np.zeros(N, dtype=complex) for l in range(N):

res = 0

for i in range(N):

res=res+y[i]*np.exp(-2*pi*1j*l*i/N) Y[l]=res

return Y

#******************

[24]: TFD2(y)

[24]: array([ 6.82842712e+00+0.00000000e+00j, -4.07889322e-32-2.82842712e+00j, 1.17157288e+00+1.43476297e-16j, -4.44089210e-16+2.82842712e+00j])

4.3 Transformée de Fourier rapide

L’algorithme de transformée de Fourrier rapide(en anglais fast Fourier transform (FFT) est basé sur le principe diviser pour régner.

(6)

Soit N un nombre pair etm tel queN = 2m. On rappelle que

Yn=

2m1

k=0

ykωNnk.

Pour 0≤n < N,Yn se décompose enYn=Pn+In avec :

Pn=y0+y2ωN2n+· · ·+y2m2ωN(2m2)n

et

In =y1ωNn+y3ωN3n+· · ·+y2m1ωN(2m1)n=ωNn(y1+y3ωN2n+· · ·+y2m1ωN(2m2)n)

On pose alorsIn=y1+y3ωN2n+· · ·+y2m1ωN(2m2)n et on obtientYn=Pn+ωnnIn. On remarque alors quePn+m =Pn etIn+m =In. cela vient du fait que

ωN2(n+m)=e2iπ2(n+m)N =e2iπ2nN 2iπ4m2m =e2iπ2nN =ω2nN

Il suffit donc de calculer Pn et In pour n = 0, . . . , m1 et de remarquer que ωN(n+m) = −ωNn pour former

{ Yn = Pn+ωNnIn

Yn+m = Pn+ω−(n+m)N In=Pn−ωNnIn

PuisqueωN2 =ωm, les listesPnetIn sont les transformées de Fourier def associées respectivement à la moitié de y constituées des numéros pairsy0, . . . , y2m2) et impairs y1, . . . , y2m1.

Ainsi(Pn)0n<m1 =TFD(y0, . . . , y2m2) et(In)0n<m1=TFD(y1, . . . , y2m1).

4.3.1 Algorithme

La fonction FFT(y)prend en entrée une liste y de taille N et retourne la transformée de Fourier discrète de y. On suppose queN est une puissance de 2.

Diviser : on découpe la liste en deux sous-listes, celle des termes de rang pair et celle des termes de rang impair.

Régner : si une sous-liste ne contient qu’un seul élément le résultat est immédiat, sinon on le trouve de manière récursive

Combiner: ayant trouvé la TFD des deux sous-listes, on combine les listes selon le point 1 de la méthode décrite ci-dessus.

• Q.FFT.1 : Ecrire le code de la fonctionFFT(y)en respectant l’algorithme.

• Q.FFT.2 : Donner sa complexité en nombre d’appels à l’explonentielle.

[33]: #***************

def FFT(y):

(7)

N = len(y) if N == 1:

return y

pairs, impairs = y[::2], y[1::2]

P , I = FFT(pairs), FFT(impairs) Y = np.zeros(N,dtype=complex)

les_k = np.array([k for k in range(N//2)])#0,1,..,m-1 les_omega = (lambda k : exp(-2*1j*pi*k/N))(les_k) Y[:N//2] = P + les_omega * I

Y[N//2:] = P - les_omega * I return Y

#***********

[34]: f = lambda x : 2*(cos(2*x/3)+sin(2*x/3)) T, N = 3*pi/2, 8

y = image_subdivision(f,T,N) y

[34]: array([ 2.00000000e+00, 2.61312593e+00, 2.82842712e+00, 2.61312593e+00, 2.00000000e+00, 1.08239220e+00, 2.22044605e-16, -1.08239220e+00]) [35]: TFD(y)

[35]: array([12.05467898+0.00000000e+00j, -1.53073373-6.52394525e+00j, 1.17157288-2.16478440e+00j, 1.53073373-8.67091005e-01j, 1.60217527+6.57529391e-16j, 1.53073373+8.67091005e-01j, 1.17157288+2.16478440e+00j, -1.53073373+6.52394525e+00j]) [36]: FFT(y)

[36]: array([12.05467898+0.j , -1.53073373-6.52394525j, 1.17157288-2.1647844j , 1.53073373-0.86709101j, 1.60217527+0.j , 1.53073373+0.86709101j, 1.17157288+2.1647844j , -1.53073373+6.52394525j]) Ce qui suit peut être utile :

[17]: t = np.array([k for k in range(8)]) t[:3]=[10,20,30]

t

[17]: array([10, 20, 30, 3, 4, 5, 6, 7]) [18]: t[::2], t[1::2]

[18]: (array([10, 30, 4, 6]), array([20, 3, 5, 7]))

#*****************

(8)

PourN = 2p, on a une complexitéu2p en nombre d’appels à l’exponentielle vérifiant une récurrence de la forme

u2p = 2u2p1 + 2p1

On y reconnaît le calcul de la complexité pour les deux appels internes et le calcul de l’exponentielle pour k= 0. . . N/2.

On a donc

u2p= 2(2u2p−2 + 2p2) + 2p1= 22u2p−2 + 2×2p1=· · ·= 2pu1+p2p1 Avec p2p1 = 1

2(NlogN) =O(NlogN).

La complexité étant croissante avec la taille N du tableau y, on extrapole ce résultat pour les valeurs de N qui ne sont pas des puissances de 2.

On a donc une complexité pseudo-linéaire en la taille du tableau y pour la transformée rapide contre quadratique pour la version impérative.

#*****************

4.4 Vérification expérimentale

La transformation de Fourier discrète est donc un outil mathématique qui sert à traiter un signal numérique(Wikipedia). Pour comprendre ce qu’on entend par là, voici une vérification expérimen- tale fournie par Jean-Julien Fleck.

4.4.1 Le signal

On dispose de l’échantillonage surN valeurs d’un signal donné. De ce signal, on sait que c’est une superposition de signaux plus simples et qu’il est de la forme t7→ a1sin(2πf1t) +a2cos(2πf2t) + a3sin(2πf3t) mais les amplitudes a1, a2, a3 et les fréquencesf1, f2, f3 nous sont inconnues.

Ecrire une fonction

def signal(a1,a2,a3,f1,f2,f3):

qui renvoie la fonctions:t7→a1sin(2πf1t) +a2cos(2πf2t) +a3sin(2πf3t).

[19]: #*******

def signal(a1,a2,a3,f1,f2,f3):

return lambda t:a1*sin(2*pi*f1*t)+a2*cos(2*pi*f2*t)+a3*sin(2*pi*f3*t)

#**********

[20]: f = signal(1,3,-5,10,30,100) f(1)

[20]: 2.999999999999978

(9)

4.5 L’analyse

Traçons la courbe de la fonctionf pour 210 valeurs entre 0 et 1 : [21]: import matplotlib.pyplot as plt

[22]: f = signal(1,3,-5,10,30,100)#le signal : on n'est pas censé le connaître t=np.linspace(0,1,2**10)

y = f(t)#l'échantillonage du signal : la seule chose qu'on est censé avoir plt.plot(t,y)

plt.xlabel('Temps en s') plt.ylabel('Signal') plt.show()

C’est bien peu lisible et les informations sur les amplitudes et fréquences sont perdues.

On considère maintenant qu’on dispose du tableau ydesN valeurs de l’échantillonage mais qu’on ne connaît pas la fonction qui décrit le signal. Ces valeurs ont été récupérées par un capteur quelconque.

On suppose pour toute la suite que la longueur de yest une puissance de 2. Rappelons-nous que les valeurs contenues dans la transformée de Fourier de ysont pertinentes pour les N/2premières.

• Q.Analyse.1 : La valeur retournée par la FFT est un tableau de nombres complexes. Ecrire une fonction module(y) qui retourne le module de la première moitié de la transformée de Fourier discrète du tableau y.

(10)

[23]: #**************

def module(y):

return np.abs(FFT(y)[:len(y)//2])

#************

[24]: #exemple de calcul de module np.abs(1+1j)

[24]: 1.4142135623730951

[25]: f = lambda x : 2*(cos(2*x/3)+1j*sin(2*x/3))# le signal T, N = 3*pi/2, 8#période, nombre de points

y = image_subdivision(f,T,N)#l'échantillonage du signal

Y = module(y) # le module de la 1ere moitie de la transfo de Fourier de y Y

[25]: array([10.25166179, 10.25166179, 3.59990489, 2.40537955])

A titre d’exemple considérons que yest le tableau résultat de la séquence suivante:

f = signal(1,3,-5,10,30,100) # fonction signal : pas censée être connue t = np.linspace(0,1,2**10)

y = f(t) # échantillonage : tout ce que je connais du signal

On dispose des valeurs y de l’échantillonage du signal mais on ne connaît pas la fonction f qui décrit ce signal.

• Q.Analyse.2 : Tracer la courbe des 200 premières valeurs demodule(y) (en absicsse l’indice, en ordonnée la valeur). Indiquer sur l’axe desx qu’il s’agit des fréquences en Hz et que l’axe desy correspond à la transformée de Fourier.

• Q.Analyse.3 : Préciser comment retrouver les valeursa1, a2, a3, f1, f2, f3 à partir du graphique obtenu. Si votre fonction

[26]: #*********

f = signal(1,3,-5,10,30,100) t=np.linspace(0,1,2**10) y = f(t)

Y = module(y)

plt.plot(Y)#abscisse : indice i, ordonnée : Y[i]

plt.xlim(0,200) plt.show()

#**********

(11)

#***************

On lit les 3 fréquences sur l’axe des abscisses et les amplitudes sont proportionnelles aux pics lus sur l’axe des ordonnées.

#***************

[40]: #*********

f = signal(1,3,-5,10,30,100) t=np.linspace(0,1,2**10) y = f(t)

Y = module(y)

plt.plot(t[:len(t)//2],Y)#abscisse : indice i, ordonnée : Y[i]

plt.xlim(0,t[len(t)//2]) plt.show()

#*********

(12)

Références

Documents relatifs

Instruction Y ( Touche F1 ) suivie du numéro de la fonction à utiliser (pour notre exemple Y1 ).. Valider avec

[r]

[r]

Si les deux pr´ ec´ edentes m´ ethodes n’ont rien donn´ e, on peut appliquer la m´ ethode de la variation de la

On cherche 0 sur la 1 re ligne du tableau et on lit son image sur la 2 de ligne.. Donne un encadrement de l’antécédent

- Mettre tout

Dans un tableau de valeur proportionnelles on passe de la 1 ère ligne à la 2 ème en multipliant partout par un même nombre. Ce nombre est appelé coefficient de proportionnalité. On

[r]