Zastosowania Procesorów Sygnałowych dr inż. Grzegorz Szwoch greg@multimed.org p. 732 - Katedra Systemów Multimedialnych Filtry FIR i biblioteka DSPLIB
Wstęp Na poprzednim wykładzie napisaliśmy algorytm liczący średnią ruchomą. Jest to przykład filtru FIR. Na tym wykładzie poruszymy następujące pojęcia. Podstawy filtrów FIR. Implementacja własnego kodu FIR w C. Wykorzystanie gotowego kodu napisanego w Asemblerze z biblioteki DSPLIB.
Filtry cyfrowe Filtry cyfrowe to algorytmy przetwarzania sygnału o wzmocnieniu zależnym od częstotliwości. Zadaniem filtrów jest wytłumienie wybranego zakresu częstotliwości. Filtry cyfrowe to podstawowy element algorytmów implementowanych na DSP. Dwa typy filtrów: FIR i IIR.
Filtry FIR FIR Finite Impulse Response Filtr cyfrowy o skończonej odpowiedzi impulsowej. Równanie różnicowe: y( n) = b0 x( n) + b1 x( n 1) + b2 x( n 2) +... + bn x( n N) N rządfiltru ile próbek wstecz b k współczynnikifiltru(n+1 współczynników) Transmitancja filtru FIR rzędu N: H ( z) = N k = 0 b k z k
Filtry FIR Schemat filtru typu FIR:
Charakterystyki filtrów
Parametry filtru Parametry projektowe filtru: częstotliwości graniczne szerokość pasma przejściowego poziom zafalowań w paśmie: przepustowym zaporowym
Rząd filtru Większy rząd filtru to: węższe pasmo przejściowe, mniejsze zafalowania. Ale większy rząd to także: większa liczba mnożeń(dłuższe przetwarzanie), większa zajętość pamięci (dłuższy bufor). Jak zawsze, musimy znaleźć złoty środek.
Rząd filtru Porównanie charakterystyk dla rzędu: 30, 60, 100
Projektowanie filtru FIR Projekt wykonujemy za pomocąoprogramowania (Matlab, python + scipy, itp.). Metoda okienkowania najprostsza: projektujemy pożądaną char. widmową obliczamy odpowiedź impulsową przez IFFT, wycinamy N próbek funkcją okna i przesuwamy. Metoda Parks-McClellan( Remez ) minimalizuje zafalowania. Standard w projektowaniu filtrów FIR.
Projektowanie filtru FIR Już na etapie projektowania filtru musimy myśleć o ewentualnych problemach z przepełnieniem. Filtr powinien byćzaprojektowany tak, aby jego maksymalne wzmocnienie wynosiło 1. Oprogramowanie powinno mieć taką funkcję. Jeżeli wzmocnienie filtru Gjest większe od 1, filtr trzeba unormowaćdzieląc współczynniki przez G.
Wzmocnienie filtru Wzór na wzmocnienie filtru FIR na częstotliwości f: G = N 1 k = 0 b k e f j2π k fs Dla filtru dolnoprzepustowego: obliczamy dla f= 0. Wzór upraszcza się do sumy współczynników. Dla f. górnoprzepustowego: liczymy dla częstotliwości Nyquista: f= fs/ 2 Dla f. pasmowo-przepustowego: f ze środka pasma.
Kwantyzacja współczynników Z oprogramowania dostajemy współczynniki w formie zmiennoprzecinkowej. Kwantyzacja współczynników konwersja na Q15 (przemnożenie przez 32768). Następnie: albo obcięciedo wartości całkowitej prostsze, ale zwiększa błędy kwantyzacji, albo zaokrąglenie mniejsze błędy, ale należy sprawdzićczy nie powoduje przepełnienia (maksymalna wartość nie może być > 32767). Dla bezpieczeństwa, można mnożyć przez 32767.
Kwantyzacja współczynników Szum kwantyzacji różnica między wynikiem filtracji dla filtru zmiennoprzecinkowego i skwantyzowanego (skala amplitudy ±0,0005)
Kwantyzacja współczynników O czym należy pamiętać: Kwantyzacja współczynników powoduje, że współczynniki filtru, a więc i jego charakterystyka, różnią się od tej otrzymanej z projektu. Szum kwantyzacji powoduje zniekształcenie wyników filtracji. Narażamy się na efekty przepełnienia zakresu.
Zapis współczynników w kodzie C W kodzie naszego programu zapisujemy współczynniki w formie stałej tablicy typu int. Przypominam: globalnie (nie w main!). Liczbę współczynników warto ustawić jako stałą. #define N 30 const int filtr_dp[] = {-4, 39, 97, 149, 133, -23, -337, -701, -883, -595, 360, 1955, 3883, 5634, 6677, 6677, 5634, 3883, 1955, 360, -595, -883, -701, -337, -23, 133, 149, 97, 39, -4}; Dobrym pomysłem jest zamieszczanie współczynników w osobnym pliku *.h.
Deklaracje zmiennych i buforów Bufor kołowy filtru deklarujemy globalnie. Bufor należy wypełnić zerami! int bufor[n]; int i; for (i = 0; i < N; i++) bufor[i] = 0; Deklaracje potrzebnych zmiennych: int indeks = 0; int poz; long wynik; // indeks bufora kołowego // pozycja odczytu z bufora // akumulator wyniku filtracji
Pętla przetwarzania // wejscie próbka odczytana z wejścia (int) bufor[indeks] = wejscie; poz = indeks; wynik = 0; // przefiltrowanie próbki wejscie for (i = 0; i < N; i++) { wynik = _smac(wynik, bufor[poz], filtr_dp[i]); poz = _circ_incr(poz, -1, N); } // wyjscie próbka wysyłana na wyjście (int) wyjscie = (int)(_sround(wynik) >> 16); // aktualizacja indeksu bufora kołowego indeks = _circ_incr(indeks, 1, N);
Typy filtrów liniowofazowych Filtry FIR projektuje się jako układy o liniowej fazie. Są cztery typy liniowofazowych filtrów FIR: typ I: nieparzysta liczba współczynników, symetryczna odpowiedź impulsowa nadaje się do wszystkich typów charakterystyki; typ II: parzysta / symetryczna tylko DP i P-Z; typ III: nieparzysta / antysymetryczna tylko P-P, typ IV: parzysta / antysymetryczna nie dla DP
Symetryczne filtry FIR Symetria odpowiedzi impulsowej: const int filtr_dp[] = {15, 58, 109, 135, 68, -151, -493, -796, -788, -201, 1076, 2884, 4798, 6263, 6812, 6263, 4798, 2884, 1076, -201, -788, -796, -493, -151, 68, 135, 109, 58, 15};
Symetryczne filtry FIR Możemy wykorzystać symetrię filtru aby zmniejszyć liczbęmnożeńo połowę. Np. dla filtru typu II o 30 współczynnikach: b0 = b29 (symetria) b 0 x(n) + b 29 x(n 29) = b 0 (x(n) + x(n 29)) Znacząco skraca to czas obliczeń, więc należy to wykorzystać. Dla typu I (nieparzysty) trzeba osobno dodać współczynnik bez pary.
Symetryczne filtry FIR Zmodyfikowany fragment //... int poz1 = indeks; int poz2 = _circ_incr(poz1, 1, N); int sumapr; // najnowsza próbka // najstarsza próbka for (i = 0; i < N/2; i++) { sumapr = _sadd(bufor[poz1], bufor[poz2]); wynik = _smac(wynik, sumapr, filtr_dp[i]); poz1 = _circ_incr(poz1, -1, N); poz2 = _circ_incr(poz2, 1, N); } // środkowy współczynnik (bez pary) if (N & 1) // nieparzyste N wynik = _smac(wynik, bufor[poz1], filtr_dp[i]);
Symetryczne filtry FIR Uwaga na sumowanie próbek: int sumapr = _sadd(bufor[poz1], bufor[poz2]); W tym miejscu niechybnie powstanie przepełnienie! Aby się przed nim uchronić, standardowo skaluje się próbki wejściowe, dzieląc je przez 2 (>>1). Po filtracji, wynik można z powrotem pomnożyć x2. Tracimy w ten sposób na precyzji zapisu liczb.
Symetryczne filtry FIR Można jeszcze szybciej. Nasz DSP ma specjalną instrukcjęfirsadd, która w jednym cyklu zegarowym wykonuje równolegle(naraz): mnożenie współczynnika przez sumępróbek i dodanie wyniku do sumy, oraz sumowanie kolejnych próbek przygotowanie do kolejnego cyklu. W języku C: instrukcja wewnętrzna _firsadd. Ta sama uwaga co do przepełnienia.
Przetwarzanie blokowe Przetwarzanie próbka po próbce nie jest wydajne. W algorytmach DSP zwykle stosuje sięprzetwarzanie blokowe: próbki z wejścia sązapisywane w buforze wejściowym, próbki z bufora wyjściowego sąwysyłane na wyjście, jeżeli bufor wejściowy jest pełny przetwarzamy cały bufor naraz.
Przetwarzanie blokowe Schemat przetwarzania blokowego bufor_wejscie[indeks_buf] = wejscie; wyjscie = bufor_wyjscie[indeks_buf]; indeks_buf++; // próbka z wejścia // próbka na wyjście if (indeks_buf == ROZMIAR_BUFORA) { // bufor zapełniony indeks_buf = 0; // przetwarzanie bufora wejściowego for (i = 0; i < ROZMIAR_BUFORA; i++) { // pobierz bufor_wejscie[i] // przefiltruj tak jak poprzednio // zapisz wynik do bufor_wyjscie[i] } }
Przetwarzanie blokowe Kiedy przetwarzanie próbka po próbce? Gdy zależy nam, aby przetworzona próbka jak najszybciej trafiła na wyjście. Kiedy przetwarzanie blokowe? Gdy zależy nam na wydajności przetwarzania, a małe opóźnienia nie są konieczne. Gdy algorytm wymaga obliczeńna bloku próbek (FFT, splot, itp.).
Filtry FIR w Asemblerze Smutna prawda: nie napiszemy w C wydajnego filtru FIR, który wykorzysta wszystkie możliwości naszego procesora sygnałowego. Trzeba sięgnąć po Asembler. Skoro filtry FIR to typowe algorytmy DSP, to na pewno ktośjużto napisał, prawda? Oczywiście, że tak. Odpowiedź brzmi: DSPLIB.
DSPLIB Co to jest DSPLIB: Zbiór typowych procedur na DSP firmy Texas Instruments filtry, FFT, itp. Napisane w Asemblerze, zoptymalizowane. Dostępny kod źródłowy możemy go modyfikować do celów naszych projektów! Opis w dokumencie o nazwie SPRU422J (można wpisać w Google).
Filtry FIR w DSPLIB Mamy trzy funkcje: fir standardowa implementacja, fir2 zoptymalizowana dla szybszego trybu dual MAC, wymaga spełnienia pewnych warunków co do alokacji buforów, firs szybsza implementacja filtrów symetrycznych, niestety, tylko parzystych (typ II), więc filtry DP i PZ. Osobno mamy specyficzne filtry FIR (Hilberta, decymacyjne, interpolacyjne i drabinkowe).
Jak czytaćdokumentację Z dokumentacji funkcji fir: Typ DATA jest synonimem int(16-bit). Gwiazdka (*) oznacza, że potrzebny jest wskaźnik: dla tablic (buforów): nazwa jest wskaźnikiem, dla zmiennych skalarnych : wskaźnik trzeba pobrać stawiając znak & przed nazwą.
FIR w DSPLIB Z dokumentacji dowiadujemy się, że potrzebny jest bufor roboczy: Musimy go sami utworzyć(oczywiście poza main!) #define N 30 // liczba współczynników DATA bufor_fir[n + 2]; const int filtr_dp[] = {...} // współczynniki filtru
FIR w DSPLIB Pierwszy przykład: przetwarzanie próbka po próbce. x próbki do przefiltrowania. U nas jedna próbka, więc &wejscie(wskaźnik!) h wektor współczynników filtru. Tu uwaga: mamy go jako const trzeba rzutować: (DATA*)filtr_dp r miejsce do zapisu przefiltrowanych próbek. Tak samo jak dla x: &wyjscie
FIR w DSPLIB Pierwszy przykład: przetwarzanie próbka po próbce. dbuffer bufor roboczy, który utworzyliśmy nx ile próbek przetwarzamy (tu: 1) nh liczba współczynników. Funkcja zwraca flagęinformującąo tym, czy wystąpiło przepełnienie. Nie przypisywaćjej do próbki wyjściowej!
FIR w DSPLIB Wywołanie dla przetwarzania próbka po próbce: fir(&wejscie, (DATA*)filtr_dp, &wyjscie, bufor_fir, 1, N); Analogicznie, dla przetwarzania blokowego: fir(bufor_wejscie, (DATA*)filtr_dp, bufor_wyjscie, bufor_fir, ROZMIAR_BUFORA, N);
FIR w DSPLIB Mamy teżw DSPLIB filtry zoptymalizowane, w tym symetryczne. Musimy spełnićwarunki określone w dokumentacji. Niezależnie od typu, pamiętajmy że to na nas spoczywa obowiązek zapewnienia, że nie wystąpi przepełnienie (np. przez skalowanie próbek):
Podsumowanie Cechy filtrów FIR: (+) łatwe w projektowaniu (+) bardzo proste w implementacji (+) mogąmiećliniowąfazę(i tak je projektujemy) (+) nie ma problemów ze stabilnością ( ) wymagająwysokiego rzędu, a więc dużej liczby cykli oraz dużej pamięci, aby uzyskać pożądaną charakterystykę(są dość wolne).
Podsumowanie Co musimy wiedzieć i umieć: Jak działa filtr FIR. Pojęcia: charakterystyka, rząd, współczynniki. Jak rząd filtru wpływa na kształt charakterystyki i na czas obliczeń. Jak zaprojektować filtr FIR. Jak skwantyzować współczynniki. Co to jest DSPLIB i jak tego używać. Jak uruchomić filtr FIR za pomocą DSPLIB.