Aplicar filtro en scipy.signal: ¿Usar lfilter o filtfilt?

21

Vi en un hilo SO una sugerencia de uso filtfiltque realiza el filtrado hacia atrás / adelante en lugar de lfilter.

¿Cuál es la motivación para usar una técnica contra la otra?

Bar
fuente
Filtfilt es más lento
Aaron
posible duplicado de ¿Cuál es la ventaja del filtfilt de MATLAB?
Matt L.
1
@Aaron filtfilthace el mismo filtro dos veces, en direcciones opuestas, por lo que no es más lento que hacerlo lfilterdos veces en una dirección, así es como obtendría la misma respuesta de frecuencia.
endolito el
Sí, eso es todo lo que quise decir. Es el doble de lento.
Aaron
Soy nuevo en esto y estaba buscando usar filtfilt. @endolith dijo que scipy.signal usa la señal original. No estoy seguro de lo que significa la señal original y cómo la obtenemos. Tengo un archivo wav que cargo en mi sistema, pero no creo que sea la señal original, ya que está dividido en una matriz numpy y un número de muestras. Por favor, si alguien puede ayudar. ¡Gracias!
Arunima Pathania

Respuestas:

30
  • filtfiltes 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.

  • lfilteres 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 :

filtfilt vs lfilter

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")
endolito
fuente
44
lfilterno es necesariamente una fase mínima, puede ser cualquier cosa dependiendo de los coeficientes del filtro, pero en cualquier caso es causal , lo que filtfiltno lo es. Por lo tanto, el resultado de la comparación que filtfilttiene un retraso cero y lfiltersiempre agrega algo de retraso no es exactamente cierto, porque filtfilten primer lugar no es causal. Lo que realmente importa es que filtfiltno causa distorsiones de fase, mientras que lo lfilterhace (a menos que se use como un filtro FIR de fase lineal, es decir, con denominador = 1).
Matt L.
También vale la pena señalar que el filtrado de enésimo orden con filtfiltcorresponde al filtrado con (2N-1) enésimo orden con lfilter.
Thomas Arildsen
@ThomasArildsen ¿No es solo 2N? Eso es lo que demostré en el guión
endolito el
@ArunimaPathania Deberías comentar bajo mi respuesta, no bajo la pregunta. "Señal original" solo significa la señal que está filtrando. Puedes filtrar con lfiltero filtfilt. Se comportan de manera diferente, como se muestra
endolito el
7

¡La respuesta de @endolith es completa y correcta! Lea primero su publicación, y luego esta además de ella. Debido a mi baja reputación, no pude responder a los comentarios donde @Thomas Arildsen y @endolith discuten sobre el orden efectivo del filtro obtenido por filtfilt:

  • lfilter aplica el filtro dado y en el espacio de Fourier esto es como aplicar la función de transferencia de filtro UNA VEZ.

  • filtfiltaplica el mismo filtro dos veces y el efecto es como aplicar la función de transferencia de filtro CUADRADO. En el caso del filtro Butterworth ( scipy.signal.butter) con la función de transferencia

sol(norte)=11-ω2nortedónde norte es orden de filtro

la ganancia efectiva será

sol(norte)FyoltFyolt=sol(norte)2=11-ω2norte

2norte2norte-1

sol(norte)FyoltFyoltsol(2norte).
drgrujic
fuente
1
Intenta no agregar comentarios como respuestas. Sin embargo, bienvenido a SE.DSP, y obtenga un +1 de mi parte. Creo que esto se suma a la respuesta ... ¡al menos trata de obtener suficiente representante para comentar! :-)
Peter K.
No creo que esto sea cierto. G (n) es la ganancia de amplitud del filtro. Si conecta en cascada la compleja función de transferencia, creo que funcionará en 2n.
Mike
Confirmé con una simulación rápida que un Butterworth de sexto orden da la misma G (ω) que 2 x (Butterworth de tercer orden) en cascada pero con la frecuencia de corte del tercer orden escalada en 1.6. Los resultados son idénticos excepto por la escala de la frecuencia de corte. Por lo tanto, el orden se escala con 2n, pero tenga en cuenta que la banda de paso se reducirá cuando se conecta en cascada y debe compensarse. Alguien se siente libre de explicar la teoría, pero realmente no quiero pasar por todas las matemáticas.
Mike