Zastosowania Procesorów Sygnałowych dr inż. Grzegorz Szwoch greg@sound.eti.pg.gda.pl p. 732 - Katedra Systemów Multimedialnych Filtry FIR i IIR
Plan wykładu Filtry FIR Instrukcje wewnętrzne DSP Filtry IIR Biblioteka DSPLIB
Wprowadzenie Filtry cyfrowe sąpodstawowym algorytmem implementowanym na DSP. Filtry modyfikujązakres przenoszonych częstotliwości tłumią( wycinają ) wybrane zakresy częstotliwości. Sąstosowane w wielu praktycznych systemach telekomunikacyjnych.
Wprowadzenie Rodzaje filtrów charakterystyka: filtry dolnoprzepustowe (ang. low pass, LP) filtry górnoprzepustowe(ang. high pass, HP) filtry pasmowo-przepustowe (ang. band pass, BP) filtry pasmowo-zaporowe (ang. band stop, BS) Rodzaje filtrów transmitancja: filtry FIR (ang. Finite Impulse Response) filtry IIR (ang. Infinite Impulse Response)
Ruchoma średnia Prosty przykład: obliczanie ruchomej średniej y( n) = 0,25 x( n) + 0,25 x( n 1) + 0,25 x( n 2) + 0.25 x( n 3)
Filtr FIR Filtr o skończonej odpowiedzi impulsowej FIR H ( z ) 1 2 = b + b z + b z + L 0 1 2 + b N z N
Filtr dolnoprzepustowy Charakterystyka filtru dolnoprzepustowego
Filtr górnoprzepustowy Charakterystyka filtru górnoprzepustowego
Projektowanie filtrów FIR Zakładamy parametry: typ charakterystyki, rząd filtru, częstotliwość graniczna, itp. Do projektowania używamy gotowego oprogramowania, np. MATLAB, Python. Normalizujemy współczynniki filtru b n tak, aby ich suma nie przekraczała 1. Zamieniamy je na liczby Q15 (x 32768). Zapisujemy otrzymane współczynniki w tablicy języka C.
Projektowanie filtrów FIR Przykładowa definicja współczynników #define N 51 // rząd filtru liczba współczynników const int High_Pass_Filter_500Hz[N] = { -35, -41, -50, -62, -79, -99, -122, -149, -180, -213, -249, -287, -326, -366, -407, -447, -486, -523, -557, -589, -617, -640, -659, -672, -681, 32116, -681, -672, -659, -640, -617, -589, -557, -523, -486, -447, -407, -366, -326, -287, -249, -213, -180, -149, -122, -99, -79, -62, -50, -41, -35 };
Instrukcje wewnętrzne DSP Procesor DSP ma specjalne instrukcje skracające czas wykonywania typowych operacji. Możemy z nich korzystać programując w asemblerze. Ale równieżw kodzie C mamy do nich dostęp za pomocąspecjalnych poleceń, nazywanych instrukcjami wewnętrznymi, ang. intrinsics. Skracają i upraszczają one pisany kod. Obie wersje (normalna i intrinsics) powinny być przez kompilator zamienione na ten sam kod, ale nie musi tak być.
Instrukcje wewnętrzne Przykład 1: bufor kołowy // inkrementacja wskaźnika wersja standardowa indeks += 1; if (indeks >= N) // zawinięcie wskaźnika indeks -= N; Instrukcja _circ_incr krótszy zapis: indeks = _circ_incr(indeks, 1, N); // działa też w drugą stronę: indeks = 0; indeks = _circ_incr(indeks, -1, N); // indeks == N-1
Instrukcje wewnętrzne Przykład 2: mnożenie liczb Q15 // y = a * b wersja standardowa int y = (int)(((long)a * b) >> 15); Instrukcja _smpy prostszy zapis int y = _smpy(a, b); // jeśli chcemy liczbę long: long y2 = _lsmpy(a, b);
Instrukcje wewnętrzne Przykład 3: dodawanie liczb Q15 Musimy sprawdzać czy nie ma przepełnienia: long tmp = (long)a + b; if (tmp > 32767) tmp = 32767; int y = (int)tmp; Instrukcja _sadd dużo krócej: int y = _sadd(a, b); // odejmowanie y2 = a - b: int y2 = _ssub(a, b);
Instrukcje wewnętrzne Przykład 4: dodawanie iloczynów Przy obliczaniu filtru FIR dokonujemy wielu mnożeń i dodajemy wynik do sumy: // suma = suma + bn * xn // suma jest Q30 (long) suma += (long)xn * bn; Jest to operacja MAC: multiply and accumulate suma = _smac(xn, bn); // UWAGA: suma jest zapisywana jako Q31 int wynik = (int)(suma >> 16);
Implementacja FIR na DSP Jesteśmy gotowi do implementacji. Deklaracje i definicje ogólne: #define N 51 // liczba wsp. rząd filtru const int wsp = { /* współczynniki filtru */ }; int bufor[n]; // bufor kołowy dla próbek int indeks = 0; // wskaźnik najnowszej próbki
Implementacja FIR na DSP Obliczanie wyniku dla próbki x: // y = fir(x, bufor, wsp) bufor[indeks] = x; // zapisanie bieżącej próbki long suma = 0; // akumulator int i = 0; int poz = indeks; // wskaźnik obliczanej próbki for (i = 0; i < N; i++) { suma = _smac(suma, bufor[poz], wsp[i]); poz = _circ_incr(poz, -1, N); // przesunięcie ind. } indeks = _circ_incr(indeks, 1, N); int y = (int)(suma >> 16); // wynik filtracji return y;
Symetryczne filtry FIR Liniowofazowe filtry FIR są zwykle symetryczne współczynniki filtru sąlustrzanym odbiciem względem (N-1)/2: b(n) = b(n n+1), n = 1,, (N 1)/2 Możemy to wykorzystać, redukując o połowę liczbę mnożeń! Liczba współczynników musi być nieparzysta. Jest też specjalna instrukcja : _firs
Symetryczne filtry FIR Symetryczna odpowiedź impulsowa FIR
Symetryczne filtry FIR Zmodyfikowany fragment: //... int poz1 = indeks; // najnowsza próbka int poz2 = _circ_incr(poz1, 1, N); // najstarsza próbka for (i = 0; i < N/2; i++) { suma = _smac(suma, bufor[poz1]+bufor[poz2], wsp[i]); poz1 = _circ_incr(poz1, -1, N); poz2 = _circ_incr(poz2, 1, N); } // środkowy współczynnik (składowa stała) suma = _smac(suma, bufor[poz1], wsp[i]); //...
Filtry IIR Filtry o nieskończonej odpowiedzi impulsowej Posiadają zera i bieguny Transmitancja: N N N N z a z a z a z b z b b z b z H + + + + + + + + = L L 2 2 1 1 2 2 1 1 0 1 ) (
Filtry IIR Wykonywanie dzielenia na DSP nie jest najszybsze. Stosuje się formę bezpośrednią. Filtr drugiego rzędu (dwukwadratowy), ang. biquad: H b + Rozwinięty zapis: b z + b 1 2 0 1 2 ( z) = 1 2 1+ a1z + a2z z
Filtry IIR Forma bezpośrednia Directform I
IIR implementacja na DSP Mały rząd nie stosujemy bufora kołowego // int b0, b1, b2, a1, a2 współczynniki // int x0, x1, x2, y1, y2 zapamiętane próbki x2 = x1; x1 = x0; x0 = x; long suma = (long)x0 * b0 + (long)x1 * b1 + (long)x2 * b2 - (long)y1 * a1 (long)y2 * a2; int y = (int)(suma >> 15); y2 = y1; y1 = y; return y;
IIR implementacja na DSP Uwagi implementacyjne. Wzmocnienie filtru nie może przekraczać 1. Suma cząstkowa może potencjalnie przekroczyć wartość 1 i spowodować przepełnienie. Warto skorzystać z 40-bitowego akumulatora. Przy małych rzędach filtru (2-3) nie opłaca się używać bufora kołowego. Często projektuje sięsekcje dwukwadratowe i łączy się je kaskadowo.
Jeszcze o filtrach IIR Directform II mniejsza liczba elementów opóźniających 2) ( 1) ( ) ( ) ( 2) ( 1) ( ) ( ) ( 2 1 0 2 1 + + = = n w b n b w n w b n y n w a n w a n x n w
Porównanie FIR/IIR Filtry FIR: (+) mogąmiećliniowąfazę, (+) sązawsze stabilne (+) mniejsze błędy zaokrągleń (-) wymagająwiększego rzędu niżiir, co za tym idzie: większa liczba operacji, większa zajętość pamięci
Porównanie FIR/IIR Filtry IIR: (-) zniekształcają fazę, (-) mogą być niestabilne (-) błędy zaokrągleń kumulują się (+) wymagająmniejszego rzędu niżiir, zatem są znacznie mniej złożone obliczeniowo (mniej cykli procesora dla uzyskania takiego samego efektu filtracji)
Filtry w asemblerze Napisanie optymalnego algorytmu filtracji FIR/IIR na DSP wymaga użycia asemblera. Jest to oczywiście trudniejsze niżw C. Filtracja jest podstawowąoperacjąna DSP, zatem istniejąjużgotowe, zoptymalizowane algorytmy w asemblerze. Producenci DSP zwykle dostarczajągotowe biblioteki podstawowych procedur.
Biblioteka DSPLIB Biblioteka DSPLIB dla procesorów Texas Instrumentszawiera zestaw zoptymalizowanych procedur w asemblerze. Mamy szereg implementacji filtrów IIR i FIR. Należy z nich korzystaćw praktycznych zastosowaniach. Przy kompilacji należy podać odpowiednią bibliotekę, np. 55xdsph.lib.
DSPLIB - FIR #include <dsplib.h> #define N 51 // liczba wsp. rząd filtru const DATA wsp = { /* współczynniki filtru */ }; int bufor[n+2]; // wewnętrzny bufor kołowy int i; for (i = 0; i < N+2; i++) bufor[i] = 0; // obliczenia dla każdej kolejnej próbki // DATA x : próbka wejściowa DATA y; fir(&x, (DATA*)wsp, &y, bufor, 1, N); // y zawiera wynik filtracji. I gotowe! // instrukcja fir zajmuje (N+2) + 25 cykli zegarowych
DSPLIB - FIR Funkcje fir z DSPLIB mogą przetwarzać więcej niż jedną próbkę(przetwarzanie blokowe), np.: int x_buf[512]; // próbki do przetworzenia int y_buf[512]; // wyniki //... fir(x_buf, (DATA*)wsp, y_buf, bufor, 512, N); Dla symetrycznego filtru FIR, np. N= 50: // wsp zawiera współczynniki b0...b24 firs(&x, (DATA*)wsp, &y, bufor, 1, 25);
DSPLIB - IIR Filtr dwukwadratowy 2. rzędu (Direct form I) #include <dsplib.h> const DATA wsp = { /* b0, b1, b2, a1, a2 */ }; int bufor[5]; // wewnętrzny bufor kołowy int i; for (i = 0; i < 5; i++) bufor[i] = 0; // obliczenia dla każdej kolejnej próbki // DATA x : próbka wejściowa DATA y; iircas51(&x, (DATA*)wsp, &y, bufor, 1, 1); // instrukcja iircas51 zajmuje 81 cykli zegarowych
Dokumentacja Dla procesorów DSP TMS320C55x: instrukcje wewnętrzne (intrinsics): TMS320C55x OptimizingC/C++ CompilerUser sguide, rozdział 6.5.5.1 (szukać w Google: SPRU281G) biblioteka DSPLIB: TMS320C55x DSP Library Programmer s Reference (SPRU422J) http://www.ti.com/product/tms320c5535/technicaldocuments