Low-Pass IIR Filter code

Hi,

The following code reacts to low frequencies. I am trying to understand the code:

// Arduino Beat Detector By Damian Peckett 2015
// License: Public Domain.

// Our Global Sample Rate, 5000hz
#define SAMPLEPERIODUS 200

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) //sfr = special fuction register , _BV converts a bit number into a BYTE. http://electronics.arunsworld.com/basic-avr/
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void setup() {
    // Set ADC to 77khz, max for 10bit
    sbi(ADCSRA,ADPS2);
    cbi(ADCSRA,ADPS1);
    cbi(ADCSRA,ADPS0);
  Serial.begin(9600);
    //The pin with the LED
    pinMode(2, OUTPUT);
}

// 20 - 200hz Single Pole Bandpass IIR Filter
float bassFilter(float sample) {
    static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
    xv[0] = xv[1]; xv[1] = xv[2]; 
    xv[2] = sample / 9.1f;
    yv[0] = yv[1]; yv[1] = yv[2]; 
    yv[2] = (xv[2] - xv[0])  + (-0.7960060012f * yv[0]) + (1.7903124146f * yv[1]);
    return yv[2];
}

// 10hz Single Pole Lowpass IIR Filter
float envelopeFilter(float sample) { //10hz low pass
    static float xv[2] = {0,0}, yv[2] = {0,0};
    xv[0] = xv[1]; 
    xv[1] = sample / 160.f;
    yv[0] = yv[1]; 
    yv[1] = (xv[0] + xv[1]) + (0.9875119299f * yv[0]);
    return yv[1];
}

// 1.7 - 3.0hz Single Pole Bandpass IIR Filter
float beatFilter(float sample) {
    static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
    xv[0] = xv[1]; xv[1] = xv[2]; 
    xv[2] = sample / 7.015f;
    yv[0] = yv[1]; yv[1] = yv[2]; 
    yv[2] = (xv[2] - xv[0])
        + (-0.7169861741f * yv[0]) + (1.4453653501f * yv[1]);
    return yv[2];
}

void loop() {
    unsigned long time = micros(); // Used to track rate
    float sample, value, envelope, beat, thresh;
    unsigned char i;

    for(i = 0;;++i){
        // Read ADC and center so +-512
        sample = (float)analogRead(0)-503.f;

        // Filter only bass component
        value = bassFilter(sample);

        // Take signal amplitude and filter
        if(value < 0)value=-value;
        envelope = envelopeFilter(value);

        // Every 200 samples (25hz) filter the envelope 
        if(i == 200) {
                // Filter out repeating bass sounds 100 - 180bpm
                beat = beatFilter(envelope);

                // Threshold it based on potentiometer on AN1
                thresh = 0.02f * (float)analogRead(1);
                
                Serial.println(analogRead(0));
                
                // If we are above threshold, light up LED
                if(beat > thresh) digitalWrite(2, HIGH);
                else digitalWrite(2, LOW);

                //Reset sample counter
                i = 0;
        }

        // Consume excess clock cycles, to keep at 5000 hz
        for(unsigned long up = time+SAMPLEPERIODUS; time > 20 && time < up; time = micros());
    }  
}

What has stymied is bassFilter function or the code section:

// 20 - 200hz Single Pole Bandpass IIR Filter
float bassFilter(float sample) {
    static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
    xv[0] = xv[1]; xv[1] = xv[2]; 
    xv[2] = sample / 9.1f;
    yv[0] = yv[1]; yv[1] = yv[2]; 
    yv[2] = (xv[2] - xv[0])  + (-0.7960060012f * yv[0]) + (1.7903124146f * yv[1]);
    return yv[2];

What is actually happening to the digital signal here line by line? How the coefficients come about. I've read a few examples but I'm still puzzled.

That piece of code was written by someone who had no clue whatsoever what they were doing. That whole stupid mess boils down to just one line, which does NOT perform any filtering at all:

float bassFilter(float sample) {
   return  sample / 9.1f ;
}

Regards,
Ray L.

That whole stupid mess boils down to just one line, which does NOT perform any filtering at all:

Not true. Every time "sample" comes in, the various (static) xv's and yv's get updated.

The code is not meant to be understood by humans at a casual glance and was undoubtedly written by a code generator to have a specific type, frequency response and number of poles. However, it is a very simple second order example of such a filter.

See this page for examples of such code generators:

A quick Google search for IIR filter turns up data on Infinite Impulse Response filters, one of the two common digital filter types. Perhaps some reading about IIR filters would help.

Thanks for the replies guys, I understand the theory but how they actually implement into programming language gets me confused with the code I linked earlier. Has anyone got an example or they would have derived to it?

I'm sure the various scaling constants are calculated based on the sample rate and the cutoff frequency. Articles on IIR filters should tell you how to calculate the constants.

// 20 - 200hz Single Pole Bandpass IIR Filter
float bassFilter(float sample) {
  static float xv[3] = {0, 0, 0}, yv[3] = {0, 0, 0};

  // This part just keeps the last three input samples
  // The samples are scaled by 1/9.1
  xv[0] = xv[1];
  xv[1] = xv[2];
  xv[2] = sample / 9.1f;

  // This part keeps the previous two output values (t=-1 and t=-2)
  yv[0] = yv[1];
  yv[1] = yv[2];

  // This part calculates a new output value
  //   The current input sample minus the input sample at t=-2
  //      minus
  //   The output value at t=-2, scaled.
  //      plus
  //   The output value at t=-1, scaled.
  yv[2] = (xv[2] - xv[0])  + (-0.7960060012f * yv[0]) + (1.7903124146f * yv[1]);

  // This part returns the output value
  return yv[2];
}

The code you posted is for a filter of the type called "biquad" and an on-line coefficient calculator is presented in this blog post (also see the links in the post): http://www.earlevel.com/main/2010/12/20/biquad-calculator/