Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

EasyFFT:Fast Fourier Transform (FFT) voor Arduino

Componenten en benodigdheden

Arduino Nano R3
× 1

Apps en online services

Arduino IDE

Over dit project

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 op 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.

Als je FFT met hoge snelheid (3x) moet uitvoeren met een klein compromis in nauwkeurigheid (ongeveer 5%), raadpleeg dan mijn ander artikel over ApproxFFT.

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

Stap 1: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 vereiste complexe vermenigvuldiging worden teruggebracht tot NlogN. wat een aanzienlijke verbetering is. Typische DFT neemt N*N complexe vermenigvuldiging voor resultaten, terwijl FFT alleen N*logN neemt. dit is een aanzienlijk voordeel wanneer de steekproefaantallen hoog zijn.

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

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

Stap 2: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 };float 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 kost veel geheugen op Arduino.

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 3:Verklaring van de 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 steekproeven en wordt de 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.

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++) //het berekenen van de niveaus {if(data[i]<=a){o=i;}} int in_ps[data[o]]={}; //invoer voor sequencingfloat out_r[data[o]]={}; //echt deel van transformfloat 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. Voer gegevens in 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 4:De code testen

Een voorbeeld van een driehoeksgolf wordt als invoer gegeven. voor deze golf is de bemonsteringsfrequentie 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 gespecificeerde bakken zijn.

Snelheid:

voor Arduino nano is nodig:

  • 16 punten:4ms
  • 32 Punten:10ms
  • 64 Punten:26ms
  • 128 punten:53ms

Stap 5: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.

Code

  • EasyFFT
EasyFFTArduino
Deze code voert FFT uit en werkt de F_peasks-array bij met de top 5 van meest dominante frequenties.
/*//Example data: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 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, //Plak dit bovenaan programma198, 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 frequenties pieken in aflopende volgorde//--------------------------------------- ------------------------------------//void setup() { Serial.begin(250000); } void loop() {/*//exampleFFT(data,64,100); //om de top vijf waarde van frequenties van X te krijgen met 64 samples bij 100Hz samplingSerial.println(f_peaks[0]);Serial.println(f_peaks[1]);delay(99999);*//* na ruing boven FFT( ), frequenties beschikbaar op f_peaks[0],f_peaks[1],f_peaks[2],f_peaks[3],f_peaks[4],*/ }//--------------- -------------- FFT-functie--------------------------------- ------------//float FFT(int in[],int N,float Frequency){/*Code om FFT uit te voeren op arduino,setup:paste sine_data [91] bovenaan het programma [ globale variabele], plak de FFT-functie aan het einde van programmaTerm:1. in[] :Data-array, 2. N :Aantal steekproeven (aanbevolen steekproefomvang 2,4,8,16,32,64,128...)3. Frequentie:bemonsteringsfrequentie vereist als invoer (Hz) Als de steekproefomvang niet de macht 2 heeft, wordt deze naar de onderkant van het nummer geknipt. dat wil zeggen, voor 150 monsters zal de code de eerste 128 monsters in overweging nemen, de resterende monsters worden weggelaten. Voor Arduino nano is FFT van meer dan 128 monsters niet mogelijk vanwege de beperking van de mamorie (64 aanbevolen). probleem, Code door ABHILASHContact:[email protected] Documentatie:https://www.instructables.com/member/abhilash_patel/instructables/2/3/2021:verander gegevenstype van N van float naar int voor>=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++) //het berekenen van de niveaus {if(data[i]<=a){o=i;}} int in_ps[data[o]]={}; //invoer voor sequencingfloat out_r[data[o]]={}; //echt deel van transformfloat out_im[data[o]]={}; // denkbeeldig deel van transformatie 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 hier verder out_r bevat amplitude en our_in bevat frequentie (Hz) for(int i=0;iout_r[i-1] &&out_r[i]>out_r[i+1] ) {in_ps[x]=i; //in_ps array gebruikt voor opslag van pieknummer x=x+1;} }s=0;c=0; for(int i=0;i360){j=j-360;} if(j>-1 &&j<91){out=sine_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 cosinus(int i){ int j=i; zweven; while(j<0){j=j+360;} while(j>360){j=j-360;} if(j>-1 &&j<91){out=sine_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);}//---------------------- -------------------------------------------------- ------------//

Schema's


Productieproces

  1. Wat is de Fourier-transformatie?
  2. DTMF-decoder met alleen Arduino
  3. Arduino Alarmsysteem:SERENA
  4. Python3- en Arduino-communicatie
  5. SMART temperatuurbewaking voor scholen
  6. 8-bit IO-poortbibliotheek voor Arduino
  7. 64-Key Prototyping Keyboard Matrix voor Arduino
  8. TFT Shield voor Arduino Nano - Start
  9. Een geïsoleerde analoge ingang voor Arduino
  10. Robot voor supercoole indoornavigatie
  11. Wat is de HS-code voor een hydraulische pomp?