# FIR filter attenuation in the passband

OK, so I am designing a 2 kHz bandpass FIR filter using the following parameters:

Fa = 1900 Hz Fb = 2100 Hz Fs = 50 kHz M = 33 pts Att = 40 dB

I calculated the coefficients using this online tool (https://www.arc.id.au/FilterDesign.html)

The code is written in C and consists of a circular buffer where the latest analog value from the ADC is stored, and for each new sample, the buffer is multiplied with the coefficients (the latest sample with coefficient 0, sample n-1 with coefficient 1 etc).

The filtering is working fine (2 kHz passes and frequencies above 3 kHz and below 1 kHz quickly drops), but what bothers me is that the output from the filter in the passband is attenuated rather heavily.

The input to the filter is in the range -2048 to +2047. I have to multiply the output with approx 15 to make the maximum output reach the same level, which also increases the noise level.

This is the first time I design this kind of filter, and I was under the impression that the attenuation in the passband would be close to zero. What am I missing out?

• are you doing fixed-point (integer) calculation? Sep 29, 2021 at 15:15
• I am doing floating point multiplications. The code runs on an ARM CPU with FPU. Sep 30, 2021 at 5:09
• As the other answer indicated, your FIR filter order 32 (tap=33) isn't high enough to provide you the filter specifications (transition bandwidth, and stopband attenuation) you set. If you cannot increase the FIR order, you can try IIR filtering instead, but that will not be linear phase like FIR. As a last resort, you can try a more efficient implementation of the FIR filter. Make use of the impulse response symmetry and cut MAC count by half. (which enables an order of M=65; better but not sufficient still.) Sep 30, 2021 at 13:13
• @Fat32 Thanks for the information, I will look into IIR. Oct 1, 2021 at 5:04

A quick test shows that you are imposing the order to be 33, but that's not enough to guarantee that the resulting transition width will cover your needs. The low order can't cover everything so the response comes out attenuated (the transition width needs to be greater). In this case the actual response is:

Which means that the linked we page displays the frequency reponse with the peak normalized, i.e. (find peak)/(max).

--it displays normalized apparently

If you wanted the peak, only, at 2 kHz, for a Kaiser window, the transition width sould have to be 2*(2 kHz - 1.9 kHz) = 200 Hz. For your sampling frequency this results in an order of 559 (length 560, shown without phase, for clarity):

As a solution, if the 33rd order filter satisfies your requirements (I don't think it does, but you know better) then multiply the coefficients by 1/0.085 = 11.76. It's not 15, but it's worth testing.

• Thanks for the detailed response. The sample frequency and filter order are constrained by the fact that I am filtering in real-time on a rather weak CPU. But I think it is good enough. Sep 30, 2021 at 5:22
• Which program did you use to calculate the transfer functions above? Sep 30, 2021 at 5:27
• @Dimlite I used LTspice, but the program, itself, doesn't have anything to do with FIRs, in general, so what you see is just a custom library I've made. But you can safely use Octave's kaiserord to calculate the order for a specific set of frequencies. Sep 30, 2021 at 6:13
• Ok, thanks a lot for your help. I would like to upvote your answer, but I don't have enought points. Hope someone else finds this useful too. Sep 30, 2021 at 9:23
• @Dimlite Upvoting is optional, but selecting the answer is needed (if it provides the necessary solution to your problem). That is the one that tells other people, in the future, searching for similar problems, that there is an accepted answer. Thank you for a vote of confidence, though. ;-) Sep 30, 2021 at 14:59