Inhaltsverzeichnis:

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

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

Video: EasyFFT: Schnelle Fourier-Transformation (FFT) für Arduino - Gunook
Video: FFT based Frequency Detector using an FPGA -Intel Quartus (IT WORKS!!) 2024, September
Anonim
Image
Image

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 innerhalb der gegebenen Zeit Nulllinien durchquert. Ein solches Verfahren funktioniert möglicherweise nicht, wenn das Signal eine Kombination verschiedener Frequenzen ist.

Dies ist irgendwie schwierig zu codieren, wenn Sie nicht aus einem solchen Hintergrund stammen. 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 gehen.

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.

Schritt 1: Einführung in die Frequenztransformation

Einführung in die Frequenztransformation
Einführung in die Frequenztransformation
Einführung in die Frequenztransformation
Einführung in die Frequenztransformation

Jedes Signal kann aus einer Kombination verschiedener Sinuswellen bestehen. So kann jedes zeitbasierte Signal auch als Kombination der verschiedenen Sinus unterschiedlicher Amplitude dargestellt werden.

Ich habe versucht, die Funktionsweise von DFT (diskrete Fourier-Transformation) in einem der vorherigen instructables (https://www.instructables.com/id/Arduino-Frequency…) zu erklären. Diese Methoden sind für jede Echtzeitanwendung extrem langsam. was es fast nutzlos macht.

Im Bild ist ein Signal dargestellt, das eine Kombination aus zwei Frequenzen f2 und f5 ist. Dieses Signal wird mit Testsinuswellen der Werte f1 bis f5 multipliziert.

Es kann mathematisch gezeigt werden, dass die Summe der Multiplikation von zwei harmonischen Datensätzen mit unterschiedlicher Frequenz gegen Null tendiert (eine höhere Anzahl von Daten kann zu einem Schlagergebnis führen). In unserem Fall, wenn diese beiden Multiplikationsfrequenzen die gleiche (oder sehr ähnliche) Frequenz haben, ist diese Multiplikationssumme die von Null verschiedene Zahl.

Wenn also unser Signal mit f1 multipliziert wird, ist die Multiplikationssummierung null (nahezu null für die reale Anwendung). Ähnliches gilt für f3, f4. Für den Wert ist die Ausgabe von f2 und f5 jedoch nicht null, sondern deutlich höher als der Rest der Werte.

Hier wird ein Signal mit 5 Frequenzen getestet, daher muss das Signal mit fünf Frequenzen multipliziert werden. Solch eine intensive Berechnung dauert länger. Mathematisch wird gezeigt, dass für eine Anzahl von N Abtastwerten N*N komplexe Multiplikationen erforderlich sind.

Schritt 2: 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, 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.

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

1.

2.

3.

4.

Schritt 3: 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 ihn als Byte speichern, das auf Arduino 1/4 Platz benötigt. Die sine_data muss am Anfang des Codes eingefügt werden, um sie als globale Variable zu deklarieren.

Abgesehen von sinus_data ist ein Array namens f_peaks als globale Variable deklariert. 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. Bei 64 Punkten ergibt sich ein Vorteil von 8 ms und bei 128 Punkten ein Vorteil von 20 ms.

Schritt 4: 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. welches 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<=a){o=i;} } int in_ps[data[o]={}; //Eingabe für die Sequenzierung float out_r[data[o]={}; //realer Teil der Transformation float out_im[data[o]={}; // imaginärer Teil von transform

Der weitere Ablauf ist wie folgt:

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

2. Eingabedaten bestellt 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 5: Testen des Codes

Testen des Codes
Testen des Codes
Testen des Codes
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 einer niedrigen Genauigkeit, aber einer schnelleren Sinuswelle.

In der Ausgangsfrequenz-Array-Frequenz sind 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 an einer beliebigen Stelle innerhalb der angegebenen Bins befinden.

Geschwindigkeit:

für Arduino Nano dauert es:

16 Punkte: 4ms32 Punkte: 10ms 64 Punkte: 26ms 128 Punkte: 53ms

Schritt 6: 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, Anregungen oder Korrekturen haben, können Sie gerne einen Kommentar abgeben.

Aktualisieren (2/5/21)

Updates://--------------------------FFT-Funktion-------------- -------------------------------------------//float FFT(int in, int N, float Frequenz)

Der Datentyp von N wurde in Integer (vorhandenes Byte) geändert, um eine Stichprobengröße von >255 zu unterstützen. Wenn die Stichprobengröße <=128 ist, sollte der Byte-Datentyp verwendet werden.

Empfohlen: