Low Pass filter in C

25.7k views Asked by At

I'm implementing a low pass filter in C wih the PortAudio library. I record my microphone input with a script from PortAudio itself. There I added the following code:

float cutoff = 4000.0;

float filter(float cutofFreq){
    float RC = 1.0/(cutofFreq * 2 * M_PI);
    float dt = 1.0/SAMPLE_RATE;
    float alpha = dt/(RC+dt);

    return alpha;
}

float filteredArray[numSamples];
filteredArray[0] = data.recordedSamples[0];

for(i=1; i<numSamples; i++){
    if(i%SAMPLE_RATE == 0){
        cutoff = cutoff - 400;
    }
    data.recordedSamples[i] = data.recordedSamples[i-1] + (filter(cutoff)*(data.recordedSamples[i] - data.recordedSamples[i-1]));
}

When I run this script for 5 seconds it works. But when I try to run this for more then 5 seconds it fails. The application records everything, but crashes on playback. If I remove the filter, the application works.

Any advice?

1

There are 1 answers

2
Spektre On BEST ANSWER

The problem:

  1. you are lowering the cutoff frequency by 400 Hz everytime i%SAMPLE_RATE == 0

    • never stop so you go below zero
    • this is not done once per second !!!
    • instead every time your for passes through second barrier in your data
    • that can occur more often then you think if you are not calling your calls in the right place
    • which is not seen in your code
  2. you are filtering in wrong oorder

    • ... a[i]=f(a[i],a[i-1]; i++;
    • that means you are filtering with already filtered a[i-1] value

What to do with it

  1. check the code placement

    • it should be in some event like on packed done sompling
    • or in thread after some Sleep(...); (or inside timer)
    • change the cut off changing (handle edge cases)
  2. reverse filter for direction

Something like this:

int i_done=0;

void on_some_timer()
 {
 cutoff-=400;
 if (cutoff<1) cutoff=1; // here change 1 for limit frequency

 if (numSamples!=i_done)
  for (i=numSamples-1,i>=i_done;i--)
   data.recordedSamples[i] = data.recordedSamples[i-1] + (filter(cutoff)*(data.recordedSamples[i] - data.recordedSamples[i-1]));
 i_done=numSamples;
 }

if your code is already OK (you did not post th whole thing so I can missing something)

  • then just add the if (cutoff<1) cutoff=1; after cutoff change