Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

EasyFFT:Schnelle Fourier-Transformation (FFT) für Arduino

Komponenten und Verbrauchsmaterialien

Arduino Nano R3
× 1

Apps und Onlinedienste

Arduino-IDE

Über dieses Projekt

Die Messung der Frequenz aus dem erfassten Signal kann eine schwierige Aufgabe sein, insbesondere bei Arduino, da es eine geringere Rechenleistung hat. Es gibt Verfahren zum Erfassen von Nulldurchgängen, bei denen die Frequenz erfasst wird, indem überprüft wird, wie oft das Signal die Nulllinien innerhalb der gegebenen Zeit durchquert. Eine solche Methode funktioniert möglicherweise nicht, wenn das Signal eine Kombination verschiedener Frequenzen ist.

Dies ist irgendwie schwierig zu codieren, wenn Sie nicht über einen solchen Hintergrund verfügen. Aber als Bastler kann dieser Code für verschiedene Projekte im Zusammenhang mit Musik und Signalanalyse sehr nützlich sein. Das Motiv dieses Projekts war es, einen Code vorzubereiten, der auf Arduino einfach zu implementieren ist, ohne in den Hintergrund zu geraten.

Dieses Projekt erklärt nicht die Funktionsweise von FFT, sondern erklärt die Anwendung der FFT-Funktion. Der gleiche Vorgang wird auch im beigefügten Video erklärt.

Wenn Sie nur an der Anwendung von Code interessiert sind und nicht an einer Erklärung davon. Sie können direkt zu Schritt Nr. 3 springen.

Wenn Sie eine FFT mit hoher Geschwindigkeit (3x) mit kleinen Kompromissen bei der Genauigkeit (ca. 5 %) durchführen müssen, lesen Sie meinen anderen Artikel über ApproxFFT.

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

Schritt 1:Schnelle Fourier-Transformation

Um die Berechnung von DFT schneller zu machen, wurde der FFT-Algorithmus von James Cooley und John Tukey entwickelt. Dieser Algorithmus gilt auch als einer der wichtigsten Algorithmen des 20. Jahrhunderts. Es teilt ein Signal in einen ungeraden und einen geraden Teil auf, was die Anzahl der erforderlichen Berechnungen verringert. Durch seine Verwendung kann die gesamte erforderliche komplexe Multiplikation auf NlogN reduziert werden. was eine deutliche Verbesserung darstellt. Eine typische DFT benötigt N*N komplexe Multiplikationen für die Ergebnisse, während FFT nur N*logN benötigt. Dies ist ein wesentlicher Vorteil, wenn die Probenanzahl hoch ist.

Sie können die folgenden Referenzen verwenden, auf die ich beim Schreiben des Codes Bezug genommen habe, um ein detailliertes Verständnis der Mathematik hinter FFT zu erhalten:

1. https://flylib.com/books/de/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...

Schritt 2:Erklärung des Codes

1. Schneller Sinus und Cosinus:

Berechnungs-FFT nimmt den Wert verschiedener Sinus- und Kosinuswerte mehrfach an. Die eingebaute Funktion von Arduino ist nicht schnell genug und benötigt viel Zeit, um den erforderlichen Wert bereitzustellen. Das macht den Code deutlich langsamer (verdoppelt die Zeit für 64 Samples). Um diesem Problem entgegenzuwirken, wird der Sinuswert für 0 bis 90 Grad als Vielfaches von 255 gespeichert. Dadurch entfällt die Notwendigkeit, Zahlen als Float zu speichern, und wir können es als Byte speichern, das auf Arduino 1/4 Platz benötigt. Sine_data[ ] muss am Anfang des Codes eingefügt werden, um ihn als globale Variable zu deklarieren.

Abgesehen von sinus_data, ein Array namens f_peaks[], das als globale Variable deklariert ist . Nach jedem Lauf der FFT-Funktion wird dieses Array aktualisiert. Dabei ist f_peaks[0] die dominanteste Frequenz und weitere Werte in absteigender Reihenfolge.

