Monday 15 October 2012

Digital Filters on ARDUINO!!!!!

My next task is to implement Digital filters on Arduino........
We live in a analog world. Everything "Natural" around us is analog in nature. But ,we being Engineers,love the Digital way. So in order to communicate with digital world, we need Sensors and ADCs. Sensors convert various quantities around us into analog electrical signals which are digitized using ADC. But during this Analog to digital conversion noise creeps into our system and it becomes necessary to remove that noise and extract only the required signals. Then comes into existence the filters.
Digital filters as the name suggests filters digitally.Or in other words it filters digital signals. Basically, it is use to implement a filter in software. This has an advantage over normal analog signals, that their properties can be changed by just changing the program. In contrast, to change the properties of an analog filter, we need to change the entire filter design.Then comes the importance of digital filters. Digital Filters are omnipresent. Any system which interfaces with the outside world or use sensors ,use s filters , most of which are digital.

A digital filter is characterized by its transfer function. Mathematical analysis of the transfer function can describe how it will respond to any input.

The transfer function for a linear, time-invariant, digital filter can be expressed as a transfer function in the z-domain; 


where the order of the filter is the greater of N or M.

This is the form for a recursive filter with both the inputs (Numerator) and outputs (Denominator), which typically leads to an IIR infinite impulse response behaviour, but if the denominator is made equal to unity i.e. no feedback, then this becomes an FIR or finite impulse response filter.
My aim is to implement Digital Filters on Arduino. I wanted to make FIR filters(all types). For an FIR filter transfer function has denominator equal to unity. The coefficients in the transfer function of equation ..1 can
be determined using MATLAB....
MATLAB (MATrix LABoratory) is a numerical computing environment and fourth-generation programming language. MATLAB attracts users from various backgrounds of engineering,science, and economics. We can determine FIR filter coefficients using fir1( ) command in MATLAB. Once we have coefficients, the rest part is simple. Now we are all set to write an arduino program for implementing digital filters.

The program is:

/*
  This is Program to implement three dgital filters:
  (1) 200Hz-600Hz
  (2) 600Hz-1200Hz
  (3) 1200Hz-2400Hz
  The output can be verified using a function generator and reading relative              magnitudes of output on Serial Monitor and on Oscilloscope if you have DACs 
*/
#define M 50
#define N 65
#include<avr/io.h>
#include<avr/delay.h>
#include <util/delay.h>
uint16_t x[N];                    //Samples

// Filter coefficiants to implement Three Digital Filters
int32_t b1[N]={1,0,-3,-5,-7,-8,-5,0,8,17,25,28,23,6,-25,-72,-134,-205,-280,-349,-401,-425,-413,-360,-262,-124,44,231,418,589,725,813,844,813,725,589,418,231,44,-124,-262,-360,-413,-425,-401,-349,-280,-205,-134,-72,-25,6,23,28,25,17,8,0,-5,-8,-7,-5,-3,0,1};
int32_t b2[N]={-3,-2,3,12,22,27,20,0,-30,-58,-69,-55,-21,14,29,11,-25,-45,-9,101,256,382,388,214,-128,-538,-855,-923,-668,-139,493,1001,1196,1001,493,-139,-668,-923,-855,-538,-128,214,388,382,256,101,-9,-45,-25,11,29,14,-21,-55,-69,-58,-30,0,20,27,22,12,3,-2,-3};
int32_t b3[N]={0,11,15,-4,-23,-14,6,0,-9,30,72,18,-89,-92,5,22,-39,45,240,174,-200,-368,-92,107,-80,-25,662,929,-288,-1827,-1380,998,2406,998,-1380,-1827,-288,929,662,-25,-80,107,-92,-368,-200,174,240,45,-39,22,5,-92,-89,18,72,30,-9,0,6,-14,-23,-4,15,11,0};

uint16_t a;
uint16_t i;

void InitADC()                    // Function to initialise ADC Channel
{
ADMUX=(1<<REFS0); 
ADMUX&=~((1<<REFS1)|(1<<ADLAR)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0));                      
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); 
}

uint16_t ReadADC(uint8_t ch)      // Function to read value of ADC
{
   ch=ch&0b00000111;
   ADMUX|=ch;
   ADCSRA|=(1<<ADSC);
   while(!(ADCSRA & (1<<ADIF)));
   //_delay_ms(1000);
   ADCSRA|=(1<<ADIF);
   return(ADC);
}
void setup()          //Setup Function to intialise ADC and Serial Communication
{
DDRC=0x00;            //PORTC as INPUT
DDRD=0xFF;            //PORTD is OUTPUT
DDRD=0xFF;
for(i=0;i<N;i++)
  {
    InitADC();
    a=ReadADC(4);
    x[i]=a;
  }
  Serial.begin(9600);
}

int32_t num1=0,num2=0,num3=0,y1[M],y2[M],y3[M],sum1=0,sum2=0,sum3=0,ans1=0,ans2=0,ans3=0;    // Various variables to determine Y-OUTPUT

void loop()            //Loop Function
{
  for(int i=0;i<M;i++)
  {
    num1=0;                //cumulative summation of filter1
    num2=0;                //cumulative summation of filter2
    num3=0;                //cumulative summation of filter3
    for(int j=0;j<N;j++)    // taking Samples
    {
      InitADC();
      x[j]=ReadADC(4);
    }
    for(int k=0;k<N;k++)   //Convolution
    {
      num1+=b1[k]*x[N-1-k];        //Filter1
      num2+=b2[k]*x[N-1-k];        //Filter2
      num3+=b3[k]*x[N-1-k];        //Filter3
    }
    
    y1[i]=num1/10000;              //Normalisation
    y2[i]=num2/10000;
    y3[i]=num3/10000;    
  }
    
  //Now take RMS values
  for(int i=0;i<M;i++)
  {
    sum1+=y1[i]*y1[i];
    sum2+=y2[i]*y2[i];
    sum3+=y3[i]*y3[i];
  }
  sum1/=M;
  sum2/=M;
  sum3/=M;
  ans1=sqrt(sum1);
  ans2=sqrt(sum2);
  ans3=sqrt(sum3);
  
  // Printing them on Serial Monitor
  Serial.print("200-600Hz::");
  Serial.println(ans1);
  Serial.print("600-1200Hz::");
  Serial.println(ans2);
  Serial.print("1200-2400Hz::");
  Serial.println(ans3);
  
  //Checking the OUTPUT on Oscilloscope
  dacx(ans1);
  dacy(ans2);
}

