Lọc - nhân trong miền tần số


7

Tôi đang cố gắng tạo bộ lọc thông thấp đơn giản, nhưng tôi đã nhận được kết quả đáng ngạc nhiên khi xem xét đáp ứng tần số của bộ lọc Butterworth đơn giản.

Tôi đã sao chép nhiều ví dụ dưới đây từ bài đăng khác này . Tôi đã thêm một số mã ở dưới cùng của tập lệnh để so sánh phổ đầu vào và đầu ra với đáp ứng tần số của bộ lọc. Tôi hy vọng rằng phổ đầu ra sẽ là sản phẩm của phổ đầu vào và đáp ứng tần số : BMộtH

B= =HMột

Tuy nhiên, biểu đồ bên dưới cho thấy bộ lọc thực sự làm tăng một số thành phần tần số thấp - xem cách đường màu đỏ ở trên màu xanh lá cây bên dưới khoảng .4 Hz

Bất cứ ai có thể giải thích tại sao điều này là?

import numpy as np
from scipy.signal import butter, lfilter, freqz
import matplotlib.pyplot as plt
from scipy.fftpack import fft as fft
def butter_lowpass(cutoff, fs, order=5):
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = butter(order, normal_cutoff, btype='low', analog=False)
    return b, a

def butter_lowpass_filter(data, cutoff, fs, order=5):
    b, a = butter_lowpass(cutoff, fs, order=order)
    y = lfilter(b, a, data)
    return y


# Filter requirements.
order = 6
fs = 30.0       # sample rate, Hz
cutoff = 3.667  # desired cutoff frequency of the filter, Hz

# Get the filter coefficients so we can check its frequency response.
b, a = butter_lowpass(cutoff, fs, order)

# Plot the frequency response.
w, h = freqz(b, a, worN=8000)
plt.subplot(2, 1, 1)
plt.plot(0.5*fs*w/np.pi, np.abs(h), 'b')
plt.plot(cutoff, 0.5*np.sqrt(2), 'ko')
plt.axvline(cutoff, color='k')
plt.xlim(0, 0.5*fs)
plt.title("Lowpass Filter Frequency Response")
plt.xlabel('Frequency [Hz]')
plt.grid()


# Demonstrate the use of the filter.
# First make some data to be filtered.
T = 5.0         # seconds
n = int(T * fs) # total number of samples
t = np.linspace(0, T, n, endpoint=False)
# "Noisy" data.  We want to recover the 1.2 Hz signal from this.
data = np.sin(1.2*2*np.pi*t) + 1.5*np.cos(9*2*np.pi*t) + 0.5*np.sin(12.0*2*np.pi*t)

# Filter the data, and plot both the original and filtered signals.
y = butter_lowpass_filter(data, cutoff, fs, order)

plt.subplot(2, 1, 2)
plt.plot(t, data, 'b-', label='data')
plt.plot(t, y, 'g-', linewidth=2, label='filtered data')
plt.xlabel('Time [sec]')
plt.grid()
plt.legend()

plt.subplots_adjust(hspace=0.35)
plt.show()

def calculateFFT(time,signal):
    N=len(signal)      
    df=1/((time[-1]-time[0]))
    frequencies=[i*df for i in range(int(N/2.0))]
    fftValues = [2.0/N*abs(i) for i in fft(signal,N)[0:N/2.0] ]
    return frequencies,fftValues

plt.subplot(2, 1, 1)
originalfreqs,originalFFT=calculateFFT(t,data)
plt.plot(originalfreqs,originalFFT,"g",label="original")

filteredfreqs,filteredFFT=calculateFFT(t,y)
plt.plot(filteredfreqs,filteredFFT,"r",label="filtered")
plt.legend()

nhập mô tả hình ảnh ở đây

Câu trả lời:


4

Tôi vui mừng nêu lên câu hỏi này, bởi vì đây là cách một câu hỏi hay sẽ như thế nào, và cũng vậy, tôi mong các sinh viên xác minh sự hiểu biết của họ về những thứ họ học. Luôn luôn tốt để hiểu được nền tảng của một cái gì đó mà bạn muốn sử dụng sau này.

Vấn đề bạn gặp phải là như sau: Về nguyên tắc bạn đúng, rằng định lý tích chập hàm ý rằng tích chập trong một miền là phép nhân trong miền khác. Do đó bạn có

F{x(t)*h(t)}= =X(f)H(f)
Ở đâu F biểu thị Biến đổi Fourier.

Vậy, cái gì x(t)h(t) trong hệ thống của bạn? x(t)là tín hiệu đầu vào của bạn (màu xanh lam), là tổng của ba hình sin, nhân với một cửa sổ hình chữ nhật. Nó hoàn toàn được nhân với một hình chữ nhật, bởi vì thời gian của bạn không (trong mô phỏng, nó không thể) đạt được từ- đến . Vì vậy, phổ củaX(f)là tích chập của một hàm chân (từ cửa sổ hình chữ nhật) với ba Dirac (ở tần số của các sin). Rõ ràng, đây không phải là một quang phổ hoàn toàn rời rạc.

Những gì là h(t)? Đó là đáp ứng xung của bộ lọc butterworth. Bộ lọc Butterworth có đáp ứng xung dài vô hạn, do đó sản phẩm tích chập của bạnx(t)*h(t)cũng rộng vô hạn. Vì vậy, về nguyên tắc, bạn không thể áp dụng một Fourier Transform hữu hạn (tức là rời rạc) và mong đợi nó tương tự như trường hợp liên tục.

Vì vậy, những gì bạn thấy là hợp lý. Bạn có thể thử zeropadding tín hiệu đầu vào, sao cho bạn nhận được (phần chính của) đáp ứng xung trong tín hiệu của bạn. Tuy nhiên, ngay cả khi đó, bạn sẽ thấy các tần số, kể từ khiX(f) không thực sự rời rạc.


5

Để mở rộng câu trả lời của @ Maximilian Matthé , bạn có thể hình dung các hiệu ứng rò rỉ quang phổ (tích chập của hàm chân trong miền tần số) bằng cách đệm không các đầu vào được sử dụng trong . Ví dụ, hàm sau không đệm các đầu vào theo chiều dàicalculateFFTk thời gian dài hơn đầu vào ban đầu (trong trường hợp này k= =4):

def calculateFFT(time,signal):
    k=4
    N=k*len(signal)      
    df=1/(k*(time[-1]-time[0]))
    frequencies=[i*df for i in range(int(N/2.0))]
    fftValues = [k*2.0/N*abs(i) for i in fft(signal,N)[0:int(N/2.0)] ]
    return frequencies,fftValues

Vẽ kết quả bạn sẽ thấy rằng các thành phần tần số thấp thực sự trùng lặp (điều này cho thấy rằng bộ lọc không thực sự làm tăng tín hiệu ở đó):

nhập mô tả hình ảnh ở đây

Vậy, những gợn sóng xung quanh mũi nhọn đó đến từ đâu? Hóa ra chúng luôn ở đó, nhưng khi tính toán FFT, bạn đã thu được giá trị của phổ ở một tập hợp các giá trị tần số riêng biệt và những gợn sóng đó xảy ra xuyên qua chính xác ở các tần số đó. Nếu bạn đã chọn tần số tín hiệu hơi khác nhau không phải là bội số chính xác của độ phân giải tần số FFT (0,2Hz trong trường hợp của bạn), ví dụ 1,25Hz thay vì 1,2Hz, việc lấy mẫu phổ tần số sẽ trông khá khác nhau (do để lấy mẫu tần số tại các điểm khác nhau trong dao động của các gợn sóng):

nhập mô tả hình ảnh ở đâ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.