Sadržaj:

EasyFFT: Brza Furijeova transformacija (FFT) za Arduino: 6 koraka
EasyFFT: Brza Furijeova transformacija (FFT) za Arduino: 6 koraka

Video: EasyFFT: Brza Furijeova transformacija (FFT) za Arduino: 6 koraka

Video: EasyFFT: Brza Furijeova transformacija (FFT) za Arduino: 6 koraka
Video: Тренинг по обучению основам дебатного искусства в форматах игр АПФ и БПФ 2024, Novembar
Anonim
Image
Image

Mjerenje frekvencije iz snimljenog signala može biti težak zadatak, posebno na Arduinu jer ima manju računsku snagu. Dostupne su metode za snimanje ukrštanja nulte točke pri čemu se frekvencija hvata provjeravajući koliko puta signal prelazi nultu liniju unutar zadanog vremena. Takva metoda možda neće raditi ako je signal kombinacija različitih frekvencija.

Ovo je nekako teško kodirati ako niste iz takvog porijekla. No, budući da je to tinker, ovaj kôd može biti vrlo koristan za razne projekte vezane za muziku, analizu signala. Motiv ovog projekta bio je pripremiti kod koji je lako implementirati na Arduino, a da ne ulazi u njegovu pozadinu.

Ovaj projekt ne objašnjava rad FFT -a, ali objašnjava primjenu funkcije FFT -a. Isti proces je objašnjen i u priloženom videu.

Ako vas zanima samo primjena koda, a ne i njegovo objašnjenje. Možete direktno preći na korak 3.

Korak 1: Uvod u frekvencijsku transformaciju

Uvod u transformaciju frekvencije
Uvod u transformaciju frekvencije
Uvod u transformaciju frekvencije
Uvod u transformaciju frekvencije

Svaki signal može biti sastavljen od kombinacije različitih sinusoidnih valova. Dakle, svaki signal zasnovan na vremenu može se prikazati i kao kombinacija različitih sinusa različitih amplituda.

Pokušao sam objasniti rad DFT-a (diskretna Fourierova transformacija) u jednoj od prethodnih instrukcija (https://www.instructables.com/id/Arduino-Frequency…). Ove metode su izuzetno spore za bilo koju aplikaciju u stvarnom vremenu. što ga čini gotovo beskorisnim.

Na slici je prikazan signal koji je kombinacija dvije frekvencije f2 i f5. Ovaj signal se množi testnim sinusnim valovima vrijednosti od f1 do f5.

Matematički se može pokazati da -zbir množenja dva skupa podataka harmonika različitih frekvencija teži nuli (veći broj podataka može dovesti do rezultata testa). U našem slučaju, ako ove dvije frekvencije množenja imaju istu (ili vrlo blisku) frekvenciju, taj zbir množenja je broj različit od nule.

Dakle, ako se naš signal pomnoži sa f1, zbir množenja bit će nula (blizu nule za stvarnu primjenu). sličan je slučaj za f3, f4. Međutim, za vrijednost, izlaz f2 i f5 neće biti nula, već znatno veći od ostalih vrijednosti.

Ovdje se testira signal sa 5 frekvencija, pa se signal mora pomnožiti sa pet frekvencija. Za tako intenzivno računanje potrebno je duže vrijeme. Matematički je pokazano da je za N broj uzoraka potrebno N*N kompleksno množenje.

Korak 2: Brza Furijeova transformacija

Da bi izračunavanje DFT -a bilo brže, algoritam FFT razvili su James Cooley i John Tukey. Ovaj algoritam se takođe smatra jednim od najvažnijih algoritama 20. veka. On dijeli signal na neparan i paran niz koji smanjuje broj potrebnih proračuna. Njegovom upotrebom ukupno potrebno kompleksno množenje može se smanjiti na NlogN. što je značajno poboljšanje.

U nastavku možete pogledati reference na koje sam se pozivao dok sam pisao kôd za detaljnije razumijevanje matematike koja stoji iza FFT -a:

1.

2.

3.

4.

Korak 3: Objašnjenje koda

1. Brzi sinus i kosinus:

Proračun FFT uzima vrijednost različitih sinusnih i kosinusnih više puta. Ugrađena funkcija Arduina nije dovoljno brza i potrebno je dosta vremena da se osigura potrebna vrijednost. Što kôd čini znatno sporijim (udvostručuje vrijeme za 64 uzorka). Kako bi se suprotstavili ovom problemu, vrijednost sinusa za 0 do 90 stupnjeva pohranjuje se kao višekratnik 255. Time ćete ukloniti potrebu za pohranjivanjem brojeva kao float, a možemo ga pohraniti i kao bajt koji zauzima 1/4 prostora na Arduinu. Sine_data treba zalijepiti na vrh koda da bi ga deklarirao kao globalnu varijablu.

Osim sine_data, niz nazvan f_peaks deklariran kao globalna varijabla. Nakon svakog pokretanja funkcije FFT ovaj niz se ažurira. Gdje je f_peaks [0] najdominantnija frekvencija i dalje vrijednosti u opadajućem redoslijedu.

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

Kako smo vrijednost sinusa pohranili za 0 do 90 stupnjeva, može se izračunati bilo koja vrijednost sinusa ili kosinusa. Ispod funkcionira prvi krug broja do nule decimalnog zareza i povratna vrijednost iz pohranjenih podataka. ovoj metodi je potrebna samo jedna plutajuća podjela. Ovo se može dodatno smanjiti izravnim pohranjivanjem sinusnih vrijednosti (ne 255 višestrukih). ali to jede mnogo memorije na Arduinu.

Korištenje gornjeg postupka smanjuje točnost, ali poboljšava brzinu. Za 64 boda daje prednost od 8 ms, a za 128 bodova prednost od 20 ms.

Korak 4: Objašnjenje koda: FFT funkcija

FFT se može izvesti samo za uzorke veličine 2, 4, 8, 16, 32, 64 itd. ako vrijednost nije 2^n, tada će uzeti donju stranu vrijednosti. Na primjer, ako odaberemo veličinu uzorka 70, tada će se uzeti u obzir samo prva 64 uzorka i izostaviti ostatak.

Uvijek se preporučuje veličina uzorka 2^n. koje mogu biti:

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

Dva plutajuća out_r i out_im će zauzeti veliku količinu memorije. jer Arduino nano neće raditi za uzorke veće od 128 (a u nekim slučajevima i 128) zbog nedostatka dostupne memorije.

nepotpisani int podaci [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 ++) // izračunavanje nivoa {if (data <= a) {o = i;}} int in_ps [data [o] = {}; // ulaz za sekvenciranje float out_r [data [o] = {}; // stvarni dio transformacije float out_im [data [o] = {}; // imaginarni dio transformacije

Daljnji tok je sljedeći:

1. Kôd generira obrnuti redoslijed bita za datu veličinu uzorka (detalji o preokretanju bita na referencama: korak 2)

2. Ulazni podaci poredani prema generiranoj narudžbi, 3. Izvršen FFT

4. Izračunata amplituda kompleksnog broja, 5. Vrhovi se otkrivaju i poredaju opadajućim redoslijedom

6. rezultatima se može pristupiti iz f_peaks.

[za pristup drugim podacima (osim vršne frekvencije) kod treba izmijeniti, tako da se lokalna varijabla može kopirati u neku unaprijed definiranu globalnu varijablu]

Korak 5: Testiranje koda

Testiranje koda
Testiranje koda
Testiranje koda
Testiranje koda

Uzorak trokutastog vala je dan kao ulaz. za ovaj talas frekvencija uzorkovanja je 10 Hz, a sama frekvencija talasa je 1,25 Hz.

Kao što se može vidjeti iz sirovog rezultata, vrijednost se podudara s FFT -om koji je izračunao Scilab. međutim, ove vrijednosti nisu potpuno iste kao kod nas niske preciznosti, već bržeg sinusnog vala.

U izlaznom frekvencijskom nizu frekvencije su 1,25 i 3,75. nije potrebno svaki put dobiti tačnu vrijednost. obično se ti brojevi nazivaju frekventni pretinci. tako da izlazna vrijednost može biti bilo gdje unutar navedenih kanti.

Brzina:

za Arduino nano potrebno je:

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

Korak 6: Zaključak

Ovaj FFT kod može se koristiti u aplikacijama u stvarnom vremenu. Kako je potrebno oko 30 ms da se dovrši proračun. Međutim, njegova rezolucija ograničena je brojem uzoraka. Broj uzorka ograničen je Arduino memorijom. Korištenjem Arduino Mega ili drugih ploča može se poboljšati preciznost.

ako imate bilo kakvih pitanja, prijedloga ili ispravki, slobodno komentirajte.

Ažuriranje (2/5/21)

Ažuriranja: // ----------------------------- FFT funkcija --------------- ------------------------------- // float FFT (int u , int N, float frekvencija)

Tip podataka N promijenjen je u Integer (postojeći bajt) kako bi podržao> 255 veličinu uzorka. Ako je veličina uzorka <= 128, treba koristiti bajtni tip podataka.

Preporučuje se: