Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

EasyFFT :transformée de Fourier rapide (FFT) pour Arduino

Composants et fournitures

Arduino Nano R3
× 1

Applications et services en ligne

Arduino IDE

À propos de ce projet

La mesure de la fréquence à partir du signal capturé peut être une tâche difficile, en particulier sur Arduino car il a une puissance de calcul plus faible. Il existe des méthodes disponibles pour capturer le passage par zéro où la fréquence est capturée en vérifiant combien de fois le signal traverse les lignes zéro dans le temps donné. Une telle méthode peut ne pas fonctionner lorsque le signal est une combinaison de plusieurs fréquences.

C'est en quelque sorte difficile à coder si vous n'êtes pas issu d'un tel contexte. Mais étant un bricoleur, ce code peut être très utile pour divers projets liés à la musique, à l'analyse du signal. Le motif de ce projet était de préparer un code facile à implémenter sur Arduino sans entrer dans le fond.

Ce projet n'explique pas le fonctionnement de FFT mais explique l'application de la fonction FFT. Le même processus est également expliqué dans la vidéo ci-jointe.

Si vous n'êtes intéressé que par l'application du code et non par une explication de celui-ci. Vous pouvez passer directement à l'étape 3.

Si vous devez effectuer une FFT à grande vitesse (3x) avec un petit compromis sur la précision (environ 5%), reportez-vous à mon autre article sur ApproxFFT.

https://create.arduino.cc/projecthub/abhilashpatel121/approxfft-fastest-fft-function-for-arduino-fd4917?ref=user&ref_id=1593632&offset=0

Étape 1 : Transformation de Fourier rapide

Pour rendre le calcul de la DFT plus rapide, l'algorithme FFT a été développé par James Cooley et John Tukey. Cet algorithme est également considéré comme l'un des algorithmes les plus importants du 20e siècle. Il divise un signal en une partie séquencée impaire et paire, ce qui réduit le nombre de calculs requis. En l'utilisant, la multiplication complexe totale requise peut être réduite à NlogN. ce qui est une amélioration significative. La DFT typique prend N*N multiplication complexe pour les résultats, tandis que la FFT ne prend que N*logN. c'est un avantage significatif lorsque le nombre d'échantillons est élevé.

Vous pouvez vous référer aux références ci-dessous auxquelles j'ai fait référence lors de l'écriture du code pour une compréhension détaillée des mathématiques derrière FFT :

1. https://flylib.com/books/en/2.729.1/derivation_of_...

2. https://jakevdp.github.io/blog/2013/08/28/understa...

3. https://cnx.org/contents/[email protected]:zmcmahhR@7/D...

4. https://en.wikipedia.org/wiki/Fast_Fourier_transfo...

Étape 2 :Explication du code

1. Sinus et cosinus rapides :

Le calcul FFT prend la valeur de divers sinus et cosinus plusieurs fois. La fonction intégrée d'Arduino n'est pas assez rapide et prend beaucoup de temps pour fournir la valeur requise. Ce qui rend le code considérablement plus lent (double le temps pour 64 échantillons). Pour contrer ce problème, la valeur du sinus de 0 à 90 degrés est stockée sous forme de multiple de 255. Cela éliminera le besoin d'utiliser le stockage de nombres comme flottant et nous pouvons le stocker sous forme d'octet qui prend 1/4 d'espace sur Arduino. Le sine_data[ ] doit être collé en haut du code pour le déclarer en tant que variable globale.

En dehors de sine_data, un tableau appelé f_peaks[] déclaré comme variable globale . Après chaque exécution de la fonction FFT, ce tableau est mis à jour. Où f_peaks[0] est la fréquence la plus dominante et les autres valeurs par ordre décroissant.

octet sine_data [91]={0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79 , 83, 87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174 , 177, 180, 183, 186, 189, 192, 195, 198, 201, 204, 206, 209, 211, 214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236 , 238, 240, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255 };float f_peaks[5 ]; 

Comme nous avons stocké la valeur du sinus de 0 à 90 degrés, toute valeur de sinus ou de cosinus peut être calculée. Ci-dessous, la fonction du premier tour du nombre à zéro point décimal et la valeur de retour à partir des données stockées. cette méthode n'a besoin que d'une division flottante. Cela peut être encore réduit en stockant directement les valeurs sinus (pas 255 multiples). mais cela consomme beaucoup de mémoire sur Arduino.

L'utilisation de la procédure ci-dessus réduit la précision mais améliore la vitesse. Pour 64 points, cela donne un avantage de 8ms et pour 128 points, cela donne un avantage de 20ms.

Étape 3 :Explication du code :fonction FFT

La FFT ne peut être effectuée que pour la taille d'échantillon de 2, 4, 8, 16, 32, 64 et ainsi de suite. si la valeur n'est pas 2^n, alors il prendra le côté inférieur de la valeur. Par exemple, si nous choisissons la taille d'échantillon de 70, il ne considérera que les 64 premiers échantillons et omettra le reste.

Il est toujours recommandé d'avoir une taille d'échantillon de 2^n. qui peut être :

2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,...

Deux flottants out_r et out_im prendront une grande quantité de mémoire. pour Arduino nano ne fonctionnera pas pour les échantillons supérieurs à 128 (et dans certains cas 128) en raison du manque de mémoire disponible.

données int non signées[13]={1,2,4,8,16,32,64,128,256,512,1024,2048};int a,c1,f,o,x;a=N; for(int i=0;i<12;i++) //calcul des niveaux { if(data[i]<=a){o=i;} } int in_ps[data[o]]={}; //entrée pour le séquençagefloat out_r[data[o]]={} ; //partie réelle de transformfloat out_im[data[o]]={}; //partie imaginaire de la transformation 

Le flux supplémentaire est le suivant :

1. Le code génère un ordre un peu inversé pour la taille d'échantillon donnée (détails sur l'inversion des bits sur les références :étape 2)

2. Saisissez les données commandées selon la commande générée,

3. FFT effectuée

4. L'amplitude du nombre complexe calculé,

5. Les pics sont détectés et classés par ordre décroissant

6. les résultats sont accessibles depuis f_peaks[].

