INHOUDSOPGAWE:

1024 monsters FFT -spektrumanaliseerder met behulp van 'n Atmega1284: 9 stappe
1024 monsters FFT -spektrumanaliseerder met behulp van 'n Atmega1284: 9 stappe

Video: 1024 monsters FFT -spektrumanaliseerder met behulp van 'n Atmega1284: 9 stappe

Video: 1024 monsters FFT -spektrumanaliseerder met behulp van 'n Atmega1284: 9 stappe
Video: Top 5 Worst Jobs In Final Fantasy Tactics Advance 2024, Julie
Anonim
1024 monsters FFT -spektrumanaliseerder met behulp van 'n Atmega1284
1024 monsters FFT -spektrumanaliseerder met behulp van 'n Atmega1284
1024 monsters FFT -spektrumanaliseerder met behulp van 'n Atmega1284
1024 monsters FFT -spektrumanaliseerder met behulp van 'n Atmega1284

Hierdie relatief maklike handleiding (met inagneming van die kompleksiteit van hierdie onderwerp) sal u wys hoe u 'n baie eenvoudige 1024 monsters spektrumanaliseerder kan maak met 'n Arduino -tipe bord (1284 smal) en die seriële plotter. Enige soort Arduino -versoenbare bord sal dit doen, maar hoe meer RAM dit het, hoe beter is die frekwensie -resolusie. Dit sal meer as 8 KB RAM benodig om die FFT met 1024 monsters te bereken.

Spektrumanalise word gebruik om die hooffrekwensie -komponente van 'n sein te bepaal. Baie klanke (soos die wat deur 'n musiekinstrument geproduseer word) bestaan uit 'n fundamentele frekwensie en 'n paar harmonieke wat 'n heelgetal veelvoud van die fundamentele frekwensie het. Die spektrumanaliseerder wys al hierdie spektrale komponente.

Miskien wil u hierdie opstelling as 'n frekwensieteller gebruik of om te kyk of daar enige seine is wat u vermoed dat dit 'n bietjie geraas in u elektroniese stroombaan veroorsaak.

Ons fokus hier op die sagtewaregedeelte. As u 'n permanente kring vir 'n spesifieke toepassing wil maak, moet u die sein versterk en filter. Hierdie vooraf kondisionering is heeltemal afhanklik van die sein wat u wil bestudeer, afhangende van die amplitude, impedansie, maksimum frekwensie, ens … U kan

Stap 1: Installeer die biblioteek

Ons sal die ArduinoFFT -biblioteek gebruik wat deur Enrique Condes geskryf is. Aangesien ons soveel as moontlik RAM wil bespaar, sal ons die ontwikkel -tak van hierdie bewaarplek gebruik wat die float -datatipe (in plaas van dubbel) kan gebruik om die bemonsterde en berekende data te stoor. Ons moet dit dus handmatig installeer. Moenie bekommerd wees nie, laai net die argief af en pak dit uit in u Arduino -biblioteekmap (byvoorbeeld in Windows 10 se standaardkonfigurasie: C: / Users / _your_user_name_ / Documents / Arduino / libraries)

U kan seker maak dat die biblioteek korrek geïnstalleer is deur een van die voorbeelde saam te stel, soos "FFT_01.ino."

Stap 2: Fourier Transform en FFT -konsepte

Waarskuwing: as u nie 'n wiskundige notasie kan sien nie, wil u moontlik na stap 3. As u dit nie alles regkry nie, moet u die gevolgtrekking aan die einde van die afdeling oorweeg.

Die frekwensiespektrum word verkry deur 'n Fast Fourier Transform -algoritme. FFT is 'n digitale implementering wat die wiskundige konsep van die Fourier Transform benader. Onder hierdie konsep, sodra u die evolusie van 'n sein na 'n tydas kry, kan u die voorstelling daarvan ken in 'n frekwensiedomein, saamgestel uit komplekse (werklike + denkbeeldige) waardes. Die konsep is wederkerig, dus as u die frekwensiedomeinvoorstelling ken, kan u dit na die tyddomein terugskakel en die sein presies terug kry soos voor die transformasie.

Maar wat gaan ons met hierdie stel berekende komplekse waardes in die tydsgebied doen? Die grootste deel daarvan word aan die ingenieurs oorgelaat. Vir ons sal ons 'n ander algoritme noem wat hierdie komplekse waardes in spektrale digtheidsdata sal omskep: dit is 'n grootte (= intensiteit) waarde wat met elke frekwensieband geassosieer word. Die aantal frekwensieband sal dieselfde wees as die aantal monsters.

U is beslis bekend met die gelykmaker -konsep, soos hierdie Terug na die 1980's met die grafiese EQ. Wel, ons sal dieselfde soort resultate behaal, maar met 1024 bands in plaas van 16 en veel meer intensiteitsresolusie. As die gelykmaker 'n globale beeld van die musiek gee, kan die fyn spektrale analise die intensiteit van elk van die 1024 bande presies bereken.

'N Perfekte konsep, maar:

  1. Aangesien die FFT 'n gedigitaliseerde weergawe van die Fourier -transform is, benader dit die digitale sein en verloor dit inligting. Dus, streng gesproke, sou die resultaat van die FFT as dit met 'n omgekeerde FFT -algoritme teruggeskakel word, nie presies die oorspronklike sein gee nie.
  2. Die teorie beskou ook 'n sein wat nie eindig is nie, maar dit is 'n ewigdurende konstante sein. Aangesien ons dit slegs vir 'n sekere tydsduur (byvoorbeeld monsters) sal digitaliseer, sal nog 'n paar foute ingestel word.
  3. Uiteindelik sal die resolusie van die analoog na digitale omskakeling die kwaliteit van die berekende waardes beïnvloed.

In die praktyk

1) Die steekproeffrekwensie (opgemerk fs)

Ons neem elke 1/fs sekonde 'n sein, dit wil sê die amplitude daarvan. fs is die bemonsteringsfrekwensie. As ons byvoorbeeld met 'n monster van 8 KHz meet, sal die ADC (analoog na digitaal omskakelaar) wat aan boord is, elke 1/8000 sekondes 'n meting lewer.

2) Die aantal monsters (aangeteken N of monsters in die kode)

Aangesien ons al die waardes moet kry voordat ons die FFT gebruik, moet ons dit stoor, en daarom beperk ons die aantal monsters. Die FFT -algoritme benodig 'n aantal monsters met 'n krag van 2. Hoe meer monsters ons het, hoe beter, maar dit verg baie geheue, des te meer sal ons ook die getransformeerde data moet stoor, wat komplekse waardes is. Die Arduino FFT -biblioteek bespaar ruimte deur te gebruik

  • Een skikking met die naam "vReal" om die gegewe monsters te stoor en dan die werklike deel van die getransformeerde data
  • Een skikking met die naam "vImag" om die denkbeeldige deel van die getransformeerde data op te slaan

Die benodigde hoeveelheid RAM is gelyk aan 2 (skikkings) * 32 (bisse) * N (monsters).

In ons Atmega1284 met 'n goeie 16 KB RAM, sal ons 'n maksimum van N = 16000*8/64 = 2000 waardes stoor. Aangesien die aantal waardes 'n krag van 2 moet wees, sal ons 'n maksimum van 1024 waardes stoor.

3) Die frekwensie -resolusie

Die FFT sal waardes bereken vir soveel frekwensiebande as die aantal monsters. Hierdie bande sal strek van 0 HZ tot die bemonsteringsfrekwensie (fs). Daarom is die frekwensie -resolusie:

Oplossing = fs / N

Die resolusie is beter as dit laer is. Vir 'n beter resolusie (laer) wil ons:

  • meer monsters, en/of
  • 'n laer fs

Maar…

4) Minimale fs

Aangesien ons baie frekwensies wil sien, waarvan sommige baie hoër is as die 'fundamentele frekwensie', kan ons nie fs te laag stel nie. In werklikheid is daar die Nyquist -Shannon -bemonsteringsstelling wat ons dwing om 'n bemonsteringsfrekwensie te hê wat baie hoër is as twee keer die maksimum frekwensie wat ons wil toets.

As ons byvoorbeeld die hele spektrum van 0 Hz wil analiseer om 15 KHz te sê, wat ongeveer die maksimum frekwensie is wat die meeste mense duidelik kan hoor, moet ons die bemonsteringsfrekwensie op 30 KHz stel. Trouens, elektronici stel dit dikwels op 2,5 (of selfs 2,52) * die maksimum frekwensie. In hierdie voorbeeld sou dit 2,5 * 15 KHz = 37,5 KHz wees. Gewone bemonsteringsfrekwensies in professionele klank is 44,1 KHz (klank -CD -opname), 48 KHz en meer.

