Cuprins:

EasyFFT: Transformată Fourier rapidă (FFT) pentru Arduino: 6 pași
EasyFFT: Transformată Fourier rapidă (FFT) pentru Arduino: 6 pași

Video: EasyFFT: Transformată Fourier rapidă (FFT) pentru Arduino: 6 pași

Video: EasyFFT: Transformată Fourier rapidă (FFT) pentru Arduino: 6 pași
Video: EasyFFT: Fast Fourier Transform (FFT) for Arduino 2024, Noiembrie
Anonim
Image
Image

Măsurarea frecvenței din semnalul capturat poate fi o sarcină dificilă, mai ales pe Arduino, deoarece are o putere de calcul mai mică. Există metode disponibile pentru a captura trecerea zero în care frecvența este capturată prin verificarea de câte ori semnalul traversează liniile zero în timpul dat. Este posibil ca o astfel de metodă să nu funcționeze atunci când semnalul este o combinație de frecvențe variate.

Acest lucru este cumva dificil de codat dacă nu sunteți dintr-un astfel de fundal. Dar, fiind un jucător, acest cod poate fi extrem de util pentru diverse proiecte legate de muzică, analiza semnalului. Motivul acestui proiect a fost de a pregăti un cod ușor de implementat pe Arduino fără a intra în fundalul acestuia.

Acest proiect nu explică funcționarea FFT, ci explică aplicarea funcției FFT. Același proces este explicat și în videoclipul atașat.

Dacă sunteți interesat doar de aplicarea codului și nu de o explicație a acestuia. Puteți trece direct la pasul nr. 3.

Pasul 1: Introducere în Transformarea frecvenței

Introducere în Transformarea frecvenței
Introducere în Transformarea frecvenței
Introducere în Transformarea frecvenței
Introducere în Transformarea frecvenței

Orice semnal poate fi compus dintr-o combinație de diverse unde sinusoidale. Deci, orice semnal bazat pe timp poate fi, de asemenea, prezentat ca o combinație a diferitelor sinusuri de amplitudini diferite.

