Pythonで高速フーリエ変換(FFT)の練習-3 逆高速フーリエ変換(IFFT)の実践

Pythonで高速フーリエ変換(FFT)の練習-3 逆高速フーリエ変換(IFFT)の実践

Pythonで高速フリーエ変換(FFT)を行う方法をモモノキ&ナノネと一緒に学習していきます。

モモノキ&ナノネと一緒にPythonでFFTの使い方を覚えよう(3)




逆高速フーリエ変換(IFFT)で元の信号に戻してみよう

今回はPythonで逆高速フリー変換(IFFT)の練習をするよ。

IFFTはinverse fast Fourier transformの略称で、逆変換という名前の通りFFTの結果を元の信号形式に戻すことができるよ。

FFTは信号の情報を時間軸から周波数軸に変換する操作。IFFTはその逆で周波数軸を時間軸に変換する作用があるよ。FFTとIFFTを利用すれば時間軸と周波数軸の相互変換ができるんだよ。

IFFTを使うとFFTで変換したデータを元に戻せるってことだね。

今回は信号をFFTで変換した値が、IFFTで本当に元の信号の値に戻るか?実践で試してみよう。

まず、テスト用の適当な信号データを一つ作ってみて。

In [1]:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

# 簡単な信号の作成
N = 128 # サンプル数
dt = 0.01 # サンプリング周期(sec):100ms =>サンプリング周波数100Hz
freq1 = 10 # 周波数(10Hz) =>正弦波の周期0.1sec
amp1 = 1 # 振幅
freq2 = 15 # 周波数(15Hz) =>正弦波の周期0.066...sec
amp2 = 1 # 振幅

t = np.arange(0, N*dt, dt) # 時間軸
f = amp1 * np.sin(2*np.pi*freq1*t) + amp2 * np.sin(2*np.pi*freq2*t) # 信号
# グラフ表示
plt.xlabel('time(sec)', fontsize=14)
plt.ylabel('signal', fontsize=14)
plt.plot(t, f)
Out[1]:
[<matplotlib.lines.Line2D at 0xad2d60ec>]

信号データできた。適当だけど周波数10Hzと15Hzの正弦波を足してみた。

OK、次はFFTで普通に変換してみて。

In [2]:
# 高速フーリエ変換(FFT)
F = np.fft.fft(f)

FFT完了。FFT結果のグラフも描いておくよ。

In [3]:
# FFTの複素数結果を絶対に変換
F_abs = np.abs(F)
# 振幅をもとの信号に揃える
F_abs_amp = F_abs / N * 2 # 交流成分はデータ数で割って2倍
F_abs_amp[0] = F_abs_amp[0] / 2 # 直流成分(今回は扱わないけど)は2倍不要

# 周波数軸のデータ作成
fq = np.linspace(0, 1.0/dt, N) # 周波数軸 linspace(開始,終了,分割数)

# グラフ表示(FFT解析結果)
plt.xlabel('freqency(Hz)', fontsize=14)
plt.ylabel('amplitude', fontsize=14)
plt.plot(fq, F_abs_amp)
Out[3]:
[<matplotlib.lines.Line2D at 0xad1f18cc>]

次は、FFTの実行結果の値がIFFTでもとの信号の値にもどるか確認してみよう。今、FFTの結果は、変数Fに入っているよね。

うん、たしか複素数の形式で入ってるはず。

In [4]:
F[:10] # FFTの結果を先頭10個だけ表示
Out[4]:
array([ 1.74137876+0.j        ,  1.75011493+0.06617893j,
        1.77689604+0.1359568j ,  1.82354371+0.21346121j,
        1.89347771+0.30403524j,  1.99244927+0.41532429j,
        2.12999556+0.55924527j,  2.32243735+0.75596177j,
        2.59961839+1.04285493j,  3.02220287+1.49779194j])

FFTの結果をIFFTで逆変換する場合は、Numpyのfft.ifft(データ)が使えば逆変換ができるよ。今回の場合はnp.fft.ifft(F)として結果を変数で受け取ればOK。元の信号データに戻っているはずだよ。

In [5]:
F_ifft = np.fft.ifft(F) # 逆フーリエ変換(IFFT)

IFFTで逆変換した。変数の値を確認してみる。

In [6]:
F_ifft[:10] # IFFTで逆変換した結果を先頭10個だけ表示
Out[6]:
array([ -2.42861287e-17 +4.33680869e-19j,
         1.39680225e+00 +7.25725317e-16j,
         1.90211303e+00 -5.41889328e-16j,
         1.26007351e+00 -7.16355130e-18j,
         2.46978144e-16 +2.04271100e-17j,
        -1.00000000e+00 -9.19914063e-16j,
        -1.17557050e+00 +4.97038933e-17j,
        -6.42039522e-01 -2.59772493e-16j,
        -1.39417531e-16 -3.36505388e-17j,   2.21231742e-01 +5.27297377e-18j])

IFFTの結果は複素数になっているから、実数部の値だけ取り出してみて。複素数.realで取得できるよ。

In [7]:
F_ifft_real = F_ifft.real # 実数部
F_ifft_real[:10]
Out[7]:
array([ -2.42861287e-17,   1.39680225e+00,   1.90211303e+00,
         1.26007351e+00,   2.46978144e-16,  -1.00000000e+00,
        -1.17557050e+00,  -6.42039522e-01,  -1.39417531e-16,
         2.21231742e-01])

実数部の値だけ取り出した。

グラフを描いて、元の信号と比べてみて。

In [8]:
plt.plot(t, F_ifft_real, c="g") # IFFT(逆変換)
Out[8]:
[<matplotlib.lines.Line2D at 0xad1253ac>]

もとの信号に戻ったみたいだけど、グラフに重ねてプロットしてみる。

In [9]:
plt.plot(t, f, label='original') # IFFT(逆変換)
plt.plot(t, F_ifft_real, c="g", linestyle='--', label='IFFT') # IFFT(逆変換)
plt.legend(loc='best')
plt.xlabel('time(sec)', fontsize=14)
plt.ylabel('signal', fontsize=14)
Out[9]:
<matplotlib.text.Text at 0xad13d3cc>

もとの信号の値とIFFTの値が一致している、逆変換成功だ。

逆変換も簡単にできたね。今回はここまでして、続きはまたにしよう。次回はノイズ除去に挑戦してみるよ。





スポンサーリンク

0 件のコメント :

コメントを投稿