こんにちは、うさじん(@Rabi_Jin_)です。
前回の記事にて、高速フーリエ変換の分解能について書きました。
本記事では、PythonのnumpyによるFFTの周波数分析について、周波数分解能の違いによる分析結果をグラフ描画して検証確認してみました。
こんにちは、うさじん(@Rabi_Jin_)です。 気温も一時期より大分暖かくなってきて、完全防寒対策して外出することもなくなってきました。 個人的には寒いより熱いほうが得意なので、早く春になればいい[…]
こんにちは、うさじん(@Rabi_Jin_)です。 昨日FFTの動作について数種類の波形で検証してみました。 FFTの周波数分解能が分析データ数とサンプリング周波数に依存している事実を再確認したため、[…]
比較データの準備
周波数分解能とは
前回記事のおさらいです。
周波数分解能は、周波数領域でパワースペクトルグラフを描いたとき、プロットされるデータの細かさです。
仮に1024個のデータについてFFTを行うと得られるFFTのデータ数は400個(=1024個/2.56)となります。
サンプリング周波数が1024Hzの場合、分析周波数は400Hz(=1024Hz/2.56)となります。
この場合、横軸スケール400Hzのグラフに400個のFFTのデータが入るため、
周波数分解能(⊿F)は1Hzとなります。
比較条件
同一波形データについて、FFTの周波数分解能の違いについて検討します。
FFTの分解能や他の諸条件は以下となります。
項目 | 記号 | ケース1 | ケース2 | ケース3 |
分析するデータ | ー | 正弦波 50.25Hz 振幅1 |
正弦波 50.25Hz 振幅1 |
正弦波 50.25Hz 振幅1 |
サンプリング周波数(Hz) | Fs(固定) | 1024 | 1024 | 1024 |
サンプリング周期(秒) | T | 0.0009765625 (=1/1024) |
0.0009765625 (=1/1024) |
0.0009765625 (=1/1024) |
分析周波数(Hz) | Frange=Fs/2.56 | 400(=1024/2.56) | 400(=1024/2.56) | 400(=1024/2.56) |
FFT処理する波形 データ数(個) |
N(固定) | 1024 | 2048 | 4096 |
FFT処理後のFFT ライン数(個) |
L=N/2.56 | 400(=1024/2.56) | 800(=2048/2.56) | 1600(=4096/2.56) |
FFTの分解能(Hz) | ⊿f=Frange/L | 1(=400/400) | 0.5(=400/800) | 0.25(=400/1600) |
今回はFFT処理する波形データの個数を調整して周波数分解能を変化させます。
分析するデータは「正弦波 50.25Hz 振幅1」となります。
ケース1~2はFFTの周波数分解能が0.5~1.0では完全に分析できない結果となり、
ケース3のみ正しい振幅値を返してくるものと予想しています。
Pythonコードの内容
from matplotlib import pyplot as plt
import numpy as np
import japanize_matplotlib
n= 1024 #データ数
Fs = 1024 #サンプリング周波数
dt = 1/Fs #サンプリング周期
Frange = Fs/2.56 #分析周波数
F1 = 50.25 #正弦波の周波数
gain = 1 #正弦波の振幅
offset = 0 #直流成分
t = 4 #データ上限(秒)
#時間軸データ #t秒まで、dt秒周期で作成
time = np.arange(0, t, dt)
# 信号を生成(周波数10の正弦波+周波数20の正弦波+ランダムノイズ)
f = gain * np.sin(2*np.pi*F1*time)
#周波数軸
Ffreq = np.fft.fftfreq(n, d = dt) #データ数、サンプリング周期を指定する。
#高速フーリエ変換
FFT_f = np.fft.fft(f[:n])
FFT_f = abs(FFT_f * 2 / n) #交流成分の正規化(2倍してサンプル数で割り算して絶対値を取る)
FFT_f[0] = abs(FFT_f[0] / 2) #直流成分の正規化(サンプル数(2)で割り算して絶対値を取る)
#FFT最大値と周波数の取得
Fmax = max(FFT_f[:int(n/2.56)]) #FFTの最大値取得
maxHz = Ffreq[np.argmax(FFT_f[:int(n/2.56)])] #FFTの最大値周波数位置の取得
fftmax = "peak:" + str(round(Fmax, 2)) + " " + "@" + str(maxHz) + "Hz"
#Figureの作成
fig = plt.figure(figsize=(7, 8), tight_layout=True) #figの設定、余分な余白削除
#グラフタイトルの作成
fig.suptitle("正弦波: " + str(F1) + "Hz", weight=5, fontsize=16) #グラフタイトルの設定、太さ、サイズ
#データ及び軸項目の作成
#正弦波のプロット
plt.subplot(3,1,1) #サブプロットの作成、位置
plt.title("時刻歴グラフ " + "FFT分析データ数:最初の" + str(n) + "データ " + str(t) + "sec波形", loc='left') #グラフタイトルの設定、位置
plt.plot(time,f) #グラフデータの指定(x, y)
plt.xlim(0,0.1) #横軸の最小値、最大値
plt.grid() #目盛線の追加
plt.xlabel("Time[sec]") #横軸ラベル
plt.ylabel("振幅[-]") #縦軸ラベル
#FFTのプロット
plt.subplot(3,1,2) #サブプロットの作成、位置
plt.title("パワースペクトルグラフ " + fftmax, loc='left') #グラフタイトルの設定、位置
plt.plot(Ffreq[:int(n/2.56)], FFT_f[:int(n/2.56)]) #グラフデータの指定(x, y)
plt.xlim(0, Frange) #横軸の最小値、最大値
plt.grid() #目盛線の追加
plt.xlabel("Frequency[Hz]") #横軸ラベル
plt.ylabel("振幅[-]") #縦軸ラベル
#FFTのプロット
plt.subplot(3,1,3) #サブプロットの作成、位置
plt.title("パワースペクトルグラフ " + fftmax, loc='left') #グラフタイトルの設定、位置
plt.plot(Ffreq[:int(n/2.56)], FFT_f[:int(n/2.56)], marker="o") #グラフデータの指定(x, y)
plt.xticks(np.arange(0, Frange + 1, step = 1)) #軸目盛りを指定値から等間隔に分割
plt.xlim(45, 55) #横軸の最小値、最大値
plt.grid() #目盛線の追加
plt.xlabel("Frequency[Hz]") #横軸ラベル
plt.ylabel("振幅[-]") #縦軸ラベル
Pythonコードは以下のステップとなります。
- 波形の条件の設定
- 波形の作成
- FFT分析の処理
- 分析値の抽出
- グラフ サブプロットの描画
5行目、「n= 1024」がFFTの周波数分解能を設定する箇所となります。
2048、4096と変更して、結果を確認します。
12行目、「t = 4」は生成する波形のデータの長さを指定するパラメータとなり、今回は4秒の長さで波形を作ります。
理由は1024Hzのサンプリング周波数に設定した際、nのデータ数に応じた秒数のデータ長さが必要になるためです。
「n = 1024, 2048, 4096」は「t = 1, 2, 4」となります。
※今回は一括して4秒のデータを作成し、FFT分析します。
nが1024及び2048の場合は最初の4秒データの内最初のnデータ数だけ読み取ります。
実行結果
ケース1~3のFFT分析の結果を横並びにしました。
それぞれの3つ目のグラフが周波数分解能を確認するための拡大グラフとなります。
比較確認
データ数が4096の周波数分解能が、生成した波形データの振幅と周波数を最も再現しているといえます。
おわりに
今回の確認によって、正しい振幅値と分析周波数を得るためには、周波数分解能の設定が重要であることがわかりました。
上記のように、Pythonをつかったデータ分析を今後も実施していきたいと思います。
よろしくお願いします。
参考サイト
周波数分解能はどのように決めるのか? | 小野測器
https://www.onosokki.co.jp/HP-WK/c_support/faq/fft_common/fft_analys_4.htm
FFTアナライザの基礎と概要 (第1回) | Tech Eyes Online
https://www.techeyesonline.com/article/tech-column/detail/Reference-FFTAnalyzer-01/?glossaryclick-01
Pythonのデータ分析を勉強したい方は以下の書籍をおすすめします。
Pythonを初めて学ぶ方は以下の書籍をおすすめします。