Làm cách nào để viết bộ lọc thông thấp cho tín hiệu được lấy mẫu trong Python?


16

Tôi có một số tín hiệu đã lấy mẫu mỗi 1 ns (1e-9 giây) và có, giả sử, 1e4 điểm. Tôi cần lọc tần số cao từ tín hiệu này. Giả sử tôi cần lọc tần số cao hơn 10 MHz. Tôi muốn rằng đối với các tần số thấp hơn tín hiệu tần số cắt sẽ được truyền không thay đổi. Điều đó có nghĩa là mức tăng của bộ lọc sẽ là 1 đối với tần số thấp hơn tần số cắt. Tôi muốn có thể chỉ định thứ tự bộ lọc. Ý tôi là, bộ lọc thứ tự đầu tiên có độ dốc 20 db / thập kỷ (tắt nguồn) sau tần số cắt, bộ lọc thứ hai có độ dốc 40 db / dec sau tần số cắt, v.v. Hiệu suất cao của mã là quan trọng.

Câu trả lời:


19

Đáp ứng tần số cho bộ lọc được thiết kế bằng chức năng là:

Phản ứng của bộ lọc Butterworth

Nhưng không có lý do gì để giới hạn bộ lọc thành một thiết kế bộ lọc đơn điệu không đổi. Nếu bạn mong muốn mức suy giảm cao hơn trong dải chuyển tiếp và dải chuyển tiếp dốc hơn, các tùy chọn khác tồn tại. Để biết thêm thông tin về việc chỉ định bộ lọc bằng cách sử dụng iirdesing, hãy xem phần này . Như thể hiện trong các ô đáp ứng tần số cho thiết kế , tần số cắt (điểm -3dB) nằm xa mục tiêu. Điều này có thể được giảm bớt bằng cách lấy mẫu xuống trước khi lọc (các chức năng thiết kế sẽ có một thời gian khó khăn với bộ lọc hẹp như vậy, 2% băng thông). Hãy xem xét việc lọc tỷ lệ mẫu ban đầu với mức cắt được chỉ định.

import numpy as np
from scipy import signal
from matplotlib import pyplot as plt

from scipy.signal import fir_filter_design as ffd
from scipy.signal import filter_design as ifd

# setup some of the required parameters
Fs = 1e9           # sample-rate defined in the question, down-sampled

# remez (fir) design arguements
Fpass = 10e6       # passband edge
Fstop = 11.1e6     # stopband edge, transition band 100kHz
Wp = Fpass/(Fs)    # pass normalized frequency
Ws = Fstop/(Fs)    # stop normalized frequency

# iirdesign agruements
Wip = (Fpass)/(Fs/2)
Wis = (Fstop+1e6)/(Fs/2)
Rp = 1             # passband ripple
As = 42            # stopband attenuation

# Create a FIR filter, the remez function takes a list of 
# "bands" and the amplitude for each band.
taps = 4096
br = ffd.remez(taps, [0, Wp, Ws, .5], [1,0], maxiter=10000) 

# The iirdesign takes passband, stopband, passband ripple, 
# and stop attenuation.
bc, ac = ifd.iirdesign(Wip, Wis, Rp, As, ftype='ellip')  
bb, ab = ifd.iirdesign(Wip, Wis, Rp, As, ftype='cheby2') 

Bộ lọc tỷ lệ mẫu gốc

Như đã đề cập, bởi vì chúng tôi đang cố gắng lọc một phần trăm nhỏ băng thông như vậy, bộ lọc sẽ không bị cắt mạnh. Trong trường hợp này, bộ lọc thông thấp, chúng ta có thể giảm băng thông để có bộ lọc tìm kiếm tốt hơn. Hàm lấy mẫu python / scipy.signal có thể được sử dụng để giảm băng thông.

Lưu ý chức năng lấy mẫu lại sẽ thực hiện lọc để ngăn răng cưa. Việc lọc sơ bộ cũng có thể được thực hiện (để giảm răng cưa) và trong trường hợp này chúng ta chỉ cần lấy mẫu lại bằng 100 và được thực hiện , nhưng câu hỏi được hỏi về việc tạo bộ lọc. Trong ví dụ này, chúng tôi sẽ giảm mẫu xuống 25 và tạo bộ lọc mới

R = 25;            # how much to down sample by
Fsr = Fs/25.       # down-sampled sample rate
xs = signal.resample(x, len(x)/25.)

Nếu chúng tôi cập nhật các tham số thiết kế cho bộ lọc FIR, phản hồi mới là.

# Down sampled version, create new filter and plot spectrum
R = 25.             # how much to down sample by
Fsr = Fs/R          # down-sampled sample rate
Fstop = 11.1e6      # modified stopband
Wp = Fpass/(Fsr)    # pass normalized frequency
Ws = Fstop/(Fsr)    # stop normalized frequency
taps = 256
br = ffd.remez(taps, [0, Wp, Ws, .5], [1,0], maxiter=10000) 

Đáp ứng bộ lọc Downsampling

Bộ lọc hoạt động trên dữ liệu được ghép xuống có phản hồi tốt hơn. Một lợi ích khác của việc sử dụng bộ lọc FIR là bạn sẽ có phản ứng pha tuyến tính.


1
Cảm ơn bạn. Làm thế nào bạn tạo đồ thị phổ tín hiệu?
Alex

Cảm ơn rất nhiều cho một câu trả lời tuyệt vời! Tôi tự hỏi nếu bạn có thể giải thích cách áp dụng bộ lọc FIR dựa trên các hệ số được tính bằng Remez? Tôi đang gặp khó khăn để hiểu những gì filtfiltmuốn cho atham số.
ali_m

Một khi bạn có các hệ số từ một thiết kế bộ lọc, ( b cho FIR bmột cho IIR), bạn có thể sử dụng một vài chức năng khác nhau để thực hiện việc lọc: lfilter , dây leo , filtfilt . Thông thường tất cả các chức năng này hoạt động tương tự nhau: y = bộ lọc (b, a, x) Nếu bạn có bộ lọc FIR, chỉ cần đặt a = 1 , x là tín hiệu đầu vào, b là hệ số FIR. Đây bài có thể giúp là tốt.
Christopher Felton

5

Cái này có hoạt động không?

from __future__ import division
from scipy.signal import butter, lfilter

fs = 1E9 # 1 ns -> 1 GHz
cutoff = 10E6 # 10 MHz
B, A = butter(1, cutoff / (fs / 2), btype='low') # 1st order Butterworth low-pass
filtered_signal = lfilter(B, A, signal, axis=0)

Mặc dù vậy, bạn đã đúng, tài liệu này không đầy đủ. Nó trông giống như buttermột trình bao bọc cho iirfilter, được ghi lại tốt hơn :

N: int Thứ tự của bộ lọc. Wn: Array_like Một chuỗi vô hướng hoặc độ dài-2 cho các tần số tới hạn.

Tuy nhiên, hầu hết những thứ này được sao chép từ matlab, vì vậy bạn cũng có thể xem tài liệu của họ :

tần số cắt chuẩn hóa Wn phải là một số trong khoảng từ 0 đến 1, trong đó 1 tương ứng với tần số Nyquist, rad rad trên mỗi mẫu.

Cập nhật:

Tôi đã thêm tài liệu cho các chức năng này. :) Github làm cho nó dễ dàng.


1

Không chắc chắn ứng dụng của bạn là gì, nhưng bạn có thể muốn kiểm tra Gnuradio: http://gnuradio.org/doc/doxygen/ classgr__firdes.html

Các khối xử lý tín hiệu được viết bằng C ++ (mặc dù biểu đồ luồng Gnuradio bằng Python), nhưng bạn đã nói hiệu suất cao là quan trọng.


1

Tôi đang có kết quả tốt với bộ lọc FIR này. Thông báo nó áp dụng bộ lọc hai lần, "chuyển tiếp" và "đảo ngược", để bù cho tín hiệu bù ( filtfiltchức năng không hoạt động, không biết tại sao):

def firfilt(interval, freq, sampling_rate):
    nfreq = freq/(0.5*sampling_rate)
    taps =  sampling_rate + 1
    a = 1
    b = scipy.signal.firwin(taps, cutoff=nfreq)
    firstpass = scipy.signal.lfilter(b, a, interval)
    secondpass = scipy.signal.lfilter(b, a, firstpass[::-1])[::-1]
    return secondpass

Một tài nguyên tuyệt vời để thiết kế và sử dụng bộ lọc, từ nơi tôi đã lấy mã này và từ đó có thể lấy ví dụ về bộ lọc băng thông và hi-pass, là NÀY .


Tôi không tin rằng có nhiều lợi ích về phía trước và đảo ngược bộ lọc FIR. Bộ lọc IIR có thể được hưởng lợi từ chuyển tiếp / đảo ngược (bộ lọc) bởi vì bạn có thể nhận được pha tuyến tính từ bộ lọc pha phi tuyến tính bằng cách lọc ngược.
Christopher Felton

2
@ChristopherFelton Tôi chỉ cần đảo ngược để đồng bộ hóa tín hiệu điện cơ RAW với phiên bản được làm mịn của chính nó. Tôi biết tôi chỉ có thể thay đổi tín hiệu, nhưng lọc hai lần cuối cùng sẽ ít gặp rắc rối hơn. Điều đáng chú ý là đường chuyền thứ hai hầu như không thay đổi đường chuyền đầu tiên đã được lọc ... Cảm ơn bạn đã lưu ý!
heltonbiker

À, vâng. Để loại bỏ độ trễ (độ trễ nhóm), điểm tốt.
Christopher Felton

1

Tôi không có quyền bình luận ...

@endolith: Tôi sử dụng giống như bạn ngoại trừ sử dụng scipy.signal.filtfilt (B, A, x) trong đó x là vectơ đầu vào được lọc - ví dụ: numpy.random.n normal (size = (N)) . bộ lọc tạo ra một tín hiệu chuyển tiếp và ngược lại. Vì mục đích hoàn chỉnh (hầu hết giống như @endolith):

import numpy as np
import scipy.signal as sps

input = np.random.normal(size=(N)) # Random signal as example
bz, az = sps.butter(FiltOrder, Bandwidth/(SamplingFreq/2)) # Gives you lowpass Butterworth as default
output = sps.filtfilt(bz, az, input) # Makes forward/reverse filtering (linear phase filter)

filtfilt cũng như đề xuất bởi @heltonbiker đòi hỏi mảng các hệ số tôi tin. Trong trường hợp bạn cần thực hiện lọc băng thông ở dải cơ sở phức tạp, cần có cấu hình liên quan hơn nhưng điều này dường như không phải là vấn đề ở đây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.