Does FIR filter remove DC offset properly?

I was checking FIR and IIR filter for offset removal. But I found that FIR can not remove DC offset properly. I think there's something more to do with the filter coefficients of FIR to remove DC offset properly. The Octave code is attached here too. I's almost similar to MATLAB.

clear all;

fs = 2000;
ts = 1/fs;
N = 500;
t = [0:N-1]*ts;

cutoff_frequency = 50;
fcl = cutoff_frequency - (cutoff_frequency/2);
fch = cutoff_frequency + (cutoff_frequency/2);

f_test = 50;
f_1  = sin(2*pi()*f_test*t);
f_2 = .3*sin(2*pi()*f_test*10*t);
Offset = 1.7;

f = Offset + f_1 + f_2;

Wl = 2*(fcl/fs);
Wh = 2*(fch/fs);
Wm = 2*(cutoff_frequency/fs);

FIR_order = 20;
fc = [0 Wl Wm Wh 1];
m = [0 .03 1 .03 0];
fir_coeff = fir2(FIR_order,fc,m);
filtered_FIR = filter(fir_coeff, 1, f);

IIR_Order = 1;
[b, a] = butter(IIR_Order,[Wl, Wh]);
filtered_IIR = filter(b, a, f);

hold on;
figure 01;
plot(f);
plot(filtered_FIR);
plot(filtered_IIR);
hold off;

• Try plotting fir_coeff, or even freqz(fir_coeff), see if that fits a highpass FIR. Commented Mar 20, 2022 at 10:07

DC offset will only be removed if the filter does not pass DC. If the filter is a low pass filter, then the DC portion of the signal will pass through, scaled by the gain of the filter.

To completely remove DC, the filter would have a zero at $$z=1$$, which will provide a null at DC. You can expect to see an initial time transient but in the settled state DC will be completely removed if the filter has a zero at $$z=1$$.

Alternatively, to implement DC with a very simple IIR filter consider the DC Nulling Filter demonstrated and detailed in these posts:

What does correcting IQ do?

Transfer function of second order notch filter

• I'll check that. I cannot upvote the comment because this account doesn't have enough points. Commented Mar 20, 2022 at 12:20
• Yes the filter was not actually high pass due to low order. The issue was solved when I changed the order to 200. Commented Mar 24, 2022 at 11:24
• In general for an FIR of any order, if you multiply the transfer function by (z-1)/z, you will get the necessary null st DC but the transition to your passband may not be tight enough and for that reason you would increase the order. I have other links posted on very efficient IIR implementations for DC nulling filters that are typically used (1 delay and 1 feedback, two multipliers). Search “DC Nulling Filter” and you should find it. Commented Mar 24, 2022 at 11:29
• ok I'm checking it. Commented Mar 24, 2022 at 12:12
• @thinkrafi I added the links in the question as it turns out they weren't as simple to find I think. Commented Mar 24, 2022 at 12:15