google-site-verification: google3bd66dd162ef54c7.html
fc2ブログ

FFT処理の入出力の値の関係を調べてみた

◆まえがき
タイトルは一般化した表現になっていますが、やったのは arduino のライブラリの arduinoFFT.h でFFTの計算を行った時の入出力の振幅の関係はどうなるか?という確認を行ったものです。

こんな話はFFTの計算の常識なのかも知れません。あるいは arduinoFFT.h のマニュアルに書かれているのかも知れません。でも調べているより実際のプログラムを動かして確認した方が手っ取り早くて確実なのでやってみました。

なお、CPUのボードには Raspberry Pi Pico を使い、arduinoFFのバージョンは1.5.6、窓関数には ハニング ハミングを使っています。

◆入力波形
振幅 1.0 の正弦波データーを作成し、FFT計算の入力に使用しました。
テスト用正弦波
ポイント数は256で、この間に正弦波が10周期分入っています。

◆FFT計算結果
256区間の結果

ナイキスト周波数の128で折り返した左右対称のデーターが得られます。理論通り10番目の要素(bin)にピークが現れ、これが入力した正弦波の周波数を表わしています。

知りたかったスペクトルのピーク値は68.889とえらく半端な値になっていました。ただ、前後の値の29.497とピーク値の三つを足すと127.884となり、対称の位置にある値と合計すると約256になり、どうもサンプル数と同じ値がスペクトル全体の振幅になっているみたいです。

この仮説を確認するためにサンプル数128でやって見ました

・サンプル数128の場合
128区間の結果

予想通りピークの高さは半分の約34になり、前項の仮説は正しかったようです。

つまりピークの高さの合計はサンプル数と一致するようです。なおこれは振幅1.0の単一周波数の正弦波を入力した場合の話です。

◆ここまでの結論
サンプル数256で振幅1.0の正弦波をFFTすると、その振幅は68.889になることが判りました。これはスペクトルの中心がFFTの周波数ステップの中央と一致した場合で、ズレがあると振幅は異なってきます。

この結果は正弦波で計算した結果なので波形が変われば当然結果は変わってきます。例えば矩形波の場合、奇数次の高調波が発生するのでそちらにもエネルギーが配分されるので、スペクトルの高さの合計はサンプル数を上回るのではないかと想像しています。ただ、実際にどうなるか確かめていません。

◆対数スケール
対数目盛
良い機会なので縦軸を対数(デシベル)でプロットしたのが上のグラフです。Arduino の浮動小数点演算は32ビットで行われているので、精度不足になっていないかちょっと心配だったのですが、グラフを見ると最大で140dBのSNが確保されているので大丈夫そうです。

◆まとめ
今回の調査で arduinoFFFT.h の変換利得が判りました。これで FFTが吐き出す結果に正確な値を付けることが出来るようになりました。(専門家から見ると、当たり前のことを言ってるだけなんでしょうが、)

関連記事

コメントの投稿

管理者にだけ表示を許可する

スペクトルのピーク値

ハニング窓を使用した場合の値と捉えていますが、どうなんでしょう?
(PCからの投稿です。今回は投稿成功です)

re:スペクトルのピーク値

まえがきに書いたようにハニング窓を使っています。

窓関数使うと振幅に影響が出ますが、スペクトルの高さが切りの良い値になったのでライブラリの中で補正が掛かっているのかな、と想像してます。

ここまで書いてハニング窓の影響を調べたら0.5倍なんですね。0.7倍くらいだと思っていたので、本文の文章は一部間違っているかも知れませんね。

re:スペクトルのピーク値

こんにちは。

プログラムを拝見して、コメント部分の誤りに気が付きました、
些細なことなんですが、色々と議論する際の勘違いの元にもなりうるのでお知らせします(プログラムで実際に使われているのはハミング窓です)。
この部分:
FFT.Windowing(vReal, NNN, FFT_WIN_TYP_HAMMING, FFT_FORWARD); // 窓関数(ハニング)適用(9ms)

関連するトリビア的なお話をすると、人の名前から命名されたHann窓がハニング(Hanning)窓とも呼ばれるようになった経緯として以下の説があるようです。
1. Hammingとの語呂合わせ(Hann -> Hanning)
2. 「Hann窓を適用する」という意味の動詞としても「Hann」が使われ始め、その現在進行形Hanningもよく用いられるようになった。

