การใช้ตัวกรองใน scipy.signal: ใช้ lfilter หรือ filtfilt หรือไม่


21

ผมเห็นในSO ด้ายข้อเสนอแนะเพื่อการใช้งานfiltfiltที่มีประสิทธิภาพไปข้างหลัง / lfilterข้างกรองแทน

อะไรคือแรงจูงใจในการใช้เทคนิคหนึ่งเทียบกับเทคนิคอื่น?


Filtfilt ช้าลง
Aaron

ความเป็นไปได้ที่ซ้ำกันของข้อดีของการกรองข้อมูลของ MATLAB คืออะไร
Matt L.

1
@Aaron filtfiltทำฟิลเตอร์เดียวกันสองครั้งในทิศทางตรงกันข้ามดังนั้นมันจะไม่ช้าไปกว่าการทำlfilterสองครั้งในทิศทางเดียวซึ่งเป็นวิธีที่คุณจะได้รับการตอบสนองความถี่เดียวกัน
endolith

ใช่นั่นคือทั้งหมดที่ฉันหมายถึง มันช้าเป็นสองเท่า
แอรอน

ฉันยังใหม่กับสิ่งนี้และมองไปรอบ ๆ เพื่อใช้ตัวกรอง @endolith กล่าวว่า scipy.signal ใช้สัญญาณดั้งเดิม ฉันไม่แน่ใจว่าสัญญาณดั้งเดิมมีความหมายอย่างไรและเราจะรับได้อย่างไร ฉันมีไฟล์ wav ที่ฉันโหลดเข้าสู่ระบบของฉัน แต่ฉันไม่คิดว่ามันเป็นสัญญาณดั้งเดิมเพราะมันถูกแบ่งออกเป็นอาเรย์ numpy และจำนวนตัวอย่าง กรุณาถ้ามีคนช่วยได้ ขอขอบคุณ!
Arunima Pathania

คำตอบ:


30
  • filtfiltเป็นการกรองแบบ zero-phase ซึ่งไม่เปลี่ยนสัญญาณในขณะที่มันทำการกรอง เนื่องจากเฟสเป็นศูนย์ที่ความถี่ทั้งหมดจึงเป็นเฟสเชิงเส้น การกรองย้อนกลับไปในเวลานั้นกำหนดให้คุณต้องทำนายอนาคตดังนั้นจึงไม่สามารถใช้ในแอปพลิเคชันในชีวิตจริง "ออนไลน์" ได้เฉพาะสำหรับการประมวลผลการบันทึกสัญญาณแบบออฟไลน์

  • lfilterเป็นสาเหตุการกรองล่วงหน้าในเวลาซึ่งคล้ายกับตัวกรองอิเล็กทรอนิกส์ในชีวิตจริง มันไม่สามารถเป็นศูนย์ได้ มันสามารถเป็นเฟสเชิงเส้น (symmetrical FIR) ได้ แต่โดยทั่วไปแล้วไม่ใช่ โดยปกติจะเพิ่มจำนวนความล่าช้าที่แตกต่างกันที่ความถี่ที่แตกต่างกัน

ตัวอย่างและรูปภาพควรทำให้ชัดเจน แม้ว่าขนาดของการตอบสนองความถี่ของตัวกรองจะเหมือนกัน (บนซ้ายและขวาบน), low-zero lowpass ขึ้นกับสัญญาณดั้งเดิมโดยไม่มีเนื้อหาความถี่สูงในขณะที่การกรองเฟสขั้นต่ำทำให้สัญญาณล่าช้าในลักษณะที่เป็นสาเหตุ :

ตัวกรอง 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
lfilterไม่จำเป็นต้องเป็นขั้นต่ำมันสามารถเป็นอะไรก็ได้ขึ้นอยู่กับสัมประสิทธิ์การกรอง แต่ในกรณีใด ๆ มันเป็นสาเหตุซึ่งfiltfiltไม่ใช่ ดังนั้นผลลัพธ์ของการเปรียบเทียบที่filtfiltมีการหน่วงเวลาเป็นศูนย์และการlfilterเพิ่มการหน่วงเวลาบางอย่างนั้นไม่เป็นความจริงอย่างแน่นอนเพราะfiltfiltไม่ใช่สาเหตุในตอนแรก สิ่งที่สำคัญจริงๆก็คือfiltfiltว่าไม่ได้ทำให้เกิดการบิดเบือนเฟสใด ๆ ในขณะที่lfilter(ยกเว้นว่ามันจะใช้เป็นตัวกรองเฟส FIR เชิงเส้นเช่นกับตัวหาร = 1)
Matt L.

นอกจากนี้ยังเป็นที่น่าสังเกตว่าการกรองของคำสั่งชับกับfiltfiltสอดคล้องกับการกรองด้วย (2N-1) lfilterเพื่อบริบูรณ์ด้วย
Thomas Arildsen

@ThomasArildsen มันไม่ใช่แค่ 2N ใช่มั้ย นั่นคือสิ่งที่ฉันแสดงให้เห็นในสคริปต์
endolith

@ArunimaPathania คุณควรแสดงความคิดเห็นภายใต้คำตอบของฉันไม่ใช่คำถาม "สัญญาณดั้งเดิม" เพียงหมายถึงสัญญาณที่คุณกำลังกรอง คุณสามารถกรองด้วยหรือlfilter filtfiltพวกเขาทำงานแตกต่างกันดังที่แสดง
endolith

7

คำตอบโดย @endolith เสร็จสมบูรณ์และถูกต้อง! โปรดอ่านโพสต์ของเขาก่อนจากนั้นโพสต์นี้เพิ่มเติม เนื่องจากชื่อเสียงที่ต่ำของฉันฉันไม่สามารถตอบกลับความคิดเห็นที่@Thomas Arildsenและ@endolithโต้แย้งเกี่ยวกับคำสั่งที่มีประสิทธิภาพของตัวกรองที่ได้รับจากfiltfilt:

  • lfilter ใช้ตัวกรองที่กำหนดและในพื้นที่ฟูริเยร์นี่เป็นเหมือนการใช้ฟังก์ชั่นการถ่ายโอนตัวกรองครั้งเดียว

  • filtfiltใช้ตัวกรองเดียวกันสองครั้งและเอฟเฟกต์จะเหมือนกับการใช้ฟังก์ชันถ่ายโอนตัวกรอง SQUARED ในกรณีของตัวกรอง Butterworth ( scipy.signal.butter) พร้อมฟังก์ชันถ่ายโอน

G(n)=11-ω2nที่ไหน n เป็นคำสั่งของตัวกรอง

กำไรที่มีประสิทธิภาพจะเป็น

G(n)ผมล.เสื้อผมล.เสื้อ=G(n)2=11-ω2n

2n2n-1

G(n)ผมล.เสื้อผมล.เสื้อG(2n).

1
โปรดอย่าเพิ่มความคิดเห็นเป็นคำตอบ อย่างไรก็ตามยินดีต้อนรับสู่ SE.DSP และมี +1 จากฉัน ฉันคิดว่านี่เป็นการเพิ่มคำตอบ ... อย่างน้อยพยายามรับตัวแทนให้แสดงความคิดเห็นอย่างเพียงพอ! :-)
Peter K.

ฉันไม่คิดว่านี่เป็นเรื่องจริง G (n) คือแอมพลิจูดของตัวกรอง ถ้าคุณเรียงซ้อนฟังก์ชั่นการถ่ายโอนที่ซับซ้อนฉันคิดว่ามันจะได้ผลเป็น 2n
Mike

ฉันยืนยันด้วยการจำลองสถานการณ์อย่างรวดเร็วว่าลำดับที่ 6 ของ Butterworth ให้ G (ω) เท่ากันกับ 2 x (ลำดับที่ 3 Butterworth) เรียงลำดับ แต่มีความถี่ตัดของลำดับที่ 3 ที่ปรับขนาด 1.6 ผลลัพธ์เหมือนกันยกเว้นการปรับสเกลความถี่การตัด ดังนั้นลำดับจะขยายด้วย 2n แต่โปรดทราบว่า passband จะลดลงเมื่อคุณเรียงซ้อนและจำเป็นต้องได้รับการชดเชย บางคนรู้สึกอิสระที่จะอธิบายทฤษฎี แต่ฉันไม่ต้องการผ่านคณิตศาสตร์ทั้งหมด
Mike
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.