Applicazione del filtro in scipy.signal: utilizzare lfilter o filtfilt?


21

Ho visto in un thread SO un suggerimento da usare filtfiltche esegue il filtraggio indietro / avanti anziché lfilter.

Qual è la motivazione per usare l'una contro l'altra tecnica?


Filtfilt è più lento
Aaron,


1
@Aaron filtfiltfa lo stesso filtro due volte, in direzioni opposte, quindi non è più lento del lfilterdoppio in una direzione, il che è il modo in cui otterresti la stessa risposta in frequenza.
endolith

Sì, questo è tutto ciò che intendevo. È due volte più lento.
Aaron,

Sono nuovo di questo e mi guardavo intorno per usare filtfilt. @endolith ha detto che scipy.signal usa il segnale originale. Non sono sicuro del significato del segnale originale e di come lo riceviamo. Ho un file wav che carico sul mio sistema ma non penso che sia il segnale originale poiché è suddiviso in un array intorpidito e numero di campioni. Per favore, se qualcuno potesse aiutare. Grazie!
Arunima Pathania,

Risposte:


30
  • filtfiltè il filtro a fase zero, che non sposta il segnale mentre filtra. Poiché la fase è zero a tutte le frequenze, è anche fase lineare. Il filtraggio indietro nel tempo richiede di prevedere il futuro, quindi non può essere utilizzato nelle applicazioni "online" nella vita reale, solo per l'elaborazione offline delle registrazioni dei segnali.

  • lfilterè solo un filtro causale forward-in-time, simile a un filtro elettronico nella vita reale. Non può essere in fase zero. Può essere una fase lineare (FIR simmetrica), ma di solito non lo è. Di solito aggiunge diverse quantità di ritardo a frequenze diverse.

Un esempio e un'immagine dovrebbero renderlo ovvio. Sebbene l'entità della risposta in frequenza dei filtri sia identica (in alto a sinistra e in alto a destra), il passa-basso a fase zero si allinea al segnale originale, solo senza contenuto ad alta frequenza, mentre il filtro di fase minimo ritarda il segnale in modo 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")

4
lfilternon è necessariamente una fase minima, può essere qualsiasi cosa a seconda dei coefficienti di filtro, ma in ogni caso è causale , che filtfiltnon lo è. Quindi il risultato del confronto che filtfiltha zero ritardi e lfilteraggiunge sempre qualche ritardo non è esattamente vero, perché filtfiltin primo luogo non è causale. Ciò che conta davvero è che filtfiltnon causa distorsioni di fase, mentre lo lfilterfa (a meno che non sia usato come filtro FIR a fase lineare, cioè con denominatore = 1).
Matt L.

Vale anche la pena notare che il filtraggio dell'ennesimo ordine con filtfiltcorrisponde al filtraggio con (2N-1) con l'ordine lfilter.
Thomas Arildsen,

@ThomasArildsen Non è solo 2N? Questo è quello che ho dimostrato nella sceneggiatura
endolito del

@ArunimaPathania Dovresti commentare sotto la mia risposta, non sotto la domanda. "Segnale originale" indica semplicemente il segnale che stai filtrando. Puoi filtrare con lfiltero filtfilt. Si comportano diversamente, come mostrato
endolith

7

La risposta di @endolith è completa e corretta! Si prega di leggere prima il suo post, quindi questo oltre a questo. A causa della mia scarsa reputazione non sono stato in grado di rispondere ai commenti in cui @Thomas Arildsen e @endolith discutono sull'efficace ordine del filtro ottenuto da filtfilt:

  • lfilter applica un determinato filtro e nello spazio di Fourier è come applicare la funzione di trasferimento del filtro UNA VOLTA.

  • filtfiltapplica lo stesso filtro due volte e l'effetto è come applicare la funzione di trasferimento del filtro SQUARED. Nel caso del filtro Butterworth ( scipy.signal.butter) con la funzione di trasferimento

sol(n)=11-ω2ndove n è l'ordine del filtro

il guadagno effettivo sarà

sol(n)fioltfiolt=sol(n)2=11-ω2n

2n2n-1

sol(n)fioltfioltsol(2n).

1
Si prega di provare a non aggiungere commenti come risposte. Tuttavia, benvenuto su SE.DSP e ricevi un +1 da parte mia. Penso che questo si aggiunge alla risposta ... almeno prova a ottenere abbastanza rappresentante per commentare! :-)
Peter K.

Non penso sia vero. G (n) è il guadagno di ampiezza del filtro. Se si collega in cascata la complessa funzione di trasferimento, penso che funzionerà a 2n.
Mike,

Ho confermato con una rapida simulazione che un Butterworth del 6 ° ordine fornisce lo stesso G (ω) di 2 x (Butterworth del 3 ° ordine) in cascata, ma con la frequenza di taglio del 3 ° ordine ridimensionata di 1,6. I risultati sono identici ad eccezione del ridimensionamento della frequenza di taglio. Quindi, l'ordine si scala con 2n, ma nota che la banda passante si ridurrà quando cadi in cascata e deve essere compensata. Qualcuno si sente libero di spiegare la teoria, ma non voglio davvero passare attraverso tutta la matematica.
Mike,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.