Application du filtre dans scipy.signal: utilisez lfilter ou filtfilt?

21

J'ai vu dans un thread SO une suggestion à utiliser filtfiltqui effectue un filtrage vers l'arrière / vers l'avant au lieu de lfilter.

Quelle est la motivation pour utiliser l'une contre l'autre technique?

Bar
la source
Filtfilt est plus lent
Aaron
doublon possible de Quel est l'avantage du filtfilt de MATLAB
Matt L.
1
@Aaron filtfiltfait le même filtre deux fois, dans des directions opposées, donc ce n'est pas plus lent que de faire lfilterdeux fois dans une direction, c'est ainsi que vous obtiendriez la même réponse en fréquence.
endolith
Ouais, c'est tout ce que je voulais dire. C'est deux fois plus lent.
Aaron
Je suis nouveau dans ce domaine et regardais autour de moi pour utiliser filtfilt. @endolith a déclaré que le scipy.signal utilise le signal d'origine. Je ne sais pas ce que signifie le signal d'origine et comment nous l'obtenons. J'ai un fichier wav que je charge sur mon système, mais je ne pense pas que ce soit le signal d'origine car il est divisé en un tableau numpy et un nombre d'échantillons. S'il vous plaît, si quelqu'un pouvait vous aider. Merci!
Arunima Pathania

Réponses:

30
  • filtfiltest un filtrage de phase zéro, qui ne décale pas le signal pendant qu'il filtre. La phase étant nulle à toutes les fréquences, elle est également linéaire. Le filtrage en arrière dans le temps vous oblige à prévoir l'avenir, il ne peut donc pas être utilisé dans des applications réelles "en ligne", uniquement pour le traitement hors ligne d'enregistrements de signaux.

  • lfilterest un filtrage causal direct dans le temps uniquement, semblable à un filtre électronique réel. Cela ne peut pas être en phase zéro. Il peut s'agir d'une phase linéaire (FIR symétrique), mais ce n'est généralement pas le cas. Habituellement, il ajoute différentes quantités de retard à différentes fréquences.

Un exemple et une image devraient le rendre évident. Bien que l'amplitude de la réponse en fréquence des filtres soit identique (en haut à gauche et en haut à droite), le passe-bas à phase nulle s'aligne avec le signal d'origine, juste sans contenu haute fréquence, tandis que le filtrage de phase minimum retarde le signal de manière causale :

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")
endolith
la source
4
lfiltern'est pas nécessairement à phase minimale, elle peut être n'importe quoi en fonction des coefficients de filtrage, mais en tout cas elle est causale , ce qui filtfiltne l'est pas. Ainsi, le résultat de la comparaison qui filtfiltn'a aucun retard et lfilterajoute toujours un certain retard n'est pas exactement vrai, car il filtfiltn'est pas causal en premier lieu. Ce qui compte réellement, c'est qu'il filtfiltne provoque aucune distorsion de phase, contrairement lfilterà ce qui est le cas (à moins qu'il ne soit utilisé comme filtre FIR à phase linéaire, c'est-à-dire avec un dénominateur = 1).
Matt L.
Il convient également de noter que le filtrage de Nième ordre avec filtfiltcorrespond au filtrage avec (2N-1) e ordre avec lfilter.
Thomas Arildsen
@ThomasArildsen N'est-ce pas seulement 2N? C'est ce que j'ai démontré dans le script
endolith
@ArunimaPathania Vous devriez commenter sous ma réponse, pas sous la question. "Signal d'origine" signifie simplement le signal que vous filtrez. Vous pouvez filtrer avec lfilterou filtfilt. Ils se comportent différemment, comme indiqué
endolith
7

La réponse de @endolith est complète et correcte! Veuillez d'abord lire son article, puis celui-ci en plus. En raison de ma faible réputation, je n'ai pas pu répondre aux commentaires où @Thomas Arildsen et @endolith discutent de l'ordre effectif du filtre obtenu par filtfilt:

  • lfilter applique un filtre donné et dans l'espace de Fourier, c'est comme appliquer UNE FOIS la fonction de transfert de filtre.

  • filtfiltappliquer deux fois le même filtre et l'effet est comme appliquer la fonction de transfert de filtre SQUARED. En cas de filtre Butterworth ( scipy.signal.butter) avec la fonction de transfert

G(n)=11ω2nwhere n is order of filter

le gain effectif sera

G(n)filtfilt=G(n)2=11ω2n

2n2n1

G(n)filtfiltG(2n).
drgrujic
la source
1
Veuillez ne pas ajouter de commentaires comme réponses. Cependant, bienvenue dans SE.DSP et recevez un +1 de ma part. Je pense que cela ajoute à la réponse ... essayez au moins d'avoir suffisamment de représentants pour commenter! :-)
Peter K.
Je ne pense pas que ce soit vrai. G (n) est le gain d'amplitude du filtre. Si vous mettez en cascade la fonction de transfert complexe, je pense que cela fonctionnera jusqu'à 2n.
Mike
J'ai confirmé avec une simulation rapide qu'un Butterworth de 6e ordre donne le même G (ω) que 2 x (Butterworth de 3e ordre) en cascade mais avec une fréquence de coupure du 3e ordre mise à l'échelle par 1,6. Les résultats sont identiques à l'exception de la mise à l'échelle de la fréquence de coupure. Ainsi, l'ordre évolue avec 2n, mais notez que la bande passante se réduira lorsque vous monterez en cascade et doit être compensée. Quelqu'un se sent libre d'expliquer la théorie mais je ne veux pas vraiment passer par tous les mathématiques.
Mike