Am încercat să explic funcționarea DFT (transformată Fourier discretă) într-unul din instructabilele anterioare (https://www.instructables.com/id/Arduino-Frequency…). Aceste metode sunt extrem de lente pentru orice aplicație în timp real. ceea ce îl face aproape inutil.

În imagine, este afișat un semnal care este o combinație de două frecvențe f2 și f5. Acest semnal este înmulțit cu undele sinusoidale de testare ale valorilor f1 la f5.

Se poate arăta matematic că -sumarea înmulțirii a două seturi de date armonice cu frecvență diferită tinde la zero (un număr mai mare de date poate duce la rezultatul bateriei). În cazul nostru, dacă aceste două frecvențe de înmulțire au aceeași (sau foarte apropiată) frecvență, suma multiplicării este numărul diferit de zero.

Deci, dacă semnalul nostru este înmulțit cu f1 sumarea înmulțirii va fi zero (aproape de zero pentru aplicația reală). similar este cazul pentru f3, f4. Cu toate acestea, pentru valoare, ieșirile f2 și f5 nu vor fi zero, ci semnificativ mai mari decât restul valorilor.

Aici un semnal este testat cu 5 frecvențe, astfel încât semnalul trebuie multiplicat cu cinci frecvențe. Un astfel de calcul intens durează mai mult. Matematic se arată că pentru N numărul de eșantioane este nevoie de N * N multiplicare complexă.

Pasul 2: Transformarea Fourier rapidă

Pentru a face calculul DFT mai rapid, algoritmul FFT a fost dezvoltat de James Cooley și John Tukey. Acest algoritm este, de asemenea, considerat ca unul dintre cei mai importanți algoritmi ai secolului XX. Împarte un semnal într-o parte impar și secvențiată, ceea ce face mai multe calcule necesare mai mici. Prin utilizarea acestuia, multiplicarea complexă necesară totală poate fi redusă la NlogN. ceea ce reprezintă o îmbunătățire semnificativă.

Puteți consulta mai jos referințe la care am făcut referire în timp ce scria codul pentru o înțelegere detaliată a matematicii din spatele FFT:

1.

2.

3.

4.

Pasul 3: Explicația Codului

1. Sinus rapid și cosinus:

Calculul FFT ia valoarea sinusului și cosinusului de mai multe ori. Funcția încorporată a Arduino nu este suficient de rapidă și necesită o cantitate bună de timp pentru a oferi valoarea necesară. Ceea ce face codul semnificativ mai lent (dublează timpul pentru 64 de eșantioane). Pentru a contracara această problemă valoarea sinusoidală de la 0 la 90 de grade este stocată ca multiplu de 255. Dacă faceți acest lucru, vom elimina necesitatea utilizării numerelor de stocare ca flotante și o putem stoca ca octet, care ocupă 1/4 spațiu pe Arduino. Sinus_data trebuie să se lipească în partea de sus a codului pentru a o declara ca o variabilă globală.

În afară de sine_data, o matrice numită f_peaks declarată ca o variabilă globală. După fiecare rulare a funcției FFT, această matrice se actualizează. Unde f_peaks [0] este cea mai dominantă frecvență și alte valori în ordine descrescătoare.

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

Deoarece am stocat valoarea sinusului pentru 0 până la 90 de grade, se poate calcula orice valoare a sinusului sau cosinusului. Mai jos funcționează prima rundă a numărului până la punctul zecimal zero și returnează valoarea din datele stocate. această metodă are nevoie de o singură diviziune plutitoare. Acest lucru poate fi redus în continuare prin stocarea directă a valorilor sinusoidale (nu 255 multiple). dar asta consumă multă memorie pe Arduino.

Utilizarea procedurii de mai sus reduce precizia, dar îmbunătățește viteza. Pentru 64 de puncte, oferă avantajul de 8 ms, iar pentru 128 de puncte oferă un avantaj de 20 ms.

Pasul 4: Explicația Codului: Funcția FFT

FFT poate fi efectuat numai pentru dimensiunea eșantionului de 2, 4, 8, 16, 32, 64 și așa mai departe. dacă valoarea nu este 2 ^ n, atunci va lua partea inferioară a valorii. De exemplu, dacă alegem dimensiunea eșantionului de 70, atunci va lua în considerare doar primele 64 de eșantioane și va omite restul.

Este întotdeauna recomandat să aveți o dimensiune a eșantionului de 2 ^ n. care poate fi:

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

Două flotări out_r și out_im vor avea o cantitate mare de memorie. pentru Arduino nano nu va funcționa pentru eșantioane mai mari de 128 (și, în unele cazuri, 128) din cauza lipsei de memorie disponibilă.

date int nesemnate [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 ++) // calcularea nivelurilor {if (date <= a) {o = i;}} int in_ps [data [o] = {}; // intrare pentru secvențierea float out_r [date [o] = {}; // parte reală a transformării float out_im [date [o] = {}; // parte imaginativă a transformării

Fluxul ulterior este următorul:

1. Codul generează un pic inversat ordinea pentru dimensiunea eșantionului dat (detalii despre inversarea biților pe referințe: pasul 2)

2. Date de intrare ordonate conform comenzii generate, 3. FFT efectuat

4. Amplitudinea numărului complex calculat, 5. Vârfurile sunt detectate și ordonate în ordine descrescătoare

6. rezultatele pot fi accesate din f_peaks.

[pentru a accesa alte date (în afară de frecvența de vârf) codul trebuie modificat, astfel încât variabila locală să poată fi copiată la o variabilă globală predefinită]

Pasul 5: Testarea codului

Testarea codului
Testarea codului
Testarea codului
Testarea codului

Un exemplu de undă triunghiulară este dat ca intrare. pentru această frecvență de eșantionare a undelor este de 10 Hz, iar frecvența undei în sine este de 1,25 Hz.

După cum se poate arăta din rezultatul brut, valoarea se potrivește cu FFT calculată de Scilab. cu toate acestea, aceste valori nu sunt exact aceleași cu o precizie redusă, ci cu o undă sinusoidală mai rapidă.

În frecvența de ieșire, frecvența matricei este de 1,25 și 3,75. nu este necesar să obțineți valoarea exactă de fiecare dată. în mod obișnuit, aceste numere se numesc coșuri de frecvență. deci valoarea de ieșire ar putea fi oriunde în coșurile specificate.

Viteză:

pentru Arduino nano este nevoie de:

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

Pasul 6: Concluzie

Acest cod FFT poate fi utilizat în aplicații în timp real. Deoarece durează aproximativ 30 ms pentru a finaliza calculul. Cu toate acestea, rezoluția sa este limitată de un număr de eșantioane. Numărul eșantionului este limitat de memoria Arduino. Folosind Arduino Mega sau alte performanțe mai ridicate, placa poate fi îmbunătățită.

dacă aveți întrebări, sugestii sau corecții, nu ezitați să comentați.

Actualizare (05.02.21)

Actualizări: // ----------------------------- Funcția FFT --------------- ------------------------------- // float FFT (int în , int N, frecvență float)

Tipul de date al lui N s-a schimbat în Integer (octet existent) pentru a accepta> 255 dimensiunea eșantionului. Dacă dimensiunea eșantionului este <= 128, trebuie utilizat tipul de date de octeți.

Recomandat: