Maîtrise d'informatique - Module 18
|
Le but de ce premier TP de traitement du signal est de mettre en oeuvre la programmation, en langage C, de l'algorithme de la transformation de Fourier rapide unidimensionnelle (TFR ou FFT) présenté en cours. Les notations du cours sont brièvement rappelées ci-dessous, ainsi que les structures de données nécessaires à l'écriture de votre programme. Le paragraphe 2 décrit les principales fonctions du programme à réaliser. Le signal discret est composé de 8 valeurs réelles. Le spectre discret sera donc composé de 8 valeurs complexes. Il vous est conseillé de créer un sous-répertoire TS. La commande de compilation est la suivante :
> gcc -ansi -pedantic -Wall tfr.c -o tfr -lm
Les bibliothèques nécessaires à l'écriture de votre programme sont <math.h> et <stdio.h>. On définit les deux constantes N=8 et P=3 (N = 2P). Les complexes utilisés seront tous représentés par des tableaux à deux dimensions. Le signal discret (fn)[0,N-1], à valeurs réelles, est stocké dans un tableau de réels de nom signal_discret[N], initialisé aux valeurs :
{0.,0.,0.,1.,1.,0.,0.,0.}
Le spectre discret (Fm)[0,N-1], à valeurs complexes, est stocké dans un tableau de réels à deux dimensions, de nom spectre[N][2]. Les puissances successives W80, W81, W82 et W83 du facteur de rotation complexe :
sont stockées dans un tableau de réels à deux dimensions,
de nom w[N/2][2].
Ecrire les fonctions permettant de réaliser les opérations suivantes sur des complexes :
void addi_comp(float res[2],float c1[2],float c2[2])
void sous_comp(float res[2],float c1[2],float c2[2])
void mult_comp(float res[2],float c1[2],float c2[2])
float modu_comp(float c[2])
Pour calculer la racine carrée d'un réel, on utilisera la fonction sqrt qui retourne un réel.
Ecrire la fonction permettant d'initialiser le tableau w[N/2][2] aux valeurs complexes des puissances successives de W8 :
void init_w(float w[N/2][2])
La valeur de pourra être évaluée en définissant la constante symbolique PI égale à la valeur suivante :
Ecrire la fonction permettant de réaliser l'initialisation du tableau spectre[N][2] aux valeurs vues en cours :
void init_spectre(float signal_discret[N],float spectre[N][2])
Cette initialisation correspond à des affectations du type :
Fi <- (fj , 0.)
La difficulté consiste à trouver les indices j correspondant aux indices i. Lorsque N = 8 (exemple traité en cours), on rappelle que ces correspondances peuvent être réalisées par la succession des trois étapes suivantes :
i= | j= | |||||
0 | 000 | 000 | 0 | |||
1 | 001 | 100 | 4 | |||
2 | 010 | 010 | 2 | |||
3 | ---1---> | 011 | ---2---> | 110 | ---3---> | 6 |
4 | 100 | 001 | 1 | |||
5 | 101 | 101 | 5 | |||
6 | 110 | 011 | 3 | |||
7 | 111 | 111 | 7 |
L'étape 1 est une conversion décimal-binaire sur P = 3 bits. L'étape 2 est une inversion des bits. L'étape 3 est une conversion binaire-décimal. Dans l'exemple précédent, la fonction init_spectre devra donc réaliser les 8 affectations suivantes :
F0 <- (f0 , 0.) F1 <- (f4 , 0.) F2 <- (f2 , 0.) F3 <- (f6 , 0.)
F4 <- (f1, 0.) F5 <- (f5 , 0.) F6 <- (f3 , 0.) F7 <- (f7 , 0.)
Les opérations binaires utiles pour l'écriture de cette fonction sont :
L'écriture de cette fonction peut présenter quelques difficultés. Si vous êtes bloqué, cliquez sur l'icône d'aide ci-dessous, et vous accéderez à l'algorithme détaillé :
Ecrire la fonction réalisant le calcul "en place" de la TFR, à partir des valeurs retournées par la fonction d'initialisation écrite précédemment :
void tfr(float spectre[N][2],float w[N/2][2])
A chaque étage (si P = 3, il y a 3 étages, correspondant aux valeurs 0, 1 et 2 de la variable locale i), le calcul consiste en une phase d'additions/soustractions, suivie d'une phase de multiplications. Voici l'écriture de la deuxième phase, qui est assez difficile :
L'appel pow(2,P-i-2) retourne la valeur de 2 à la puissance (P-i-2). Il est demandé d'écrire la phase d'additions/soustractions. La principale difficulté consiste à déterminer, à chaque étage, les 4 couples d'indices. Il est conseillé d'introduire, en variable locale, un tableau de booléens, de nom non_apparie[N], initialisés à chaque étage à 1, qui permet de savoir si un des 8 indices a déjà été apparié ou non. Lorsqu'un indice ind1 non encore apparié a été détecté, il forme un couple avec l'indice ind2 tel que :
ind2=ind1+2i
Ecrire le programme principal, qui permet d'afficher les valeurs du signal discret, de calculer sa TFR, puis d'afficher les modules des valeurs de son spectre discret.
Avec les valeurs du signal discret données précédemment, vérifiez que vous trouvez bien les 8 valeurs suivantes pour le module du spectre discret :
2.000000 1.847759 1.414214 0.765367
0.000000 0.765367 1.414214 1.847759
En modifiant les valeurs des constantes par N=16 et P=4, et avec les valeurs suivantes du signal discret :
{0.,0.,0.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,0.,0.,0.}
vérifiez également que vous trouvez les 16 valeurs suivantes pour le module du spectre discret :
10.000000 4.735651 1.847759 0.688812
1.414214 0.460249 0.765367 0.941979
0.000000 0.941979 0.765367 0.460249
1.414214 0.688812 1.847759 4.735651
Lorsque ces vérifications auront été faites avec succès, votre programme sera prêt pour la deuxième séance de travaux pratiques.