[pour accéder à d'autres données (en dehors de la fréquence de pointe), le code doit être modifié, de sorte que la variable locale puisse être copiée dans une variable globale prédéfinie]

Étape 4 :Tester le code

Un exemple d'onde triangulaire est donné en entrée. pour cette onde, la fréquence d'échantillonnage est de 10 Hz et la fréquence de l'onde elle-même est de 1,25 Hz.

Comme le montre la sortie brute, la valeur correspond à la FFT calculée par Scilab. cependant, ces valeurs ne sont pas exactement les mêmes que celles d'une onde sinusoïdale de faible précision mais plus rapide.

Dans la fréquence de sortie, la fréquence du tableau est de 1,25 et 3,75. il n'est pas nécessaire d'obtenir la valeur exacte à chaque fois. généralement, ces nombres sont appelés groupes de fréquences. donc la valeur de sortie peut être n'importe où dans les bacs spécifiés.

Vitesse :

pour Arduino nano il faut :

  • 16 points :4 ms
  • 32 points :10 ms
  • 64 points :26 ms
  • 128 points :53 ms

Étape 5 :Conclusion

Ce code FFT peut être utilisé dans des applications temps réel. Comme il faut environ 30 ms pour terminer le calcul. Cependant, sa résolution limitée par un certain nombre d'échantillons. Le nombre d'échantillons est limité par la mémoire Arduino. En utilisant Arduino Mega ou une autre carte plus performante, la précision peut être améliorée.

Si vous avez des questions, des suggestions ou des corrections, n'hésitez pas à commenter.

Code

  • EasyFFT
EasyFFTArduino
Ce code exécute FFT et met à jour le tableau F_peasks avec les 5 fréquences les plus dominantes.
/*//Example data:int data[64]={14, 30, 35, 34, 34, 40, 46, 45, 30 , 4, -26, -48, -55, -49, -37,-28, -24, -22, -13, 6, 32, 55, 65, 57, 38, 17, 1, -6, - 11, -19, -34, -51, -61, -56, -35, -7, 18, 32, 35, 34, 35, 41, 46, 43, 26, -2, -31, -50, -55, -47, -35, -27, -24, -21, -10, 11, 37, 58, 64, 55, 34, 13, -1, -7} ;*///---- -------------------------------------------------- ---------------------//octet sine_data [91]={0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79, 83, 87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174, 177, 180, 183, 186, 189, 192, 195, //Coller ceci en haut du programme198, 201, 204, 206, 209, 211 , 214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252 , 253, 253, 254, 254, 254, 255, 255, 255, 255 };float f_peaks[5]; // top 5 des pics de fréquences par ordre décroissant //---------------------------------------- ------------------------------------//configuration void() { Serial.begin(250000); } void loop() {/*//exampleFFT(data,64,100); //pour obtenir les cinq premières valeurs des fréquences de X ayant 64 échantillons à 100Hz d'échantillonnageSerial.println(f_peaks[0]);Serial.println(f_peaks[1]);delay(99999);*//* après ruine au-dessus de FFT( ), fréquences disponibles à f_peaks[0],f_peaks[1],f_peaks[2],f_peaks[3],f_peaks[4],*/ }//--------------- --------------Fonction FFT--------------------------------- ------------//float FFT(int in[],int N,float Frequency){/*Code pour effectuer FFT sur arduino, setup:paste sine_data [91] en haut du programme [ variable globale], collez la fonction FFT à la fin du programmeTerm:1. in[] :Tableau de données, 2. N :Nombre d'échantillons (taille d'échantillon recommandée 2,4,8,16,32,64,128...)3. Fréquence :fréquence d'échantillonnage requise comme entrée (Hz) Si la taille de l'échantillon n'est pas en puissance de 2, elle sera écrêtée au côté inférieur du nombre. c'est-à-dire que pour un nombre de 150 échantillons, le code considérera le premier échantillon 128, l'échantillon restant sera omis. Pour Arduino nano, une FFT de plus de 128 échantillons n'est pas possible en raison de la limitation de la mémoire (64 recommandé) problème, Code par ABHILASHContact :[email protected] Documentation :https://www.instructables.com/member/abhilash_patel/instructables/2/3/2021 :modifiez le type de données de N de float à int pour>=256 échantillons* /unsigned int data[13]={1,2,4,8,16,32,64,128,256,512,1024,2048};int a,c1,f,o,x;a=N; for(int i=0;i<12;i++) //calcul des niveaux { if(data[i]<=a){o=i;} } int in_ps[data[o]]={}; //entrée pour le séquençagefloat out_r[data[o]]={} ; //partie réelle de transformfloat out_im[data[o]]={}; //partie imaginaire de la transformation x=0; for(int b=0;ba) {out_r[i]=in[in_ps[i]-a];} }int i10,i11,n1;float e,c,s,tr,ti; for(int i=0;i ici out_r contient l'amplitude et our_in contient la fréquence (Hz) for(int i=0;iout_r[i-1] &&out_r[i]>out_r[i+1] ) {in_ps[x]=i; // tableau in_ps utilisé pour le stockage du nombre de pics x=x+1;} }s=0;c=0; for(int i=0;i360){j=j-360;} if(j>-1 &&j<91){out=sine_data[j];} else if (j>90 &&j<181){out=sine_data[180-j];} else if(j>180 &&j<271){out=-sine_data[j-180];} else if(j>270 &&j<361){out=-sine_data[360-j];} return (out/255);}float cosinus(int i){ int j=i; flotter; while(j<0){j=j+360;} while(j>360){j=j-360;} if(j>-1 &&j<91){out=sine_data[90-j];} else if(j>90 &&j<181){out=-sine_data[j-90];} else if(j>180 &&j<271){out=-sine_data[270-j];} else if(j>270 &&j<361){out=sine_data[j-270];} return (out/255);}//---------------------- -------------------------------------------------- ------------//

Schémas


Processus de fabrication

  1. Qu'est-ce que la transformée de Fourier ?
  2. Décodeur DTMF utilisant uniquement Arduino
  3. Système d'alarme Arduino :SERENA
  4. Communication Python3 et Arduino
  5. Surveillance SMART de la température pour les écoles
  6. Bibliothèque de ports E/S 8 bits pour Arduino
  7. Une entrée analogique isolée pour Arduino
  8. Robot pour une navigation intérieure super cool
  9. Quel est le code SH pour la pompe hydraulique ?