sin関数のFFT
scilabではfft(高速フーリエ変換)という関数を用いて、離散フーリエ変換を計算することができる。
x=440Hzのsin波, を、fftで変換してプロットしてみよう。
xx=fft(x,-1);
plot2d(n,abs(xx));Q このプロットでは横軸をサンプル番号とし、縦軸もそのままとした。しかし、本来このプロットの横軸と縦軸はどのようにすべきだろうか?
A 右端がfsになるようにし、振幅は2/l倍すると、sin波の振幅と周波数を読み取ることができる。
実際にやってみよう。
plot2d(fs*n/(2*fs),abs(xx*2/l));
ちょうど目盛が440の部分に高さは0.6のサンプルがあることが読み取れる。これは、440Hzで振幅0.6のsin波が検出されたことを意味する。
それでは以下の3つのsin波を合わせた波形をフーリエ変換してプロットしてみよう。
周波数 振幅 440 0.6 660 0.3 880 0.4
x=sin(2*%pi*440*t)*0.6+sin(2*%pi*660*t)*0.3+sin(2*%pi*880*t)*0.4;
xx=fft(x,-1);
plot2d(fs*n/(2*fs),abs(xx*2/l));
各波形の周波数と振幅が、正確にプロットから読み取れる。
このように、離散フーリエ変換の結果は、各周波数のsin波の振幅を表している。つまり、時間軸のサンプルが、周波数軸のサンプルに変換された、と見ることができる。
そこで、周波数軸に変換されたサンプルを、「周波数サンプル」と呼ぶ。
周波数範囲、周波数間隔
離散フーリエ変換の変換前と変換後の関係を、調べておこう。
tをサンプル間隔、fをサンプリング周波数、Nをサンプル数とする。
変換前と変換後のサンプル数は同じだ。
変換後の周波数範囲は、変換前のサンプリング間隔の逆数になる。
したがって、
周波数サンプルのサンプル間の間隔(周波数間隔) = f/N
となる。
離散フーリエ変換の絶対値の 2/l倍を求めると、元の信号に含まれていたsin波の振幅になる。周波数はサンプル番号の fs/n 倍だ。
対称性
適当な波形の離散フーリエ変換の結果の実部をプロットすると。
x1=abs(x) - (sum(abs(x))/length(x));
xx=fft(x1,-1);
plot2d(fs*n/(2*fs),real(xx*2/l),rect=[0,-1,fs,1]);
このように、fft結果の実部は、4000Hzを中心として左右対称になっているように見える。
虚数部をプロットすると、
plot2d(fs*n/(2*fs),imag(xx*2/l),rect=[0,-1,fs,1]);
このように実数部は0で、虚数部は4000Hzを中心に反対称になっている。
離散フーリエ変換の式を見て、注意深く計算を行えば、上記が一般的に言えることも確認することができる。
独立な数値の数
ところで、2N個の独立な数値の組(独立変数)を誤差を生じずにN個の数値(独立変数)に変換し、また元に戻すことはできないはずである。プロットを見ると左右対称になっている。つまりl個のサンプルから計算したDFTの結果は、l/2個しか独立した値はない。これでは計算上、l個の数値を表すことはできないはずだ。
しかし、DFTの結果は「複素数」なので、1サンプル当たり2個の数値を持っている。だから、互いに独立な数値(独立変数)の数はどちらもl個で同じになる。