Afsluiting:

Punte 1 tot 4 lei tot: ons wil soveel monsters as moontlik gebruik. In ons geval met 'n 16 KB RAM -toestel, sal ons 1024 monsters oorweeg. Ons wil op die laagste bemonsteringsfrekwensie moontlik meet, solank dit hoog genoeg is om die hoogste frekwensie wat ons in ons sein verwag, te ontleed (ten minste 2,5 * hierdie frekwensie).

Stap 3: Simuleer 'n sein

Simuleer 'n sein
Simuleer 'n sein

Vir ons eerste poging, sal ons die TFT_01.ino -voorbeeld wat in die biblioteek gegee word, effens verander om 'n sein wat uit

  • Die fundamentele frekwensie, ingestel op 440 Hz (musikale A)
  • 3de harmoniese met die helfte van die krag van die fundamentele ("-3 dB")
  • 5de harmoniese by 1/4 van die krag van die fundamentele ("-6 dB)

U kan die sein bo -op die prentjie sien. Dit lyk inderdaad baie na 'n werklike sein wat 'n mens soms op 'n ossilloskoop kan sien (ek sou dit 'Batman' noem) in 'n situasie as daar 'n sinusvormige sein uitknip.

Stap 4: Ontleding van 'n gesimuleerde sein - kodering

0) Sluit die biblioteek in

#sluit "arduinoFFT.h" in

1) Definisies

In die verklaringsafdelings het ons

const byte adcPin = 0; // A0

const uint16_t monsters = 1024; // Hierdie waarde MOET ALTYD 'n krag van 2 konst uint16_t samplingFrequency = 8000 wees; // Sal die maksimum waarde van die timer in timer_setup () SYSCLOCK/8/sampling beïnvloed Die frekwensie moet 'n heelgetal wees

Aangesien die sein 'n 5de harmonika het (frekwensie van hierdie harmoniese = 5 * 440 = 2200 Hz), moet ons die bemonsteringsfrekwensie bo 2,5 * 2200 = 5500 Hz stel. Hier het ek 8000 Hz gekies.

Ons verklaar ook die skikkings waar ons die rou en berekende data sal stoor

float vReal [monsters];

float vImag [monsters];

2) Instantiëring

Ons skep 'n ArduinoFFT -voorwerp. Die dev -weergawe van ArduinoFFT gebruik 'n sjabloon sodat ons óf die float óf die dubbele datatipe kan gebruik. Float (32 bis) is genoeg met betrekking tot die algehele presisie van ons program.

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, monsters, samplingFrequency);

3) Simuleer die sein deur die vReal -skikking te vul, in plaas daarvan dat dit gevul word met ADC -waardes.

Aan die begin van die lus vul ons die vReal -skikking in met:

vlot siklusse = (((monsters) * seinfrekwensie) / steekproeffrekwensie); // Aantal seinsiklusse wat die steekproefneming sal lees

for (uint16_t i = 0; i <samples; i ++) {vReal = float ((amplitude * (sin ((i * (TWO_PI * siklusse)) / monsters))))) / / Bou data met positiewe en negatiewe waardes */ vReal += float ((amplitude * (sin ((3 * i * (TWO_PI * siklusse))/ monsters)))/ 2.0);/ * Bou data met positiewe en negatiewe waardes */ vReal += float ((amplitude * (sin ((5 * i * (TWO_PI * siklusse)) / monsters))) / 4.0); / * Bou data met positiewe en negatiewe waardes * / vImag = 0.0; // Die denkbeeldige deel moet nul word in die geval van 'n lus om verkeerde berekeninge en oorstromings te vermy}

Ons voeg 'n digitalisering van die fundamentele golf en die twee harmonieke by met minder amplitude. Dan begin ons die denkbeeldige skikking met nulle. Aangesien hierdie skikking deur die FFT -algoritme ingevul word, moet ons dit weer voor elke nuwe berekening uitvee.

4) FFT -rekenaars

Dan bereken ons die FFT en die spektrale digtheid

FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Forward);

FFT.compute (FFTDirection:: Forward); / * Bereken FFT */ FFT.complexToMagnitude (); / * Bereken groottes */

FFT.windowing (…) werking verander die rou data omdat ons die FFT op 'n beperkte aantal monsters gebruik. Die eerste en laaste monsters toon 'n diskontinuïteit (daar is "niks" aan die een kant). Dit is 'n bron van foute. Die "venster" -bewerking is geneig om hierdie fout te verminder.

FFT.compute (…) met die rigting "Vorentoe" bereken die transformasie van die tyddomein na die frekwensiedomein.

Dan bereken ons die grootte (d.w.s. intensiteit) waardes vir elk van die frekwensiebande. Die vReal -skikking is nou gevul met grootteswaardes.

5) Seriële plottertekening

Laat ons die waardes op die reeksplotter druk deur die funksie printVector (…) te noem

PrintVector (vReal, (monsters >> 1), SCL_FREQUENCY);

Dit is 'n generiese funksie waarmee data met 'n tydas of 'n frekwensie -as gedruk kan word.

Ons druk ook die frekwensie van die band met die hoogste groottewaarde af

float x = FFT.majorPeak ();

Serial.print ("f0 ="); Reeks.afdruk (x, 6); Serial.println ("Hz");

Stap 5: Ontleding van 'n gesimuleerde sein - Resultate

Ontleding van 'n gesimuleerde sein - Resultate
Ontleding van 'n gesimuleerde sein - Resultate

Ons sien 3 spykers wat ooreenstem met die fundamentele frekwensie (f0), die 3de en 5de harmonieke, met die helfte en 1/4 van die f0 -grootte, soos verwag. Ons kan bo in die venster lees f0 = 440.430114 Hz. Hierdie waarde is nie presies 440 Hz nie, as gevolg van al die redes hierbo verduidelik, maar dit is baie naby aan die werklike waarde. Dit was nie regtig nodig om soveel onbeduidende desimale aan te toon nie.

Stap 6: Ontleding van 'n werklike sein - Bedrading van die ADC

Ontleding van 'n werklike sein - Bedrading van die ADC
Ontleding van 'n werklike sein - Bedrading van die ADC

Aangesien ons weet hoe om teoreties te werk te gaan, wil ons 'n werklike sein ontleed.

Die bedrading is baie eenvoudig. Koppel die gronde en die seinlyn aan die A0 -pen van u bord deur 'n reeksweerstand met 'n waarde van 1 KOhm tot 10 KOhm.

Hierdie reeksweerstand beskerm die analoog insette en voorkom dat dit lui. Dit moet so hoog as moontlik wees om te voorkom dat dit lui, en so laag as moontlik om genoeg stroom te gee om die ADC vinnig te laai. Raadpleeg die MCU -datablad om die verwagte impedansie van die sein wat by die ADC -ingang gekoppel is, te ken.

Vir hierdie demo het ek 'n funksiegenerator gebruik om 'n sinusvormige sein van frekwensie 440 Hz en amplitude rondom 5 volt te voer (dit is die beste as die amplitude tussen 3 en 5 volt is, sodat die ADC naby volle skaal gebruik word), deur 'n weerstand van 1,2 KOhm.

Stap 7: Ontleding van 'n werklike sein - kodering

0) Sluit die biblioteek in

#sluit "arduinoFFT.h" in

1) Verklarings en instansie

In die deklarasie -afdeling definieer ons die ADC -invoer (A0), die aantal monsters en die bemonsteringsfrekwensie, soos in die vorige voorbeeld.

const byte adcPin = 0; // A0

const uint16_t monsters = 1024; // Hierdie waarde MOET ALTYD 'n krag van 2 konst uint16_t samplingFrequency = 8000 wees; // Sal die maksimum waarde van die timer in timer_setup () SYSCLOCK/8/sampling beïnvloed Die frekwensie moet 'n heelgetal wees

Ons skep die ArduinoFFT -voorwerp

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, monsters, samplingFrequency);

2) Timer en ADC opstelling

Ons stel timer 1 in sodat dit met die bemonsteringsfrekwensie (8 KHz) siklusse kry en 'n onderbreking van die uitset vergelyk.

