ЛР5(а) > Реалізація КІХ – фільтру: блоковий фільтр

Тема: Розробка фільтру із кінцевою імпульсною характеристикою блокового типу

 

КІХ– фільтри (фільтри з кінцевою імпульсною характеристикою) широко використовуються в різноманітних областях цифрової обробки сигналів, таких як аудіо- та відео- обробка, бездротовий зв’язок, медичні прилади та інше. Для багатьох практичних застосувань, таких як бездротовий зв’язок (БДКР – багатостанційний доступ з кодовим розділенням каналів / БДЧР – багатостанційний доступ з розділенням каналів у часі), потокове відео (MPEG/JPEG) та передача голосу по IP мережам (протокол Інтернету) (VoIP), цифрові вибірки вхідного сигналу, зазвичай, згруповані у кадри з часовою тривалістю від декількох мілісекунд до декількох сотень мілісекунд. Можливі два варіанти обчислення алгоритму цифрової фільтрації – блокова (обробляється одночасно декілька відліків вхідного сигналу) та послідовна (обробляється лише один наступний відлік вхідного сигналу) фільтрація. Зрозуміло, що більш ефективною є блокова обробка. Наведений нижче приклад являє собою програму на мові С обчислення КІХ– фільтру (fir.c), спроектованого для послідовної обробки сигналу. Вона легко може бути змінена на програму блокової обробки, тобто реалізацію блокового фільтру.

Приклад 1: Програма на мові С, яка реалізує КІХ-фільтр що послідовно обробляє М вхідних відліків сигналу.

 



Як правило, при розробці та відпрацюванні програмного забезпечення для ЦОС, використовуються різноманітні методи симуляції та емуляції. Вони також є дуже корисними при вивченні та аналізі алгоритмів ЦОС. Використовуючи програму генератора сигналу, можна створювати необхідні сигнали для застосування в процесі налагодження та аналізу алгоритму. Нижче наведено приклад програми генератора синусного сигналу (signal_gen.c), яка може бути використана для генерації вхідних експериментальних даних (файлу input5.dat) для перевірки роботи фільтру.



Приклад 2: програма генератора синусного сигналу для перевірки.

 

Завдання А.

Реалізація блокового КІХ-фільтру

 

Наведений вираз:


відображає алгоритм роботи КІХ-фільтра. Він включає до себе два різних процеси: (1) Перший виконує додавання результатів множення відліків вхідного сигналу на коефіцієнти фільтру; (2) Другий поновлює масив зберігання вхідного сигналу для включення до нього нової вибірки. Щоб виконати операцію фільтрації КІХ-фільтром з L коефіцієнтами (фільтр L-порядку), необхідно виконати L операцій множення та (L-1) операцій додавання. Крім того, потрібні додаткові операції для переміщення даних у пам’яті. Поновлення масиву вхідного сигналу в прикладі 1 потребує виконання операції зсуву у пам’яті. Операція зсуву (L-1) вибірок в масиві вхідного сигналу потребує додаткових командних циклів. Зазначені операції роблять задачу реалізації КІХ-фільтра для мікропроцесорів загального призначення достатньо складною, яка потребує великого об’єму обчислення.

Процесор TMS320C55x має наступні важливі особливості, які суттєво спрощують алгоритм реалізації КІХ-фільтру. Його система команд включає операції множення з накопиченням які виконуються за один цикл. Це означає, що процесор С55х може завершити обчислення для одного каскаду фільтру в кожному машинному циклі. В прикладі 1, поновлення масиву вхідного сигналу шляхом зміщення даних у пам’яті, потребує виконання декількох операцій по переміщенню даних. На практиці, можна використовувати оператори циклу. Фрагмент програми на мові асемблер, який використовує операції циклу для реалізації КІХ-фільтра, наведений в прикл.3. Щоб вилучити програмний контроль за виконанням циклу, в процесорі TMS320C55х використовується спеціальне апаратне забезпечення, що дозволяє реалізувати лічильники циклу. Воно дозволяє підтримувати до трьох рівней вкладеності циклів за допомогою регістрів BRC0, BRC1 та CSR.

 


 

Прикл.3 Фрагмент програми на мові асемблер, який використовує операції циклу для реалізації КІХ-фільтра.

 

В даному прикладі використовуються чотири допоміжні регістри-вказівники, AR0-AR3. AR0 вказує адресу розміщення масиву вхідного сигналу in[]. Масив сигналу x[], на адресу якого вказує регістр AR3, містить черговий відлік даних x(n) та (L-1) попередніх відліків. На адресу коефіцієнтів фільтру (масив h[]) вказує регістр AR1. На кожному кроці зовнішнього циклу нова вибірка розміщується в масиві сигналу, а внутрішній цикл повторює команди множення з накопиченням. Наприкінці, вихідні дані фільтру y(n) округлюються та зберігаються в масиві вихідних даних out[], на адресу якого вказує регістр AR2. Регістри AR1 та AR3 використовуються у режимі циклічної адресації. Значення в регістрі-вказівникі AR1 змінюється циклічно, таким чином, в кінці обчислення регістр знову буде вказувати на перший коефіцієнт фільтру.

В програмі на мові асемблер до лічильника повторень CSR завантажується значення L-3 (буде виконано L-2 ітерацій). Така кількість ітерацій визначена тому, що одна команда множення використовується до початку циклу, а ще одна команда множення з накопиченням та округленням результату – після закінчення циклу. Програма на мові асемблер (fir.asm), яка реалізує алгоритм роботи КІХ-фільтру, наведена нижче.

;

; fir.asm – Generic FIR filter

;

; prototype: unsigned int fir(int *, unsigned int, int *,

; unsigned int, int *, int *, unsigned int);    

;

; Entry: arg0: AR0 – filter input buffer pointer

; arg1: T0 – number of samples in input buffer

; arg2: AR1 – FIR coefficients array pointer

; arg3: T1 – FIR filter order

; arg4: AR2 – output buffer pointer

; arg5: AR3 – signal buffer pointer

; arg6: AR4 – signal buffer index

;

; Return: T0 = signal buffer index

;

.def _fir

.sect “fir_code”

    

_fir

pshm ST1_55 ; Save ST1, ST2, and ST3

pshm ST2_55

pshm ST3_55

        

or #0x340,mmap(ST1_55); Set FRCT,SXMD,SATD

bset SMUL ; Set SMUL

mov mmap(AR1),BSA01 ; AR1=base address for coeff

mov mmap(T1),BK03     ; Set coefficient array size

mov mmap(AR3),BSA23 ; AR3=base address for signal buffer

or #0xA,mmap(ST2_55) ; AR1 & AR3 as circular pointers

mov #0,AR1 ; Start from zero offset

mov AR4,AR3 ; Start with offset=index

sub #1,T0 ; T0=M-1

mov T0,BRC0 ; Init outer loop for M times

sub #3,T1,T0 ; T0=L-3

mov T0,CSR ; Init inner loop L-2 times

|| rptblocal sample_loop-1 ; Start the outer loop

mov *AR0+,*AR3 ; Put the new sample to signal buffer

mpym *AR3+,*AR1+,AC0 ; Do the 1st operation

|| rpt CSR ; Start the inner loop

macm *AR3+,*AR1+,AC0

macmr *AR3,*AR1+,AC0 ; Do the last operation     

mov hi(AC0),*AR2+ ; Save Q15 filtered value

sample_loop

 

popm ST3_55 ; Restore ST1, ST2, and ST3

popm ST2_55

popm ST1_55    

mov AR3,T0 ; Return signal buffer index

|| ret

.end

 

Головна програма на мові С (exp5A.c) зчитує вхідні дані з файлу input5.dat, та викликає підпрограму fir() для виконання алгоритму низькочастотної фільтрації. Глобальна змінна index зберігає індекс масиву вхідного сигналу для відстеження початкової позиції при кожному зчитуванні чергового блоку вибірки сигналу.

Компілятор процесора С55х підтримує декілька спеціальних директив. Найбільш часто використовуються з них дві – CODE_SECTION та DATA_SECTION, що призначені для розміщення даних та програм в спеціальних областях пам’яті процесора. Повний перелік підтриманих директив мови С наведено у настанові користувача по оптимізації роботи компілятора мови С для процесора TMS320C55x.

Нижче наведена головна програма (exp5A.c) на мові С.

 

/*

exp5a.c – Block FIR filter function experiment

using input data file

*/

#define M 128 /* Input sample size */

#define L 48 /* Number of FIR filter coefficients */

#define SN L /* Signal buffer size */

extern unsigned int fir(int *, unsigned int, int *, unsigned int, int *, int *, unsigned int);

 

/* Define DSP system memory map */

#pragma DATA_SECTION(LP_h, “fir_coef”);

#pragma DATA_SECTION(x, “fir_data”);

#pragma DATA_SECTION(index, “fir_data”);

#pragma DATA_SECTION(out, “output”);

#pragma DATA_SECTION(in, “input”);

#pragma DATA_SECTION(input, “input”);

#pragma CODE_SECTION(main, “fir_code”);

 

/* Input data */

#include “input5.dat”

 

/* Low-pass FIR filter coefficients */

int LP_h[L]={

-6,28,46,27,-35,-100,-93,26,191,240,52,-291,-497,-278,

337,888,773,-210,-1486,-1895,-442,2870,6793,9445,

9445,6793,2870,-442,-1895,-1486,-210,773,888,337,

-278,-497,-291,52,240,191,26,-93,-100,-35,27,46,28,-6};

 

int x[SN]; /* Signal buffer */

unsigned int index; /* Signal buffer index */

int out[M]; /* Output buffer */

int in[M]; /* Input buffer */

 

void main(void)

{

unsigned int i,j;

 

/* Initialize filter signal buffer */

for (i=0; i<SN;i++)

x[i]=0;    

index = 0;

 

/* Processing samples using a block FIR filter */

j=0;

for (;;)

{

for (i=0; i<M; i++)

{

in[i]=input[j++];    /* Get a buffer of samples */

if (j == 160)

j=0;

}

index=fir(in,M,LP_h,L,out,x,index); /* FIR filter */

}

}

CODE_SECTION – це директива, що розміщує об’єктні коди програми до вказаного сегменту пам’яті програм. Синтаксис даної директиви задається так:

#pragma CODE_SECTION(func_name, “section_name”);

 

де func_name – це назва функції (підпрограми) на мові С, яка буде розміщена в сегменті пам’яті програм, який визначений ім’ям section_name. Командний файл компоновника використовує цю директиву для визначення та виділення спеціальних сегментів пам’яті програм, і розміщення там вказаної функції.

DATA_SECTION – це директива, що розміщує дані у відповідні, зазначені сегменти пам’яті даних. Синтаксис даної директиви задається так:

 

#pragma DATA_SECTION(var_name, “section_name”);

 

де var_name це ім’я змінної, яка знаходиться у програмі, і яка буде розміщена в сегменті пам’яті даних, який визначений ім’ям section_name. Командний файл компоновника використовує цю директиву для виділення сегменту пам’яті даних і розміщення там вказаної змінної.

 

Виконайте наступні кроки:

 

1. Створіть новий проект у середовищі CCS; назвіть його expА та збережіть його у відповідній директорії. Напишіть програму exp5А.с на основі наведеного вище коду. Скопіюйте командний файл лінкера exp5.cmd з директорії вхідних даних до завдання. Додайте до проекту файли exp5А.с, exp5.cmd, fir.asm. Підключить бібліотеку засобів динамічної підтримки rst55.lib (розташована у директорії C:\ti\c5500\cgtools\lib). Запустіть програму на компіляцію. Використайте згенерований файл input5.dat (розміщений в директорії вхідних даних до завдання), як вхідний сигнал для обробки.

2. Завантажте програму до процесора. Відкрийте чотири графічних вікна для перегляду вхідного сигналу, його спектру, вихідного сигналу та його спектру. Параметри налагодження графічних вікон наведені на рис.1.



Рис.1 Приклад настройки графічних вікон для виведення вхідного та вихідного сигналів.

3. Встановіть точку переривання в передостанньому рядку головної програми exp5А.с. Запустіть програму на виконання в режимі анімації. Проаналізуйте отриманий результат.