Club robotique de Sophia-Antipolis

Accueil > Projets, études > Etudes techniques > Son > Traitement du son par FFT (fast fourier transformer)

Traitement du son par FFT (fast fourier transformer)

lundi 20 mai 2013, par Audrick F.

Pour mon projet DRIKYBOT le robot danseur, j’ai voulu créer des effets de lumière musicale (type équalizer) pour cela j’ai dû procéder à un traitement de signal sonore. Il existe énormément de méthodes pour traiter le signal sonore, cet article est un retour des différentes solutions adaptables pour l’Arduino.

Première solution

Le système d’analyse de son de l’oreille humaine est très complexe. Il est capable de capter des sons sur une large plage d’intensité et de fréquence.

La première solution se porte exclusivement sur l’analyse de l’intensité des sons, elle consiste à brancher un microphone sur l’Arduino en 3.3V afin de faire interagir les LED en fonction de la tonalité des sons extérieurs. Les LED s’allument selon l’amplitude du signal sonore.

Pour un fonctionnement correcte des LED il faut réaliser une baisse de tension car elles n’ont pas besoin de 3.3V.

Il faut donc utiliser la loi d’ohm U=R*I pour choisir la valeur de la résistance.

Avec une diode led à 1.8 Volts pour 10 mA de courant, la led étant branchée à 3.3V sur l’Arduino on a :
R = (3.3 - 1.8) / 0.01 = 150
Donc une résistance de 150 Ohm convient.

Matériel :

 une Arduino UNO
 3 Leds (de couleurs différente de préférence)
 microphone ADMP401 MEMS
 une platine d’essai
 3 résistances 150 Ohms

Code Source

int Micro = A0; //entrée annalogique du microphone
int LED1 = 5; //Sorti numérique connecté à la LED1
int LED2 = 4; //Sorti numérique connecté à la LED2
int LED3 = 3; //Sorti numérique connecté à la LED3
void setup() {
    Serial.begin(115200);

    pinMode(pinLED1, OUTPUT);
    pinMode(pinLED2, OUTPUT);
    pinMode(pinLED3, OUTPUT);
}

void loop() {
    int valMicro = analogRead(Micro);

    Serial.println(valMicro);

    if (valMicro > 200)
    digitalWrite(LED1, HIGH);
    
    else
    digitalWrite(LED1, LOW);

    if (valMicro > 300)
    digitalWrite(LED2, HIGH);
    
    else 
    digitalWrite(LED2, LOW);

    if (valMicro > 400)
    digitalWrite(LED3, HIGH);
    
    else
    digitalWrite(LED3, LOW);
}

Deuxième solution

On utilise une méthode appelée FFT (Fast Fourier Transformer).

Pour traiter directement les fréquences de la musique et non l’intensité il faut avoir recours à la Transformer de Fourier discrète Rapide (FFT).

La FFT permet la conversion de données temporelles en données fréquentiel (très utiles pour les équalizers).

De la doc à lire pour mieux comprendre la FFT sur ce site (anglais).

Librairie FFT

Pour télécharger la librairie, le projet arduino-integer-fft.

Le programme d’exemple consiste à diviser les fréquences perçues de 0 à 32KHz en 64 échantillons séparé d’environ 500Hz.Ce qui permet de choisir une fréquence précise et de l’utiliser en sortie.

C’est une simple librairie FFT inspirée du programme assembleur décrit sur ce site.

Code source exemple pour le contrôle de LED

#include <fix_fft.h>

char im[128];
char data[128]; 
const int pinLED0 = 3;// Sorti numérique connecté à la LED0
const int pinLED1 = 4; // Sorti numérique connecté à la LED1
const int pinLED2 = 5;// Sorti numérique connecté à la LED2


void setup()
{
    Serial.begin(115200);
    pinMode(pinLED0, OUTPUT);
    pinMode(pinLED1, OUTPUT);
    pinMode(pinLED2, OUTPUT);
 
}

void loop(){
  int static i = 0;
  static long tt;
  int val;
   
      if (millis() > tt){
	if (i < 128){
	  val = analogRead(A0);
	  data[i] = val / 4 - 128;
	  im[i] = 0;
	  i++; 
         
	  
	}
	else{
	  //this could be done with the fix_fftr function without the im array.
	  fix_fft(data,im,7,0);
	  // I am only interessted in the absolute value of the transformation
	  for (i=0; i< 64;i++){
	     data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);     
          
	  }
        
        for (int e=0; e< 64; e++){
    
          Serial.print(data[e], DEC);
          Serial.print(" ");

	  //do something with the data values 1..64 and ignore im
	  if(e == 63){ 
  Serial.print("\n\n");
delay(100);
}

if(data[0]>22)
{
  digitalWrite(pinLED0, HIGH);
 
}

if(data[1]>14)
{
  digitalWrite(pinLED1, HIGH);
  
}
if(data[24]>1)
{
  digitalWrite(pinLED1, HIGH);
  
}
 else {
      digitalWrite(pinLED0, LOW); 
      digitalWrite(pinLED1, LOW);
      digitalWrite(pinLED2, LOW); 
  
  
        }
       tt = millis();
}
      }
      }

Troisième solution

Une autre solution est d’utiliser le logiciel Processing avec la carte Arduino et de cette manière laisser l’analyse du son via un ordinateur.

Pour mieux comprendre la détection de beat (pulsations graves), voir cet article.

Voici le programme Processing qui utilise la musique numérique de l’ordinateur et sépare les fréquences via une librairie FFT en trois échantillons basse, médium et aigue représenté par les textes : http://www.openprocessing.org/sketc...

Il convient par la suite de transférer les 3 signaux dans les sorties Arduino désirées.

Conclusion

L’Arduino n’est pas la meilleure carte pour réaliser le traitement de signal mais peut suffire pour une FFT simple. Néanmoins pour un meilleur traitement du signal il est préférable d’avoir une carte plus puissante voire un ordinateur.

Vos commentaires

  • Le 13 novembre 2016 à 15:06, par Akira En réponse à : Traitement du son par FFT (fast fourier transformer)

    Bonjour,
    Concernant l’utilisation de la FFT, de quel manière ce fait l’échantillonnage dans le programme et du coup comment du peux savoir qu’on échantillonné par pas de 500hz.
    Merci

    Répondre à ce message

  • Le 22 mars 2016 à 11:16, par BEKAERT En réponse à : Traitement du son par FFT (fast fourier transformer)

    Bonjour,
    Je suis tombé sur ton article qui est vraiment sympa.
    J’ai commencer à utiliser la librairie avec Arduino.
    Concernant le message d’erreur
    C :\Users\utilisateur\Documents\Arduino\libraries\fix_fft/fix_fft.h:4:22 : fatal error : WProgram.h : No such file or directory
    Il faut remplacer <WProgram.h> par <Arduino.h> dans le fichier .h et .cpp.
    Concernant le message d’erreur
    In file included from fix_fft.cpp:1:0 :
    fix_fft.cpp : In function ’int fix_fft(char*, char*, int, int)’ :
    fix_fft.cpp:199:28 : error : ’Sinewave’ was not declared in this scope
    wr = pgm_read_word_near(Sinewave + j+N_WAVE/4) ;
    ^
    fix_fft.cpp:209:28 : error : ’Sinewave’ was not declared in this scope
    wi = -pgm_read_word_near(Sinewave + j) ;
    J’ai tout simplement retiré le retour de la fonction Sinewave qui était un const prog_int8_t en const int8_t
    Me voila donc avec une librairie qui fonctionne sous mon environnement Arduino
    Maintenant j’aimerai utiliser cette librairie pour faire une comparaison des sons obtenus sur deux micros différents . J’ai donc deux micros espacé de 7cm avec lesquels je récupére un tableau de données en FFT. Seulement je n’ai jamais les même valeurs sur les deux micros quand je produis un son
    J’ai besoin d’aide pour comprendre les données recu

    Répondre à ce message

  • Le 25 avril 2015 à 16:01, par Jean-Claude Verdin En réponse à : Traitement du son par FFT (fast fourier transformer)

    Bonjour,
    Je travaille sur un projet de contrôle de moteur / le son.
    Inévitablement, je suis tombé sur Arduino et votre page.
    J’essaye la solution N° 2 depuis hier midi et me heurte à un problème.
    J’ai bien téléchargé et installé la librairie fix_fft sur Arduino Uno 1.6.1 et lors du test : j’obtiens un message d’erreur :
    C :\Users\utilisateur\Documents\Arduino\libraries\fix_fft/fix_fft.h:4:22 : fatal error : WProgram.h : No such file or directory
    fix_fft.h se trouve bien à cet endroit, mais pas WProgram.h
    Ai-je le (s) bon(s) fichier(s) ?
    Sinon, pouvez vous me dire où je peux le(s) trouver ?
    D’avance merci à vous !
    Ci-dessous le contenu de fix_fft.h (Un partie du commentaire supprimée par manque de place).
    #ifndef FIXFFT_H
    #define FIXFFT_H
    #include <WProgram.h>
    /*
    fix_fft() - perform forward/inverse fast Fourier transform.
    fr[n],fi[n] are real and imaginary arrays, both INPUT AND
    RESULT (in-place FFT), with 0 <= n < 2**m ; set inverse to
    0 for forward transform (FFT), or 1 for iFFT.
    */
    int fix_fft(char fr[], char fi[], int m, int inverse) ;
    int fix_fftr(char f[], int m, int inverse) ;
    #endif

    • Le 25 avril 2015 à 23:10, par Eric P. En réponse à : Traitement du son par FFT (fast fourier transformer)

      Je ne connais pas la lib citée et n’utilise pas l’Arduino moi-même de manière régulière. J’ai à tout hasard tenté un simple Google avec "wprogram.h" comme requête.
      Le premier hit est celui-ci : http://forum.arduino.cc/index.php?topic=147680.0
      Il donne textuellement la réponse à la question 😕
      Pour paraphraser un dicton célèbre : "Aide-toi et Google t’aidera". Autrement dit, un petit effort (15 secondes montre en main) personnel de recherche permet très souvent de gagner pas mal de temps ;)

    • Le 2 mai 2015 à 18:32, par Jean-Claude En réponse à : Traitement du son par FFT (fast fourier transformer)

      Bonjour,
      Merci à vous ! J’ai remplacé WProgram.h par Arduino.h et j’ai pu avancer d’un grand pas.
      De plus, cette fois, j’ai installé les deux fichiers préconisés arduino-integer-fft (fix_fft.h et fix_fft.ccp).
      Je me trouve maintenant avec un message d’erreur et suis à nouveau coincé...
      Suis-je encore en train de bêtement tourner en rond ?
      Jean-Claude
      In file included from fix_fft.cpp:1:0 :
      fix_fft.cpp : In function ’int fix_fft(char*, char*, int, int)’ :
      fix_fft.cpp:199:28 : error : ’Sinewave’ was not declared in this scope
      wr = pgm_read_word_near(Sinewave + j+N_WAVE/4) ;
      ^
      fix_fft.cpp:209:28 : error : ’Sinewave’ was not declared in this scope
      wi = -pgm_read_word_near(Sinewave + j) ;
      ^
      Erreur lors de la compilation.

    • Le 13 mai 2015 à 22:43, par Eric P. En réponse à : Traitement du son par FFT (fast fourier transformer)

      Pas la moindre idée. Il faudrait éplucher le code source (s’agit-il du vôtre ou de celui de la lib ?) pour comprendre ce qu’il en est.
      Et comme l’Arduino n’est pas trop mon trip, quelqu’un d’autre aura sans doute une idée à proposer.
      Eric

    Répondre à ce message

  • Le 13 janvier 2015 à 14:22, par David En réponse à : Traitement du son par FFT (fast fourier transformer)

    Bonjour,
    Je travaille actuellement sur un projet qui utilise une librairie Arduino FFT. Votre site nous a bien aidé mais on ne comprend pas certaines choses comme :
    data[i] = val / 4 - 128 ;
    Pourquoi diviser par 4 et soustraire 128 ?
    De même, qu’est ce que la librairie renvoie dans le tableau data[] ? Ce sont des fréquences ?
    Merci d’avance.

    • Le 19 avril 2015 à 10:49, par Eric P. En réponse à : Traitement du son par FFT (fast fourier transformer)

      Je ne connais pas particulièrement cette librairie, mais la réponse est la même pour les deux questions : lisez la documentation (en bon Anglais d’informaticien : RTFM 😄.
      L’information, tant sur le contenu de data que sur la règle appliquée (qui ressemble comme deux gouttes d’eau au décodage de la résolution et de l’offset utilisés par la lib pour retourner la valeur) y est obligatoirement indiquée.
      Ne pas oublier que dans le monde de l’open source, la documentation ne se résume pas à de jolis manuels en couleurs avec des dessins à toutes les pages (ça c’est bon pour les utilisateurs de Oueurd et Aiqueselle ;)), mais est aussi (et surtout) contenue dans les commentaires présents dans les codes sources, et dans le cas de librairies en C, dans les includes (.h) qui définissent les fonctions et classes utilisées.

    Répondre à ce message

  • Le 9 avril 2015 à 12:08, par racra En réponse à : Traitement du son par FFT (fast fourier transformer)

    erreur sur WProgram.h(il n’existe pas) besoin d’aide s’il vous plait

    • Le 19 avril 2015 à 10:38, par Eric P. En réponse à : Traitement du son par FFT (fast fourier transformer)

      Pas facile de vous aider avec un tel message : vous compilez quoi ? avec quelle tool chain ? dans quel environnent ?
      Je vais quand même essayer...
      Le message est explicite : un include (wprogram.h) nécessaire à la compilation n’a pas été trouvé.
      Deux raisons possibles :
       il n’existe réellement pas, parce que la lib à laquelle il appartient n’est pas installée
       il n’a pas été trouvé parce que l’option de compilation ou la variable d’environnement qui indique la liste des répertoires de recherche des includes n’est pas correctement configurée et n’inclut pas celui où se trouve le fichier en question
      Bonne chasse maintenant ;)

    Répondre à ce message

Un message, un commentaire ?

modération a priori

Attention, votre message n’apparaîtra qu’après avoir été relu et approuvé.

Qui êtes-vous ?

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.