Recomposer un signal avec des sinusoïdes

L'objet de ce chapitre est très similaire au chapitre précédent. Sauf que cette fois-ci, nous allons utiliser une base complète de signaux assez particulière pour recomposer le signal de température que nous avions étudié lors du chapitre Évaluer un modèle.

Cette base est constituée de fonctions de forme sinusoïdale (cosinus et sinus).

Acquisition et visualisation des données

Comme d'habitude, commencez par importer les données. Cette fois, trois fichiers (temperatures.datBanqueSinus.dat | BanqueCosinus.dat) sont fournis : d'un côté les données et de l'autre une série de signaux qui vont servir de base.

data = load('temperatures.dat');
%On en profite pour regarder :
plot(data,'o');


Chargeons ensuite les sinus et  cosinus :

BanqueSinus = load('BanqueSinus.dat');
BanqueCosinus = load('BanqueCosinus.dat');
   
%ici BanqueSinus est un tableau
%regardons la première colonne (en bleu), et la 4e (en rouge)
plot(BanqueSinus(:,1),'b')
hold on
plot(BanqueSinus(:,4),'r')
hold off


Vous obtenez :

Visualisation de deux vecteurs de la banque de Sinus
Visualisation de deux vecteurs de la banque de Sinus

Si vous tracez d'autres vecteurs, vous remarquerez que plus le numéro de colonne est élevé, plus les oscillations sont rapides. Vous pouvez également représenter les cosinus avec la même méthode et le résultat est similaire.

Vous remarquerez également que contrairement au chapitre précédent où l'on ne disposait que de 4 vecteurs de base, il y a cette fois-ci un très grand nombre de signaux qui serviront de base (48 cosinus et 48 sinus différents).

%Pour savoir combien de colonnes il y a dans les données:
size(BanqueSinus)


ans =

 96 48

Ce résultat signifie qu'il y a 48 colonnes contenant chacune 96 points.

Le nombre total (96) n'est pas un hasard. Vous remarquerez qu'il correspond au nombre de points des données expérimentales.

S'agit-il ici de sinus et cosinus quelconques ?
Évidemment la réponse est non : ces vecteurs ont été choisis soigneusement et vous verrez dans la suite du cours, dans le détail, comment ils ont été choisis.

Les signaux sinusoïdaux forment-ils une base ?

Comme dans le chapitre précédent, nous allons voir que tous ces vecteurs forment une base.

Cela n'est pas très compliqué, il suffit de tester :

%testons si le vecteur 1 et le vecteur 2 de la Banque des Sinus sont orthogonaux
%dot est une fonction intégrée de matlab qui calcule le produit scalaire de deux vecteurs (c'est en pratique la même chose que la fonction prodScal que vous aviez construite dans le tuto précédent)
dot(BanqueSinus(:,1),BanqueSinus(:,2))


Auquel Matlab répond :

ans = -5.1051e-18

Ce qui suggère que ces deux vecteurs sont bien orthogonaux (ce nombre est négligeable devant 1). Il ne nous reste plus qu'à tester les 9119 autres combinaisons de vecteurs possibles restantes...

Autant vous le dire, je vous déconseille de le faire à la main. Nous allons donc le faire de façon automatique. Voici une implémentation possible qui utilise deux boucles imbriquées.

% on met tous les vecteurs dans une grosse matrice
TousLesVecteurs = [BanqueCosinus BanqueSinus];
%on initialise un tableau "orthogonalite" qui contiendra les valeurs des produits scalaires
orthogonalite = []; % [] signifie tableau vide
for i = 1:96
    for j = 1:96
        if i ~= j % ~= signifie "different de" on ne teste pas l'orthogonalite si ce sont les même vecteurs
            v1 = TousLesVecteurs(:,i);
            v2 = TousLesVecteurs(:,j);
            orthogonalite = [orthogonalite dot(v1,v2)]; % on rajoute au tableau "orthogonalite" la valeur du produit scalaire qui nous  intéresse
        end
    end
end

Vous pouvez explorer les valeurs contenues dans le tableau orthogonalite, et vous verrez que toutes les valeurs sont nulles.  Vous pouvez le vérifier en comptant le nombre de fois où le produit scalaire est plus petit que \( 10−6 \) :

sum(orthogonalite < 1e-6)


Auquel Matlab répond :

ans = 9120


Ce qui est aussi la taille totale du tableau orthogonalite.

Nous sommes donc rassurés, tous les vecteurs sont orthogonaux entre eux (encore une fois un miracle ?). Il s'agit bien d'une base. Je vous laisse vérifier qu'ils sont tous également tous unitaires (une seule boucle suffira).

Recomposition du signal

Maintenant que l'on est certain d'avoir une base orthonormée, il est garanti que nous allons pouvoir reconstituer n'importe quel vecteur de taille 96. En particulier le vecteur correspondant aux données expérimentales (la série de température).

Profitons au passage de la recomposition pour stocker la valeur des projections sur chaque vecteur de base (les composantes).

N = length(data); % ici N = 96 normalement
coefficients = [];% on initialise un tableau pour mettre tous les composantes
recomp = zeros(N,1); % on initialise un vecteur recomposition

%Boucle sur tous les vecteurs de base
for k = 1:N
    vectBase = TousLesVecteurs(:,k); % on selectionne un vecteur
    coef = dot(data,vectBase); % on calcule la composante
    coefficients = [coefficients coef]; % on stocke la composante
    recomp = recomp + coef*vectBase; % on ajoute au vecteur recomposé la bonne proportion du vecteur de base
end

% on représente la recomposition en rouge, et les données en noir
plot(recomp,'r')
hold on
plot(data,'k+')
hold off
legend({'Signal recomposé' 'Données'})

Vous obtenez :

Nous avons pu parfaitement recomposer le signal d'origine avec la décomposition sur des sinus/cosinus
Nous avons pu parfaitement recomposer le signal d'origine avec la décomposition sur des sinus/cosinus

Peut-on interpréter les composantes ?

Alors certes, la recomposition a donné un excellent résultat, mais peut-on essayer de comprendre un peu mieux ce qui s'est passé ?

Pour cela, jetons un œil à la liste des composantes. Vous pouvez par exemple la représenter avec plot(coefficients).

Vous remarquerez que la plupart des coefficients sont faibles, sauf peut-être le 1er, le 5e, le 9e et le 52e.

Le premier coefficient vaut ainsi 197.08. Cela signifie que pour recomposer la série de température, il faut ajouter 197.08 fois le tout premier vecteur.

Regardons à quoi cela correspond:

plot(197.08*TousLesVecteurs(:,1),'r'); % on représente la contribution du premier vecteur
hold on
plot(data,'k+')
hold off


Vous obtenez :

La contribution du premier vecteur correspond à un ajout de valeur moyenne

La contribution du premier vecteur correspond à un ajout de valeur moyenn

Le tout premier vecteur est en fait un vecteur tout plat (il s'agit en fait de , un cosinus de fréquence nulle). La contribution du premier vecteur (en rouge) tombe pile sur la valeur moyenne du signal à recomposer.

Ajoutons maintenant la composante numéro 5 (cette composante vaut coefficients(5), soit 20.059 d'après Matlab), que nous avons remarqué précédemment :

plot(197.08*TousLesVecteurs(:,1)+20.059*TousLesVecteurs(:,5),'r'); % on représente la contribution du premier vecteur
hold on
plot(data,'k+')
hold off

On rajoute la composante numéro 5, qui est une composante qui oscille à la même fréquence que le signal d'origine

On rajoute la composante numéro 5, qui est une composante qui oscille à la même fréquence que le signal d'origine

Si vous continuiez à rajouter les composantes suivantes vous vous rapprocheriez de plus en plus du signal original.

Ici le signal de départ était lui-même oscillant. Et il paraît donc naturel de décomposer ce signal sur une base oscillante, les sinusoïdes.
Mais puisque la base que nous utilisons est orthonormée, il faut bien comprendre que n'importe quelle forme de signal pourra être recomposée grâce à cette base, y compris des formes de signaux pas du tout oscillantes.

Vous pouvez aussi regarder cette petite animation qui peut-être vous aidera à visualiser un peu mieux ce que l'on peut faire avec une décomposition en sinusoïdes.


Conclusion

Dans cette partie, nous avons vu :

  • ce qu'était un signal au sens physique/mathématique
  • comment mettre des nombres dessus
  • comment le comparer à d'autres signaux
  • comment le recomposer à partir d'une base

Dans le chapitre suivant, vous verrez ce que l'on entend par représentation fréquentielle d'un signal. Mais avant d'y passer, je vous invite à tester vos connaissances avec le quiz sur la manipulation du signal 1D.