Spisu treści:

EasyFFT: Szybka transformata Fouriera (FFT) dla Arduino: 6 kroków
EasyFFT: Szybka transformata Fouriera (FFT) dla Arduino: 6 kroków

Wideo: EasyFFT: Szybka transformata Fouriera (FFT) dla Arduino: 6 kroków

Wideo: EasyFFT: Szybka transformata Fouriera (FFT) dla Arduino: 6 kroków
Wideo: Dyskretne przekształcenie Fouriera (DFT), Szybka transformacja Fouriera (FFT) - Zadanie 2 2024, Listopad
Anonim
Image
Image

Pomiar częstotliwości z przechwyconego sygnału może być trudnym zadaniem, zwłaszcza na Arduino, ponieważ ma mniejszą moc obliczeniową. Dostępne są metody przechwytywania przejścia przez zero, gdzie częstotliwość jest wychwytywana przez sprawdzenie, ile razy sygnał przekracza linie zerowe w określonym czasie. Taka metoda może nie działać, gdy sygnał jest kombinacją różnych częstotliwości.

Jest to jakoś trudne do zakodowania, jeśli nie jesteś z takiego środowiska. Ale będąc majsterkowiczem ten kod może być bardzo przydatny w różnych projektach związanych z muzyką, analizą sygnału. Motywem tego projektu było przygotowanie kodu, który jest łatwy do zaimplementowania na Arduino bez wchodzenia w jego tło.

Ten projekt nie wyjaśnia działania FFT, ale wyjaśnia zastosowanie funkcji FFT. Ten sam proces wyjaśniono również w załączonym filmie.

Jeśli interesuje Cię tylko zastosowanie kodu, a nie jego wyjaśnienie. Możesz przejść bezpośrednio do kroku nr 3.

Krok 1: Wprowadzenie do transformacji częstotliwości

Wprowadzenie do transformacji częstotliwości
Wprowadzenie do transformacji częstotliwości
Wprowadzenie do transformacji częstotliwości
Wprowadzenie do transformacji częstotliwości

Każdy sygnał może składać się z kombinacji różnych fal sinusoidalnych. Tak więc każdy sygnał oparty na czasie może być również pokazany jako kombinacja różnych sinusów o różnych amplitudach.

Próbowałem wyjaśnić działanie DFT (dyskretnej transformacji Fouriera) w jednym z poprzednich instrukcji (https://www.instructables.com/id/Arduino-Frequency…). Te metody są bardzo powolne dla każdej aplikacji działającej w czasie rzeczywistym. co czyni go prawie bezużytecznym.

Na obrazku pokazany jest sygnał będący kombinacją dwóch częstotliwości f2 i f5. Sygnał ten jest mnożony przez testowe sinusoidy o wartościach od f1 do f5.

Z matematycznego punktu widzenia można wykazać, że -sumowanie mnożenia dwóch zbiorów danych harmonicznych o różnej częstotliwości dąży do zera (większa liczba danych może skutkować biciem). W naszym przypadku, jeśli te dwie częstotliwości mnożenia mają taką samą (lub bardzo bliską) częstotliwość, suma mnożenia jest liczbą niezerową.

Czyli jeśli nasz sygnał jest pomnożony przez f1 suma mnożenia wyniesie zero (blisko zeru dla rzeczywistego zastosowania). podobnie jest w przypadku f3, f4. Jednak dla tej wartości wyjście f2 i f5 nie będzie zerowe, ale znacznie wyższe niż pozostałe wartości.

Tutaj sygnał jest testowany z 5 częstotliwościami, więc sygnał musi być pomnożony przez pięć częstotliwości. Taka intensywna kalkulacja zajmuje więcej czasu. Wykazano matematycznie, że dla liczby N próbek pobiera N*N mnożenia zespolonego.

Krok 2: Szybka transformata Fouriera

Aby przyspieszyć obliczenia DFT, algorytm FFT został opracowany przez Jamesa Cooleya i Johna Tukeya. Algorytm ten jest również uważany za jeden z najważniejszych algorytmów XX wieku. Dzieli sygnał na nieparzystą i parzystą część sekwencjonowaną, co zmniejsza liczbę wymaganych obliczeń. Używając go można zredukować całkowite wymagane mnożenie zespolone do NlogN. co jest znaczącą poprawą.

Możesz odwołać się do poniższych odnośników, o których wspomniałem podczas pisania kodu, aby uzyskać szczegółowe zrozumienie matematyki stojącej za FFT:

1.

2.

3.

4.

Krok 3: Wyjaśnienie kodu

1. Szybki sinus i cosinus:

Obliczenie FFT przyjmuje wielokrotnie wartości różnych sinusów i cosinusów. Wbudowana funkcja Arduino nie jest wystarczająco szybka i zajmuje dużo czasu, aby zapewnić wymaganą wartość. Co sprawia, że kod jest znacznie wolniejszy (podwaja czas dla 64 próbek). Aby temu przeciwdziałać, wartość sinusa od 0 do 90 stopni jest przechowywana jako wielokrotność 255. Wyeliminuje to potrzebę przechowywania liczb jako zmiennoprzecinkowych i możemy przechowywać go jako bajt, który zajmuje 1/4 miejsca na Arduino. Sine_data należy wkleić na górze kodu, aby zadeklarować go jako zmienną globalną.

Oprócz sine_data, tablica o nazwie f_peaks zadeklarowana jako zmienna globalna. Po każdym uruchomieniu funkcji FFT tablica ta aktualizuje się. Gdzie f_peaks[0] to najbardziej dominująca częstotliwość, a kolejne wartości w kolejności malejącej.

byte sinus_data [91]= { 0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79, 83, 87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174, 177, 180, 183, 186, 189, 192, 195, 198, 201, 204, 206, 209, 211, 214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255 }; float f_peaks[5];

Ponieważ przechowujemy wartość sinusa od 0 do 90 stopni, można obliczyć dowolną wartość sinusa lub cosinusa. Poniżej funkcja pierwsza zaokrąglenie liczby do zera przecinka i zwrócenie wartości z zapisanych danych. ta metoda wymaga tylko jednego podziału zmiennego. Można to dodatkowo zredukować poprzez bezpośrednie przechowywanie wartości sinus (nie wielokrotności 255). ale to pochłania pamięć Arduino.

Zastosowanie powyższej procedury zmniejsza dokładność, ale poprawia szybkość. Dla 64 punktów daje to 8ms przewagi, a dla 128 punktów 20ms przewagi.

Krok 4: Wyjaśnienie kodu: Funkcja FFT

FFT można wykonać tylko dla wielkości próbki 2, 4, 8, 16, 32, 64 i tak dalej. jeśli wartość nie wynosi 2^n, to przyjmie niższą stronę wartości. Na przykład, jeśli wybierzemy wielkość próby 70, to uwzględni ona tylko pierwsze 64 próbki i pominie resztę.

Zawsze zaleca się, aby wielkość próbki wynosiła 2^n. który może być:

2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, …

Dwa zmiennoprzecinkowe out_r i out_im zajmują dużą ilość pamięci. dla Arduino nano nie będzie działać dla próbek wyższych niż 128 (aw niektórych przypadkach 128) z powodu braku dostępnej pamięci.

unsigned int data[13]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};

int a, c1, f, o, x; a=N; for(int i=0;i<12;i++) //obliczanie poziomów { if(data<=a){o=i;} } int in_ps[data[o]={}; //wejście do sekwencjonowania float out_r[data[o]={}; //rzeczywista część przekształcenia float out_im[data[o]={}; //wyimaginowana część przekształcenia

Dalszy przepływ jest następujący:

1. Kod generuje bitową odwróconą kolejność dla podanej wielkości próbki (szczegóły dotyczące odwrócenia bitów w referencjach: krok 2)

2. Dane wejściowe uporządkowane według wygenerowanego zamówienia, 3. Wykonano FFT

4. Amplituda obliczonej liczby zespolonej, 5. Piki są wykrywane i porządkowane w porządku malejącym

6. Wyniki można uzyskać z f_peaks.

[aby uzyskać dostęp do innych danych (oprócz częstotliwości szczytowej) należy zmodyfikować kod tak, aby zmienna lokalna mogła zostać skopiowana do jakiejś predefiniowanej zmiennej globalnej]

Krok 5: Testowanie kodu

Testowanie Kodeksu
Testowanie Kodeksu
Testowanie Kodeksu
Testowanie Kodeksu

Jako dane wejściowe podaje się przykładową falę trójkątną. dla tej fali częstotliwość próbkowania wynosi 10 Hz, a częstotliwość samej fali wynosi 1,25 Hz.

Jak widać na podstawie danych wyjściowych, wartość jest zgodna z FFT obliczoną przez Scilab. jednak te wartości nie są dokładnie takie same, jak nasza niska dokładność, ale szybsza fala sinusoidalna.

W tablicy częstotliwości wyjściowej częstotliwości wynoszą 1,25 i 3,75. nie jest konieczne każdorazowe uzyskiwanie dokładnej wartości. zazwyczaj te liczby są nazywane pojemnikami częstotliwości. więc wartość wyjściowa może znajdować się w dowolnym miejscu w określonych przedziałach.

Prędkość:

dla Arduino nano zajmuje:

16 punktów: 4ms32 punkty: 10ms 64 punkty: 26ms 128 punktów: 53ms

Krok 6: Wniosek

Ten kod FFT może być używany w aplikacjach czasu rzeczywistego. Ponieważ ukończenie obliczeń zajmuje około 30 ms. Jednak jego rozdzielczość jest ograniczona liczbą próbek. Liczba próbek jest ograniczona pamięcią Arduino. Dzięki zastosowaniu Arduino Mega lub innej wyższej wydajności można poprawić dokładność płyty.

jeśli masz jakieś pytania, sugestie lub poprawki, możesz je skomentować.

Aktualizacja (2/5/21)

Updates://-----------------------------Funkcja FFT--------------- -------------------------------//float FFT(int in, int N, float Częstotliwość)

Typ danych N zmienił się na Integer (istniejący Byte), aby obsłużyć rozmiar próbki >255. Jeśli wielkość próbki wynosi <=128, należy użyć typu danych bajtowych.

Zalecana: