みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

サンプリングを高くするほどフーリエ変換値がずれる?

ある周波数解析ソフトで「フーリエ変換」釦があるのですが、サンプリング周波数を高くするほど、フーリエ変換値がずれてしまいます。
(例)60Hzの正弦波のみの1s間の波形を「フーリエ変換」釦を押すと、
(1)サンプリング周期(10ms)→ 50.5Hz、 52.5Hz、 76.5Hz、の順でピーク点
(2)   〃    (1.0ms)→ 62.5Hz がピーク点。
(3)   〃    (0.1ms)→ 98.5Hz が 〃
(4)   〃   (0.001ms)→  0.0Hz が 〃
となり、周波数ピーク点が60Hzに合いません。このように大きくずれてしまうものでしょうか?
なお、同ソフトで「フーリエ級数展開」釦では特定区間指定でき、60Hzの「1次」のみに表示されるのですが、「フーリエ変換」機能には、区間指定釦がありません。
詳しい説明書きはないのですが、通常そのような使い方となるものでしょうか?

投稿日時 - 2018-12-02 14:40:22

QNo.9563877

困ってます

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.2

> このように大きくずれてしまうものでしょうか?

条件1
  サンプリング周期= 1 / サンプリング周波数 である

条件2
  フーリエ変換とは離散フーリエ変換(DFT・FFT)である

上記の2つが当てはまる条件で、かつ波形が十分な長さサンプリングできているのであれば大きくはずれません。ただ、本件では条件1・2とも当てはまらないようです。
・サンプリング周期10ms=サンプリング周波数100Hzでは
 ふつう50Hz以上のことを語ることはできません
・FFT後のデータに対応する周波数は、
 サンプリング周波数100Hzサンプリング区間長1秒(100点)の場合
   0, 1, 2, ... , 50 Hz
 となります。一方、50.5Hz、 52.5Hz、 76.5Hz
 に対応するデータがあるということはおそらく0.5Hzきざみ。
 単純にFFTして0.5Hzの分解能となると、サンプリング周波数にかかわらず
 2秒分のデータが要ります。
 また、FFTの事情[1]の為入力データ長は2のべき乗点数にするのが一般的です。
 その場合サンプリング周波数かフーリエ変換後の各サンプルに対応する周波数
 のどちらかは切りのいい値になりません。
 あなたがお使いのソフトの場合、FFTを使っているとしても
 単純にFFTするのではなく何かの処理を併用しているのでしょう。

参考
[1] https://jp.mathworks.com/help/matlab/ref/fft.html
  高速フーリエ変換 - MATLAB fft - MathWorks 日本

引用:
関数 fft の実行時間は、変換する長さに依存します。この時間は 2 のべき乗で最短であり、小さい素因数のみをもつ長さの場合とほぼ同じです。一般に、素数の長さ、あるいは大きい素因数を含む長さの場合、時間は数倍長くなります。



何のひねりもないFFTでしたら数値計算用ソフトで体験できます。Scilabのスクリプトを添付します。パラメータを変えたりコメントアウトする/外すしたりして何度かやってみると感覚を掴む助けになると思います。
// q9563877
// Scilab 6.0.0で動作確認
// スクリプトをtest.sceというファイルに保存した場合の実行コマンド例
// --> exec('test.sce');
// コマンド入力では履歴(↑キー)、補完(tabキー)も使えます。
// また、数文字入力しておくと候補が絞れます
//
// コマンドのヘルプはhelp コマンド名で。
// 例
// --> help fft

Ts = 1/1000; //サンプリング周期 [s] 1ms
//Ts = 0.1/1000; //0.1ms
Fs = 1/Ts; //サンプリング周波数 [Hz]

t = 0:Ts:(1-Ts); //時刻。Ts間隔で0~1-Ts秒まで
//ixt = 1:1024; t = t(ixt); //必要があれば、一部を切り出す

s = sin(2*%pi*60*t); //60Hz正弦波
//s(1001:1024) = 0; //1001~1024サンプルが0の条件の場合

//必要に応じてここで窓かけ
//n = size(s,2); //サンプル点数
//x = (0:(n-1))/(n-1); //0<=x<=1, n samples
//w = 0.5 - 0.5 * cos(2*%pi.*x); //hann窓
//s = s .* w;

x = fft(s); //フーリエ変換。戻り値は複素数で返される

sp_a=abs(x); //スペクトルの振幅成分

//描画
//h = scf(0);
//h.figure_position = [200,20];
//h.figure_size = [8+640,118+480]; //サイズ指定。640x480 ※補正値は環境依存
clf() //描画領域を消去

subplot(211)
plot(s)
n = size(s,2); //サンプル点数
xtitle('60Hz sine wave '+string(n)+' samples' ,'Time [sample]','Amplitude');

subplot(212)
f = 0:(Fs/n):Fs; //横軸・周波数軸の軸ラベル用
ixf = 1:int(1+n/2); //必要な部分を切り出すのに使うindex。全周波数帯域の場合
ixf = 41:80;
plot(f(ixf), 20*log(sp_a(ixf)), '.-') //プロット。対数尺度にしています

//px = f(ixf); py = 20*log(sp_a(ixf));
//plot(px,py,'.'); plot([1;1]*px,[py*0+min(py);py],'-b') //stem plot風プロット

xtitle('','Frequency [Hz]','20 log |X(f)|');

投稿日時 - 2018-12-22 20:08:00

お礼

非常に詳しい説明ありがとうございます。
まだ、十分理解できていないのですが、「0.5Hz刻みだと、2s以上のデータが必要」ということでしょうか。
これらのツールでも試してみたいと思います。

投稿日時 - 2018-12-23 07:23:57

ANo.1

そのソフトを知らないが元々データがない周波数でサンプリングしたって計算しようがないかと思うけど。形式上表示してるだけでは?

投稿日時 - 2018-12-02 15:45:32

お礼

さっそくにありがとうございます。
電源周波数60Hzの正弦波回路の波形を抽出するのだけど、その波形データ値はサンプリング周期で並んでいます。
それをフーリエ変換していると思っているのだけど、やっぱり値はおかしいですかね。
普通は、ほぼ60Hzとなるものでしょうか?

投稿日時 - 2018-12-02 18:06:11

あなたにオススメの質問