フィルタリング-周波数領域での乗算


7

単純なローパスフィルターを作成しようとしていますが、単純なバターワースフィルターの周波数応答を見て、驚くべき結果が得られました。

この他の投稿から以下の例の多くをコピーしました。スクリプトの下部にコードを追加して、入力と出力のスペクトルをフィルターの周波数応答と比較します。出力スペクトルがB 入力スペクトルの積でなければなりません A と周波数応答 H

B=HA

ただし、下のプロットは、フィルターが実際に一部の低周波成分を増加させていることを示しています。赤い線が下の緑の上にある様子を確認してください 4 Hz

これがなぜであるか誰でも説明できますか?

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()

ここに画像の説明を入力してください

回答:


4

私はこの質問に喜んで賛成票を投じます。これは、良い質問がどのように見えるか、また、生徒が学んだことの理解を確認することを生徒に期待するためです。後で使用したいものの背景を理解することに熱心であるのは常に良いことです。

発生する問題は次のとおりです。原理的には正しいです。たたみ込み定理は、あるドメインのたたみ込みが他のドメインの乗算であることを意味します。したがって、あなたは持っています

F{x(t)h(t)}=X(f)H(f)
どこ F フーリエ変換を示します。

だから、何ですか x(t) そして h(t) あなたのシステムでは? x(t)入力信号(青色)です。これは、3つの正弦の合計に長方形のウィンドウを掛けたものです。時間は(シミュレーションでは)到達しないため、暗黙的に長方形が乗算されます。。だから、のスペクトルX(f)(長方形の窓からの)sinc関数と3つのディラック(正弦の周波数で)のたたみ込みです。明らかに、これは純粋に離散的なスペクトルではありません。

とは h(t)?バターワースフィルターのインパルス応答です。バターワースフィルターのインパルス応答は無限に長いため、畳み込み積x(t)h(t)また、無限に広いです。したがって、原則として、有限(離散)フーリエ変換(fft)を適用することはできず、連続的な場合と同様であると期待できます。

だから、あなたが見るものは合理的です。入力信号の(主な部分)インパルス応答が得られるように、入力信号のゼロパディングを試すことができます。ただし、その場合でも、周波数が表示されます。X(f) 実際には離散ではありません。


5

@ MaximilianMatthé答えを拡張するには、で使用される入力にゼロパディングを行うことで、スペクトル漏れ効果(周波数領域でのsinc関数によるたたみ込み)を視覚化できますcalculateFFT。たとえば、次の関数は、入力に長さをゼロ埋めします。k 元の入力(この場合、 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

結果をプロットすると、低周波成分が実際に重複していることがわかります(これは、フィルター処理によって実際に信号が増加しないことを示しています)。

ここに画像の説明を入力してください

では、スパイクの周りの波紋はどこから来たのでしょうか?それは常にそこにあることがわかりますが、FFTを計算するとき、周波数値の離散的なセットでスペクトルの値を取得していて、これらのリップルはこれらの周波数でたまたまゼロを通過していました。FFT周波数分解能の正確な倍数ではないわずかに異なる信号周波数(この場合は0.2Hz)を選択した場合、たとえば1.2Hzではなく1.25Hzの場合、周波数スペクトルのサンプリングはまったく異なるように見えます(さざ波の振動の異なるポイントでの周波数サンプリングに):

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.