nietig timer_setup () {

// reset timer 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bietjie (CS11) | bietjie (WGM12); // CTC, prescaler van 8 TIMSK1 = bit (OCIE1B); OCR1A = ((16000000 /8) / steekproef frekwensie) -1; }

En stel die ADC so in

  • Gebruik A0 as invoer
  • Triggers outomaties op elke timer 1 uitset vergelyk wedstryd B
  • Genereer 'n onderbreking wanneer die omskakeling voltooi is

Die ADC -klok word op 1 MHz gestel, deur die stelselklok (16 MHz) vooraf te skaal met 16. Omdat elke omskakeling ongeveer 13 horlosies op volle skaal neem, kan omskakelings bereik word met 'n frekwensie van 1/13 = 0,076 MHz = 76 KHz. Die bemonsteringsfrekwensie moet aansienlik laer as 76 KHz wees, sodat die ADC tyd het om die data te neem. (ons het fs = 8 KHz gekies).

ongeldig adc_setup () {

ADCSRA = bietjie (ADEN) | bietjie (ADIE) | bietjie (ADIF); // skakel ADC aan, wil onderbreking by voltooiing ADCSRA | = bit (ADPS2); // Voorverkoeler van 16 ADMUX = bit (REFS0) | (adcPin & 7); // die ADC -invoer instel ADCSRB = bit (ADTS0) | bietjie (ADTS2); // Timer/Counter1 Vergelyk Match B -snellerbron ADCSRA | = bit (ADATE); // skakel outomatiese sneller aan}

Ons verklaar die onderbrekingshanteerder wat na elke ADC -omskakeling gebel sal word, om die omskepte data in die vReal -skikking te stoor en die onderbreking te verwyder

// ADC volledige ISR

ISR (ADC_vect) {vReal [resultNumber ++] = ADC; as (resultNumber == monsters) {ADCSRA = 0; // skakel ADC}} EMPTY_INTERRUPT (TIMER1_COMPB_vect) af;

U kan 'n volledige uiteensetting hê van die ADC -omskakeling op die Arduino (analogRead).

3) Opstel

In die opstelfunksie maak ons die denkbeeldige datatabel skoon en skakel die timer en ADC -opstelfunksies

zeroI (); // 'n funksie wat al die denkbeeldige data op 0 stel - verduidelik in die vorige afdeling

timer_setup (); adc_setup ();

3) Lus

FFT.dcRemoval (); // Verwyder die GS -komponent van hierdie sein, aangesien die ADC na die aarde verwys word

FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Forward); // Weeg data FFT.compute (FFTDirection:: Forward); // Bereken FFT FFT.complexToMagnitude (); // Bereken groottes // druk die spektrum en die fundamentele frekwensie uit f0 PrintVector (vReal, (monsters >> 1), SCL_FREQUENCY); float x = FFT.majorPeak (); Serial.print ("f0 ="); Reeks.afdruk (x, 6); Serial.println ("Hz");

Ons verwyder die GS -komponent omdat die ADC na die aarde verwys en die sein ongeveer 2,5 volt gesentreer is.

Dan bereken ons die data soos uiteengesit in die vorige voorbeeld.

Stap 8: Ontleding van 'n werklike sein - Resultate

Ontleding van 'n werklike sein - Resultate
Ontleding van 'n werklike sein - Resultate

Ons sien inderdaad slegs een frekwensie in hierdie eenvoudige sein. Die berekende fundamentele frekwensie is 440.118194 Hz. Ook hier is die waarde 'n baie noue benadering van die werklike frekwensie.

Stap 9: Wat van 'n geknipte sinusvormige sein?

Wat van 'n geknipte sinusvormige sein?
Wat van 'n geknipte sinusvormige sein?

Laat ons nou die ADC 'n bietjie oordryf deur die amplitude van die sein bo 5 volt te verhoog, sodat dit geknip word. Moenie te veel druk om nie die ADC -invoer te vernietig nie!

Ons kan 'n paar harmonieke sien verskyn. Deur die sein te knip, word hoëfrekwensie -komponente gevorm.

U het die grondbeginsels van FFT -analise op 'n Arduino -bord gesien. Nou kan u die bemonsteringsfrekwensie, die aantal monsters en die venstervenster probeer verander. Die biblioteek voeg ook 'n parameter by om die FFT vinniger te bereken met minder presisie. U sal opmerk dat as u die bemonsteringsfrekwensie te laag stel, die berekende groottes totaal verkeerd sal lyk as gevolg van spektrale vou.

Aanbeveel: