Spisu treści:
- Krok 1: Instalacja biblioteki
- Krok 2: Transformacja Fouriera i koncepcje FFT
- Krok 3: Symulacja sygnału
- Krok 4: Analiza symulowanego sygnału - kodowanie
- Krok 5: Analiza symulowanego sygnału – wyniki
- Krok 6: Analiza sygnału rzeczywistego – okablowanie ADC
- Krok 7: Analiza rzeczywistego sygnału - kodowanie
- Krok 8: Analiza rzeczywistego sygnału – wyniki
- Krok 9: A co z obciętym sygnałem sinusoidalnym?
Wideo: Analizator widma 1024 próbek FFT przy użyciu Atmega1284: 9 kroków
2024 Autor: John Day | [email protected]. Ostatnio zmodyfikowany: 2024-01-30 11:28
Ten stosunkowo prosty samouczek (zważywszy na złożoność tej tematyki) pokaże, jak można wykonać bardzo prosty analizator widma 1024 próbek przy użyciu płytki typu Arduino (1284 Narrow) i plotera szeregowego. Dowolna płyta kompatybilna z Arduino sprawdzi się, ale im więcej ma pamięci RAM, tym najlepszą rozdzielczość częstotliwości uzyskasz. Do obliczenia FFT z 1024 próbkami potrzeba więcej niż 8 KB pamięci RAM.
Analiza widma służy do określenia głównych składowych częstotliwości sygnału. Wiele dźwięków (takich jak te wytwarzane przez instrument muzyczny) składa się z częstotliwości podstawowej i niektórych harmonicznych, których częstotliwość jest całkowitą wielokrotnością częstotliwości podstawowej. Analizator widma pokaże ci wszystkie te składowe widmowe.
Możesz użyć tej konfiguracji jako licznika częstotliwości lub sprawdzić wszelkiego rodzaju sygnały, które podejrzewasz, że powodują szum w twoim obwodzie elektronicznym.
Skupimy się tutaj na części oprogramowania. Jeśli chciałbyś wykonać stały obwód dla określonej aplikacji, będziesz musiał wzmocnić i przefiltrować sygnał. To wstępne kondycjonowanie jest całkowicie zależne od sygnału, który chcesz badać, w zależności od jego amplitudy, impedancji, maksymalnej częstotliwości itp. Możesz sprawdzić
Krok 1: Instalacja biblioteki
Będziemy używać biblioteki ArduinoFFT napisanej przez Enrique Condes. Ponieważ chcemy oszczędzić jak najwięcej pamięci RAM, użyjemy gałęzi deweloperskiej tego repozytorium, która pozwala na użycie typu danych float (zamiast double) do przechowywania danych próbkowanych i obliczanych. Więc musimy go zainstalować ręcznie. Nie martw się, po prostu pobierz archiwum i rozpakuj je w folderze biblioteki Arduino (na przykład w domyślnej konfiguracji systemu Windows 10: C:\Users\_twoja_nazwa_użytkownika_\Documents\Arduino\libraries)
Możesz sprawdzić, czy biblioteka jest poprawnie zainstalowana, kompilując jeden z podanych przykładów, np. „FFT_01.ino”.
Krok 2: Transformacja Fouriera i koncepcje FFT
Uwaga: jeśli nie możesz znieść oglądania jakiejkolwiek notacji matematycznej, możesz przejść do kroku 3. W każdym razie, jeśli nie rozumiesz wszystkiego, po prostu rozważ wniosek na końcu sekcji.
Widmo częstotliwości uzyskuje się za pomocą algorytmu szybkiej transformacji Fouriera. FFT to cyfrowa implementacja, która przybliża matematyczną koncepcję transformacji Fouriera. Zgodnie z tą koncepcją, gdy uzyskasz ewolucję sygnału podążającą za osią czasu, możesz poznać jego reprezentację w domenie częstotliwości, złożonej ze złożonych (rzeczywistych + urojonych) wartości. Koncepcja jest wzajemna, więc kiedy znasz reprezentację w domenie częstotliwości, możesz ją przekształcić z powrotem do domeny czasu i uzyskać sygnał dokładnie tak, jak przed transformacją.
Ale co zrobimy z tym zbiorem obliczonych wartości złożonych w dziedzinie czasu? Cóż, większość zostanie pozostawiona inżynierom. Dla nas nazwiemy inny algorytm, który przekształci te złożone wartości w dane o gęstości widmowej: jest to wartość wielkości (= intensywność) powiązana z każdym pasmem częstotliwości. Liczba pasm częstotliwości będzie taka sama jak liczba próbek.
Z pewnością znasz koncepcję korektora, taką jak ta. Powrót do lat 80. z korektorem graficznym. Cóż, uzyskamy ten sam rodzaj wyników, ale z 1024 pasmami zamiast 16 io wiele większą rozdzielczością intensywności. Kiedy korektor daje globalny obraz muzyki, dokładna analiza widmowa pozwala precyzyjnie obliczyć intensywność każdego z 1024 pasm.
Idealna koncepcja, ale:
- Ponieważ FFT jest cyfrową wersją transformaty Fouriera, przybliża sygnał cyfrowy i traci pewne informacje. Tak więc, ściśle mówiąc, wynik FFT po przekształceniu z powrotem za pomocą odwróconego algorytmu FFT nie dawałby dokładnie oryginalnego sygnału.
- Teoria ta uwzględnia również sygnał, który nie jest skończony, ale jest to zawsze trwający stały sygnał. Ponieważ będziemy go digitalizować tylko przez pewien czas (np. próbki), wprowadzimy trochę więcej błędów.
- Wreszcie rozdzielczość konwersji analogowo-cyfrowej wpłynie na jakość obliczanych wartości.
W praktyce
1) Częstotliwość próbkowania (oznaczona fs)
Będziemy próbkować sygnał, czyli mierzyć jego amplitudę, co 1/fs sekundy. fs to częstotliwość próbkowania. Na przykład, jeśli próbkujemy z częstotliwością 8 kHz, ADC (przetwornik analogowo-cyfrowy), który znajduje się na chipie, zapewni pomiar co 1/8000 sekundy.
2) Liczba próbek (z zaznaczeniem N lub próbek w kodzie)
Ponieważ musimy uzyskać wszystkie wartości przed uruchomieniem FFT, będziemy musieli je zapisać, a więc ograniczymy liczbę próbek. Algorytm FFT potrzebuje liczby próbek, która jest potęgą 2. Im więcej próbek mamy, tym lepiej, ale zajmuje dużo pamięci, tym bardziej, że będziemy potrzebować również do przechowywania przekształconych danych, które są wartościami złożonymi. Biblioteka Arduino FFT oszczędza trochę miejsca dzięki użyciu
- Jedna tablica o nazwie „vReal” do przechowywania próbkowanych danych, a następnie rzeczywistej części przekształconych danych
- Jedna tablica o nazwie „vImag” do przechowywania wyimaginowanej części przekształconych danych
Potrzebna ilość pamięci RAM wynosi 2 (tablice) * 32 (bity) * N (próbki).
Tak więc w naszej Atmega1284, która ma ładne 16 KB pamięci RAM, przechowamy maksymalnie N = 16000*8/64 = 2000 wartości. Ponieważ liczba wartości musi być potęgą 2, przechowamy maksymalnie 1024 wartości.
3) Rozdzielczość częstotliwości
FFT obliczy wartości dla tylu pasm częstotliwości, ile jest próbek. Pasma te będą rozciągać się od 0 Hz do częstotliwości próbkowania (fs). Stąd rozdzielczość częstotliwości to:
Rozdzielczość = fs / N
Rozdzielczość jest lepsza, gdy jest niższa. Więc dla lepszej rozdzielczości (niższej) chcemy:
- więcej próbek i/lub
- niższy fs
Ale…
4) Minimalny fs
Ponieważ chcemy zobaczyć wiele częstotliwości, niektóre z nich są znacznie wyższe niż "częstotliwość podstawowa", nie możemy ustawić fs zbyt nisko. W rzeczywistości istnieje twierdzenie o próbkowaniu Nyquista-Shannona, które zmusza nas do częstotliwości próbkowania znacznie powyżej dwukrotności maksymalnej częstotliwości, którą chcielibyśmy przetestować.
Na przykład, jeśli chcielibyśmy przeanalizować całe widmo od 0 Hz do powiedzmy 15 KHz, co jest w przybliżeniu maksymalną częstotliwością, którą większość ludzi może wyraźnie usłyszeć, musimy ustawić częstotliwość próbkowania na 30 KHz. W rzeczywistości elektronicy często ustawiają ją na 2,5 (lub nawet 2,52) * maksymalną częstotliwość. W tym przykładzie byłoby to 2,5 * 15 KHz = 37,5 KHz. Zwykłe częstotliwości próbkowania w profesjonalnym audio to 44,1 KHz (nagrywanie audio CD), 48 KHz i więcej.
Wniosek:
Punkty od 1 do 4 prowadzą do: chcemy użyć jak największej liczby próbek. W naszym przypadku z 16 kB pamięci RAM rozważymy 1024 próbki. Chcemy próbkować z najniższą możliwą częstotliwością próbkowania, o ile jest ona wystarczająco wysoka, aby analizować najwyższą częstotliwość, jakiej oczekujemy w naszym sygnale (przynajmniej 2,5 * ta częstotliwość).
Krok 3: Symulacja sygnału
Przy pierwszej próbie zmodyfikujemy nieco przykład TFT_01.ino podany w bibliotece, aby przeanalizować sygnał złożony z
- Częstotliwość podstawowa, ustawiona na 440 Hz (muzyka A)
- 3. harmoniczna przy połowie mocy podstawowej („-3 dB”)
- 5-ta harmoniczna przy 1/4 mocy podstawowej ("-6 dB)
Na powyższym obrazku widać wynikowy sygnał. Rzeczywiście wygląda to bardzo podobnie do rzeczywistego sygnału, który czasami można zobaczyć na oscyloskopie (ja nazwałbym go „Batmanem”) w sytuacji, gdy sygnał sinusoidalny jest przesterowany.
Krok 4: Analiza symulowanego sygnału - kodowanie
0) Dołącz bibliotekę
#include "arduinoFFT.h"
1. Definicje
W sekcjach deklaracji mamy
const bajt adcPin = 0; // A0
const próbki uint16_t = 1024; // Ta wartość MUSI ZAWSZE być potęgą 2 const uint16_t samplingFrequency = 8000; // Wpłynie na maksymalną wartość timera w timer_setup() SYSCLOCK/8/samplingFrequency powinna być liczbą całkowitą
Ponieważ sygnał ma piątą harmoniczną (częstotliwość tej harmonicznej = 5 * 440 = 2200 Hz) musimy ustawić częstotliwość próbkowania powyżej 2,5*2200 = 5500 Hz. Tutaj wybrałem 8000 Hz.
Deklarujemy również tablice, w których będziemy przechowywać dane surowe i obliczone
float vReal[przykłady];
float vImag[próbki];
2) Instancja
Tworzymy obiekt ArduinoFFT. Wersja dev ArduinoFFT używa szablonu, więc możemy użyć typu float lub double data. Float (32 bity) jest wystarczający ze względu na ogólną precyzję naszego programu.
ArduinoFFT FFT = ArduinoFFT(vReal, vImag, próbki, częstotliwość próbkowania);
3) Symulowanie sygnału przez wypełnienie tablicy vReal zamiast wypełniania jej wartościami ADC.
Na początku Loop wypełniamy tablicę vReal:
cykle zmiennoprzecinkowe = (((próbki) * częstotliwość sygnału) / częstotliwość próbkowania); //Liczba cykli sygnału, które odczyta próbkowanie
for (uint16_t i = 0; i < próbki; i++) { vReal = float((amplituda * (sin((i * (DWA_PI * cykle)) / próbki))));/* Zbuduj dane z dodatnimi i wartości ujemne*/ vReal += float((amplituda * (sin((3 * i * (DWA_PI * cykle)) / próbki))) / 2.0);/* Buduj dane z wartościami dodatnimi i ujemnymi*/ vReal += float((amplituda * (sin((5 * i * (DWA_PI * cykle)) / próbki))) / 4.0);/* Buduj dane z wartościami dodatnimi i ujemnymi*/ vImag = 0.0; //Część urojona musi być wyzerowana w przypadku zapętlenia, aby uniknąć błędnych obliczeń i przepełnień }
Dodajemy digitalizację fali podstawowej i dwóch harmonicznych o mniejszej amplitudzie. Następnie inicjujemy wyimaginowaną tablicę zerami. Ponieważ tablica ta jest wypełniana przez algorytm FFT, musimy ją wyczyścić ponownie przed każdym nowym obliczeniem.
4) Obliczenia FFT
Następnie obliczamy FFT i gęstość widmową
FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward);
FFT.compute(FFTDirection::Forward); /* Oblicz FFT */ FFT.complexToMagnitude(); /* Oblicz wielkości */
Operacja FFT.windowing(…) modyfikuje surowe dane, ponieważ FFT uruchamiamy na ograniczonej liczbie próbek. Pierwsza i ostatnia próbka wykazują nieciągłość (po jednej stronie nie ma „niczego”). To jest źródło błędu. Operacja „okienkowania” ma tendencję do zmniejszania tego błędu.
FFT.compute(…) o kierunku „Naprzód” oblicza transformację z dziedziny czasu do dziedziny częstotliwości.
Następnie obliczamy wartości wielkości (tj. Intensywności) dla każdego z pasm częstotliwości. Tablica vReal jest teraz wypełniona wartościami wielkości.
5) Rysunek seryjny plotera
Wydrukujmy wartości na ploterze szeregowym wywołując funkcję printVector(…)
PrintVector(vReal, (przykłady >> 1), SCL_FREQUENCY);
Jest to ogólna funkcja pozwalająca na drukowanie danych z osią czasu lub osią częstotliwości.
Drukujemy również częstotliwość pasma, które ma największą wartość amplitudy
float x = FFT.majorPeak();
Serial.print("f0="); Serial.print(x, 6); Serial.println("Hz");
Krok 5: Analiza symulowanego sygnału – wyniki
Widzimy 3 skoki odpowiadające częstotliwości podstawowej (f0), 3. i 5. harmonicznej, z połową i 1/4 wielkości f0, zgodnie z oczekiwaniami. W górnej części okna możemy odczytać f0=440.430114 Hz. Ta wartość nie jest dokładnie 440 Hz z powodów wyjaśnionych powyżej, ale jest bardzo zbliżona do rzeczywistej wartości. Tak naprawdę nie trzeba było pokazywać tylu nieznacznych cyfr dziesiętnych.
Krok 6: Analiza sygnału rzeczywistego – okablowanie ADC
Ponieważ wiemy, jak postępować w teorii, chcielibyśmy przeanalizować prawdziwy sygnał.
Okablowanie jest bardzo proste. Połącz ze sobą masy i linię sygnałową do pinu A0 swojej płytki poprzez rezystor szeregowy o wartości od 1 kOhm do 10 kOhm.
Ten rezystor szeregowy ochroni wejście analogowe i uniknie dzwonienia. Musi być tak wysoki, jak to możliwe, aby uniknąć dzwonienia, i tak niski, jak to możliwe, aby zapewnić wystarczający prąd do szybkiego ładowania ADC. Zapoznaj się z arkuszem danych MCU, aby poznać oczekiwaną impedancję sygnału podłączonego do wejścia ADC.
W tym pokazie użyłem generatora funkcji do podawania sinusoidalnego sygnału o częstotliwości 440 Hz i amplitudzie około 5 woltów (najlepiej, jeśli amplituda wynosi od 3 do 5 woltów, aby ADC był używany w pobliżu pełnej skali), przez rezystor 1,2 kΩ.
Krok 7: Analiza rzeczywistego sygnału - kodowanie
0) Dołącz bibliotekę
#include "arduinoFFT.h"
1) Deklaracje i instancje
W sekcji deklaracji definiujemy wejście ADC (A0), liczbę próbek oraz częstotliwość próbkowania, jak w poprzednim przykładzie.
const byte adcPin = 0; // A0
const próbki uint16_t = 1024; // Ta wartość MUSI ZAWSZE być potęgą 2 const uint16_t samplingFrequency = 8000; // Wpłynie na maksymalną wartość timera w timer_setup() SYSCLOCK/8/samplingFrequency powinna być liczbą całkowitą
Tworzymy obiekt ArduinoFFT
ArduinoFFT FFT = ArduinoFFT(vReal, vImag, próbki, częstotliwość próbkowania);
2) Konfiguracja timera i ADC
Ustawiamy timer 1 tak, aby pracował cyklicznie z częstotliwością próbkowania (8 kHz) i podniósł przerwanie przy porównywaniu danych wyjściowych.
void timer_setup(){
// zresetuj Timer 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; TCCR1B = bit (CS11) | bit (WGM12); // CTC, preskaler 8 TIMSK1 = bit (OCIE1B); OCR1A = ((16000000 / 8) / częstotliwość próbkowania) -1; }
I ustaw ADC tak
- Wykorzystuje A0 jako wejście
- Wyzwala się automatycznie na każdym wyjściu timera 1 porównaj mecz B
- Generuje przerwanie po zakończeniu konwersji
Zegar ADC jest ustawiony na 1 MHz, przez przeskalowanie zegara systemowego (16 MHz) o 16. Ponieważ każda konwersja zajmuje około 13 zegarów w pełnej skali, konwersje można osiągnąć z częstotliwością 1/13 = 0,076 MHz = 76 KHz. Częstotliwość próbkowania powinna być znacznie niższa niż 76 kHz, aby ADC miał czas na próbkowanie danych. (wybraliśmy fs = 8 KHz).
void adc_setup() {
ADCSRA = bit (ADEN) | bit (ADIE) | bit (ADIF); // włącz ADC, chcesz przerwać po zakończeniu ADCSRA |= bit (ADPS2); // Preskaler 16 ADMUX = bit (REFS0) | (adcPin i 7); // ustawienie wejścia ADC ADCSRB = bit (ADTS0) | bit (ADTS2); // Zegar/Licznik1 Porównaj źródło wyzwalacza dopasowania B ADCSRA |= bit (ADATE); // włącz automatyczne wyzwalanie }
Deklarujemy obsługę przerwań, która będzie wywoływana po każdej konwersji ADC w celu przechowywania przekonwertowanych danych w tablicy vReal i wyczyszczenia przerwania
// ADC kompletny ISR
ISR (ADC_vect) { vReal[numer wyniku++] = ADC; if(resultNumber == sample) { ADCSRA = 0; // wyłącz ADC } } EMPTY_INTERRUPT (TIMER1_COMPB_vect);
Możesz mieć wyczerpujące wyjaśnienie konwersji ADC na Arduino (analogRead).
3) Konfiguracja
W funkcji konfiguracji czyścimy wyobrażoną tabelę danych i wywołujemy funkcje konfiguracji timera i ADC
zeroI(); // funkcja, która ustawia na 0 wszystkie urojone dane - wyjaśnione w poprzedniej sekcji
timer_setup(); adc_setup();
3) Pętla
FFT.dcUsunięcie(); // Usuń składnik DC z tego sygnału, ponieważ ADC jest odniesiony do masy
FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward); // Dane ważenia FFT.compute(FFTDirection::Forward); // Oblicz FFT FFT.complexToMagnitude(); // Oblicz wielkości // drukowanie widma i częstotliwości podstawowej f0 PrintVector(vReal, (samples >> 1), SCL_FREQUENCY); float x = FFT.majorPeak(); Serial.print("f0="); Serial.print(x, 6); Serial.println("Hz");
Usuwamy składnik DC, ponieważ ADC jest odniesiony do masy, a sygnał jest wyśrodkowany wokół około 2,5 wolta.
Następnie obliczamy dane, jak wyjaśniono w poprzednim przykładzie.
Krok 8: Analiza rzeczywistego sygnału – wyniki
W rzeczywistości w tym prostym sygnale widzimy tylko jedną częstotliwość. Obliczona częstotliwość podstawowa to 440.118194 Hz. Tutaj znowu wartość jest bardzo bliskim przybliżeniem częstotliwości rzeczywistej.
Krok 9: A co z obciętym sygnałem sinusoidalnym?
Teraz pozwalamy trochę przesterować ADC, zwiększając amplitudę sygnału powyżej 5 woltów, więc jest on obcinany. Nie naciskaj zbyt mocno, aby nie zniszczyć wejścia ADC!
Widzimy pojawianie się niektórych harmonicznych. Obcinanie sygnału tworzy składowe o wysokiej częstotliwości.
Poznałeś podstawy analizy FFT na płycie Arduino. Teraz możesz spróbować zmienić częstotliwość próbkowania, liczbę próbek i parametr okienkowania. Biblioteka dodaje również kilka parametrów, aby szybciej obliczać FFT z mniejszą precyzją. Zauważysz, że jeśli ustawisz zbyt niską częstotliwość próbkowania, obliczone wielkości będą wyglądały na całkowicie błędne z powodu fałdowania widma.
Zalecana:
Jak zrobić analizator widma dźwięku LED: 7 kroków (ze zdjęciami)
Jak zrobić analizator widma dźwięku LED: Analizator widma dźwięku LED generuje piękny wzór oświetlenia w zależności od intensywności muzyki. Na rynku dostępnych jest wiele zestawów DIY LED Music Spectrum, ale tutaj stworzymy LED Audio Spectrum Analizator za pomocą NeoPixe
Analizator widma audio FFT DIY: 3 kroki
DIY FFT Audio Spectrum Analyzer: Analizator widma FFT to sprzęt testowy, który wykorzystuje analizę Fouriera i techniki cyfrowego przetwarzania sygnału w celu zapewnienia analizy widma. Stosując analizę Fouriera możliwe jest przeliczenie jednej wartości na przykład w dziedzinie czasu ciągłego
Neopixel Ws2812 Rainbow LED Glow z M5stick-C - Uruchamianie Rainbow na Neopixel Ws2812 przy użyciu M5stack M5stick C przy użyciu Arduino IDE: 5 kroków
Neopixel Ws2812 Rainbow LED Glow z M5stick-C | Uruchamianie Rainbow na Neopixel Ws2812 Używając M5stack M5stick C Używając Arduino IDE: Cześć chłopaki, w tej instrukcji dowiemy się, jak używać neopikselowych ws2812 LED lub taśmy LED lub matrycy LED lub pierścienia LED z płytką rozwojową m5stack m5stick-C z Arduino IDE i zrobimy wzór tęczy z nim
Analizator próbek skał: 4 kroki
Analizator próbek skał: Analizator próbek skał służy do identyfikacji i analizy rodzajów próbek skał przy użyciu techniki miękkich wibracji młotkowych. Jest to nowatorska metoda identyfikacji próbek skał. Jeśli znajduje się tam meteoryt lub jakakolwiek nieznana próbka skały, można oszacować
DIY lutownica na gorące powietrze przy użyciu 12-18 woltów prądu stałego przy 2-3 amperach: 18 kroków (ze zdjęciami)
DIY lutownica na gorące powietrze przy użyciu 12-18 woltów prądu stałego przy 2-3 amperach: to moja pierwsza publikacja eva artykułu o majsterkowaniu w Internecie. Więc przepraszam za literówki, protokoły itp. Poniższe instrukcje pokazują, jak zrobić PRACOWĄ lutownicę na gorące powietrze odpowiednią do WSZYSTKICH zastosowań wymagających lutowania. To lutowanie gorącym powietrzem