Inhoudsopgave:

EasyFFT: Fast Fourier Transform (FFT) voor Arduino - Ajarnpa
EasyFFT: Fast Fourier Transform (FFT) voor Arduino - Ajarnpa

Video: EasyFFT: Fast Fourier Transform (FFT) voor Arduino - Ajarnpa

Video: EasyFFT: Fast Fourier Transform (FFT) voor Arduino - Ajarnpa
Video: EasyFFT: Fast Fourier Transform (FFT) for Arduino 2024, November
Anonim
Image
Image

Het meten van de frequentie van het vastgelegde signaal kan een moeilijke taak zijn, vooral op Arduino omdat het minder rekenkracht heeft. Er zijn methoden beschikbaar om nuldoorgang vast te leggen waarbij de frequentie wordt vastgelegd door te controleren hoe vaak het signaal binnen de gegeven tijd nullijnen overschrijdt. Een dergelijke methode werkt mogelijk niet wanneer het signaal een combinatie is van verschillende frequenties.

Dit is op de een of andere manier moeilijk te coderen als je niet van zo'n achtergrond bent. Maar als knutselaar kan deze code zeer nuttig zijn voor verschillende projecten met betrekking tot muziek, signaalanalyse. De drijfveer van dit project was om een code voor te bereiden die eenvoudig op Arduino te implementeren is zonder in de achtergrond te treden.

Dit project legt niet de werking van FFT uit, maar legt de toepassing van de FFT-functie uit. Hetzelfde proces wordt ook uitgelegd in de bijgevoegde video.

Als je alleen geïnteresseerd bent in het toepassen van code en niet in een uitleg ervan. U kunt direct doorgaan naar stap nr. 3.

Stap 1: Inleiding tot frequentietransformatie

Inleiding tot frequentietransformatie
Inleiding tot frequentietransformatie
Inleiding tot frequentietransformatie
Inleiding tot frequentietransformatie

Elk signaal kan zijn samengesteld uit een combinatie van verschillende sinusoïdale golven. Dus elk op tijd gebaseerd signaal kan ook worden weergegeven als een combinatie van de verschillende sinussen met verschillende amplitudes.

Ik heb geprobeerd de werking van DFT (discrete Fourier-transformatie) uit te leggen in een van de vorige instructables (https://www.instructables.com/id/Arduino-Frequency…). Deze methoden zijn extreem traag voor elke realtime toepassing. waardoor het bijna nutteloos is.

In de afbeelding wordt een signaal getoond dat een combinatie is van twee frequenties f2 en f5. Dit signaal wordt vermenigvuldigd met testsinusgolven met waarden f1 tot f5.

Het kan wiskundig worden aangetoond dat -sommatie van vermenigvuldiging van twee harmonische datasets met verschillende frequentie naar nul neigt (een hoger aantal gegevens kan leiden tot beslagresultaat). In ons geval, als deze twee vermenigvuldigingsfrequenties dezelfde (of zeer dichte) frequentie hebben, is de som van de vermenigvuldiging het getal dat niet nul is.

Dus als ons signaal wordt vermenigvuldigd met f1 zal de som van de vermenigvuldiging nul zijn (bijna nul voor echte toepassing). vergelijkbaar is het geval voor f3, f4. Voor de waarde zal de uitvoer van f2 en f5 echter niet nul zijn, maar aanzienlijk hoger dan de rest van de waarden.

Hier wordt een signaal getest met 5 frequenties, dus signaal moet vermenigvuldigd worden met vijf frequenties. Zo'n intensieve berekening kost meer tijd. Wiskundig wordt aangetoond dat voor N aantal monsters N*N complexe vermenigvuldiging nodig is.

Stap 2: Snelle Fourier-transformatie

Om de berekening van DFT sneller te maken, is het FFT-algoritme ontwikkeld door James Cooley en John Tukey. Dit algoritme wordt ook beschouwd als een van de belangrijkste algoritmen van de 20e eeuw. Het verdeelt een signaal in een oneven en even sequentieel deel waardoor een aantal vereiste berekeningen lager wordt. Door het te gebruiken kan de totale benodigde complexe vermenigvuldiging worden teruggebracht tot NlogN. wat een aanzienlijke verbetering is.

U kunt onderstaande referenties raadplegen waarnaar ik verwees tijdens het schrijven van de code voor een gedetailleerd begrip van de wiskunde achter FFT:

1.

2.

3.

4.

Stap 3: Verklaring van de code

1. Snelle sinus en cosinus:

Berekening FFT neemt de waarde van verschillende sinussen en cosinus meerdere keren. De ingebouwde functie van Arduino is niet snel genoeg en kost veel tijd om de vereiste waarde te leveren. Wat de code aanzienlijk langzamer maakt (verdubbelt de tijd voor 64 samples). Om dit probleem tegen te gaan, wordt de waarde van sinus voor 0 tot 90 graden opgeslagen als een veelvoud van 255. Als u dit doet, hoeft u geen getallen op te slaan als float en kunnen we het opslaan als byte, wat 1/4e ruimte in beslag neemt op Arduino. De sine_data moet bovenaan de code worden geplakt om het als een globale variabele te declareren.

Afgezien van sine_data, een array genaamd f_peaks gedeclareerd als een globale variabele. Na elke uitvoering van de FFT-functie wordt deze array bijgewerkt. Waar f_peaks[0] de meest dominante frequentie is en verdere waarden in aflopende volgorde.

byte 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 }; zweven f_peaks[5];

Omdat we de sinuswaarde voor 0 tot 90 graden hebben opgeslagen, kan elke waarde van sinus of cosinus worden berekend. Hieronder functie de eerste ronde van het getal tot nul decimale punt en retourwaarde van opgeslagen gegevens. deze methode heeft slechts één zwevende deling nodig. Dit kan verder worden verminderd door sinuswaarden direct op te slaan (niet 255 multiple). maar dat vreet veel geheugen op Arduino op.

Het gebruik van de bovenstaande procedure vermindert de nauwkeurigheid maar verbetert de snelheid. Voor 64 punten geeft het het voordeel van 8 ms en voor 128 punten geeft het een voordeel van 20 ms.

Stap 4: Verklaring van code: FFT-functie

FFT kan alleen worden uitgevoerd voor de steekproefomvang van 2, 4, 8, 16, 32, 64 enzovoort. als de waarde niet 2^n is, dan zal deze de lagere waarde aannemen. Als we bijvoorbeeld de steekproefomvang van 70 kiezen, wordt alleen rekening gehouden met de eerste 64 monsters en wordt rust weggelaten.

Het wordt altijd aanbevolen om een steekproefomvang van 2^n te hebben. wat kan zijn:

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

Twee floats out_r en out_im zullen veel geheugen in beslag nemen. voor Arduino nano werkt niet voor samples hoger dan 128 (en in sommige gevallen 128) vanwege een gebrek aan beschikbaar geheugen.

niet-ondertekende int data[13]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};

int a, cl, f, o, x; een=N; for(int i=0;i<12;i++) //de niveaus berekenen {if(data<=a){o=i;} } int in_ps[data[o]={}; //invoer voor sequencing float out_r[data[o]={}; //echt deel van transformatie float out_im[data[o]={}; // denkbeeldig deel van transformatie

Verdere stroom is als volgt:

1. Code genereert een bit in omgekeerde volgorde voor de gegeven steekproefomvang (details over bitomkering op referenties: stap 2)

2. Invoergegevens besteld volgens gegenereerde bestelling, 3. FFT uitgevoerd

4. De amplitude van het berekende complexe getal, 5. Pieken worden gedetecteerd en gerangschikt in aflopende volgorde

6. resultaten zijn toegankelijk via f_peaks.

[om toegang te krijgen tot andere gegevens (behalve de piekfrequentie) moet de code worden gewijzigd, zodat de lokale variabele kan worden gekopieerd naar een vooraf gedefinieerde globale variabele]

Stap 5: De code testen

De code testen
De code testen
De code testen
De code testen

Een voorbeeld van een driehoeksgolf wordt als invoer gegeven. voor deze golfbemonsteringsfrequentie is 10 Hz en de frequentie van de golf zelf is 1,25 Hz.

Zoals kan worden aangetoond aan de hand van de onbewerkte uitvoer, komt de waarde overeen met de FFT berekend door Scilab. deze waarden zijn echter niet precies hetzelfde als een lage nauwkeurigheid, maar snellere sinusgolf.

In uitgangsfrequentie zijn de array-frequenties 1,25 en 3,75. het is niet nodig om elke keer de exacte waarde te krijgen. meestal worden deze nummers frequentiebakken genoemd. dus de uitvoerwaarde kan overal binnen de opgegeven bakken zijn.

Snelheid:

voor Arduino nano is nodig:

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

Stap 6: Conclusie

Deze FFT-code kan worden gebruikt in realtime toepassingen. Het duurt ongeveer 30 ms om de berekening te voltooien. De resolutie wordt echter beperkt door een aantal voorbeelden. Het nummer van het monster wordt beperkt door het Arduino-geheugen. Door Arduino Mega of een ander bord met hogere prestaties te gebruiken, kan de nauwkeurigheid worden verbeterd.

als je vragen, suggesties of correcties hebt, voel je vrij om commentaar te geven.

Bijwerken (2/5/21)

Updates://----------------------------- FFT-functie--------------- -------------------------------//float FFT(int in, int N, float Frequentie)

Het gegevenstype van N is gewijzigd in Integer (bestaande byte) om een steekproefgrootte van >255 te ondersteunen. Als de steekproefomvang <=128 is, moet het gegevenstype byte worden gebruikt.

Aanbevolen: