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?
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 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).
$\endgroup$
filtfilt
corresponds to filtering with (2N-1)th order with lfilter
.
$\endgroup$
Commented
Nov 21, 2014 at 10:30
lfilter
or filtfilt
. They behave differently, as shown
$\endgroup$
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).$$
+
sign in the denominator of fliter $G(n)$?
$\endgroup$
filtfilt
does the same filter twice, in opposite directions, so it's not any slower than doinglfilter
twice in one direction, which is how you would get the same frequency response. $\endgroup$