Obsah:

1024 vzorků FFT spektrálního analyzátoru pomocí kroků Atmega1284: 9
1024 vzorků FFT spektrálního analyzátoru pomocí kroků Atmega1284: 9

Video: 1024 vzorků FFT spektrálního analyzátoru pomocí kroků Atmega1284: 9

Video: 1024 vzorků FFT spektrálního analyzátoru pomocí kroků Atmega1284: 9
Video: Digitální mikroskop Levenhuk Discovery Artisan 1024 – Videorecenze 2024, Červenec
Anonim
1024 vzorků FFT spektrálního analyzátoru pomocí Atmega1284
1024 vzorků FFT spektrálního analyzátoru pomocí Atmega1284
1024 vzorků FFT spektrálního analyzátoru pomocí Atmega1284
1024 vzorků FFT spektrálního analyzátoru pomocí Atmega1284

Tento relativně snadný návod (s ohledem na složitost tohoto předmětu) vám ukáže, jak lze pomocí desky typu Arduino (1284 Narrow) a sériového plotru vytvořit velmi jednoduchý 1024 vzorkový spektrální analyzátor. Postačí jakýkoli druh desky kompatibilní s Arduino, ale čím více RAM má, tím nejlepší frekvenční rozlišení získáte. K výpočtu FFT s 1024 vzorky bude potřebovat více než 8 kB RAM.

Spektrální analýza se používá k určení hlavních frekvenčních složek signálu. Mnoho zvuků (jako ty produkované hudebním nástrojem) se skládá ze základní frekvence a některých harmonických, které mají frekvenci, která je celočíselným násobkem základní frekvence. Spektrální analyzátor vám ukáže všechny tyto spektrální složky.

Toto nastavení můžete použít jako čítač kmitočtů nebo ke kontrole jakéhokoli druhu signálů, u kterých máte podezření, že způsobují určitý šum ve vašem elektronickém obvodu.

Zde se zaměříme na softwarovou část. Pokud chcete vytvořit trvalý obvod pro konkrétní aplikaci, budete muset signál zesílit a filtrovat. Tato předběžná úprava je zcela závislá na signálu, který chcete studovat, v závislosti na její amplitudě, impedanci, maximální frekvenci atd … Můžete zkontrolovat

Krok 1: Instalace knihovny

Budeme používat knihovnu ArduinoFFT napsanou Enrique Condesem. Protože chceme co nejvíce ušetřit RAM, použijeme vývojovou větev tohoto úložiště, která umožňuje ukládat vzorkovaná a vypočítaná data pomocí datového typu float (namísto dvojitého). Musíme jej tedy nainstalovat ručně. Nebojte se, stáhněte si archiv a rozbalte jej ve své složce knihovny Arduino (například ve výchozí konfiguraci Windows 10: C: / Users / _ název_ vašeho_uživatele_ / Documents / Arduino / libraries)

Správnou instalaci knihovny můžete zkontrolovat kompilací jednoho z uvedených příkladů, například „FFT_01.ino“.

Krok 2: Fourierova transformace a koncepty FFT

Varování: pokud nemůžete vydržet vidět žádný matematický zápis, možná budete chtít přeskočit na krok 3. Každopádně, pokud to všechno nepochopíte, vezměte v úvahu závěr na konci části.

Frekvenční spektrum je získáno pomocí algoritmu Fast Fourierova transformace. FFT je digitální implementace, která přibližuje matematický koncept Fourierovy transformace. V rámci tohoto konceptu, jakmile získáte vývoj signálu po časové ose, můžete znát jeho zastoupení ve frekvenční oblasti složené ze složitých (reálných + imaginárních) hodnot. Tento koncept je reciproční, takže když znáte reprezentaci frekvenční domény, můžete ji transformovat zpět do časové domény a získat signál zpět přesně jako před transformací.

Co ale uděláme s touto sadou vypočítaných komplexních hodnot v časové oblasti? Většina z toho bude ponechána na inženýrech. Pro nás budeme volat další algoritmus, který tyto komplexní hodnoty převede na data spektrální hustoty: to je hodnota velikosti (= intenzita) spojená s každým frekvenčním pásmem. Počet frekvenčních pásem bude stejný jako počet vzorků.

Určitě jste obeznámeni s konceptem ekvalizéru, jako je tento Zpět do 80. let s grafickým ekvalizérem. Získáme stejný druh výsledků, ale s 1024 pásy místo 16 a mnohem větším rozlišením intenzity. Když ekvalizér poskytuje globální pohled na hudbu, jemná spektrální analýza umožňuje přesně vypočítat intenzitu každého z 1024 pásem.

Perfektní koncept, ale:

  1. Protože FFT je digitalizovanou verzí Fourierovy transformace, přibližuje digitální signál a ztrácí některé informace. Přesně řečeno, výsledek FFT, pokud by byl transformován zpět pomocí obráceného FFT algoritmu, by nedal přesně původní signál.
  2. Teorie také zvažuje signál, který není konečný, ale je to stále trvající konstantní signál. Protože jej budeme digitalizovat pouze po určitou dobu (tj. Vzorky), budou zavedeny některé další chyby.
  3. Konečně rozlišení převodu z analogového na digitální bude mít vliv na kvalitu vypočítaných hodnot.

V praxi

1) Vzorkovací frekvence (zaznamenaná fs)

Signál, tj. Změříme jeho amplitudu, budeme vzorkovat každou 1/fs sekundy. fs je vzorkovací frekvence. Pokud například vzorkujeme na 8 KHz, ADC (analogově digitální převodník), který je na čipu, poskytne měření každých 1/8 000 sekund.

2) Počet vzorků (v kódu uvedeno N nebo vzorků)

Protože před spuštěním FFT musíme získat všechny hodnoty, budeme je muset uložit, a tak omezíme počet vzorků. Algoritmus FFT potřebuje řadu vzorků o síle 2. Čím více vzorků máme, tím lépe, ale zabere to spoustu paměti, tím více, že budeme také potřebovat ukládat transformovaná data, což jsou komplexní hodnoty. Knihovna Arduino FFT šetří místo pomocí

  • Jedno pole s názvem „vReal“pro uložení vzorkovaných dat a poté skutečné části transformovaných dat
  • Jedno pole s názvem „vImag“pro uložení imaginární části transformovaných dat

Potřebné množství paměti RAM se rovná 2 (pole) * 32 (bitů) * N (vzorky).

Takže v našem Atmega1284, který má pěkných 16 KB RAM, uložíme maximálně N = 16000*8/64 = 2000 hodnot. Protože počet hodnot musí být mocninou 2, uložíme maximálně 1024 hodnot.

3) Rozlišení frekvence

FFT vypočítá hodnoty pro tolik frekvenčních pásem, jako je počet vzorků. Tato pásma budou sahat od 0 HZ do vzorkovací frekvence (fs). Rozlišení frekvence je tedy:

Fresolution = fs / N

Rozlišení je lepší, když je nižší. Pro lepší rozlišení (nižší) tedy chceme:

  • více vzorků a/nebo
  • nižší fs

Ale…

4) Minimální fs

Protože chceme vidět mnoho frekvencí, z nichž některé jsou mnohem vyšší než „základní frekvence“, nemůžeme nastavit fs příliš nízko. Ve skutečnosti existuje vzorkovací věta Nyquist – Shannon, která nás nutí mít vzorkovací frekvenci výrazně nad dvojnásobkem maximální frekvence, kterou bychom chtěli testovat.

Pokud bychom například chtěli analyzovat celé spektrum od 0 Hz, řekněme 15 KHz, což je přibližně maximální frekvence, kterou většina lidí zřetelně slyší, musíme nastavit vzorkovací frekvenci na 30 KHz. Ve skutečnosti to elektronici často nastavují na 2,5 (nebo dokonce 2,52) * maximální frekvenci. V tomto případě by to bylo 2,5 * 15 KHz = 37,5 KHz. Obvyklé vzorkovací frekvence v profesionálním zvuku jsou 44,1 KHz (záznam zvukového disku CD), 48 KHz a další.

Závěr:

Body 1 až 4 vedou k: chceme použít co nejvíce vzorků. V našem případě se 16 kB zařízení RAM budeme uvažovat 1024 vzorků. Chceme vzorkovat na nejnižší vzorkovací frekvenci, jak je to možné, pokud je dostatečně vysoká na analýzu nejvyšší frekvence, kterou v našem signálu očekáváme (alespoň 2,5 * této frekvence).

Krok 3: Simulace signálu

Simulace signálu
Simulace signálu

Pro náš první pokus mírně upravíme příklad TFT_01.ino uvedený v knihovně, abychom analyzovali signál složený z

  • Základní frekvence nastavená na 440 Hz (hudební A)
  • 3. harmonická při polovičním výkonu základního („-3 dB“)
  • 5. harmonická při 1/4 výkonu základního ("-6 dB)

Výsledný signál můžete vidět na obrázku. Vypadá to opravdu velmi podobně jako skutečný signál, který lze někdy vidět na osciloskopu (nazval bych to „Batman“) v situaci, kdy dojde k oříznutí sinusového signálu.

Krok 4: Analýza simulovaného signálu - kódování

0) Zahrnout knihovnu

#include "arduinoFFT.h"

1) Definice

V sekcích prohlášení máme

const byte adcPin = 0; // A0

const uint16_t vzorky = 1024; // Tato hodnota MUSÍ BÝT VŽDY mocninou 2 konst uint16_t samplingFrequency = 8000; // Ovlivní maximální hodnotu časovače v timer_setup () SYSCLOCK/8/samplingFrequency by mělo být celé číslo

Protože signál má 5. harmonickou (frekvence této harmonické = 5 * 440 = 2200 Hz), musíme nastavit vzorkovací frekvenci nad 2,5 * 2200 = 5500 Hz. Zde jsem zvolil 8000 Hz.

Deklarujeme také pole, kam budeme ukládat nezpracovaná a vypočítaná data

float vReal [vzorky];

float vImag [vzorky];

2) Instance

Vytváříme objekt ArduinoFFT. Verze ArduinoFFT pro vývoj používá šablonu, takže můžeme použít buď datový typ float, nebo dvojitý. Float (32 bitů) je s ohledem na celkovou přesnost našeho programu dostačující.

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

3) Simulace signálu naplněním pole vReal namísto jeho naplnění hodnotami ADC.

Na začátku smyčky naplníme pole vReal:

float cykly = ((((vzorky) * signalFrequency) / samplingFrequency); // Počet signálních cyklů, které vzorkování přečte

pro (uint16_t i = 0; i <vzorky; i ++) {vReal = float ((amplituda * (sin ((i * (TWO_PI * cykly)) / vzorky)))) / / * Vytváření dat s kladnými a záporné hodnoty */ vReal += float ((amplituda * (sin ((3 * i * (TWO_PI * cykly))/ vzorky))))/ 2.0);/ * Vytváření dat s kladnými a zápornými hodnotami */ vReal += float ((amplituda * (sin ((5 * i * (TWO_PI * cyklů)) / vzorky))) / 4.0); / * Vytváření dat s kladnými a zápornými hodnotami * / vImag = 0,0; // Imaginární část musí být v případě smyčky vynulována, aby se předešlo chybným výpočtům a přetečení}

Přidáme digitalizaci základní vlny a dvou harmonických s menší amplitudou. Potom imaginární pole inicializujeme nulami. Protože toto pole je naplněno algoritmem FFT, musíme jej před každým novým výpočtem znovu vymazat.

4) FFT výpočetní technika

Poté vypočítáme FFT a spektrální hustotu

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

FFT.compute (FFTDirection:: Forward); / * Compute FFT */ FFT.complexToMagnitude (); / * Výpočtové veličiny */

Operace FFT.windowing (…) upravuje nezpracovaná data, protože spouštíme FFT na omezeném počtu vzorků. První a poslední vzorky představují diskontinuitu (na jedné z jejich strany není „nic“). Toto je zdroj chyb. Operace „okenování“má tendenci tuto chybu snižovat.

FFT.compute (…) se směrem „Vpřed“vypočítá transformaci z časové domény do frekvenční domény.

Poté vypočítáme hodnoty velikosti (tj. Intenzity) pro každé z frekvenčních pásem. Pole vReal je nyní naplněno hodnotami veličin.

5) Kreslení sériového plotru

Vytiskneme hodnoty na sériovém plotru voláním funkce printVector (…)

PrintVector (vReal, (ukázky >> 1), SCL_FREQUENCY);

Toto je obecná funkce, která umožňuje tisk dat s časovou nebo frekvenční osou.

Vytiskneme také frekvenci pásma, které má nejvyšší hodnotu magnitudy

float x = FFT.majorPeak ();

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

Krok 5: Analýza simulovaného signálu - výsledky

Analýza simulovaného signálu - výsledky
Analýza simulovaného signálu - výsledky

Vidíme 3 špičky odpovídající základní frekvenci (f0), 3. a 5. harmonickou, podle očekávání polovinu a 1/4 magnitudy f0. V horní části okna můžeme číst f0 = 440,430114 Hz. Tato hodnota není ze všech výše vysvětlených důvodů přesně 440 Hz, ale je velmi blízko skutečné hodnotě. Nebylo opravdu nutné ukazovat tolik bezvýznamných desetinných míst.

Krok 6: Analýza skutečného signálu - zapojení ADC

Analýza skutečného signálu - zapojení ADC
Analýza skutečného signálu - zapojení ADC

Protože víme, jak teoreticky postupovat, chtěli bychom analyzovat skutečný signál.

Zapojení je velmi jednoduché. Připojte uzemnění dohromady a signální vedení ke kolíku A0 vaší desky prostřednictvím sériového odporu s hodnotou 1 KOhm až 10 KOhm.

Tento odpor série ochrání analogový vstup a zabrání vyzvánění. Musí být co nejvyšší, aby se zabránilo vyzvánění, a co nejnižší, aby poskytoval dostatek proudu k rychlému nabíjení ADC. Informace o očekávané impedanci signálu připojeného na vstupu ADC najdete v datovém listu MCU.

Pro toto demo jsem použil generátor funkcí k napájení sinusového signálu o frekvenci 440 Hz a amplitudě kolem 5 voltů (nejlepší je, když je amplituda mezi 3 a 5 volty, takže se ADC používá v blízkosti plného rozsahu), přes odpor 1,2 KOhm.

Krok 7: Analýza skutečného signálu - kódování

0) Zahrnout knihovnu

#include "arduinoFFT.h"

1) Prohlášení a instanciace

V deklarační sekci definujeme vstup ADC (A0), počet vzorků a vzorkovací frekvenci, jako v předchozím příkladu.

const byte adcPin = 0; // A0

const uint16_t vzorky = 1024; // Tato hodnota MUSÍ BÝT VŽDY mocninou 2 konst uint16_t samplingFrequency = 8000; // Ovlivní maximální hodnotu časovače v timer_setup () SYSCLOCK/8/samplingFrequency by mělo být celé číslo

Vytváříme objekt ArduinoFFT

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

2) Nastavení časovače a ADC

Nastavíme časovač 1 tak, aby cykloval na vzorkovací frekvenci (8 KHz) a zvýšil přerušení při porovnání výstupu.

