Turinys:

1024 mėginiai FFT spektro analizatorius naudojant „Atmega1284“: 9 žingsniai
1024 mėginiai FFT spektro analizatorius naudojant „Atmega1284“: 9 žingsniai

Video: 1024 mėginiai FFT spektro analizatorius naudojant „Atmega1284“: 9 žingsniai

Video: 1024 mėginiai FFT spektro analizatorius naudojant „Atmega1284“: 9 žingsniai
Video: Kaip padirbti vaizdo įrašą naudojant „DeepFaceLab“ – visas vadovas | Deepfake kūrimas nuo A iki Z 2024, Liepa
Anonim
1024 mėginiai FFT spektro analizatorius naudojant „Atmega1284“
1024 mėginiai FFT spektro analizatorius naudojant „Atmega1284“
1024 mėginiai FFT spektro analizatorius naudojant „Atmega1284“
1024 mėginiai FFT spektro analizatorius naudojant „Atmega1284“

Ši gana paprasta pamoka (atsižvelgiant į šios temos sudėtingumą) parodys, kaip galite sukurti labai paprastą 1024 mėginių spektro analizatorių, naudojant „Arduino“tipo plokštę (1284 siaura) ir serijinį braižytuvą. Tiks bet kokia su „Arduino“suderinama plokštė, tačiau kuo daugiau RAM, tuo geriausią dažnio skiriamąją gebą gausite. Norint apskaičiuoti FFT su 1024 mėginiais, reikės daugiau nei 8 KB RAM.

Spektro analizė naudojama norint nustatyti pagrindinius signalo dažnio komponentus. Daugelį garsų (pvz., Tuos, kuriuos sukuria muzikos instrumentas) sudaro pagrindinis dažnis ir kai kurios harmonikos, kurių dažnis yra sveikasis pagrindinio dažnio kartotinis. Spektro analizatorius parodys visus šiuos spektrinius komponentus.

Galbūt norėsite naudoti šią sąranką kaip dažnio skaitiklį arba patikrinti bet kokius signalus, kurie, jūsų manymu, sukelia triukšmą jūsų elektroninėje grandinėje.

Čia mes sutelksime dėmesį į programinės įrangos dalį. Jei norite sukurti nuolatinę grandinę konkrečiai programai, turėsite sustiprinti ir filtruoti signalą. Šis išankstinis kondicionavimas visiškai priklauso nuo signalo, kurį norite ištirti, priklausomai nuo jo amplitudės, varžos, maksimalaus dažnio ir tt … Galite patikrinti

1 veiksmas: bibliotekos diegimas

Mes naudosime ArduinoFFT biblioteką, kurią parašė Enrique Condes. Kadangi norime kiek įmanoma taupyti RAM, naudosime šios saugyklos kūrimo šaką, leidžiančią atrinktiems ir apskaičiuotiems duomenims saugoti naudoti plūdės duomenų tipą (o ne dvigubą). Taigi mes turime jį įdiegti rankiniu būdu. Nesijaudinkite, tiesiog atsisiųskite archyvą ir išspauskite jį savo „Arduino“bibliotekos aplanke (pvz., „Windows 10“numatytojoje konfigūracijoje: C: / Users / _your_user_name_ / Documents / Arduino / libraries)

Galite patikrinti, ar biblioteka tinkamai įdiegta, sudarydami vieną iš pateiktų pavyzdžių, pvz., „FFT_01.ino“.

2 žingsnis: Furjė transformacija ir FFT sąvokos

Įspėjimas: jei negalite matyti jokių matematinių žymėjimų, galbūt norėsite pereiti prie 3 veiksmo. Bet kokiu atveju, jei visko nesuprantate, tiesiog apsvarstykite išvadą skyriaus pabaigoje.

Dažnių spektras gaunamas naudojant greito Furjė transformacijos algoritmą. FFT yra skaitmeninis įgyvendinimas, kuris apytiksliai atitinka Furjė transformacijos matematinę koncepciją. Pagal šią sąvoką, kai gausite signalo evoliuciją pagal laiko ašį, galite sužinoti, kaip jis vaizduojamas dažnių srityje, susidedančioje iš sudėtingų (realių + įsivaizduojamų) verčių. Ši sąvoka yra abipusė, todėl žinodami dažnio srities vaizdavimą, galite jį pakeisti į laiko sritį ir atgauti signalą lygiai taip pat, kaip ir prieš transformaciją.

Bet ką mes darysime su šiuo apskaičiuotų sudėtingų verčių rinkiniu laiko srityje? Na, didžioji dalis bus palikta inžinieriams. Mums vadinsime kitą algoritmą, kuris šias sudėtingas vertes pavers spektrinio tankio duomenimis: tai yra dydžio (= intensyvumo) reikšmė, susieta su kiekviena dažnių juosta. Dažnių juostos skaičius bus toks pat kaip mėginių skaičius.

Jūs tikrai esate susipažinę su ekvalaizerio koncepcija, tokia kaip ši Atgal į 1980 -uosius su grafiniu EQ. Na, mes gausime tokio paties pobūdžio rezultatus, bet turėdami 1024 juostas, o ne 16 ir daug didesnę intensyvumą. Kai ekvalaizeris suteikia visapusišką muzikos vaizdą, tiksli spektrinė analizė leidžia tiksliai apskaičiuoti kiekvienos iš 1024 juostų intensyvumą.

Ideali koncepcija, bet:

  1. Kadangi FFT yra suskaitmeninta Furjė transformacijos versija, ji apytiksliai atitinka skaitmeninį signalą ir praranda dalį informacijos. Taigi, griežtai tariant, FFT rezultatas, jei jis būtų pakeistas naudojant apverstą FFT algoritmą, neduotų tiksliai pradinio signalo.
  2. Taip pat teorija laiko signalą, kuris nėra baigtinis, tačiau tai yra nuolatinis nuolatinis signalas. Kadangi mes jį skaitmeninsime tik tam tikrą laiką (t. Y. Pavyzdžius), bus įvesta dar keletas klaidų.
  3. Galiausiai analoginio pavertimo skaitmenine raiška turės įtakos apskaičiuotų verčių kokybei.

Praktikoje

1) Mėginių ėmimo dažnis (pažymėtas fs)

Mes imsime signalą, t. Y. Išmatuosime jo amplitudę, kas 1 sekundę. fs yra mėginių ėmimo dažnis. Pavyzdžiui, jei imame mėginius 8 KHz dažniu, mikroschemoje esantis ADC (analoginis -skaitmeninis keitiklis) matuoja kas 1/8000 sekundžių.

2) mėginių skaičius (pažymėtas N arba mėginiai kode)

Kadangi prieš paleisdami FFT turime gauti visas reikšmes, turėsime jas išsaugoti, todėl apribosime mėginių skaičių. FFT algoritmui reikia daugybės pavyzdžių, kurių galia yra 2. Kuo daugiau pavyzdžių turime, tuo geriau, tačiau tai užima daug atminties, tuo labiau, kad mums taip pat reikės išsaugoti transformuotus duomenis, kurie yra sudėtingos vertės. „Arduino FFT“biblioteka sutaupo šiek tiek vietos

  • Vienas masyvas, pavadintas „vReal“, skirtas atrinktiems duomenims ir tikrajai transformuotų duomenų daliai saugoti
  • Vienas masyvas, pavadintas „vImag“, skirtas išsaugoti įsivaizduojamą transformuotų duomenų dalį

Reikalingas RAM kiekis yra lygus 2 (masyvai) * 32 (bitai) * N (pavyzdžiai).

Taigi mūsų „Atmega1284“, turinčioje gražią 16 KB RAM, išsaugosime daugiausia N = 16000*8/64 = 2000 reikšmių. Kadangi reikšmių skaičius turi būti 2 galios, mes išsaugosime ne daugiau kaip 1024 reikšmes.

3) Dažnio skiriamoji geba

FFT apskaičiuos vertes tiek dažnių juostų, kiek mėginių. Šios juostos bus nuo 0 HZ iki mėginių ėmimo dažnio (fs). Taigi dažnio skiriamoji geba yra tokia:

Išsiskyrimas = fs / N

Skiriamoji geba yra geresnė, kai mažesnė. Taigi norėdami geresnės rezoliucijos (mažesnės) norime:

  • daugiau mėginių ir (arba)
  • mažesnis fs

Bet…

4) Minimalus fs

Kadangi norime matyti daug dažnių, kai kurie iš jų yra daug didesni už „pagrindinį dažnį“, negalime nustatyti fs per žemai. Tiesą sakant, egzistuoja Nyquist - Shannon atrankos teorema, kuri verčia mus turėti atrankos dažnį, kuris yra daug didesnis nei dvigubai didesnis už maksimalų dažnį, kurį norėtume išbandyti.

Pavyzdžiui, jei norime išanalizuoti visą spektrą nuo 0 Hz iki 15 KHz, o tai yra maksimalus dažnis, kurį dauguma žmonių gali aiškiai išgirsti, turime nustatyti 30 KHz atrankos dažnį. Tiesą sakant, elektronikai dažnai nustato 2,5 (ar net 2,52) * didžiausią dažnį. Šiame pavyzdyje tai būtų 2,5 * 15 KHz = 37,5 KHz. Įprastas mėginių ėmimo dažnis profesionaliame garso įraše yra 44,1 KHz (garso CD įrašymas), 48 KHz ir daugiau.

Išvada:

1–4 punktai lemia: norime naudoti kuo daugiau pavyzdžių. Mūsų atveju, naudojant 16 KB RAM įrenginį, atsižvelgsime į 1024 pavyzdžius. Mes norime imti mėginius kuo mažesniu mėginių ėmimo dažniu, jei tik jis yra pakankamai aukštas, kad būtų galima išanalizuoti aukščiausią dažnį, kurio tikimės savo signale (bent 2,5 karto).

3 žingsnis: signalo modeliavimas

Signalo imitavimas
Signalo imitavimas

Pirmajam bandymui šiek tiek pakeisime bibliotekoje pateiktą TFT_01.ino pavyzdį, kad išanalizuotume signalą, sudarytą iš

  • Pagrindinis dažnis, nustatytas į 440 Hz (muzikinis A)
  • Trečioji harmonika esant pusei pagrindinės galios („-3 dB“)
  • 5-oji harmonika esant 1/4 pagrindinės galios (-6 dB)

Galite pamatyti paveikslėlyje virš gauto signalo. Iš tiesų tai labai panašu į tikrą signalą, kurį kartais galima pamatyti naudojant osciloskopą (aš jį pavadinčiau „Betmenu“), kai yra iškarpomas sinusinis signalas.

4 žingsnis: imituoto signalo kodavimo analizė

0) Įtraukite biblioteką

#include "arduinoFFT.h"

1) Apibrėžimai

Deklaracijų skyriuose turime

konst baitas adcPin = 0; // A0

const uint16_t pavyzdžiai = 1024; // Ši vertė VISADA TURI būti 2 galių konstanta uint16_t samplingFrequency = 8000; // Įtakoja maksimalią laikmačio reikšmę timer_setup () SYSCLOCK/8/samplingFrequency should be sveikas skaičius

Kadangi signalas turi 5 -ąją harmoniką (šios harmonikos dažnis = 5 * 440 = 2200 Hz), turime nustatyti mėginių ėmimo dažnį virš 2,5 * 2200 = 5500 Hz. Čia aš pasirinkau 8000 Hz.

Taip pat deklaruojame masyvus, kuriuose laikysime neapdorotus ir apskaičiuotus duomenis

float vReal [pavyzdžiai];

plūdė vImag [mėginiai];

2) Instantiacija

Mes sukuriame „ArduinoFFT“objektą. „ArduinoFFT“kūrėjo versijoje naudojamas šablonas, kad galėtume naudoti plūdę arba dvigubą duomenų tipą. Plūdės (32 bitų) pakanka, atsižvelgiant į bendrą mūsų programos tikslumą.

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, mėginiai, mėginių ėmimo dažnis);

3) Simuliuojant signalą užpildant „vReal“masyvą, užuot jį užpildžius ADC reikšmėmis.

Ciklo pradžioje užpildome „vReal“masyvą:

plūdės ciklai = ((((mėginiai) * signalFrequency) / samplingFrequency); // Signalo ciklų, kuriuos skaitys atranka, skaičius

(uint16_t i = 0; i <mėginiai; i ++) {vReal = plūdė ((amplitudė * (sin ((i * (TWO_PI * ciklai))) / mėginiai)))))); / * Sukurkite teigiamų ir neigiamos reikšmės */ vReal += plūdė ((amplitudė * (sin ((3 * i * (TWO_PI * ciklai)))))))))/))/ 2.0);/ *) += plūdė ((amplitudė * (sin ((5 * i * (TWO_PI * ciklai))))))))); // Įsivaizduojama dalis turi būti nulinė, jei ciklas kartojamas, kad būtų išvengta klaidingų skaičiavimų ir perpildymų}

Pridedame pagrindinės bangos ir dviejų mažesnės amplitudės harmonikų skaitmeninimą. Tuomet mes įsivaizduojamą masyvą inicijuojame nuliais. Kadangi šis masyvas yra užpildytas FFT algoritmu, prieš kiekvieną naują skaičiavimą turime jį išvalyti dar kartą.

4) FFT skaičiavimas

Tada mes apskaičiuojame FFT ir spektrinį tankį

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

FFT.compute (FFTDirection:: Pirmyn); / * Apskaičiuoti FFT */ FFT.complexToMagnitude (); / * Apskaičiuoti dydžius */

FFT.windowing (…) operacija modifikuoja neapdorotus duomenis, nes mes atliekame FFT ribotam mėginių skaičiui. Pirmasis ir paskutinis mėginiai turi pertrauką (vienoje jų pusėje nėra „nieko“). Tai klaidų šaltinis. „Lango“operacija linkusi sumažinti šią klaidą.

FFT.compute (…) kryptimi „Pirmyn“apskaičiuoja transformaciją iš laiko srities į dažnio sritį.

Tada mes apskaičiuojame kiekvienos dažnių juostos dydžio (ty intensyvumo) vertes. Dabar „vReal“masyvas užpildytas dydžių reikšmėmis.

5) Serijinio braižytuvo brėžinys

Išspausdinkime vertes serijiniame braižytuve, iškviesdami funkciją printVector (…)

„PrintVector“(„vReal“, (pavyzdžiai >> 1), SCL_FREQUENCY);

Tai yra bendra funkcija, leidžianti spausdinti duomenis naudojant laiko arba dažnio ašį.

Mes taip pat spausdiname dažnio juostą, kurios vertė yra didžiausia

plūdė x = FFT.majorPeak ();

Serijinis atspaudas ("f0 ="); Serijinis atspaudas (x, 6); Serial.println ("Hz");

5 žingsnis: imituoto signalo analizė - rezultatai

Simuliuoto signalo analizė - rezultatai
Simuliuoto signalo analizė - rezultatai

Matome 3 smaigalius, atitinkančius pagrindinį dažnį (f0), 3 ir 5 harmonikas, kurių pusė ir 1/4 f0 dydžio, kaip tikėtasi. Mes galime skaityti lango viršuje f0 = 440,430114 Hz. Dėl visų aukščiau paaiškintų priežasčių ši vertė nėra tiksliai 440 Hz, tačiau ji yra labai artima tikrajai vertei. Tikrai nereikėjo rodyti tiek nereikšmingų dešimtųjų.

6 žingsnis: tikro signalo analizė - ADC prijungimas

Tikro signalo analizė - ADC prijungimas
Tikro signalo analizė - ADC prijungimas

Kadangi teoriškai žinome, kaip elgtis toliau, norėtume išanalizuoti tikrą signalą.

Elektros instaliacija yra labai paprasta. Prijunkite pagrindą ir signalo liniją prie plokštės A0 kaiščio per serijinį rezistorių, kurio vertė yra nuo 1 KOhm iki 10 KOhm.

Šis serijos rezistorius apsaugos analoginį įėjimą ir išvengs skambėjimo. Jis turi būti kuo aukštesnis, kad neskambėtų, ir kuo mažesnis, kad būtų pakankamai srovės, kad būtų galima greitai įkrauti ADC. Norėdami sužinoti numatomą signalo, prijungto prie ADC įvesties, varžą, skaitykite MCU duomenų lape.

Šiai demonstracijai aš naudoju funkcijų generatorių, skirtą tiekti sinusinį signalą, kurio dažnis yra 440 Hz ir amplitudė yra apie 5 voltai (geriausia, jei amplitudė yra nuo 3 iki 5 voltų, todėl ADC naudojamas beveik visu mastu) per 1,2 KOhm rezistorių.

7 žingsnis: tikro signalo analizė - kodavimas

0) Įtraukite biblioteką

#include "arduinoFFT.h"

1) Deklaracijos ir instancija

Deklaracijos skyriuje mes apibrėžiame ADC įvestį (A0), mėginių skaičių ir mėginių ėmimo dažnumą, kaip ir ankstesniame pavyzdyje.

konst baitas adcPin = 0; // A0

const uint16_t pavyzdžiai = 1024; // Ši vertė VISADA TURI būti 2 galios konstanta uint16_t samplingFrequency = 8000; // Įtakoja maksimalią laikmačio reikšmę timer_setup () SYSCLOCK/8/samplingFrequency should be sveikas skaičius

Mes kuriame ArduinoFFT objektą

ArduinoFFT FFT = ArduinoFFT (vReal, vImag, mėginiai, mėginių ėmimo dažnis);

2) Laikmatis ir ADC sąranka

Mes nustatėme 1 laikmatį, kad jis veiktų mėginių ėmimo dažniu (8 KHz) ir padidintų išvesties palyginimo pertrauką.

void timer_setup () {

// atstatyti 1 laikmatį TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bitas (CS11) | bitas (WGM12); // CTC, prescaler of 8 TIMSK1 = bit (OCIE1B); OCR1A = ((16000000/8) / atrankos dažnis) -1; }

Ir nustatykite ADC taip

  • Naudoja A0 kaip įvestį
  • Automatiškai suaktyvina kiekvieną 1 laikmačio išvestį, palyginti palyginimą B
  • Sukuria pertraukimą, kai konversija baigta

ADC laikrodis nustatomas 1 MHz greičiu, iš anksto keičiant sistemos laikrodžio (16 MHz) skaičių 16. Mėginių ėmimo dažnis turėtų būti gerokai mažesnis nei 76 KHz, kad ADC turėtų laiko atrinkti duomenis. (pasirinkome fs = 8 KHz).

void adc_setup () {

ADCSRA = bitas (ADEN) | bitas (ADIE) | bitų (ADIF); // įjungti ADC, norėti pertraukimo baigus ADCSRA | = bit (ADPS2); // Prescaler iš 16 ADMUX = bitų (REFS0) | („adcPin & 7“); // ADC įvesties nustatymas ADCSRB = bit (ADTS0) | bitų (ADTS2); // Laikmatis/skaitiklis1 Palyginkite B rungtynių trigerio šaltinį ADCSRA | = bit (ADATE); // įjungti automatinį paleidimą}

Skelbiame pertraukimo tvarkytoją, kuris bus iškviestas po kiekvienos ADC konversijos, kad išsaugotų konvertuotus duomenis „vReal“masyve ir pašalintų pertrauką

// ADC pilnas ISR

ISR (ADC_vect) {vReal [resultNumber ++] = ADC; if (resultNumber == mėginiai) {ADCSRA = 0; // išjungti ADC}} EMPTY_INTERRUPT (TIMER1_COMPB_vect);

Galite turėti išsamų paaiškinimą apie ADC konversiją „Arduino“(analogRead).

3) Sąranka

Sąrankos funkcijoje išvalome įsivaizduojamą duomenų lentelę ir iškviečiame laikmačio bei ADC sąrankos funkcijas

nulisI (); // funkcija, kuri nustatė 0 visus įsivaizduojamus duomenis - paaiškinta ankstesniame skyriuje

timer_setup (); adc_setup ();

3) kilpa

FFT.dcRemoval (); // Pašalinkite šio signalo nuolatinės srovės komponentą, nes ADC yra nuoroda į žemę

FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Pirmyn); // Pasverkite duomenis FFT.compute (FFTDirection:: Forward); // Apskaičiuoti FFT FFT.complexToMagnitude (); // Apskaičiuoti dydžius // spausdinti spektrą ir pagrindinį dažnį f0 PrintVector (vReal, (pavyzdžiai >> 1), SCL_FREQUENCY); plūdė x = FFT.majorPeak (); Serijinis atspaudas ("f0 ="); Serijinis atspaudas (x, 6); Serial.println ("Hz");

Mes pašaliname nuolatinės srovės komponentą, nes ADC yra susijęs su žeme, o signalas yra maždaug 2,5 volto centre.

Tada mes apskaičiuojame duomenis, kaip paaiškinta ankstesniame pavyzdyje.

8 žingsnis: tikro signalo analizė - rezultatai

Tikro signalo analizė - rezultatai
Tikro signalo analizė - rezultatai

Iš tiesų šiame paprastame signale matome tik vieną dažnį. Apskaičiuotas pagrindinis dažnis yra 440,118194 Hz. Čia vėlgi vertė yra labai artima tikrojo dažnio apytikslei.

9 žingsnis: Ką apie nukirptą sinusinį signalą?

Ką apie nukirptą sinusinį signalą?
Ką apie nukirptą sinusinį signalą?

Dabar leiskite šiek tiek pervargti ADC, padidindami signalo amplitudę virš 5 voltų, todėl jis yra nukirptas. Nespauskite per daug košės, kad nesunaikintumėte ADC įvesties!

Mes galime pamatyti kai kurias harmonikas. Iškirpus signalą, sukuriami aukšto dažnio komponentai.

Jūs matėte FFT analizės pagrindus „Arduino“lentoje. Dabar galite pabandyti pakeisti mėginių ėmimo dažnumą, mėginių skaičių ir lango parametrą. Biblioteka taip pat prideda tam tikrą parametrą, kad FFT būtų apskaičiuojama greičiau ir mažiau tiksliai. Pastebėsite, kad jei nustatysite per mažą mėginių ėmimo dažnį, apskaičiuotas dydis atrodys visiškai klaidingas dėl spektrinio lankstymo.

Rekomenduojamas: