filtfilt
es un filtro de fase cero, que no cambia la señal mientras se filtra. Como la fase es cero en todas las frecuencias, también es de fase lineal. Filtrar hacia atrás en el tiempo requiere que prediga el futuro, por lo que no se puede usar en aplicaciones de la vida real "en línea", solo para el procesamiento fuera de línea de grabaciones de señales.
lfilter
es un filtrado causal directo en el tiempo solamente, similar a un filtro electrónico de la vida real. No puede ser de fase cero. Puede ser de fase lineal (FIR simétrica), pero generalmente no lo es. Por lo general, agrega diferentes cantidades de retraso a diferentes frecuencias.
Un ejemplo y una imagen deberían hacerlo obvio. Aunque la magnitud de la respuesta de frecuencia de los filtros es idéntica (arriba a la izquierda y arriba a la derecha), el paso bajo de fase cero se alinea con la señal original, simplemente sin contenido de alta frecuencia, mientras que el filtrado de fase mínimo retrasa la señal de manera causal :
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")