neplatné timer_setup () {

// reset časovače 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | bit (WGM12); // CTC, prescaler 8 TIMSK1 = bit (OCIE1B); OCR1A = ((16000000 /8) / vzorkovací frekvence) -1; }

A nastavte ADC tak

  • Jako vstup používá A0
  • Spouští automaticky při každém výstupu časovače 1 porovnání B
  • Po dokončení převodu generuje přerušení

Hodiny ADC jsou nastaveny na 1 MHz, a to tak, že se systémový takt (16 MHz) předcaluje na 16. Protože každá konverze zabere přibližně 13 hodin v plném měřítku, lze převodu dosáhnout na frekvenci 1/13 = 0,076 MHz = 76 KHz. Vzorkovací frekvence by měla být výrazně nižší než 76 KHz, aby měl ADC čas na vzorkování dat. (vybrali jsme fs = 8 KHz).

neplatné adc_setup () {

ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // zapnout ADC, chtít po dokončení přerušení ADCSRA | = bit (ADPS2); // Předzměňovač 16 ADMUX = bit (REFS0) | (adcPin & 7); // nastavení vstupu ADC ADCSRB = bit (ADTS0) | bit (ADTS2); // Časovač/Počitadlo1 Porovnat spouštěcí zdroj Match B ADCSRA | = bit (ADATE); // zapnout automatické spouštění}

Deklarujeme obslužnou rutinu přerušení, která bude volána po každém převodu ADC, aby se převedená data uložila do pole vReal a vymazání přerušení

// ADC kompletní ISR

ISR (ADC_vect) {vReal [resultNumber ++] = ADC; if (resultNumber == vzorky) {ADCSRA = 0; // vypnout ADC}} EMPTY_INTERRUPT (TIMER1_COMPB_vect);

Můžete mít vyčerpávající vysvětlení převodu ADC na Arduino (analogRead).

3) Nastavení

Ve funkci nastavení vymažeme imaginární tabulku dat a vyvoláme funkce nastavení časovače a ADC

nulaI (); // funkce, která nastavila na 0 všechna imaginární data - vysvětleno v předchozí části

timer_setup (); adc_setup ();

3) Smyčka

FFT.dcRemoval (); // Odeberte DC součást tohoto signálu, protože ADC je vztaženo k zemi

FFT.windowing (FFTWindow:: Hamming, FFTDirection:: Forward); // Vážení dat FFT.compute (FFTDirection:: Forward); // Compute FFT FFT.complexToMagnitude (); // Výpočtové veličiny // tisk spektra a základní frekvence f0 PrintVector (vReal, (ukázky >> 1), SCL_FREQUENCY); float x = FFT.majorPeak (); Serial.print ("f0 ="); Serial.print (x, 6); Serial.println ("Hz");

Odebereme stejnosměrnou složku, protože ADC je vztaženo k zemi a signál je soustředěn přibližně na 2,5 voltů.

Potom vypočítáme data, jak je vysvětleno v předchozím příkladu.

Krok 8: Analýza skutečného signálu - výsledky

Analýza skutečného signálu - výsledky
Analýza skutečného signálu - výsledky

V tomto jednoduchém signálu skutečně vidíme pouze jednu frekvenci. Vypočítaná základní frekvence je 440,118194 Hz. I zde je hodnota velmi blízkým přiblížením skutečné frekvence.

Krok 9: Co oříznutý sinusový signál?

Co oříznutý sinusový signál?
Co oříznutý sinusový signál?

Nyní umožňuje trochu přehnat ADC zvýšením amplitudy signálu nad 5 voltů, takže je oříznut. Netlačte příliš kašovitě, abyste nezničili vstup ADC!

Vidíme, jak se objevují nějaké harmonické. Oříznutí signálu vytváří vysokofrekvenční složky.

Viděli jste základy analýzy FFT na desce Arduino. Nyní se můžete pokusit změnit vzorkovací frekvenci, počet vzorků a parametr okna. Knihovna také přidává některé parametry pro rychlejší výpočet FFT s menší přesností. Všimnete si, že pokud nastavíte vzorkovací frekvenci příliš nízko, vypočítané veličiny budou kvůli spektrálnímu skládání vypadat zcela chybně.

Doporučuje: