質問: np.fft.fft(windowdate) f_abs =np.abs(f) plt.xticks(np.arange(0,itr,10)) plt.bar(time,f_abs) plt.show() ```
回答: fft自体の計算や結果の周波数成分はあっていると思いますが、それをプロットするにあたり横軸の次元を間違って扱っておられるようです。 * (A)元の波形の横軸 次元は「時間」です。コードではサンプルリングデータの単位を単純に用いてプロットしておられますが、それをそのまま受け入れるなら波形の一周期は25**単位時間**ほどであるといえます。 * (B)FFT結果の横軸 次元は「周波数」です。周波数は「単位時間あたりに何周期するか」ということですので、一周期が25単位時間であるならその波の周波数は1/25=0.04ですね。質問者さんは26あたりにスペクトルのピークが出ることを期待しておられますが正しくは周波数1/26=0.038あたりにピークが来ると考えるべきです。 具体的なコードの問題を挙げますと「本来はFFT結果の横軸に周波数を指定すべきところ、元波形の横軸(time)をそのまま設定している」ということになります。 結果のスペクトルの棒グラフをプロットする際に注意すべき点としては * 横軸の値は基本周波数(※1)の倍数の数列にする * 基本周波数が1より小さいとき、棒グラフの幅が広すぎて見づらくなるためwidthに適当な値を指定する くらいかと思います。検証のため、サンプリング周波数=1、サンプル数=50として周期25の正弦波を用いてスペクトルをプロットするコードを書いてみました。なお、本件に直接関係ないですが、matplotlibの関数的インターフェース(plt.xxxを呼び出す)ではなくオブジェクト指向的インターフェース(figureやaxesに対してメソッドを呼び出すスタイル)で記述しています。わかりにくかったらすみません。 ``` import matplotlib.pyplot as plt import numpy as np N = 50 # サンプル数 Fs = 1 # サンプリング周波数 Dt = 1 / Fs # サンプル間の時間差 Fb = Fs / N # 基本周波数 # 元波形の横軸 ts = np.linspace(0, Dt * N, N, endpoint=False) # テスト用の波形 Ft = 0.04 # 周波数(周期=25) data = np.sin(2 * np.pi * Ft * t for t in ts]) # 元波形のプロット fig = plt.figure() ax1 = fig.add_subplot(211) ax1.plot(ts, data) # FFT spectrum = np.fft.fft(data) abs_spectrum = np.abs(spectrum) # 周波数成分のプロット fs = np.linspace(0, Fb * N, N, endpoint=False) ax2 = fig.add_subplot(212) ax2.bar(fs, abs_spectrum, width=Fb * 0.8) # tick間隔をFtにしたほうが結果がよりはっきりわかるのですが、そうしてしまうと # 横軸ラベルが重なってしまい視認できなかったのでFtの倍の間隔にしてあります ax2.xaxis.set_ticks(np.arange(0, 1, Ft * 2)) plt.show() ``` ※1:基本周波数 離散フーリエ変換では、サンプリング周波数Fs、サンプル数Nのとき、計算結果のスペクトルは基本周波数(=Fs/N)の倍数の周波数のものが出てきます。 結果 ![イメージ説明 この結果を見ると、質問者さんの棒グラフでいえば横軸の値が2のところ(実際は周波数0.04にあたる場所)に期待どおりのスペクトルが出ていることがわかると思います。