Sisukord:

1024 proovi FFT spektrinalüsaator Atmega1284 abil: 9 sammu
1024 proovi FFT spektrinalüsaator Atmega1284 abil: 9 sammu

Video: 1024 proovi FFT spektrinalüsaator Atmega1284 abil: 9 sammu

Video: 1024 proovi FFT spektrinalüsaator Atmega1284 abil: 9 sammu
Video: Training Midjourney Level Style And Yourself Into The SD 1.5 Model via DreamBooth Stable Diffusion 2024, Juuli
Anonim
1024 proovi FFT spektrinalüsaator Atmega1284 abil
1024 proovi FFT spektrinalüsaator Atmega1284 abil
1024 proovi FFT spektrinalüsaator Atmega1284 abil
1024 proovi FFT spektrinalüsaator Atmega1284 abil

See suhteliselt lihtne õpetus (arvestades selle teema keerukust) näitab teile, kuidas saate Arduino tüüpi plaati (1284 Narrow) ja jadaplotterit kasutades valmistada väga lihtsa 1024 proovi spektrinalüsaatori. Igasugune Arduinoga ühilduv plaat sobib, kuid mida rohkem on sellel RAM -i, seda parem on teie eraldusvõime. 1024 prooviga FFT arvutamiseks on vaja rohkem kui 8 KB muutmälu.

Spektri analüüsi kasutatakse signaali peamiste sageduskomponentide määramiseks. Paljud helid (nagu muusikainstrumendi helid) koosnevad põhisagedusest ja mõnest harmoonilisest, mille sagedus on põhisageduse täisarvuline mitmekordne. Spektrianalüsaator näitab teile kõiki neid spektrikomponente.

Võib -olla soovite seda seadet kasutada sagedusloendurina või kontrollida mis tahes signaale, mis kahtlustavad teie elektroonilises vooluringis müra.

Keskendume siin tarkvarale. Kui soovite luua konkreetse rakenduse jaoks alalisvooluahela, peate signaali võimendama ja filtreerima. See eelkonditsioneerimine sõltub täielikult signaalist, mida soovite uurida, sõltuvalt selle amplituudist, impedantsist, maksimaalsest sagedusest jne … Saate vaadata

Samm: kogu installimine

Kasutame ArduinoFFT raamatukogu, mille on kirjutanud Enrique Condes. Kuna tahame RAM -i võimalikult palju säästa, kasutame selle hoidla arendusharu, mis võimaldab proovivõetud ja arvutatud andmete salvestamiseks kasutada ujukandmetüüpi (kahekordse asemel). Seetõttu peame selle käsitsi installima. Ärge muretsege, laadige lihtsalt arhiiv alla ja pakkige see oma Arduino raamatukogu kausta lahti (näiteks Windows 10 vaikekonfiguratsioonis: C: / Users / _your_user_name_ / Documents / Arduino / libraries)

Saate kontrollida, kas kogu on õigesti installitud, koostades ühe esitatud näidetest, näiteks „FFT_01.ino”.

2. samm: Fourier 'teisendus ja FFT mõisted

Hoiatus: kui te ei talu ühtegi matemaatilist märget, võiksite minna 3. sammu juurde. Kui te ei saa sellest kõigest aru, kaaluge lihtsalt lõigu lõpus tehtud järeldust.

Sagedusspekter saadakse kiire Fourier -teisenduse algoritmi abil. FFT on digitaalne rakendus, mis lähendab Fourier 'teisenduse matemaatilist kontseptsiooni. Selle kontseptsiooni kohaselt, kui olete signaali evolutsiooni ajateljele järgnenud, saate teada selle esitamist sageduspiirkonnas, mis koosneb keerukatest (reaalsetest + kujuteldavatest) väärtustest. Kontseptsioon on vastastikune, nii et kui teate sageduspiirkonna esitusviisi, saate selle muuta ajadomeeniks ja saada signaal tagasi täpselt nagu enne teisendamist.

Aga mida me selle arvutuslike kompleksväärtuste kogumiga ajavaldkonnas tegema hakkame? Noh, suurem osa jääb inseneride hooleks. Meie jaoks kutsume teist algoritmi, mis muudab need keerukad väärtused spektraalse tiheduse andmeteks: see on iga sagedusalaga seotud suurusjärgu (= intensiivsuse) väärtus. Sagedusribade arv on sama, mis proovide arv.

Olete kindlasti kursis ekvalaiseri kontseptsiooniga, nagu see Tagasi 1980ndatesse graafilise ekvalaiseriga. Noh, me saame samalaadseid tulemusi, kuid 1024 riba asemel 16 ja palju suurema intensiivsusega. Kui ekvalaiser annab muusikale globaalse ülevaate, võimaldab peen spektraalanalüüs täpselt arvutada iga 1024 riba intensiivsuse.

Ideaalne kontseptsioon, kuid:

  1. Kuna FFT on Fourier 'teisenduse digitaliseeritud versioon, lähendab see digitaalsignaali ja kaotab teatud teabe. Seega, rangelt võttes, ei anna FFT tulemus ümberpööratud FFT algoritmiga tagasi teisendamisel täpselt algset signaali.
  2. Ka teooria käsitleb signaali, mis ei ole lõplik, kuid see on alati kestev signaal. Kuna me digitaliseerime selle ainult teatud aja jooksul (st proovid), tuuakse sisse veel mõned vead.
  3. Lõpuks mõjutab analoog -digitaalse muundamise eraldusvõime arvutatud väärtuste kvaliteeti.

Praktikas

1) proovivõtu sagedus (märgitud fs)

Proovime signaali, st mõõdame selle amplituudi iga 1/fs sekundi järel. fs on proovivõtu sagedus. Näiteks kui võtame proovi sagedusel 8 KHz, annab kiibil olev ADC (analoog -digitaalmuundur) mõõtmise iga 1/8000 sekundi järel.

2) Proovide arv (koodis märgitud N või proovid)

Kuna peame enne FFT käivitamist hankima kõik väärtused, peame need salvestama ja seega piirame proovide arvu. FFT algoritm vajab mitut näidist, mille võimsus on 2. Mida rohkem proove meil on, seda parem, kuid see võtab palju mälu, seda enam, et meil on vaja salvestada ka teisendatud andmed, mis on keerulised väärtused. Arduino FFT raamatukogu säästab kasutamisel ruumi

  • Üks massiiv nimega "vReal", et salvestada proovivõetud andmed ja seejärel teisendatud andmete tegelik osa
  • Üks massiiv nimega "vImag" teisendatud andmete kujuteldava osa salvestamiseks

Vajalik RAM -i kogus on 2 (massiivid) * 32 (bitti) * N (proovid).

Nii et meie Atmega1284, millel on kena 16 KB muutmälu, salvestame maksimaalselt N = 16000*8/64 = 2000 väärtust. Kuna väärtuste arv peab olema 2, salvestame maksimaalselt 1024 väärtust.

3) Sageduse eraldusvõime

FFT arvutab väärtused nii paljude sagedusribade jaoks kui proovide arv. Need ribad ulatuvad 0 HZ -st kuni proovivõtu sageduseni (fs). Seega on sageduse eraldusvõime järgmine:

Lahutusvõime = fs / N

Eraldusvõime on madalamal parem. Nii et parema eraldusvõime (madalama) tagamiseks soovime:

  • rohkem proove ja/või
  • madalam fs

Aga…

4) Minimaalne fs

Kuna me tahame näha palju sagedusi, millest mõned on "põhisagedusest" palju kõrgemad, ei saa me fs liiga madalaks seada. Tegelikult on olemas Nyquisti - Shannoni proovivõtu teoreem, mis sunnib meid valimissagedust tunduvalt ületama maksimaalsest sagedusest, mida tahaksime testida.

Näiteks kui tahame analüüsida kogu spektrit vahemikus 0 Hz kuni 15 KHz, mis on ligikaudu maksimaalne sagedus, mida enamik inimesi selgelt kuuleb, peame proovivõtmise sageduseks seadistama 30 KHz. Tegelikult määravad elektroonikud sageli maksimaalse sageduse 2,5 (või isegi 2,52) *. Selles näites oleks see 2,5 * 15 KHz = 37,5 KHz. Tavalised proovivõtu sagedused professionaalses helis on 44,1 KHz (audio -CD salvestus), 48 KHz ja rohkem.

Järeldus:

Punktid 1 kuni 4 toovad kaasa: me tahame kasutada võimalikult palju proove. 16 KB RAM -i puhul kaalume 1024 proovi. Tahame võtta proove võimalikult madalal diskreetimissagedusel, kui see on piisavalt kõrge, et analüüsida kõrgeimat sagedust, mida me oma signaalis ootame (vähemalt 2,5 korda).

3. samm: signaali simuleerimine

Signaali simuleerimine
Signaali simuleerimine

Esimese katse jaoks muudame veidi raamatukogus toodud TFT_01.ino näidet, et analüüsida signaali, mis koosneb

  • Põhisagedus, 440 Hz (muusikaline A)
  • Kolmas harmooniline põhivõimsuse poole võimsusega ("-3 dB")
  • 5. harmooniline 1/4 põhivõimsuse võimsusest ("-6 dB)

Saadud signaali kohal oleval pildil näete. See näeb tõepoolest välja nagu tõeline signaal, mida ostsilloskoopil (ma nimetaksin seda "Batmaniks") mõnikord näha olukorras, kus toimub sinusoidaalse signaali lõikamine.

4. samm: simuleeritud signaali analüüs - kodeerimine

0) Kaasa raamatukogu

#include "arduinoFFT.h"

1) Mõisted

Deklaratsioonide osades on meil

konst bait adcPin = 0; // A0

const uint16_t proovid = 1024; // See väärtus PEAB ALATI olema võimsus 2 const uint16_t samplingFrequency = 8000; // Mõjutab taimeri max väärtust timer_setup () SYSCLOCK/8/samplingSagedus peab olema täisarv

Kuna signaalil on 5. harmooniline (selle harmoonilise sagedus = 5 * 440 = 2200 Hz), peame proovivõtusageduse seadma üle 2,5 * 2200 = 5500 Hz. Siin valisin 8000 Hz.

Samuti deklareerime massiivid, kuhu töötlemata ja arvutatud andmed salvestame

float vReal [proovid];

float vImag [proovid];

2) Instantiatsioon

Loome ArduinoFFT objekti. ArduinoFFT arendusversioon kasutab malli, et saaksime kasutada kas ujukit või kahekordset andmetüüpi. Ujuk (32 bitti) on meie programmi üldise täpsuse seisukohast piisav.

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, proovid, proovide võtmise sagedus);

3) Signaali simuleerimine vReal massiivi täitmisega, selle asemel, et seda täita ADC väärtustega.

Tsükli alguses täidame massiivi vReal järgmiselt:

ujuktsüklid = ((((proovid) * signalFrequency) / samplingFrequency); // Signaalitsüklite arv, mida proovivõtt loeb

jaoks (uint16_t i = 0; i <proovid; i ++) {vReal = float ((amplituud * (sin ((i * (TWO_PI * tsüklit))) / proovid)))))); / * Koostage andmed positiivse ja negatiivsed väärtused */ vReal += float ((amplituud * (sin ((3 * i * (TWO_PI * tsüklit)))))))/) += ujuk ((amplituud * (sin ((5 * i * (TWO_PI * tsüklit))))) / proovid))) / 4,0); / * Koostage andmed positiivsete ja negatiivsete väärtustega * / vImag = 0,0; // Kujuteldav osa tuleb loopimise korral nullida, et vältida valesid arvutusi ja ületäitumist}

Lisame põhilaine ja kahe väiksema amplituudiga harmoonilise digitaliseerimise. Seejärel lähtestame kujuteldava massiivi nullidega. Kuna see massiiv on täidetud FFT algoritmiga, peame selle enne iga uut arvutust uuesti tühjendama.

4) FFT andmetöötlus

Seejärel arvutame FFT ja spektraaltiheduse

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

FFT.compute (FFTDirection:: Edasi); / * Arvuta FFT */ FFT.complexToMagnitude (); / * Arvuta suurusjärgud */

FFT.windowing (…) toiming muudab lähteandmeid, kuna käivitame FFT piiratud arvu proovide puhul. Esimesel ja viimasel proovil on katkestus (ühel küljel pole "midagi"). See on vigade allikas. Operatsioon "akendamine" kipub seda viga vähendama.

FFT.compute (…) suunaga "Edasi" arvutab teisenduse ajadomeenist sagedusdomeeniks.

Seejärel arvutame iga sagedusala jaoks suuruse (st intensiivsuse) väärtused. Massiiv vReal on nüüd täisväärtuste väärtustega täidetud.

5) Seeriaplotteri joonis

Prindime väärtused jadaplotterile, kutsudes funktsiooni printVector (…)

PrintVector (vReal, (näidised >> 1), SCL_FREQUENCY);

See on üldine funktsioon, mis võimaldab printida andmeid ajatelje või sagedusteljega.

Prindime ka sagedusriba, millel on suurim suurusjärk

float x = FFT.majorPeak ();

Seeria.print ("f0 ="); Seeriatrükk (x, 6); Serial.println ("Hz");

5. samm: simuleeritud signaali analüüs - tulemused

Simuleeritud signaali analüüs - tulemused
Simuleeritud signaali analüüs - tulemused

Näeme 3 naelu, mis vastavad põhisagedusele (f0), 3. ja 5. harmoonilist, poolega ja 1/4 f0 suurusjärgust, nagu oodatud. Akna ülaosast saame lugeda f0 = 440,430114 Hz. Kõigi ülalkirjeldatud põhjuste tõttu ei ole see väärtus täpselt 440 Hz, kuid on tegelikule väärtusele väga lähedal. Nii palju tühiseid kümnendkohti polnud tegelikult vaja näidata.

6. samm: tõelise signaali analüüs - ADC juhtmestik

Tõelise signaali analüüs - ADC juhtmestik
Tõelise signaali analüüs - ADC juhtmestik

Kuna teame, kuidas teoorias edasi minna, tahaksime analüüsida tõelist signaali.

Juhtmestik on väga lihtne. Ühendage maapind ja signaalliin oma plaadi A0 tihvtiga jadatakistuse abil, mille väärtus on 1 KOhm kuni 10 KOhm.

See seeria takisti kaitseb analoogsisendit ja väldib helisemist. See peab olema helisemise vältimiseks võimalikult kõrge ja võimalikult madal, et tagada piisavalt voolu ADC kiireks laadimiseks. Vaadake MCU andmelehte, et teada saada ADC sisendiga ühendatud signaali eeldatav takistus.

Selle demo jaoks kasutasin funktsioonigeneraatorit, et toita sinusoidaalset signaali sagedusega 440 Hz ja amplituudiga umbes 5 volti (kõige parem, kui amplituud on vahemikus 3 kuni 5 volti, nii et ADC -d kasutatakse täisskaala lähedal), 1,2 KOhm takisti kaudu.

7. samm: tegeliku signaali analüüs - kodeerimine

0) Kaasa raamatukogu

#include "arduinoFFT.h"

1) Deklaratsioonid ja instants

Deklaratsiooni osas määratleme ADC sisendi (A0), proovide arvu ja proovivõtu sageduse, nagu eelmises näites.

konst bait adcPin = 0; // A0

const uint16_t proovid = 1024; // See väärtus PEAB ALATI olema võimsuseks 2 const uint16_t samplingFrequency = 8000; // Mõjutab taimeri max väärtust timer_setup () SYSCLOCK/8/samplingSagedus peab olema täisarv

Loome ArduinoFFT objekti

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, proovid, proovide võtmise sagedus);

2) Taimer ja ADC seadistamine

Seadsime taimeri 1 nii, et see toimiks diskreetimissagedusel (8 KHz) ja tõstaks katkestust väljundi võrdlemisel.

void timer_setup () {

// lähtesta taimer 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | bit (WGM12); // CTC, eelseadistaja 8 TIMSK1 = bit (OCIE1B); OCR1A = (((16000000 /8) / proovivõtu sagedus) -1; }

Ja seadke ADC nii

  • Kasutab sisendina A0
  • Käivitab automaatselt igal taimeri 1 väljundil võrdlus vaste B
  • Loob katkestuse, kui teisendus on lõpule viidud

ADC kell on seatud 1 MHz -le, eelkvalifitseerides süsteemi kella (16 MHz) 16 -ga. Kuna iga teisendus võtab täies ulatuses umbes 13 kella, saab teisendusi teha sagedusel 1/13 = 0,076 MHz = 76 KHz. Proovivõtu sagedus peaks olema oluliselt madalam kui 76 KHz, et ADC -l oleks aega andmete proovimiseks. (valisime fs = 8 KHz).

void adc_setup () {

ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // lülita ADC sisse, taha katkestada lõpetamisel ADCSRA | = bit (ADPS2); // Eelskaala 16 ADMUX = bit (REFS0) | (adcPin & 7); // ADC sisendi seadistamine ADCSRB = bit (ADTS0) | bit (ADTS2); // Taimer/loendur1 Võrdle mängu B päästikuallikat ADCSRA | = bit (ADATE); // automaatse käivitamise sisselülitamine}

Deklareerime katkestuste käitleja, kellele pärast iga ADC konversiooni helistatakse, et salvestada teisendatud andmed vReal massiivi ja katkestuse kustutamine

// ADC täielik ISR

ISR (ADC_vect) {vReal [resultNumber ++] = ADC; if (resultNumber == proovid) {ADCSRA = 0; // lülita ADC välja}} EMPTY_INTERRUPT (TIMER1_COMPB_vect);

Arduino (analogRead) ADC konversiooni kohta saate ammendava selgituse.

3) Seadistamine

Seadistusfunktsioonis kustutame kujuteldava andmetabeli ning kutsume taimer ja ADC seadistusfunktsioonid

nullI (); // funktsioon, mis seadis kõik kujuteldavad andmed väärtuseks 0 - selgitatud eelmises osas

timer_setup (); adc_setup ();

3) Silmus

FFT.dcRemoval (); // Eemaldage selle signaali alalisvoolukomponent, kuna ADC on viidatud maandusele

FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Edasi); // Kaaluge andmeid FFT.compute (FFTDirection:: Edasi); // Arvuta FFT FFT.complexToMagnitude (); // Suuruste arvutamine // spektri ja põhisageduse trükkimine f0 PrintVector (vReal, (proovid >> 1), SCL_FREQUENCY); float x = FFT.majorPeak (); Seeria.print ("f0 ="); Seeriatrükk (x, 6); Serial.println ("Hz");

Me eemaldame alalisvoolukomponendi, kuna ADC on viidatud maapinnale ja signaal on umbes 2,5 volti ümber.

Seejärel arvutame andmed, nagu eelmises näites selgitatud.

8. samm: tõelise signaali analüüs - tulemused

Tõelise signaali analüüs - tulemused
Tõelise signaali analüüs - tulemused

Tõepoolest, selles lihtsas signaalis näeme ainult ühte sagedust. Arvutatud põhisagedus on 440,118194 Hz. Ka siin on väärtus tegeliku sageduse väga lähedane ligikaudne väärtus.

Samm 9: Kuidas on lood kärbitud sinusoidaalse signaaliga?

Aga kärbitud sinusoidne signaal?
Aga kärbitud sinusoidne signaal?

Nüüd laseme ADC -l veidi üle sõita, suurendades signaali amplituudi üle 5 volti, nii et see on kärbitud. Ärge suruge liiga pudru, et mitte hävitada ADC sisendit!

Näeme mõningate harmooniliste ilmumist. Signaali lõikamine loob kõrgsageduslikud komponendid.

Olete näinud Arduino tahvlil FFT analüüsi põhialuseid. Nüüd võite proovida muuta proovivõtu sagedust, proovide arvu ja aknaparameetrit. Raamatukogu lisab ka mõned parameetrid, et FFT kiiremini ja vähem täpselt välja arvutada. Märkate, et kui seate diskreetimissageduse liiga madalaks, tunduvad arvutatud suurused spektri voltimise tõttu täiesti ekslikud.

Soovitan: