Aplicando filtro no scipy.signal: use lfilter ou filtfilt?

21

Eu vi em um tópico SO uma sugestão de uso filtfiltque executa a filtragem para trás / para a frente em vez de lfilter.

Qual é a motivação para usar uma contra a outra técnica?

Barra
fonte
Filtfilt é mais lento
Aaron
possível duplicata de Qual é a vantagem do filtfilt do MATLAB
Matt L.
1
O @Aaron filtfiltfaz o mesmo filtro duas vezes, em direções opostas, por isso não é mais lento do que fazer lfilterduas vezes em uma direção, e é assim que você obteria a mesma resposta de frequência.
endolith
Sim, foi tudo o que eu quis dizer. É duas vezes mais lento.
Aaron
Eu sou novo nisso e estava olhando em volta para usar filtfilt. O @endolith disse que o scipy.signal usa o sinal original. Não sei ao certo o que significa o sinal original e como o recebemos. Eu tenho um arquivo wav que carrego no meu sistema, mas não acho que seja o sinal original, pois ele é dividido em uma matriz numpy e número de amostras. Por favor, se alguém puder ajudar. Obrigado!
Arunima Pathania

Respostas:

30
  • filtfilté a filtragem de fase zero, que não muda o sinal ao filtrar. Como a fase é zero em todas as frequências, também é linear. A filtragem para trás no tempo exige que você preveja o futuro, para que não possa ser usado em aplicativos da vida real "online", apenas para processamento offline de gravações de sinais.

  • lfilteré apenas uma filtragem causal de encaminhamento no tempo, semelhante a um filtro eletrônico da vida real. Não pode ser de fase zero. Pode ser de fase linear (FIR simétrico), mas geralmente não é. Geralmente, ele adiciona diferentes quantidades de atraso em diferentes frequências.

Um exemplo e imagem devem torná-lo óbvio. Embora a magnitude da resposta de frequência dos filtros seja idêntica (canto superior esquerdo e canto superior direito), o passa-baixo da fase zero se alinha com o sinal original, apenas sem conteúdo de alta frequência, enquanto a filtragem mínima de fase atrasa o sinal de maneira 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")
endólito
fonte
4
lfilternão é necessariamente fase mínima, pode ser qualquer coisa dependendo dos coeficientes do filtro, mas, em qualquer caso, é causal , o que filtfiltnão é. Portanto, o resultado da comparação que filtfilttem atraso zero e lfiltersempre adiciona algum atraso não é exatamente verdadeiro, porque filtfilté não causal em primeiro lugar. O que realmente importa é que filtfiltnão causa distorções de fase, enquanto lfiltercausa (a menos que seja usado como um filtro FIR de fase linear, ou seja, com denominador = 1).
Matt L.
Também é importante notar que a filtragem da enésima ordem com filtfiltcorresponde à filtragem com (2N-1) a ordem com lfilter.
Thomas Arildsen
@ThomasArildsen Não é apenas 2N? Foi o que demonstrei no script
endolith
@ArunimaPathania Você deve comentar na minha resposta, não na pergunta. "Sinal original" significa apenas o sinal que você está filtrando. Você pode filtrar com lfilterou filtfilt. Eles se comportam de maneira diferente, como mostrado
endolith 31/07
7

Responder por @endolith está completo e correto! Por favor, leia primeiro o post dele, e depois este, além dele. Devido à minha baixa reputação, não consegui responder aos comentários em que @Thomas Arildsen e @endolith discutem sobre a ordem efetiva do filtro obtida por filtfilt:

  • lfilter aplica determinado filtro e, no espaço de Fourier, é como aplicar a função de transferência de filtro UMA VEZ.

  • filtfiltaplique o mesmo filtro duas vezes e o efeito é como aplicar a função de transferência de filtro SQUARED. No caso de filtro Butterworth ( scipy.signal.butter) com a função de transferência

G(n)=11-ω2nOnde n é a ordem do filtro

o ganho efetivo será

G(n)fEueutfEueut=G(n)2=11-ω2n

2n2n-1

G(n)fEueutfEueutG(2n).
drgrujic
fonte
1
Por favor, tente não adicionar comentários como respostas. No entanto, seja bem-vindo ao SE.DSP e receba um +1 de mim. Eu acho que isso contribui para a resposta ... pelo menos tente obter rep suficiente para comentar! :-)
Peter K.
Eu não acho que isso seja verdade. G (n) é o ganho de amplitude do filtro. Se você colocar em cascata a função de transferência complexa, acho que funcionará para 2n.
Mike
Confirmei com uma simulação rápida que um Butterworth de 6ª ordem fornece o mesmo G (ω) que 2 x (Butterworth de 3ª ordem) em cascata, mas com a frequência de corte da 3ª ordem dimensionada em 1,6. Os resultados são idênticos, exceto pelo dimensionamento da frequência de corte. Portanto, o pedido é escalonado com 2n, mas observe que a banda passante será reduzida quando você fizer uma cascata e precisar ser compensada. Alguém fica à vontade para explicar a teoria, mas eu realmente não quero passar por toda a matemática.
Mike