FFT処理の入出力の値の関係を調べてみた
◆まえがき
タイトルは一般化した表現になっていますが、やったのは arduino のライブラリの arduinoFFT.h でFFTの計算を行った時の入出力の振幅の関係はどうなるか?という確認を行ったものです。
こんな話はFFTの計算の常識なのかも知れません。あるいは arduinoFFT.h のマニュアルに書かれているのかも知れません。でも調べているより実際のプログラムを動かして確認した方が手っ取り早くて確実なのでやってみました。
なお、CPUのボードには Raspberry Pi Pico を使い、arduinoFFのバージョンは1.5.6、窓関数には ハニング ハミングを使っています。
◆入力波形
振幅 1.0 の正弦波データーを作成し、FFT計算の入力に使用しました。
ポイント数は256で、この間に正弦波が10周期分入っています。
◆FFT計算結果
ナイキスト周波数の128で折り返した左右対称のデーターが得られます。理論通り10番目の要素(bin)にピークが現れ、これが入力した正弦波の周波数を表わしています。
知りたかったスペクトルのピーク値は68.889とえらく半端な値になっていました。ただ、前後の値の29.497とピーク値の三つを足すと127.884となり、対称の位置にある値と合計すると約256になり、どうもサンプル数と同じ値がスペクトル全体の振幅になっているみたいです。
この仮説を確認するためにサンプル数128でやって見ました
・サンプル数128の場合
予想通りピークの高さは半分の約34になり、前項の仮説は正しかったようです。
つまりピークの高さの合計はサンプル数と一致するようです。なおこれは振幅1.0の単一周波数の正弦波を入力した場合の話です。
◆ここまでの結論
サンプル数256で振幅1.0の正弦波をFFTすると、その振幅は68.889になることが判りました。これはスペクトルの中心がFFTの周波数ステップの中央と一致した場合で、ズレがあると振幅は異なってきます。
この結果は正弦波で計算した結果なので波形が変われば当然結果は変わってきます。例えば矩形波の場合、奇数次の高調波が発生するのでそちらにもエネルギーが配分されるので、スペクトルの高さの合計はサンプル数を上回るのではないかと想像しています。ただ、実際にどうなるか確かめていません。
◆対数スケール
良い機会なので縦軸を対数(デシベル)でプロットしたのが上のグラフです。Arduino の浮動小数点演算は32ビットで行われているので、精度不足になっていないかちょっと心配だったのですが、グラフを見ると最大で140dBのSNが確保されているので大丈夫そうです。
◆まとめ
今回の調査で arduinoFFFT.h の変換利得が判りました。これで FFTが吐き出す結果に正確な値を付けることが出来るようになりました。(専門家から見ると、当たり前のことを言ってるだけなんでしょうが、)