ついでに私がこれまでにFFTに関して、気が付いたこと、考えたことをご紹介します(誤り、勘違いなどがあるかも)。
1. arduinoFFTライブラリのHann窓の重み定義の式の誤り(2か所あり)
(誤)weighingFactor = 0.54 * (1.0 - cos(twoPi * ratio));
(正)weighingFactor = 0.5 * (1.0 - cos(twoPi * ratio));
FFTで使われるすべての窓関数は最大の重み値が1となるように定義されていますが、そうはなっていません。
おそらくHann窓の定義式をHamming窓の定義式をコピペ、修正して作ろうとした際にミスったようです。このミスはArduinoライブラリへのフォーク元(#makefurt作)からそのまま受け継がれているということでしょう。
この誤りについては既にGitHub上でissueとして繰り返し指摘されているにもかかわらず未対応です。原作をforkした際の縛りがあるのか、管理者のEnrique Condes氏の問題意識、関心が薄いからか理由はよくわかりません。
ともかく私はarduinoFFT.cppを修正して使っています。

2. Magnitudeの総和について
エリアス部分も含めたMagnitudeの総和についてですが、サンプル数×振幅となるのは、入力された波形が完全な繰り返し波形(開始ポイントと終了ポイントが完全に整合してつながる)であって、かつ、窓関数を適用しない(矩形窓適用とも言える)場合のみです(あるいは矩形窓適用とも言える)。
それ以外の場合は、大きくなります(スペクトルピークの幅が大きくなったり、裾野(リーク)を生じます)。

3. Magnitudeの補正について
私は個々のbinのMagnitude値を(サンプル数×1/2×窓関数の減衰率)で除したものとしています。減衰率はHann窓の場合は0.5、Hamming窓の場合は0.54です。
スペクトルピークの補正後のMagnitude値は、完全な繰り返し波形を入力した場合よりも一般的には小さくなります。

4. arduinoでFFTを使ってみての所感
ともかく入力信号が同じであっても処理条件を変えるとスペクトル波形はグニャグニャと変わります。読み取れる電圧値やdB値(の差)はあくまで参考と捉えておいた方がよいようです。
FFTを使っていると簡単には整理できない疑問が次々と湧いてきて、きりがありません。なかなか奥が深いです。

私は、内部で基本的な波形を表す入力データを生成し、入力データの周波数、振幅、FFTのサンプル数、窓関数などのパラメータを変えて、出力を確認できるプログラムを作成し、上記のことなどを確認しています。
以前、Arduino Unoベースで作ったものがPico用としてそのまま使えました。CVD形式のテキストをシリアル出力するだけなので使えて当たり前ですが、Picoではサンプル数を飛躍的に増やすことができて非常に良かったです。

以上

re2:スペクトルのピーク値

ご指摘ありがとうございます。

最初の頃の記事では、
http://radiopench.blog96.fc2.com/blog-entry-1184.html
プログラムのコメントにハミングと書いているのですが、
ネットを読むとこれをハニングと呼ぶようだったので、勘違いして途中からハニングと呼ぶようになってました。
そうですか、両者は違うものだったんですね。お恥ずかしいことに全く知りませんでした。

あと、いろいろ書いていただいてる内容は理解するのに時間がかかりそうなので、ゆっくり検討させてください。FFT結果のオーバーオール値を表示するようにすると見通しが良くなるのかなと漠然と思っています。

re3:スペクトルのピーク値

先日のコメントで触れたプログラムを公開しました。
参考にしていただければ幸いです。
cuiなので操作が面倒ですが。

re4:スペクトルのピーク値

FFT_Magnitude_testing_sinewave2r0_sjis.ino 動かしてみました、と言ってもいきなりexecとやっただけですが、正常に動きました。

他の人が書かれたコードを読むと勉強になります。コマンドをパースするところとか、参考になりましたす。

とりあえず今はFFTの条件をいじる必要は無いのですが、何かの時に使わせていただきます。

PS:FC2ブログにプログラムのコードをリンクで置く場合、文字化け防止のため私はBOM付きのUTF-8にしてます。どこかの設定の影響でエンコードがうまく伝わらないみたいです。

re5:スペクトルのピーク値

使っていただいて有難うございます。
コマンドをパースするところは、あくまでArduinoのシリアルモニタを使うことを前提として書いています。リターンキーを押すと、'/r'、'/n'がセットで送られるところをどう処理するか、が問題でした。
きっともっと賢いやり方があるはずとは思います。
またTera Term等のターミナルソフト相手だと色々問題があると思います。

先ほど窓関数に関する記事を投稿しました。ご覧いただけると幸いです。

re6:スペクトルのピーク値

記事拝見しました、判り易いです。

これ読むと一番有名なハニング窓の振幅が8%の誤差で処理されちゃうんですね。
窓関数で迷ったらハニングにしとけ、と習った人が多いはずなのにこのバグは残念ですね。
カレンダー
02 | 2024/03 | 04
- - - - - 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 - - - - - -
プロフィール

ラジオペンチ

Author:ラジオペンチ
電子工作を中心としたブログです。たまに近所(東京都稲城市)の話題など。60過ぎて視力や器用さの衰えを感じつつ日々挑戦!
コメントを入れる時にメールアドレスの記入は不要です。なお、非公開コメントは受け付けていません。
記事の内容のご利用は読者の自己責任でお願いします。

記事が気に入ったらクリックを!
最新記事
カテゴリ
最新コメント
リンク
FC2カウンター
検索フォーム
月別アーカイブ
RSSリンクの表示
QRコード
QRコード