前ページの周波数解析で,雑音がある場合,雑音が大きくなりすぎると周期的成分が雑音に埋もれて, あるはずのピークが周波数解析により見いだせなくなった. サンプリング周波数を十分にあげれば何とか見つけることもできたが, 元の信号の成分を知らない時にどうやって十分と判断すればよいのか. 実験環境によってはサンプリング周波数を上げられないこともある.
フィルター(濾過器)によっていらない信号を取り除こう. まずは,二つの周波数からなる信号の一部を取り除く. 前ページと同じく \(f(x)=1.0\sin(0.1*2\pi*x)+1.0\cos(1.0*2\pi*x)\) より得られる信号があった時に, たとえば後半の1Hzの信号を取り除きたいとする.
フーリエ変換と逆フーリエ変換を利用する.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | import numpy as np
import matplotlib.pyplot as plt
from scipy import fftpack
def f(x):
pi2 = 2.*np.pi
return 1.0*np.sin(0.1*pi2*x) + 1.0*np.cos(1.*pi2*x)
low_pass_freq = 0.5
num_of_sample = 1024
sampling_time = 100.0
sampling_freq = num_of_sample /sampling_time
print 'sampling_freq is',sampling_freq,'[Hz]'
#Periodic data with/without random noise
xdata = np.linspace(0, sampling_time, num=num_of_sample)
np.random.seed(1234)
ydata = f(xdata) #+ 1.0*np.random.randn(xdata.size)
#FFT
time_step = xdata[1]-xdata[0]
sample_freq = fftpack.fftfreq(ydata[:].size, d=time_step)
y_fft = fftpack.fft(ydata[:])
pidxs = np.where(sample_freq > 0)
freqs, power = sample_freq[pidxs], np.abs(y_fft)[pidxs]
freq = freqs[power.argmax()]
#iFFT
y_fft[np.abs(sample_freq) > low_pass_freq] = 0
filtered_ydata = fftpack.ifft(y_fft)
filtered_ydata = filtered_ydata.real
#FFT2
y_fft2 = fftpack.fft(filtered_ydata[:])
pidxs2 = np.where(sample_freq > 0)
freqs2, power2 = sample_freq[pidxs2], np.abs(y_fft2)[pidxs2]
freq2 = freqs[power2.argmax()]
#PLot
plt.figure(figsize=(8,10))
plt.subplot(211)
plt.plot(xdata,ydata,'b-', linewidth=0.5)
plt.plot(xdata,filtered_ydata,'r-',linewidth=1, label='filtered')
plt.xlim(0.,20.)
plt.xlabel('Time')
plt.ylabel('Ydata')
plt.grid(True)
plt.subplot(212)
#plt.semilogx(freqs, power,'b.-',lw=1)
plt.loglog(freqs, power,'b.-',lw=1)
plt.loglog(freqs2, power2,'r.-',lw=1)
plt.ylim(0.1,10.**4)
plt.xlabel('Frequency')
plt.ylabel('Power')
plt.grid(True)
plt.show()
|
※出だしの書き方が前ページから少し変更.
9行目:ここで指定する値以下の周波数成分だけを残すことにする.0.5Hzとした.
28行目:low_pass_freq(0.5Hz)より大きい周波数成分をゼロにする. 29,30行目:逆フーリエ変換を行い,時間領域データを得る. 32行目~:さらに得られたデータをフーリエ変換し,周波数領域でフィルターの効果を確認.
実行結果は以下の通り,
上の図の青い線が元の信号で,赤い線が0.5Hz以下の成分だけを残した信号である. (ある値以下の信号だけを残すフィルターをLow pass filter(低い成分だけが通過できるフィルター)という) 0.1Hzのきれいなsinカーブである. 下の図は,周波数領域での表示.フィルター通過後の赤い線では,カットした0.5Hz以上の成分がほとんどなくなっているのが分かる.
しかし,やはり前述のエイリアス現象には注意しなくてはいけない. サンプリング数(num_of_sample = 1024)が不十分なまま,cosの周波数を10Hzにすると,
return 1.0*np.sin(0.1*pi2*x) + 1.0*np.cos(10.*pi2*x)
やはりうまくいかないのである.おそるべしエイリアス. もちろん,サンプリング数を倍にしてサンプリング周波数が10Hzの2倍になるようにすればうまくいく.
そのうち.