void dacx(unsigned char a)            // Function to write values on one of the DACs DACx
{
  byte k=0;
   for(unsigned char i=0;i<2;i++)
    {
      k=a&(1<<i);
      if(k)
      PORTB|=(1<<i);
      else
      PORTB&=~(1<<i);      
    }
   for(unsigned char i=0;i<6;i++)
    {
      k=a&(1<<(i+2));
      if(k)
      PORTD|=(1<<(7-i));
      else
      PORTD&=~(1<<(7-i));     
    }


void dacy(unsigned char a)              // Function to write values on one of the DACs DACy
{
  byte k=0;
  for(unsigned char i=0;i<4;i++)
    {
      k=a&(1<<i);
      if(k)
      PORTC|=(1<<(3-i));
      else
      PORTC&=~(1<<(3-i));     
    }
  for(unsigned char i=0;i<4;i++)
    {
      k=a&(1<<(i+4));
      if(k)
      PORTB|=(1<<(5-i));
      else
      PORTB&=~(1<<(5-i));
    }
}



12 comments:

  1. Hi, i got a question on how to get the filter coefficiants? let say if i wanted a filter of 20-100Hz, 2400Hz- 4800Hz, etc etc... hope to hear from you..

    ReplyDelete
  2. Hello Ong..!!
    I used a function 'fir1' in MATALB.
    The syntax of this function is
    b = fir1(n,Wn)
    b = fir1(n,Wn,'ftype')
    b = fir1(n,Wn,window)
    b = fir1(n,Wn,'ftype',window)
    b = fir1(...,'normalization')

    DESCRiPTION: fir1 implements the classical method of windowed linear-phase FIR digital filter design. It designs filters in standard lowpass, highpass, bandpass, and bandstop configurations. By default the filter is normalized so that the magnitude response of the filter at the center frequency of the passband is 0 dB.

    b = fir1(n,Wn) returns row vector b containing the n+1 coefficients of an order n lowpass FIR filter. This is a Hamming-window based, linear-phase filter with normalized cutoff frequency Wn. The output filter coefficients, b, are ordered in descending powers of z.

    If Wn is a two-element vector, Wn = [w1 w2], fir1 returns a bandpass filter with passband w1 < ω< w2.

    If Wn is a multi-element vector, Wn = [w1 w2 w3 w4 w5 ... wn], fir1 returns an order n multiband filter with bands 0 < ω< w1, w1 < ω< w2, ..., wn < ω< 1.


    b = fir1(n,Wn,'ftype') specifies a filter type, where 'ftype' is:

    'high' for a highpass filter with cutoff frequency Wn.
    'stop' for a bandstop filter, if Wn = [w1 w2]. The stopband frequency range is specified by this interval.
    'DC-1' to make the first band of a multiband filter a passband.
    'DC-0' to make the first band of a multiband filter a stopband.

    fir1 always uses an even filter order for the highpass and bandstop configurations. This is because for odd orders, the frequency response at the Nyquist frequency is 0, which is inappropriate for highpass and bandstop filters. If you specify an odd-valued n, fir1 increments it by 1.

    b = fir1(n,Wn,window) uses the window specified in column vector window for the design. The vector window must be n+1 elements long. If no window is specified, fir1 uses a Hamming window (see hamming) of length n+1.

    b = fir1(n,Wn,'ftype',window) accepts both 'ftype' and window parameters.

    b = fir1(...,'normalization') specifies whether or not the filter magnitude is normalized. The string 'normalization' can be the following:

    'scale' (default): Normalize the filter so that the magnitude response of the filter at the center frequency of the passband is 0 dB.
    'noscale': Do not normalize the filter.

    The group delay of the FIR filter designed by fir1 is n/2.

    Apart from this, you can also use GUI functions available in MATLAB. You can always use it. They also give same coefficients.

    Hope it helps..!!

    ReplyDelete
  3. Hi, my question is if I want to implement IIR filter, how should I do that?

    ReplyDelete
  4. what is your sampling frequency?

    ReplyDelete
  5. The sampling freq is the maximum achievable by an Arduino running at 16MHz. I did not give any delay between samples. So the time between two samples is the time to execute instructions between two sampling instructions.

    ReplyDelete
  6. a small correction : the time between two samples is not the "time to execute instructions between two sampling instructions", which is very small if your cas, but it is 13 cycles of adc frequency, this frequency being the processor freq (16MHz) divided by a divider between 1 and 128. So I would suspect that your sampling rate is not exactly what you thought. Maybe you could be sure of this by outputing 1 and 1 on a digital pin that you can observe with your scope
    Very, very nice work anyway !

    ReplyDelete
    Replies
    1. Very nice work. He used a prescaler of 128 for his ADC clock. It's in his InitADC() routine. That's 125kHz sampling frequency

      Delete
    2. I am sorry. You are correct.
      And Thank you.

      Delete
  7. hello, i have a project in which i need to to deteced a car horn frequency range 2400-2500Hz but i didn't get the fir1 function or how to enter my parameters in order to get cofficient [N,WN,bandpass,]
    is it right?
    and also how to enter WN i want 2400-2500HZ
    thank you
    regards

    ReplyDelete
  8. If you are using MATLAB, you can read this: http://in.mathworks.com/help/signal/ref/fir1.html , this link explains the usage of fir1 function with examples.

    For ocatve, which is an open source software, read this:
    http://octave.sourceforge.net/signal/function/fir1.html

    ReplyDelete
  9. How can we implement the filter which has both num and den ???

    ReplyDelete
  10. Hello,
    For my ECG project , I want to remove powerline interference noise from ecg signal.it frequency is 50hz.i want to do it on arduino. How can I do that..how can I implement a band stop filter using arduino

    ReplyDelete