byte sinus_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 ]; 

Da wir den Sinuswert für 0 bis 90 Grad gespeichert haben, kann jeder beliebige Sinus- oder Kosinuswert berechnet werden. Unten Funktion die erste Runde der Zahl auf Null Dezimalpunkt und Rückgabewert aus gespeicherten Daten. diese Methode benötigt nur eine schwebende Division. Dies kann durch direktes Speichern von Sinuswerten (nicht 255-fach) weiter reduziert werden. aber das frisst viel Speicher auf Arduino.

Die Verwendung des obigen Verfahrens verringert die Genauigkeit, verbessert jedoch die Geschwindigkeit. Für 64 Punkte gibt es einen Vorteil von 8 ms und für 128 Punkte einen Vorteil von 20 ms.

Schritt 3:Erklärung des Codes:FFT-Funktion

FFT kann nur für die Stichprobengröße 2, 4, 8, 16, 32, 64 usw. durchgeführt werden. Wenn der Wert nicht 2^n ist, wird die niedrigere Seite des Wertes verwendet. Wenn wir beispielsweise die Stichprobengröße von 70 wählen, werden nur die ersten 64 Stichproben berücksichtigt und der Rest weggelassen.

Es wird immer empfohlen, eine Stichprobengröße von 2^n zu verwenden. was sein kann:

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

Zwei Floats out_r und out_im benötigen viel Speicher. für Arduino nano funktioniert nicht für Samples, die höher als 128 (und in einigen Fällen 128) sind, da kein verfügbarer Speicher vorhanden ist.

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++) //Berechnung der Pegel { if(data[i]<=a){o=i;} } int in_ps[data[o]]={}; //Eingabe für die Sequenzierungfloat out_r[data[o]]={}; //realer Teil von transformfloat out_im[data[o]]={}; //imaginärer Teil der Transformation 

Der weitere Ablauf ist wie folgt:

1. Code generiert ein Bit in umgekehrter Reihenfolge für die angegebene Samplegröße (Details zur Bitumkehr bei Referenzen:Schritt 2)

2. Eingabedaten geordnet nach generierter Bestellung,

3. FFT durchgeführt

4. Die Amplitude der berechneten komplexen Zahl,

5. Peaks werden erkannt und in absteigender Reihenfolge geordnet

6. Auf die Ergebnisse kann von f_peaks[] zugegriffen werden.

[um auf andere Daten (außer der Spitzenfrequenz) zuzugreifen, sollte der Code geändert werden, damit die lokale Variable in eine vordefinierte globale Variable kopiert werden kann]

Schritt 4:Testen des Codes

Als Eingabe wird eine Beispiel-Dreieckswelle angegeben. für diese Welle beträgt die Abtastfrequenz 10 Hz und die Frequenz der Welle selbst beträgt 1,25 Hz.

Wie aus der Rohausgabe ersichtlich ist, stimmt der Wert mit der von Scilab berechneten FFT überein. Diese Werte sind jedoch nicht genau die gleichen wie bei unserer niedrigen Genauigkeit, aber einer schnelleren Sinuswelle.

Im Ausgangsfrequenz-Array sind die Frequenzen 1,25 und 3,75. Es ist nicht notwendig, jedes Mal den genauen Wert zu erhalten. typischerweise werden diese Zahlen als Frequenz-Bins bezeichnet. Der Ausgabewert kann sich also überall innerhalb der angegebenen Bins befinden.

Geschwindigkeit:

für Arduino Nano braucht es:

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

Schritt 5:Fazit

Dieser FFT-Code kann in Echtzeitanwendungen verwendet werden. Da die Berechnung etwa 30 ms dauert. Allerdings ist seine Auflösung durch eine Anzahl von Samples begrenzt. Die Anzahl der Samples ist durch den Arduino-Speicher begrenzt. Durch die Verwendung von Arduino Mega oder anderen Hochleistungsplatinen kann die Genauigkeit verbessert werden.

Wenn Sie Fragen, Vorschläge oder Korrekturen haben, können Sie gerne einen Kommentar abgeben.

Code

  • EasyFFT
EasyFFTArduino
Dieser Code führt eine FFT durch und aktualisiert das F_peasks-Array mit den fünf dominantesten Frequenzen.
/*//Beispieldaten: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};*///---- -------------------------------------------------- ----------------------//byte sinus_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, // Füge dies oben in das Programm ein198, 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 Frequenzspitzen in absteigender Reihenfolge //-------------------------------------- ---------------------------------- //void setup () { Serial.begin(250000); aufrechtzuerhalten. Void Schleife () {/* // BeispielFFT (Daten, 64, 100); // um die obersten fünf Werte der Frequenzen von X mit 64 Samples bei 100 Hz zu erhalten SamplingSerial.println(f_peaks[0]);Serial.println(f_peaks[1]);delay(99999);*//* nach dem Überschreiten von FFT( ), Frequenzen verfügbar bei f_peaks[0],f_peaks[1],f_peaks[2],f_peaks[3],f_peaks[4],*/ }//---------------- --------------FFT-Funktion ---------------------------------- ------------//float FFT(int in[],int N,float Frequency){/*Code zum Ausführen von FFT auf arduino,setup:paste sine_data [91] oben im Programm [ globale Variable], FFT-Funktion am Ende von programTerm:1 einfügen. in[] :Datenarray, 2. N :Nummer der Stichprobe (empfohlener Stichprobenumfang 2,4,8,16,32,64,128...)3. Frequenz:als Eingabe erforderliche Abtastfrequenz (Hz) Wenn die Abtastgröße nicht in der Potenz von 2 liegt, wird sie auf die untere Seite der Zahl abgeschnitten. dh bei einer Anzahl von 150 Samples berücksichtigt der Code die ersten 128 Samples, die restlichen Samples werden weggelassen. Für Arduino nano ist eine FFT von mehr als 128 Samples aufgrund der Speicherbeschränkung nicht möglich (64 empfohlen). Ausgabe, Code von ABHILASHKontakt:[email protected] Dokumentation:https://www.instructables.com/member/abhilash_patel/instructables/2/3/2021:Ändern Sie den Datentyp von N von float in int für>=256 Samples* /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++) //Berechnung der Pegel { if(data[i]<=a){o=i;} } int in_ps[data[o]]={}; //Eingabe für die Sequenzierungfloat out_r[data[o]]={}; //realer Teil von transformfloat out_im[data[o]]={}; //imaginärer Teil der 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 ab hier out_r enthält die Amplitude und our_in enthält die Frequenz (Hz) for(int i=0;iout_r[i-1] &&out_r[i]>out_r[i+1] ) {in_ps[x]=i; //in_ps-Array zum Speichern der Spitzennummer x=x+1;} }s=0;c=0; for(int i=0;i360){j=j-360;} if(j>-1 &&j<91){out=sinus_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 cosine(int i){int j=i; schweben; while(j<0){j=j+360;} while(j>360){j=j-360;} if(j>-1 &&j<91){out=sinus_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);}//--------------------- -------------------------------------------------- ------------//

Schaltpläne


Herstellungsprozess

  1. Was ist die Fourier-Transformation?
  2. DTMF-Decoder, der nur Arduino verwendet
  3. Arduino-Alarmsystem:SERENA
  4. Python3- und Arduino-Kommunikation
  5. SMART-Temperaturüberwachung für Schulen
  6. 8-Bit-IO-Port-Bibliothek für Arduino
  7. 64-Tasten-Prototyping-Tastaturmatrix für Arduino
  8. Ein isolierter Analogeingang für Arduino
  9. Roboter für supercoole Indoor-Navigation
  10. Was ist der HS-Code für Hydraulikpumpen?