Як уже згадували інші, вам слід розглянути фільтр IIR (нескінченний імпульсний відгук), а не фільтр FIR (скінченна імпульсна відповідь), який ви використовуєте зараз. Тут є більше, але на перший погляд фільтри FIR реалізуються як явні згортки та фільтри IIR з рівняннями.
Конкретний IIR фільтр, який я багато використовую в мікроконтролерах, - це однополюсний фільтр низьких частот. Це цифровий еквівалент простого RC-аналогового фільтра. Для більшості застосунків вони матимуть кращі характеристики, ніж коробчастий фільтр, який ви використовуєте. Більшість застосувань коробкового фільтра, які я стикався, є результатом того, що хтось не звертає уваги в класі цифрової обробки сигналів, а не внаслідок необхідності їх конкретних характеристик. Якщо ви просто хочете ослабити високі частоти, про які ви знаєте, шум, краще однополюсний низькочастотний фільтр. Найкращий спосіб впровадити один цифровий мікроконтролер:
FILT <- FILT + FF (НОВО - FILT)
FILT - шматок стійкого стану. Це єдина стійка змінна, яка вам потрібна для обчислення цього фільтра. NEW - нове значення, яке фільтр оновлюється за допомогою цієї ітерації. FF - фільтрова фракція , яка регулює «важкість» фільтра. Подивіться на цей алгоритм і побачите, що для FF = 0 фільтр нескінченно важкий, оскільки вихід ніколи не змінюється. Для FF = 1, це насправді зовсім не фільтр, оскільки вихід просто слідує за входом. Корисні значення знаходяться між ними. У невеликих системах ви вибираєте FF на рівні 1/2 Nтак що множення на FF може бути здійснено як правильний зсув на N біт. Наприклад, FF може бути 1/16, а множення на FF, отже, правильний зсув 4 біта. В іншому випадку для цього фільтра потрібно лише одне віднімання та одне додавання, хоча цифри зазвичай мають бути ширшими за вхідне значення (докладніше про числову точність в окремому розділі нижче).
Зазвичай я приймаю показання A / D значно швидше, ніж вони потрібні, і застосовую два з цих фільтрів каскадно. Це цифровий еквівалент двох RC-фільтрів послідовно і ослаблюється на 12 дБ / октаву вище частоти відкатки. Однак для читання A / D зазвичай більш релевантно дивитися на фільтр у часовій області, враховуючи його ступінчату відповідь. Це говорить про те, наскільки швидко ваша система побачить зміни, коли те, що ви вимірюєте, зміниться.
Для полегшення проектування цих фільтрів (що означає лише вибір FF та визначення кількості їх каскаду), я використовую свою програму FILTBITS. Ви визначаєте кількість бітів зсуву для кожного FF у каскадній серії фільтрів, і він обчислює ступінчасту відповідь та інші значення. Насправді я зазвичай запускаю це за допомогою мого сценарію обгортки PLOTFILT. Це запускає FILTBITS, який створює файл CSV, а потім малює файл CSV. Наприклад, ось результат "PLOTFILT 4 4":
Два параметри для PLOTFILT означають, що буде два фільтри, каскадні типу описаного вище. Значення 4 вказують на кількість бітів зсуву для реалізації множення на FF. Отже, два значення FF в цьому випадку становлять 1/16.
Червоний слід - це відповідь одиничного кроку, і це головне, на що слід звернути увагу. Наприклад, це говорить про те, що якщо вхід зміниться миттєво, вихід комбінованого фільтра осяде до 90% від нового значення за 60 ітерацій. Якщо вам важливо 95% часу відстоювання, тоді вам доведеться почекати приблизно 73 ітерації, а для 50% часу відстеження - лише 26 ітерацій.
Зелений слід показує вам вихід з одного шипа повного амплітуди. Це дає вам деяке уявлення про випадкове придушення шуму. Схоже, що жоден зразок не спричинить більше 2,5% зміни у виході.
Синій слід - це дати суб'єктивне відчуття того, що робить цей фільтр із білим шумом. Це не суворий тест, оскільки немає гарантії, який саме вміст був випадкових чисел, вибраних як вхід білого шуму для цього пробігу PLOTFILT. Це лише дати тобі грубе відчуття того, наскільки воно буде розчавлене і наскільки воно гладке.
PLOTFILT, можливо, FILTBITS та багато інших корисних речей, особливо для розробки програмного забезпечення PIC доступні у випуску програмного забезпечення PIC Tools на моїй сторінці завантаження програмного забезпечення .
Додано про числову точність
Я бачу з коментарів і тепер нову відповідь, що є інтерес до обговорення кількості бітів, необхідних для впровадження цього фільтра. Зауважте, що множення на FF створить Log 2 (FF) нові біти нижче бінарної точки. У малих системах FF зазвичай вибирається рівним 1/2 N, так що це множення реально реалізується правильним зсувом N біт.
Тому FILT зазвичай є цілим числом фіксованої точки. Зауважте, що це не змінює жодної математики з точки зору процесора. Наприклад, якщо ви фільтруєте 10-бітові читання A / D і N = 4 (FF = 1/16), тоді вам знадобляться 4 дроби фракції нижче 10-бітових цілих чисел A / D. Один з найбільш процесорів, ви б виконували 16-бітові цілочисельні операції через 10-бітових A / D показань. У цьому випадку ви все ще можете виконати абсолютно ті ж 16-бітові цілочисельні операції, але почніть з зчитування A / D зліва, зміщеного на 4 біти. Процесор не знає різниці і не потребує цього. Виконання математики на цілих 16 бітових цілих числах працює, чи вважаєте ви їх 12,4 фіксованою точкою або справжніми 16-бітовими цілими числами (16,0 фіксованою точкою).
Взагалі вам потрібно додати N біт на кожен полюс фільтра, якщо ви не хочете додавати шум через числове представлення. У наведеному вище прикладі, другий фільтр з двох повинен мати 10 + 4 + 4 = 18 біт, щоб не втратити інформацію. На практиці на 8-бітовій машині, що означає, що ви використовуєте 24-бітні значення. Технічно лише другий полюс з двох потребує ширшого значення, але для простоти вбудованого програмного забезпечення я зазвичай використовую те саме представлення, і тим самим той самий код, для всіх полюсів фільтра.
Зазвичай я пишу підпрограму або макрос для виконання однієї операції зі стовпом фільтра, а потім застосовую її до кожного полюса. Будь підпрограма чи макрос залежить від того, чи важливіші цикли чи пам'ять програми у цьому конкретному проекті. Так чи інакше, я використовую деякий стан подряпин, щоб передати NEW в підпрограму / макрос, який оновлює FILT, але також завантажує його в той самий стан подряпини NEW. Це полегшує застосування декількох полюсів, оскільки оновлений FILT одного полюса є НОВИЙ наступний. У підпрограмі корисно мати вказівник на FILT на шляху, який оновлюється відразу після FILT на виході. Таким чином підпрограма автоматично працює на послідовних фільтрах у пам'яті, якщо їх викликає кілька разів. З макросом вам не потрібен вказівник, оскільки ви передаєте адресу для роботи над кожною ітерацією.
Приклади коду
Ось приклад макросу, як описано вище для PIC 18:
////////////////////////////////////////////////// //////////////////////////////
//
// Фільтр макросів FILTER
//
// Оновіть один полюс фільтра новим значенням у NEWVAL. NEWVAL оновлено до
// містять нове відфільтроване значення.
//
// FILT - назва змінної стану фільтра. Передбачається, що це 24 біта
// широкий і в місцевому банку.
//
// Формула оновлення фільтра:
//
// FILT <- FILT + FF (NEWVAL - FILT)
//
// Множення на FF здійснюється правильним зсувом бітів FILTBITS.
//
/ макрофільтр
/ писати
dbankif lbankadr
movf [arg 1] +0, w; NEWVAL <- NEWVAL - FILT
subwf newval + 0
movf [arg 1] +1, ж
subwfb newval + 1
movf [arg 1] +2, ш
subwfb newval + 2
/ писати
/ loop n filtbits; один раз за кожен біт зміщувати NEWVAL вправо
rlcf newval + 2, w; зсунути NEWVAL вправо на один біт
rrcf newval + 2
rrcf newval + 1
rrcf newval + 0
/ endloop
/ писати
movf newval + 0, w; додайте зміщене значення у фільтр та збережіть у NEWVAL
addwf [arg 1] +0, ш
movwf [arg 1] +0
movwf newval + 0
movf newval + 1, w
addwfc [arg 1] +1, ш
movwf [arg 1] +1
movwf newval + 1
movf newval + 2, ш
addwfc [arg 1] +2, ш
movwf [arg 1] +2
movwf newval + 2
/ endmac
І ось подібний макрос для PIC 24 або dsPIC 30 або 33:
////////////////////////////////////////////////// //////////////////////////////
//
// Макрос FILTER ffbits
//
// Оновлення стану одного фільтра низьких частот. Нове вхідне значення знаходиться у W1: W0
// і стан фільтра, який потрібно оновити, вказується на W2.
//
// Оновлене значення фільтра також буде повернуто у W1: W0 і W2 вкажуть
// до першої пам'яті минулого стану фільтра. Таким макросом може бути такий
// посилається послідовно оновлювати серію каскадних фільтрів низьких частот.
//
// Формула фільтра:
//
// FILT <- FILT + FF (NEW - FILT)
//
// де множення на FF виконується арифметичним зсувом правої частини
// FFBITS.
//
// ПОПЕРЕДЖЕННЯ: W3 скидається.
//
/ макрофільтр
/ var new ffbits integer = [arg 1]; отримайте кількість бітів для зсуву
/ писати
/ write "; Виконайте однополюсну фільтрацію низьких частот, біт shift =" ffbits
/ написати ";"
sub w0, [w2 ++], w0; НОВО - ФІЛЬТ -> W1: W0
subb w1, [w2--], w1
lsr w0, # [v ffbits], w0; змістіть результат на W1: W0 вправо
sl w1, # [- 16 ffbits], w3
ior w0, w3, w0
asr w1, # [v ffbits], w1
додайте w0, [w2 ++], w0; додайте FILT, щоб отримати остаточний результат у W1: W0
addc w1, [w2--], w1
mov w0, [w2 ++]; результат запису до стану фільтра, вказівник заздалегідь
mov w1, [w2 ++]
/ писати
/ endmac
Обидва ці приклади реалізовані у вигляді макросів за допомогою мого препроцесора асемблеру PIC , який є більш здатним, ніж будь-який із вбудованих макро-засобів.