Author Topic: Simple FIR filter to audio  (Read 5933 times)

0 Members and 1 Guest are viewing this topic.

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Simple FIR filter to audio
« on: August 09, 2017, 04:35:06 pm »
Hello.

I need help to build a simple audio filter.

Currently my system (a 48MHz ARM M0+) can read the ADC at 20KHz and make an LPF FIR (20taps) at the frequency of 2KHz.

I need to make a BPF with a bandwidth of 100Hz centered at 1KHz.

Basically I'm using 2 cascade FIR filters.
First I calculate the LPF to 2KHz and then I apply a BPF FIR to 1KHz.
This cycle is repeated at the frequency of 5KHz, because only with this frequency of sampling I can get the BW of 100Hz.
Basically I first filter the entire signal to avoid aliasing above 2KHz and then sample at 5KHz to run the BPF.

I was able to make a 20taps FIR filter, in cycles of 20KHz, with a cut-off frequency of 2KHz.
Works well! The audio is filtered and have quality.

When I put the 2 filters together, the sound sucks and it looks like the BPF is not working  ???.


Can someone give me some help?

I'm using my own algorithm, but do you think using the CMSIS algorithm could be better?


Thanks!
« Last Edit: August 09, 2017, 04:51:50 pm by Dave_PT »
 

Online Benta

  • Super Contributor
  • ***
  • Posts: 5840
  • Country: de
Re: Simple FIR filter to audio
« Reply #1 on: August 09, 2017, 06:34:13 pm »
What's your input signal? Is it already band-limited? Or do you have an anti-aliasing filter before the ADC?
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #2 on: August 09, 2017, 07:21:04 pm »
Thank you for the reply.

Yes I did a 3rd order filter with Fc = 5KHz.

I can sample at 20KHz without aliasing problems.
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #3 on: August 09, 2017, 08:02:08 pm »
These are the 2 main functions in my code.

I do not know if there will be any problem in using 2 cascaded FIR filters ...

All times are OK. I change a pin state in the various places and the ADC is read every 1/20KHz, the filter runs every 1/5KHz and the duration of the calculations does not exceed the time available. So everything seems to be right ...


Code: [Select]
#define LPF_ORDER                     20
#define LPF_HALF_ORDER          (LPF_ORDER/2)
#define FILTER_COEFF_MULT       13  //2^13
#define BPF_ORDER                     50
#define BPF_ORDER_1                (BPF_ORDER - 1)
#define BPF_HALF_ORDER          (BPF_ORDER/2)

//buffer com as últimas leituras da ADC
int16_t ADC_readings_array[LPF_ORDER];
//Index para executar buffer circular da ADC
uint8_t adc_buf_head;
//buffer com as últimas leituras da ADC
int16_t LPF_results_array[BPF_ORDER];
//ultimo resultado do calculo do FIR
int32_t fir_result;

//LOW-PASS FILTER
const int16_t LPF_2000Hz[LPF_HALF_ORDER] =
{ -14, -23, -12, 41, 155, 335, 565, 807, 1010, 1127 };

//BAND-PASS FILTER
const int16_t BPF_100Hz[BPF_HALF_ORDER] =
{ 3, -3, -18, -9, 35, 49, -25, -106, -41, 133, 161, -73, -273, -97, 285, 318, -133, -469, -156, 433, 456, -181, -604,
        -190, 503 };


//Interrupt routine to read the ADC value
void Routine_20KHz(void)
{
    //save the ADC reading to circular buffer
    ADC_readings_array[adc_buf_head] = ADC_DMA[SIGNAL_ADC] - ADC_in_avg;

    //update buffer head index
    adc_buf_head++;

    if (adc_buf_head >= LPF_ORDER)
        adc_buf_head = 0;
}

//Function called every 1/5KHz
void FIR_cascade_filter(void)
{
    int8_t i;
    uint8_t circular_head;
    int16_t ADC_order_buffer[LPF_ORDER];
    int32_t fir_result;

    //Update the ouput "DAC" with the last filter calculation to maintain syncronism
    update_output(fir_result);

    //*************************************** INIT LOW PASS FILTER****************************

    //Order the ADC readings
    circular_head = adc_buf_head;
    for (i = 0; i < LPF_ORDER; i++)
    {
        ADC_order_buffer[i] = ADC_readings_array[circular_head];
        circular_head++;
        if (circular_head >= LPF_ORDER)
            circular_head = 0;
    }

    //Reset fir_result variable
    fir_result = 0;

    //first part of coeffs
    for (i = 0; i < LPF_HALF_ORDER; i++)
    {
        //multiplication and sum of filter
        fir_result += ADC_order_buffer[i] * LPF_2000Hz[i];
    }

    //second part of coeffs
    circular_head = LPF_HALF_ORDER;
    for (i = (LPF_HALF_ORDER - 1); i >= 0; i--)
    {
        //multiplication and sum of filter
        fir_result += ADC_order_buffer[circular_head] * LPF_2000Hz[i];

        circular_head++;
    }

    //Divide filter result by 2^13
    fir_result = fir_result >> FILTER_COEFF_MULT;

    //*************************************** END LOW PASS FILTER****************************

    //*************************************** INIT BAND PASS FILTER**************************
    //order the LPF results
    for (i = 0; i < (BPF_ORDER - 1); i++)
    {
        LPF_results_array[i + 1] = LPF_results_array[i];
    }

    //add the last calculation
    LPF_results_array[0] = (int16_t) fir_result;

    fir_result = 0;

    //first part of coeffs
    for (i = 0; i < BPF_HALF_ORDER; i++)
    {
        //multiplication and sum of filter
        fir_result += LPF_results_array[i] * BPF_100Hz[i];
    }

    //second part of coeffs
    circular_head = BPF_HALF_ORDER;
    for (i = (BPF_HALF_ORDER - 1); i >= 0; i--)
    {
        //multiplication and sum of filter
        fir_result += LPF_results_array[circular_head] * BPF_100Hz[i];

        circular_head++;
    }

    //Divide filter result by 2^13
    fir_result = fir_result >> FILTER_COEFF_MULT;

    //*************************************** END BAND PASS FILTER**************************
}
« Last Edit: August 09, 2017, 08:09:08 pm by Dave_PT »
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Simple FIR filter to audio
« Reply #4 on: August 09, 2017, 08:15:40 pm »
You can test your filter in PC using C by creating suitable stimulus file or sample stream, and by analyzing its performance by plotting the output samples and some intermediate samples. Of course, you can do quick testing using Excel or OpenOffice Calc.
 
The following users thanked this post: diyaudio

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #5 on: August 09, 2017, 08:29:08 pm »
I will try it with excel...
 

Online Benta

  • Super Contributor
  • ***
  • Posts: 5840
  • Country: de
Re: Simple FIR filter to audio
« Reply #6 on: August 09, 2017, 09:41:05 pm »
Thank you for the reply.

Yes I did a 3rd order filter with Fc = 5KHz.

I can sample at 20KHz without aliasing problems.

In that case, why use cascading filters? You can make a bandpass FIR directly.
 

Offline diyaudio

  • Frequent Contributor
  • **
  • !
  • Posts: 683
  • Country: za
Re: Simple FIR filter to audio
« Reply #7 on: August 09, 2017, 09:47:16 pm »
I will try it with excel...
yuck! no, use Matlab or Octave.

if you not using these tools by now, you not armed to debug DSP algorithms. its non negotiable debugging tools.
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #8 on: August 09, 2017, 09:52:02 pm »
But will not I have aliasing?

I need to do sampling at 5KHz, which is the same frequency as my external filter cuts ...
In this case I need to have an external filter to cut at least 2.5KHz.

Am I wrong?

yuck! no, use Matlab or Octave.

if you not using these tools by now, you not armed to debug DSP algorithms. its non negotiable debugging tools.

I do not have any of them installed ...  :-\ :-\
I will install the Octave.
« Last Edit: August 09, 2017, 09:54:52 pm by Dave_PT »
 

Offline trampas

  • Contributor
  • Posts: 44
  • Country: us
Re: Simple FIR filter to audio
« Reply #9 on: August 09, 2017, 10:35:04 pm »
I used MATLAB for years and even octave, I have not switched to Python, which I like better.

Trampas
www.misfittech.net
 

Online Benta

  • Super Contributor
  • ***
  • Posts: 5840
  • Country: de
Re: Simple FIR filter to audio
« Reply #10 on: August 09, 2017, 10:44:07 pm »
This is a mess... 20 kHz, 5 kHz, 2.5 kHz, 1 kHz, 100 Hz. My eyes are rolling in my head when I try to follow this.

Dave_PT, could you PLEASE list the requirements and signals and limitations here?
Perhaps start from scratch? What you have etc.

Thanks (or rather, you should be thankful that someone is following this...)
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #11 on: August 09, 2017, 11:02:27 pm »
OK ... from the beginning.

I want to make a FIR filter that has a passband of 100Hz centered at 1KHz (passband 950HZ <-> 1050HZ).
My input signal will be up to about 10KHz.
Before the ADC I put a 3rd order filter with Fc = 5KHz.

As proof that the basic operating principle is right, I can sample the signal at 20KHz and apply a 20-taps FIR LP Filter without problems.

I wanted to apply the filter in the next picture ... but the sampling frequency has to lower at least 5KHz. At this frequency I will have aliasing. So I had the idea to sample at 20KHz, make a LP Filter at 2KHz and then "feed" the BP Filter that would make 5KHz loops.

« Last Edit: August 15, 2017, 10:47:24 pm by Dave_PT »
 

Online Benta

  • Super Contributor
  • ***
  • Posts: 5840
  • Country: de
Re: Simple FIR filter to audio
« Reply #12 on: August 09, 2017, 11:22:34 pm »
I understand your setup now.
So why not just do the bandpass filtering directly on your 20 ksps sample stream? Do you have computational limitations?
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #13 on: August 09, 2017, 11:27:06 pm »
Yes ... I have and can do all the calculations within the loop time.

But with 20Ksps, I can not run any BP Filter with a 100Hz BW. The minimum with 20Ksps is around 500Hz. My old setup worked that way, but 500Hz is a very large BW.
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #14 on: August 15, 2017, 10:29:51 pm »
Hello.

I've done some calculations using Octave, and now I see what's going on.

The problem is when I sample at 5KHz the signal that has passed through the low pass filter.

So, what is your suggestion?

What is the best way for me to have a 100Hz passband using what I have available?

 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26757
  • Country: nl
    • NCT Developments
Re: Simple FIR filter to audio
« Reply #15 on: August 15, 2017, 10:34:22 pm »
I'd use an IIR filter. These need much less computing power for the same filter.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #16 on: August 15, 2017, 10:43:51 pm »
Thanks for the answer.

I'm going to try an IIR filter. With these filters are fewer calculation operations, but as it uses floats, each operation will take more time...

 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #17 on: August 15, 2017, 10:46:08 pm »
You don't have to run 2kHz LPF at 20ksps. You can run it at only 5ksps
Yes. That's what I'm doing.

My samples are made at 20KHz, but only at 5KHz I perform LPF followed by BPF ...
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #18 on: August 15, 2017, 11:05:12 pm »
Yes, you're right.
But using FIR this does not work ...  |O

Let's try again before I go to test the IIR filters.


Sampling the signal at 20KHz (20ksps).


A timer will change a flag (1/5KHz) so in my main program I can perform the filter.


Calculate the 20tap low pass filter to 2KHz. For this I use the last 20 readings of the ADC (20ksps).


After calculating the LPF, I "feed" the band pass filter so that it can then filter the signal and pass only the 100Hz that I want.

5th
After all the calculations, I wait for the new cycle to update my output. I do this to isolate the delays caused by calculations.


What am I doing wrong in the process?
I think it must be some calculation problem ...
 

Offline danadak

  • Super Contributor
  • ***
  • Posts: 1875
  • Country: us
  • Reactor Operator SSN-583, Retired EE
Re: Simple FIR filter to audio
« Reply #19 on: August 15, 2017, 11:32:40 pm »
Caution on ISR controlling filter loop. ISR should be very terse
in code, not call other functions (results in lots of stack push),
set a flag, and return to main() to process the filter. Make sure
other ISRs are inactive if at all possible to minimize sampling
jitter on output writes. Same can be said for input sampling de-
pending on how its implemented.


Regards, Dana.
Love Cypress PSOC, ATTiny, Bit Slice, OpAmps, Oscilloscopes, and Analog Gurus like Pease, Miller, Widlar, Dobkin, obsessed with being an engineer
 

Offline f5r5e5d

  • Frequent Contributor
  • **
  • Posts: 349
Re: Simple FIR filter to audio
« Reply #20 on: August 16, 2017, 01:23:25 am »
the signal processing theory and specification is confused - in addition to getting sampling/decimation/anti-alliasing correct, many calcs need ADC bits and acceptable noise budget, both analog and for the DSP

5 kHz 3rd order analog low pass is feeble for 20k sample rate - (20/5)**3, only a factor of 64 attenuation for any 20 kHz signal component - 6 bits


sometimes theoretically poor anti-alias works if the signal before filtering has low enough higher frequency content - but you need numbers, what's the signal look like at 200 kHz sample rate? (or the 192k that many PC sound cards can do)


if all you want is to detect the narrow band @ 1 kHz then I'd move the analog anti-alias down to 2 kHz or even incorporate its cutoff (& Q) into the wanted notch filter design

biquad filters are named for the Quadratic s or z domain polynomials in both numerator and denominator - in general that means 6 coefficients and multiplies per each biquad

and fixed point biquads are fine, can use integer multipliers - but often need very long wordlengths for the accumulators

since that's still a lot of ops per biquad you may want several stages of Half Band FIR filtering with decimation

https://www.google.com/search?q=half+band+filter+theory&oq=half+band+filter+theory&aqs=chrome..69i57.2999j0j1&sourceid=chrome&ie=UTF-8
https://www.mathworks.com/help/dsp/examples/fir-halfband-filter-design.html
« Last Edit: August 16, 2017, 01:36:43 am by f5r5e5d »
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #21 on: August 16, 2017, 09:26:27 am »
Caution on ISR controlling filter loop. ISR should be very terse
in code, not call other functions (results in lots of stack push),
set a flag, and return to main() to process the filter. Make sure
other ISRs are inactive if at all possible to minimize sampling
jitter on output writes. Same can be said for input sampling de-
pending on how its implemented.


Regards, Dana.

There is only 2 ISRs: 1 for acquisition at 20ksps, 1 to start the filter calculation (1/5KHz).
In both routines there it's just enter, modify and exit.
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 26757
  • Country: nl
    • NCT Developments
Re: Simple FIR filter to audio
« Reply #22 on: August 16, 2017, 09:40:14 am »
Caution on ISR controlling filter loop. ISR should be very terse
in code, not call other functions (results in lots of stack push),
set a flag, and return to main() to process the filter. Make sure
other ISRs are inactive if at all possible to minimize sampling
jitter on output writes. Same can be said for input sampling de-
pending on how its implemented.


Regards, Dana.

There is only 2 ISRs: 1 for acquisition at 20ksps, 1 to start the filter calculation (1/5KHz).
In both routines there it's just enter, modify and exit.
I would do the filtering in the 20ksps interrupt. That way you don't waste time to store/recover the data. You need to process each sample anyway sooner or later. An option is to filter in 2 stages where you decimate to 1kHz first and filter that signal using a lower samplerate. BTW IIR doesn't need floating point. 32 bit integers will do just fine but you have to check overflow conditions. 14 bit coefficients help to give some extra headroom.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline f5r5e5d

  • Frequent Contributor
  • **
  • Posts: 349
Re: Simple FIR filter to audio
« Reply #23 on: August 16, 2017, 10:54:29 am »
sorry but this is just wrong - this prescription is decimating without the required filtering - you will get aliasing

Quote

Sampling the signal at 20KHz (20ksps).


A timer will change a flag (1/5KHz) so in my main program I can perform the filter.


Calculate the 20tap low pass filter to 2KHz. For this I use the last 20 readings of the ADC (20ksps).

again you need more problem definition info - the spectrum/level of frequency components in the raw signal, the required output resolution to design the ADC sampling and analog antialias filter frequencies and order, and to design the DSP processing


as an example if your actual input signal has the high frequency content rolling fast off enough to work with your current 5 kHz 3rd order filter in front of 20 kHz sampling ADC, then maybe reducing the anaolg filter fc by 4x would let you cut the sample frequency by 2x

then with FIR Half Band filtering and decimation to cut the sample rate to 2.5 kHz in 2 stages may let you save enough processing time to be able to do the 1 kHz bandpass
 

Offline Dave_PTTopic starter

  • Frequent Contributor
  • **
  • Posts: 315
  • Country: pt
    • DavidMartinsEngineering
Re: Simple FIR filter to audio
« Reply #24 on: August 16, 2017, 11:12:08 am »
then with FIR Half Band filtering and decimation to cut the sample rate to 2.5 kHz in 2 stages may let you save enough processing time to be able to do the 1 kHz bandpass

Can you explain this part better?

I'm sure I'm doing a lot of confusion ...
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf