# Applying filter in scipy.signal: Use lfilter or filtfilt?

I saw in a SO thread a suggestion to use filtfilt which performs backwards/forwards filtering instead of lfilter.

What is the motivation for using one against the other technique?

• Filtfilt is slower Commented Nov 10, 2014 at 16:24
• possible duplicate of What is the advantage of MATLAB's filtfilt Commented Nov 10, 2014 at 16:35
• @Aaron filtfilt does the same filter twice, in opposite directions, so it's not any slower than doing lfilter twice in one direction, which is how you would get the same frequency response. Commented Nov 11, 2014 at 14:57
• Yeah that's all I meant. It's twice as slow. Commented Nov 11, 2014 at 17:11
• I am new to this and was looking around to use filtfilt. @endolith said that the scipy.signal uses the original signal. I am not sure what the original signal means and how we get it. I have a wav file that I load onto my system but I do not think it is the original signal since it is broken up into a numpy array and number of samples. Please if someone could help. Thank you! Commented Jul 31, 2018 at 7:34

• filtfilt is zero-phase filtering, which doesn't shift the signal as it filters. Since the phase is zero at all frequencies, it is also linear-phase. Filtering backwards in time requires you to predict the future, so it can't be used in "online" real-life applications, only for offline processing of recordings of signals.

• lfilter is causal forward-in-time filtering only, similar to a real-life electronic filter. It can't be zero-phase. It can be linear-phase (symmetrical FIR), but usually isn't. Usually it adds different amounts of delay at different frequencies.

An example and image should make it obvious. Although the magnitude of the frequency response of the filters is identical (top left and top right), the zero-phase lowpass lines up with the original signal, just without high frequency content, while the minimum phase filtering delays the signal in a causal way:

from __future__ import division, print_function
import numpy as np
from numpy.random import randn
from numpy.fft import rfft
from scipy import signal
import matplotlib.pyplot as plt

b, a = signal.butter(4, 0.03, analog=False)

# Show that frequency response is the same
impulse = np.zeros(1000)
impulse[500] = 1

# Applies filter forward and backward in time
imp_ff = signal.filtfilt(b, a, impulse)

# Applies filter forward in time twice (for same frequency response)
imp_lf = signal.lfilter(b, a, signal.lfilter(b, a, impulse))

plt.subplot(2, 2, 1)
plt.semilogx(20*np.log10(np.abs(rfft(imp_lf))))
plt.ylim(-100, 20)
plt.grid(True, which='both')
plt.title('lfilter')

plt.subplot(2, 2, 2)
plt.semilogx(20*np.log10(np.abs(rfft(imp_ff))))
plt.ylim(-100, 20)
plt.grid(True, which='both')
plt.title('filtfilt')

sig = np.cumsum(randn(800))  # Brownian noise
sig_ff = signal.filtfilt(b, a, sig)
sig_lf = signal.lfilter(b, a, signal.lfilter(b, a, sig))
plt.subplot(2, 1, 2)
plt.plot(sig, color='silver', label='Original')
plt.plot(sig_ff, color='#3465a4', label='filtfilt')
plt.plot(sig_lf, color='#cc0000', label='lfilter')
plt.grid(True, which='both')
plt.legend(loc="best")

• lfilter is not necessarily minimum-phase, it can be anything depending on the filter coefficients, but in any case it is causal, which filtfilt is not. So the result of the comparison that filtfilt has zero delay, and lfilter always adds some delay is not exactly true, because filtfilt is non-causal in the first place. What actually matters is that filtfilt does not cause any phase distortions, whereas lfilter does (unless it is used as a linear phase FIR filter, i.e. with denominator = 1). Commented Nov 10, 2014 at 17:52
• It is also worth noting that filtering of Nth order with filtfilt corresponds to filtering with (2N-1)th order with lfilter. Commented Nov 21, 2014 at 10:30
• @ThomasArildsen Isn't it just 2N? That's what I demonstrated in the script Commented Nov 21, 2014 at 15:13
• @ArunimaPathania You should comment under my answer, not under the question. "Original signal" just means the signal that you're filtering. You can filter with either lfilter or filtfilt. They behave differently, as shown Commented Jul 31, 2018 at 13:57

Answer by @endolith is complete and correct! Please read his post first, and then this one in addition to it. Due to my low reputation I was unable to respond to comments where @Thomas Arildsen and @endolith argue about effective order of filter obtained by filtfilt:

• lfilter does apply given filter and in Fourier space this is like applying filter transfer function ONCE.

• filtfilt apply the same filter twice and effect is like applying filter transfer function SQUARED. In case of Butterworth filter (scipy.signal.butter) with the transfer function

$$G(n)=\frac{1}{\sqrt{1-\omega^{2n}}}\quad\text{where } n \text{ is order of filter}$$

the effective gain will be

$$G(n)_{filtfilt}=G(n)^2=\frac{1}{1-\omega^{2n}}$$

and this cannot be interpreted as $2n$ nor $2n-1$ order Butterworth filter

$$G(n)_{filtfilt}\neq G(2n).$$