Softverska realizacija
Jedan od softverskih načina direktne realizacije FIR filtera je sledećia C funkcija:
void Filter(Int16 *input, Int16 *h, Int16 *output,
Int16 NumOfInput, Int16 NumOfCoeff) {
volatile Int16 i,j;
volatile Int32 y;
static Int16 xind = 0;
static Int32 x[NumOfCoeff];
volatile Int16 hind;
ST1_55 |= 0x2000; // Pali LED
for (j=0; j<NumOfInput; j++) {
y=0; // resetuj izlaz
x[xind] = input[j]; // ubaci ulaz u baffer
hind = NumOfCoeff – xind - 1;
for (i=0; i<NumOfCoeff; i++) {
y += h[hind] * x[i];
if (++hind == NumOfCoeff) hind=0;
}
if (++xind == NumOfCoeff) xind=0;
output[j] = (Int16)(y >> 15); // izlaz Q15
}
ST1_55 &= 0xDFFF; // Gasi LED
}
Funkcija kao parametre ima:
- input – ulazni bafer, bafer u kome se nalaze podaci dobijeni AD konverzijom.
- h – koeficijenti filtera,
- output – izlazni bafer, bafer u kome se nalaze podatci koji će biti poslati na DA konverziju.
- NumOfInput – veličina bafera,
- NumOfCoef – broj koeficijenata
U našem slučaju SampleRate je 48kHz, što znači da nam je vreme između dva odbirka 1/48000=0.000020833s=0.020833ms=20.833us. To znači da imamo vremena od ~21us da izfiltriramo ulaz, pre nego što stigne sledeći odbirak na red. To je veoma tesno vreme. Ovo možemo “povećati” tako što ćemo baferovati podatke. Za baferovanje se koristi DMA. DSP zada komandu DMA da napuni bafer i dok ova (DMA) to radi, DSP radi obradu. Kada DMA napuni bafer, imamo vremena, do punjenja sledećeg bafera, da obradimo pristigli bafer.
Paljenje i gašenje LED u ovoj funkciji služi za merenje vremena rada same funkcije. Što LED jače svetli, to funkcija ima manje “slobodnog” vremena.
U petlji, linija 12, uzima se po jedan odbirak iz ulaznog bafera i smešta u privremeni (delay) bafer (linija 14). Kada se taj podatak obradi (linije 16-19), vrednost Y (pogledaj formulu) šalje se izlaznom baferu. S obzirom da je rezultat 32-obitni, a da je moguće poslati 16-obitni broj, potrebno je 32-obitni broj “pretvoriti” u 16-obitni format Q15. To se najbrže radi šiftovanjem za 15 mesta desno i kastovanjem u Int16 format (linija 21). Kod u liniji 15 postavlja vrednost indeksa koeficijenata, a kod u liniji 20 glumi kružni bafer.
Kada posmatramo sliku na kojoj je prikazana direktna realizacija FIR filtera, softverska realizacija bi bila, da pre nego što ubacimo podatak na nulti indeks u delay baferu, prvo šiftujemo taj bafer, za jedno mesto, kako bi nulti indeks pripremili za novi podatak, a najstariji podatak izbacili iz bafera. Samo šiftovanje bafera je vremenski zahtevan posao, stoga, to nećemo raditi nego ćemo baratanjem sa indeksima u baferima i pokušati da simuliramo kružni bafer. Ovde ćemo imati dva “kružna” bafera. U jednom će se nalaziti koeficijenti filtera (h), a drugi će biti delay bafer (x).
Pretpostavimo sledeće:
- NumOfInput = 8
- NumOfCoef = 4
Pogledajmo impulsni odziv filtera, videćemo da je simetričan i da je h[0]=h[poslednji] odnosno da je h[1]=h[pretposlednji]. Postoje i antisimetrični filteri ali se njima nećemo baviti.
Evo tabelarnog prikaza kako je to izvedeno u ovom primeru.
Koraci 1-4
korak | j | xind | i | hind |
---|---|---|---|---|
1 | 0 | 0 | 0 | 3 |
2 | 1 | 0 | ||
3 | 2 | 1 | ||
4 | 3 | 2 |
Komentar
y=h[3]*x[0]+h[0]*x[1]+h[1]*x[2]+h[2]*x[3]
Ovde je x[0] najnoviji podatak. Ovo je prvi korak i u x[1]-x[3] nalaze se nule, nisu popunjeni sa podacima.
Koraci 5-8
korak | j | xind | i | hind |
---|---|---|---|---|
5 | 1 | 1 | 0 | 2 |
6 | 1 | 3 | ||
7 | 2 | 0 | ||
8 | 3 | 1 |
Komentar
y=h[2]*x[0]+h[3]*x[1]+h[0]*x[2]+h[1]*x[3]
Sada je x[1] najnoviji podatak i moramo mu prilagoditi indekse. Uvek se najnoviji podatak množi sa nutim koeficijentom.
Koraci 9-12
korak | j | xind | i | hind |
---|---|---|---|---|
9 | 2 | 2 | 0 | 1 |
10 | 1 | 2 | ||
11 | 2 | 3 | ||
12 | 3 | 0 |
Komentar
y=h[1]*x[0]+h[2]*x[1]+h[3]*x[2]+h[0]*x[3]
Uz najnoviji x[2] nameštamo koefivijent h[3]. i dalje nemamo dovoljno podataka da se napuni poslednji član delay bufera.
Koraci 13-16
korak | j | xind | i | hind |
---|---|---|---|---|
13 | 3 | 3 | 0 | 0 |
14 | 1 | 1 | ||
15 | 2 | 2 | ||
16 | 3 | 3 |
Komentar
y=h[0]*x[0]+h[1]*x[1]+h[2]*x[2]+h[3]*x[3]
Uz najnoviji x[3] nameštamo koeficijent h[3]. Sad je ceo filter utisnut u bafer, a ujedno je i delay bafer napunjen podacima.
Koraci 17-20 ...
korak | j | xind | i | hind |
---|---|---|---|---|
17 | 4 | 4 | 0 | 3 |
18 | 1 | 0 | ||
19 | 2 | 1 | ||
20 | 3 | 2 |
Komentar
y=h[3]*x[4]+h[1]*x[1]+h[2]*x[2]+h[3]*x[3]
Uz najnoviji x[4] nameštamo koefivijent h[3] i tako redom. Delay buffer je definisan kao static tako da ce podaci u njemu ostati za sledeci ulazni bafer.
Obrada će trajati NumOfInput * NumOfCoef, u ovom slučaju 8*4=32 ciklusa. Ukoliko imamo da je broj koeficijenata 32, a veličina bafera 64, broj koraka će biti 2048 i cela obrada će trajati 1310us. Da bi se napunio bafer veličine 64, potrebno je 20.833us*64 = 1333us što znači da je obrada na granici da propusti sledeći bafer.