Простой цифровой фильтр на микроконтроллере

Введение

   Во многих цифровых устройствах для преобразования аналоговых сигналов используется АЦП. Часто аналоговые сигналы содержат нежелательный высокочастотный шум. 
   Чтобы "очистить" сигнал от этих шумов применяются аналоговые RC фильтры низких частот, которые устанавливаются после источника сигнала. Такой подход не всегда идеален и практичен. Например, для больших постоянных времени требуются большие значения R и C.
   В качестве альтернативы, можно "очистить" зашумленный сигнал с помощью цифрового эквивалента аналогового RC фильтра нижних частот. 

Алгоритм цифрового фильтра

   По сути, программа этого цифрового фильтра состоит всего из двух строчек на Си.:

Dacc = Dacc + Din - Dout
Dout = Dacc/K

где Dout - выходное значение фильтра, Din - входное значение фильтра, K - постоянный коэффициент, который рассчитывается по формуле:

K = T x SPS

где T - это постоянная времени фильтра, SPS - частота дискретизации АЦП.

   Dacc и Dout должны сохранять свои значения, после выполнения алгоритма. Если алгоритм реализовать в виде функции, то эти переменные можно просто сделать статическими.

   Для 8-ми разрядных входных данных алгоритм цифрового фильтра в Си коде может выглядеть так:

#define SPS 9600UL 
#define Trc 0.001f
#define K (SPS*Trc)

uint8_t Filtr(uint8_t data)
{
   static uint16_t Dacc = 0;
   static uint8_t Dout = 0;
   uint8_t Din = data;

   Dacc = Dacc + Din - Dout;
   Dout = Dacc/(uint16_t)K;

   return Dout;
}


Пример реализации цифрового фильтра на mega16

   Для наглядности рассмотрим реальный пример использования этого алгоритма в микроконтроллере AVR atmega16. Допустим мы хотим сымитировать RC фильтр с постоянной времени 0.001 c. Схема представлена на рисунке ниже. 

аналоговый RC фильтр низкой частоты


R1 = 10 кОм 
C1 = 0.1 мкФ
Trc = R1*C1 = 10000 Ом * (0.1/1000000) Ф = 0.001 с
F = 1/(2*Pi*R1*C1) = 1/(6.28 * Trc) = ~50 Гц 

   Тактовая частота модуля АЦП в микроконтроллерах AVR зависит от его тактовой частоты и внутреннего предделителя. Допустим, наш микроконтроллер тактируется от внутреннего генератора с частотой 8 МГц, а предделитель в модуле АЦП установлен равным 64. Тогда тактовая частота модуля АЦП будет равна:

Fadc = Fcpu/Pre = 8000000/64 = 125000 Гц

   Из этой частоты можно рассчитать частоту дискретизации АЦП при работе в режиме непрерывного преобразования. Она равна отношению тактовой частоты АЦП к количеству тактов, которые требуются для выполнения одного преобразования. По даташиту можно узнать, что одно преобразование выполняется за 13 тактов (если это не первое преобразование).

Fs = Fadc/n = 125000/13 = ~9600 Гц

Итак, частота дискретизации равна 9600 Гц, а постоянная времени 0.001 с. Коэффициент фильтра будет равен:

K = SPS x T = 9600 * 0.001 = 9.6 = ~ 10

Теперь все данные известны и можно написать тестовую программу для проверки алгоритма. 

   Я сделал эту программу очень простой. АЦП работает в режиме непрерывного преобразования. В прерывании 8-ми разрядный результат преобразования обрабатывается алгоритмом и записывается в порт C. К порту C подключен схема R-2R ЦАПа на основе резисторов, чтобы можно было сравнить полученный сигнал с сигналом от аналогового RC фильтра. Тактовая частота микроконтроллера atmega16 - 8МГц, коэффициент предделителя АЦП - 64. Тестовая схема показана на рисунке ниже. 

схема для тестирования цифрового фильтра


Код программы 


#include <ioavr.h>
#include <intrinsics.h>
#include <stdint.h>

#define SPS 9600UL
#define Trc 0.001f
#define K (SPS*Trc)

int main( void )
{
/*инициализация АЦП*/
 ADMUX = (0<<REFS1)|(1<<REFS0)|(1<<ADLAR);
 ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);

/*инициализация порта*/
 DDRC = 0xff;
 PORTC = 0x00;

 __enable_interrupt(); 
 while(1); 
 return 0;
}

/*обработчик прерывания АЦП*/
#pragma vector = ADC_vect
__interrupt void Adc(void)
{
 static uint16_t Dacc = 0;
 static uint8_t Dout = 0;
 uint8_t Din = ADCH;

 Dacc = Dacc + Din - Dout;
 Dout = Dacc/(uint16_t)K;

 PORTC = Dout; 
}


   Результат моделирования

   Результат моделирования программы в Proteus`e показан на рисунке ниже. Красный сигнал - это входной меандр частотой 200 Гц, синий - сигнал на выходе RC фильтра с постоянной времени 0.001 с, а желтый - сигнал обработанный микроконтроллером. Он имеет ступенчатую форму, так как после ЦАПа не подвергался фильтрации.

   Как видно из рисунка форма сигнала микроконтроллера достаточно точно повторяет сигнал с выхода RC фильтра. 

результаты моделирования цифрового фильтра в Proteus`e


Заключение

   Для наибольшего быстродействия коэффициент К лучше выбирать кратным степени 2 (например 2, 4, 8..), тогда компилятор будет заменять операцию деления сдвигами. В противном случае при высокой частоте дискретизации, микроконтроллер может не успевать рассчитывать следующее выходное значение фильтра. Я столкнулся с этим при моделировании. 
   Также необходимо учесть тот момент, что при больших значениях коэффициента К, переменная Dacc должна иметь достаточную разрядность, чтобы не наступало ее переполнение.

Файлы

rc-filtr-iar.rar


У вас недостаточно прав для комментирования.