bunex-industries

Séries de Fourier - Calcul des coefficients

Cela faisait longtemps que je souhaitais étudier plus concrètement cet incontournable outil mathématique. Au delà du principe générale de l'analyse fréquentielle qui est je crois assez intuitif et accessible pour qui a vu une fois un un spectre sonore, je ne me sentais pas de m'attaquer aux calculs. Il faut dire que ces intégrales d'exponentielles complexes ne sont pas très engageantes... En en restant à l'approche trigonométrique, avec des nombres réels, et avec un jeu de points en entrées et non une fonction, cela s'est tout de même révélé accessible (il s'agit donc plutôt d'une transformée de Fourier discrète ou TFD).

Je conseille et remercie El Jj pour son très beau travail ! Cette vidéo m'a particulièrement éclairé. Il existe de nombreux algorithmes et librairies spécialisés (dont Web Audio API) pour accomplir ces opérations très efficacement mais l'exemple ci-dessous n'y fait pas appel.

Le but de cette démo est donc d'approximer un signal d'entrée (liste de n valeurs discrètes x0, x1,...xn-1) sous la forme d'une fonction, somme (potentiellement infinie) de sinus et cosinus d'amplitudes diverses et de fréquences croissantes, multiples entiers "k" d'une fondamentale (1Hz ici), c.à.d. des harmoniques. La variable "t" représente le temps et varie entre 0s et 1s, durée arbitrairement décidée du signal. Le problème consiste donc à trouver la valeur des coefficients a0, ak et bk dans l'équation ci-après.

$$ f(t) = a_0 + \sum_{k=1}^\infty a_k\cdot\cos(k2\pi t) + b_k\cdot\sin(k2\pi t) $$

Le coefficient a0 représente la partie constante du signal (composante continue), moyenne des valeurs de la liste :

$$ a_0 = \frac{1}{n}\cdot\sum_{k=0}^n x_k $$

Les amplitudes des sinus et cosinus des harmoniques suivantes sont calculées ainsi :

$$ a_k = \frac{2}{n}\cdot\sum_{k=1}^n x_k\cdot\cos(k2\pi t) $$ $$ b_k = \frac{2}{n}\cdot\sum_{k=1}^n x_k\cdot\sin(k2\pi t) $$

Les coefficients sont calculés pour toutes les valeurs de k. Certains coefficients peuvent parfois être très petits et négligeables et l'équation finale pourrait alors être simplifiée (pas fait ici). Le nombre d'harmoniques à calculer dépendra du niveau de fidélité voulu et de la complexité du signal d'entrée. Observez que le contenu en fréquence se ramasse vers les basses fréquences lorsque le signal est lissé. Inversement, il faut augmenter le nombre d'harmoniques calculées pour fidèlement reproduire un signal "riche". Si les signaux aléatoires voient toutes les fréquences de leur spectre "peuplées" (voir la notion de bruit blanc), les deux cas non-aléatoires (le signal carré et le signal composite de sinus) exposent au contraire un certain ordre propre au signal.


Signal en entrée (1024 échantillons) :

Harmoniques calculées jusqu'à : Hz (cliquer sur le champ et modifier avec les flèches haut/bas du clavier. Attention aux performances pour des valeurs > 200 :-)

Signal reconstitué :

Contenu en fréquence (spectre) :
colonne de gauche = niveau constant (0Hz), puis d'hertz en hertz de gauche à droite.

Formule mathématique :

Application sur des dessins

Je conseille cet article !

La même technique est appliquée à la liste des coordonnées x d'une part et y d'autre part. On obtient finalement 2 équations, une pour chaque axe, leur combinaison permet de dessiner. El Jj explique tout cela très bien.

Vous pouvez dessiner votre propre SVG (taille du document 400x800px). Le module d'importation supporte seulement les balises "polyline", "polygon" et "path". Avec Illustrator, un dessin au crayon simplement enregistré en SVG fonctionne.

Un aparté à propos de l'interprétation des objets "paths" : il faut aplatir les courbes de Bezier, en choisissant un "pas curviligne". Cette fonctionnalité n'est pas sans rappeler les questions de pilotage CNC et de génération de GCode. Voici la fonction qui extrait les coordonnées des objet "path" d'un SVG :

if(paths.length > 0) { 						// paths est la liste des éléments "path" dans le document
	for(var p = 0 ; p < paths.length ; p++) {
		var path = paths[p];
		var pathLength = path.getTotalLength(); 	// longueur curviligne du tracé
		var pos = 0;					// abscisse curviligne
		var step = 5; 					// pas
		while (pos<=pathLength) {
			var point = path.getPointAtLength(pos);	// SVGPathElement.getPointAtLength()
			figurex.push(point.x);
			figurey.push(point.y);
			pos = pos+step;
		}
	}	
}

Ou cliquer sur un dessin :


Harmoniques calculées jusqu'à : Hz

Dessin reconstitué :

Dessin source (svg avec 1553 points) :