フーリエめも
by K.I
2017/02/08〜
Index
- FFTを使ってはいるものの、フーリエ変換についてはあまり良く分かっていないことも多いので、
- 基礎から復習の意味で、自分なりにいろいろ確認しながら纏めてみたメモです。
- フーリエ変換の公式については、いろいろ流儀があるみたいで、微妙に違っていたりする
- Maximaによる実験は、ほとんど 工業数学の基礎のページに載っていたものそのまま
- 周期関数x(t)は、その周期T0の整数倍の周期を持つ正弦波の重ね合わせで表すことが出来る
- 複素係数Ck(複素スペクトル)は離散的であり、その間隔は1/T0となる
 e^{-j \omega_0 k t} dt&chf=bg,s,ffffff00)
- フーリエ級数の式で、周期が無限大になると、複素スペクトルの間隔はゼロになり連続したものとなる
- 極限を考えると、連続した周波数スペクトルX(jω)と時間関数x(t)で、以下のような関係となる
→フーリエ変換
→フーリエ逆変換
- フーリエ級数を、tで離散化(サンプリング)すると、周波数スペクトルは周期的となる
- 以下のDFTの式は、離散周期スペクトルXkと離散周期信号xnの関係を表している
→離散フーリエ変換
→離散逆フーリエ変換
- 実際にフーリエ変換をデジタル信号処理で使う場合は、時間的にも周波数的にも離散値なので
- フーリエ変換を、tで離散化(サンプリング)すると、周波数は周期的となる
- 時間関数x(nt)は離散的、周波数スペクトルXsは周期的だが連続している
→時間離散フーリエ変換
→時間離散逆フーリエ変換
[top]
- 工業数学の基礎のページで、Maximaによるフーリエ級数の実験が載っていたので、そのままやってみた
- こちらで紹介されている 特講・工業数学では、 Scilabを使って、いろいろ実験しているらしい。
- Maximaの実験は前ふりで、書籍の方でもっと詳しく解説されているらしいので、ちょっと読んでみたい。
- 周期的な波形の場合、周波数は離散的(フーリエ級数)となる
- つまり周期信号は、1/Tの整数倍の正弦波の重ね合わせで表すことが出来る
 e^{-j \omega_0 k t} dt&chf=bg,s,ffffff00)
- 時間領域でパルス波形の場合を考える。Maximaでパルス波のデータを作る
- 本当は連続だけど、仮に8ポイントのデータとする
kill(all)$ N:8$ k:makelist(k-N/2,k,0,N);
T:1$ f0:1/T$ x:1$ a:1/2$
R(t):=if abs(t)<= a/2 then 1 else 0$
wxplot2d(R(t),[t,-T/2,T/2],[y,-0.2,1.2],[xlabel,"t"],[ylabel,"Amplitude"]);
- 簡略化して、xが1の範囲のみ積分して、Maximaでフーリエ係数を求める
- [-4,-3,-2,-1,0,1,2,3,4]
- 周波数領域ではSINC関数のような形に分布している
j:%i$ omega:2*%pi*f0$
Ck:(1/T)*integrate(x*exp(-j*omega*k*t),t,-a/2,a/2);
wxplot2d([discrete,k/T,realpart(Ck)],[style,[points,2,1,1]],[xlabel,"f[Hz]"],[ylabel,"Ck"]);
wxplot2d([realpart(Ck.exp(j*omega*k*t)),R(t)],[t,-T/2,T/2],[ylabel,"Amplitude"]);
- 求めたフーリエ級数(N=8)の周波数を合成して、元のパルス波形と比較してみる
- 少し近い形になってはいるが、パルス波とは言いにくい
- もう少しサンプル数を増やして、N=16の場合は、
- [-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8]
N:16$ k:makelist(k-N/2,k,0,N);
Ck:(1/T)*integrate(x*exp(-j*omega*k*t),t,-a/2,a/2);
wxplot2d([discrete,k/T,realpart(Ck)],[style,[points,2,1,1]],[xlabel,"f[Hz]"],[ylabel,"Ck"]);
wxplot2d([realpart(Ck.exp(j*omega*k*t)),R(t)],[t,-T/2,T/2],[ylabel,"Amplitude"]);
- さらにサンプル数を増やして、N=32の場合は、
- [-16,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
N:32$ k:makelist(k-N/2,k,0,N);
Ck:(1/T)*integrate(x*exp(-j*omega*k*t),t,-a/2,a/2);
wxplot2d([discrete,k/T,realpart(Ck)],[style,[points,2,1,1]],[xlabel,"f[Hz]"],[ylabel,"Ck"]);
wxplot2d([realpart(Ck.exp(j*omega*k*t)),R(t)],[t,-T/2,T/2],[ylabel,"Amplitude"]);


[top]
- これも 工業数学の基礎のページの記事そのままだが、Maximaで離散時間フーリエ変換について実験してみる
- 実のところ、自分は離散時間フーリエ変換(TDFT)っていうものを知らなかったんだけど、
- 時間領域でサンプリング(離散化)しているので、周波数領域では周期的ではあるが、DFTと違って連続している
→時間離散フーリエ変換
→時間離散逆フーリエ変換
- Maximaで、離散時間フーリエ変換してみる
- 3/8秒のパルスを用意して、
kill(all)$
x:[0,0,1,1,1,0,0,0];
N:length(x)$ Ts:1/N$
n:makelist(n,n,0,N-1); t:Ts*n;
wxplot2d([discrete,n-3,x],[y,-0.2,1.2],[style,[points,2,1,1]]);
- 離散時間フーリエ変換すると、連続した周波数スペクトルとなる
- 時間領域でサンプリング(離散化)しているので、周波数領域では周期的になっている
Xs:sum(exp(-%i*w*Ts*n)*x[n+1],n,0,N-1);
wxplot2d(abs(Xs),[w,-4*%pi/Ts,4*%pi/Ts]);
xo:expand(Ts*integrate(exp(%i*w*Ts*n)*Xs,w,-%pi/Ts,%pi/Ts)/(2*%pi));
[0,0,1,1,1,0,0,0]
- パルス波のフーリエ変換は、SINC関数の形になるということらしい
 = \frac{sin(a*\omega/2)}{\omega/2}&chf=bg,s,ffffff00)
- 例えば、3/8秒のパルスのフーリエ変換は、以下のようにSINC関数で表される
a:3/8$ N:8$ Ts:1/N$
wxplot2d([sin(a*w/2)/(w/2)],[w,-10*%pi/Ts,10*%pi/Ts],[y,-0.2,0.5]);
- 3/8秒のパルスを、離散時間フーリエ変換してみる
- 前項の場合は、絶対値をとっていたが、今度はそのままプロットする
kill(all)$
x:[0,0,1,1,1,0,0,0];
N:length(x)$ Ts:1/N$
n:makelist(n,n,0,N-1); t:Ts*n;
Xs:sum(exp(-%i*w*Ts*(n-3))*x[n+1],n,0,N-1);
wxplot2d(Xs,[w,-4*%pi/Ts,4*%pi/Ts]);
- ただの正弦波で、SINC関数にはなっていないようにみえる
- DTFTのXsは振幅が1/Tsになっているらしいので、
- Tsを掛けて、SINC関数と重ねてプロットしてみる
a:3/8$
wxplot2d([sin(a*w/2)/(w/2),realpart(Xs)*Ts],[w,-4*%pi/Ts,4*%pi/Ts],[y,-0.2,0.5]);
- 周波数が低い範囲で、ちょっと形が似ていることが分かる
x:[0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0];
N:length(x)$ Ts:1/N$
n:makelist(n,n,0,N-1); t:Ts*n;
wxplot2d([discrete,n-N/2+1,x],[y,-0.2,1.2],[style,[points,2,1,1]]);
- これを時間離散フーリエ変換すると
- ちょっとSINC波形っぽくなってくる
Xs:sum(exp(-%i*w*Ts*(n-N/2+1))*x[n+1],n,0,N-1);
wxplot2d(realpart(Xs),[w,-4*%pi/Ts,4*%pi/Ts]);
a:3/8$
wxplot2d([sin(a*w/2)/(w/2),realpart(Xs)*Ts],[w,-4*%pi/Ts,4*%pi/Ts],[y,-0.2,0.5]);
- 時間離散フーリエ変換は、時間領域でサンプリング(離散化)しているので、周波数領域では周期的なものになる
- DFTと違って、時間領域では周期的としないので、周波数領域では連続したデータになる
[top]
- プログラムで、矩形パルス波形をフーリエ変換したらどうなるかやってみる
- 擬似インパルスのプログラムの波形を、fftwに通して周波数特性を見る
- インパルスといっても、大きさが1で、それ以外は0のデータ(サンプリング周波数128Hz1)
- 左側がインパルス波形で、右側がfftwで周波数特性を見たもの
- インパルスが1個の場合は、全周波数に一様に分布したものになる
% pulse 128 1 | gp_pulse2 > p128_1w.png
% pulse 128 1 | fftw | gp_fftl > p128_1fft.png
% pulse 128 2 | gp_pulse2 > p128_2w.png
% pulse 128 2 | fftw | gp_fftl > p128_2fft.png
% pulse 128 3 | gp_pulse2 > p128_3w.png
% pulse 128 3 | fftw | gp_fftl > p128_3fft.png
% pulse 128 4 | gp_pulse2 > p128_4w.png
% pulse 128 4 | fftw | gp_fftl > p128_4fft.png
% pulse 128 8 | gp_pulse2 > p128_8w.png
% pulse 128 8 | fftw | gp_fftl > p128_8fft.png
% pulse 128 16 | gp_pulse2 > p128_16w.png
% pulse 128 16 | fftw | gp_fftl > p128_16fft.png
- fftwの結果から見ても、
- 時間領域でパルス波形は、周波数領域ではSINC波形になってるのが分かる
- 逆に周波数領域の矩形パルス波形が、時間領域ではどんな波形になるか調べる
- 擬似ホワイトノイズのプログラムで、周波数領域で短い範囲のデータを作って、合成された波形をみてみる
- 左側がfftwで周波数を確認したもの、右側が合成された波形(サンプリング周波数は1MHz)
- まず、1Hzから順に同じ大きさのデータを加算していく
% white0 1000000 1 | fftw | head -40 | gp_fftl > w1_1fft.png
% white0 1000000 1 | gp_wav2 > w1_1w.png
% white0 1000000 2 | fftw | head -40 | gp_fftl > w1_2fft.png
% white0 1000000 2 | gp_wav2 > w1_2w.png
% white0 1000000 3 | fftw | head -40 | gp_fftl > w1_3fft.png
% white0 1000000 3 | gp_wav2 > w1_3w.png
% white0 1000000 4 | fftw | head -40 | gp_fftl > w1_4fft.png
% white0 1000000 4 | gp_wav2 > w1_4w.png
% white0 1000000 8 | fftw | head -40 | gp_fftl > w1_8fft.png
% white0 1000000 8 | gp_wav2 > w1_8w.png
% white0 1000000 16 | fftw | head -40 | gp_fftl > w1_16fft.png
% white0 1000000 16 | gp_wav2 > w1_16w.png
% white0 1000000 100 | fftw | head -200 | gp_fftl > w1_100fft.png
% white0 1000000 100 | gp_wav2 > w1_100w.png
- 周波数領域で0Hzから加算していくと、時間領域では段々とインパルス状になっていく
- 0Hzからではなく、少し高い周波数から加算して矩形状にしてみよう。
- 左側がfftwで周波数を確認したもの、右側が合成された波形
% white0 1000000 100 100 | fftw | head -120 | tail -25 | gp_fftl > w100_100fft.png
% white0 1000000 100 100 | gp_wav2 > w100_100w.png
% white0 1000000 101 100 | fftw | head -120 | tail -25 | gp_fftl > w100_101fft.png
% white0 1000000 101 100 | gp_wav2 > w100_101w.png
% white0 1000000 102 100 | fftw | head -120 | tail -25 | gp_fftl > w100_102fft.png
% white0 1000000 102 100 | gp_wav2 > w100_102w.png
% white0 1000000 103 100 | fftw | head -120 | tail -25 | gp_fftl > w100_103fft.png
% white0 1000000 103 100 | gp_wav2 > w100_103w.png
% white0 1000000 107 100 | fftw | head -120 | tail -25 | gp_fftl > w100_107fft.png
% white0 1000000 107 100 | gp_wav2 > w100_107w.png
% white0 1000000 115 100 | fftw | head -120 | tail -25 | gp_fftl > w100_115fft.png
% white0 1000000 115 100 | gp_wav2 > w100_115w.png
- 周波数領域で矩形状のパルスは、時間領域では振幅的にSINC波形になっている
1サンプリング周波数を高くすれば、周波数領域でより細かくなるが、敢えてバラに見える程度にした。
2これは電気回路の場合で、一般的な言い方じゃないと思うけど、他の言い方ってあるのかなぁ。
30Hzのみっていうのを作りたいんだけど、ちょっと無理なので。
[top]
- 逆にSINC波形をフーリエ変換したらどうなるか、やってみる
- プログラムは、正規化SINC関数にする。
- この方が、xが整数の時、零になるから指定しやすいかなと
 = \frac{sin(\pi x)}{\pi x}&chf=bg,s,ffffff00)
- SINC関数の零点の数n(片側)と、出力ポイント数tapを指定して、出力する
- という感じで考えたんだけど、折角なのでFIRフィルタとして動作するようにした
#include<stdio.h>
#include<math.h>
#define TAP 301
#define N 1000000
double para[N];
double buff[N];
double sinc(double x) {
if (!x) return 1;
return sin(M_PI*x)/(M_PI*x);
}
int make_para(int tap, int z)
{
double d;
int t, n=0;
d = (double)z*2/(tap-1);
for (t=-(tap-1)/2; t<=(tap-1)/2 ;t++) {
para[n++] = sinc(t*d);
if (n>=N) break;
}
return n;
}
main( int argc, char *argv[] )
{
int z, tap, s, n, i=0, x;
double in, out;
tap = TAP;
z = 10;
s = 0;
if (argc>1)
z = atoi(argv[1]);
if (argc>2)
tap = atoi(argv[2]);
if (argc>3)
s = atoi(argv[3]);
if (z<1 || tap<2) return;
n = make_para(tap,z);
if (!s) {
while(fscanf(stdin,"%lf",&in)!=EOF) {
buff[i] = in;
out = 0;
for (x=0; x<n ;x++)
out += buff[(x+i+n)%n] * para[x];
printf("%lf\n",out);
i = (i+1)%n;
}
}
else {
for (x=0; x<s ;x++)
printf("%lf\n",para[x]);
for (; x<s ;x++)
printf("%lf\n",0.0);
}
}
- まぁ、こうしておけば、SINC関数を係数としたフィルタとして動作するし、
- インパルス(最初が1で、後は0のデータ)を入れれば、単にSINC関数の値が見られる
- でも、実際にやってみたら、サンプリング周波数が大きいときは、畳み込みにとんでもなく時間が掛かるので、
- 3番目の引数として、サンプリング周波数を指定すれば、単にSINC関数を出力して、残りは零で埋めるように4した
% sincf 10 301 301 | gp_wav2 > sinc10_301.png
% sincf 10 301 301 | fftw | gp_fftl > sinc10_301fft.png
- 零点を増やす、零点が片側20個でタップ301個の時
% sincf 20 301 301 | gp_wav2 > sinc20_301.png
% sincf 20 301 301 | fftw | gp_fftl > sinc20_301fft.png
- もっと増やす、零点が片側40個でタップ301個の時
% sincf 40 301 301 | gp_wav2 > sinc40_301.png
% sincf 40 301 301 | fftw | gp_fftl > sinc40_301fft.png
- さらに増やす、零点が片側80個でタップ301個の時
% sincf 80 301 301 | gp_wav2 > sinc80_301.png
% sincf 80 301 301 | fftw | gp_fftl > sinc80_301fft.png
- さらに増やす、零点が片側100個でタップ301個の時
% sincf 100 301 301 | gp_wav2 > sinc100_301.png
% sincf 100 301 301 | fftw | gp_fftl > sinc100_301fft.png
- さらに増やす、零点が片側140個でタップ301個の時
% sincf 140 301 301 | gp_wav2 > sinc140_301.png
% sincf 140 301 301 | fftw | gp_fftl > sinc140_301fft.png
- さらに増やす、零点が片側149個でタップ301個の時
% sincf 149 301 301 | gp_wav2 > sinc149_301.png
% sincf 149 301 301 | fftw | gp_fftl > sinc149_301fft.png
- さらに増やす、零点が片側150個でタップ301個の時
% sincf 150 301 301 | gp_wav2 > sinc150_301.png
% sincf 150 301 301 | fftw | gp_fftl > sinc150_301fft.png
- 零点が増えるほど、遮断周波数は上がり、サンプリング周波数に対する比率としても、遮断周波数が高くなる
- 零点がタップ数に近づくとSINC関数とは言えないぐらい崩れているが、それでもフィルタとして働いている
- 最後は、ただのインパルスになるので、全てパスするようになる
% sincf 10 301 301 | gp_wav2 > sinc10_301.png
% sincf 10 301 301 | fftw | gp_fftl > sinc10_301fft.png
- サンプリング数を増やす。零点が片側10個でタップ301個で、サンプリング周波数を302Hzに
% sincf 10 301 302 | gp_wav2 > sinc10_301_302s.png
% sincf 10 301 302 | fftw | gp_fftl > sinc10_301_302sfft.png
- サンプリング数を増やす。零点が片側10個でタップ301個で、サンプリング周波数を303Hzに
% sincf 10 301 303 | gp_wav2 > sinc10_301_303s.png
% sincf 10 301 303 | fftw | gp_fftl > sinc10_301_303sfft.png
- サンプリング数を増やす。零点が片側10個でタップ301個で、サンプリング周波数を400Hzに
% sincf 10 301 400 | gp_wav2 > sinc10_301_400s.png
% sincf 10 301 400 | fftw | gp_fftl > sinc10_301_400sfft.png
- サンプリング数を増やす。零点が片側10個でタップ301個で、サンプリング周波数を1kHzに
% sincf 10 301 1000 | gp_wav2 > sinc10_301_1ks.png
% sincf 10 301 1000 | fftw | gp_fftl > sinc10_301_1ksfft.png
- サンプリング数を増やす。零点が片側10個でタップ301個で、サンプリング周波数を10kHzに
% sincf 10 301 10000 | gp_wav2 > sinc10_301_10ks.png
% sincf 10 301 10000 | fftw | gp_fftl > sinc10_301_10ksfft.png
- サンプリング数を増やす。零点が片側10個でタップ301個で、サンプリング周波数を100kHzに
% sincf 10 301 100000 | gp_wav2 > sinc10_301_100ks.png
% sincf 10 301 100000 | fftw | gp_fftl > sinc10_301_100ksfft.png
- サンプリング数を増やす。零点が片側10個でタップ301個で、サンプリング周波数を1MHzに
% sincf 10 301 1000000 | gp_wav2 > sinc10_301_1Ms.png
% sincf 10 301 1000000 | fftw | gp_fftl > sinc10_301_1Msfft.png
- サンプリング周波数を増やしていくと、矩形フィルタとSINCフィルタの合成みたいな周波数特性になる
- サンプリング周波数を増やすと、遮断周波数は上がっていくが、
- サンプリング周波数に対する比率としては、遮断周波数は変わらない。
- 零点が片側10個でタップ301個で、サンプリング周波数を1MHz
% sincf 10 301 1000000 | gp_wav2 > sinc10_301_1Ms.png
% sincf 10 301 1000000 | fftw | gp_fftl > sinc10_301_1Msfft.png
- 零点が片側10個でタップ302個で、サンプリング周波数を1MHz
% sincf 10 302 1000000 | gp_wav2 > sinc10_302_1Ms.png
% sincf 10 302 1000000 | fftw | gp_fftl > sinc10_302_1Msfft.png
- 零点が片側10個でタップ1000個で、サンプリング周波数を1MHz
% sincf 10 1000 1000000 | gp_wav2 > sinc10_1k_1Ms.png
% sincf 10 1000 1000000 | fftw | gp_fftl > sinc10_1k_1Msfft.png
- 零点が片側10個でタップ10000個で、サンプリング周波数を1MHz
% sincf 10 10000 1000000 | gp_wav2 > sinc10_10k_1Ms.png
% sincf 10 10000 1000000 | fftw | gp_fftl > sinc10_10k_1Msfft.png
- 零点が片側10個でタップ100000個で、サンプリング周波数を1MHz
% sincf 10 100000 1000000 | gp_wav2 > sinc10_100k_1Ms.png
% sincf 10 100000 1000000 | fftw | gp_fftl > sinc10_100k_1Msfft.png
- 零点が片側10個でタップ1000000個で、サンプリング周波数を1MHz
% sincf 10 1000000 1000000 | gp_wav2 > sinc10_1M_1Ms.png
% sincf 10 1000000 1000000 | fftw | gp_fftl > sinc10_1M_1Msfft.png
- タップ数を増やしても、遮断周波数は変わらないので、サンプリング周波数に対する比率としては下がっていく
- そして、遮断領域の底が深くなっていく。タップを増やすことで、フィルタが鋭くなる感じ
4こうすれば、インパルス応答と等価になるので。
[top]
- フーリエ変換では、時間領域と周波数領域で、お互いに対称に影響する関係にある
- 一方が周期化すればもう一方が離散化、離散化すれば周期化する
- 逆に周期が広がると、もう一方はポイントが増えていき、周期が無限になれば連続になる
- サンプリングポイントが増えれば、周期は広がって極限では周期的ではなくなる
- フーリエ変換(FT)を時間領域で周期化すると、
- 周波数領域では離散化して、フーリエ級数(FS)になる
- フーリエ級数(FS)を時間領域で離散化(サンプリング)すると、
- 周波数領域で周期化して、離散フーリエ変換(DFT)
- フーリエ変換(FT)を時間領域で離散化(サンプリング)すると、
- 周波数領域で周期化して、時間離散フーリエ変換(DTFT)
- 時間離散フーリエ変換(DTFT)を時間領域で周期化すると、
- 周波数領域で離散化して、離散フーリエ変換(DFT)
- フーリエ変換・逆変換の式は、やはり対称な関係なので、
- ある波形をフーリエ変換した結果と、同じ波形を逆変換した結果は、基本的に同じになるらしい。例えば、
- 時間領域で矩形パルス波は、周波数領域ではSINC波形になる
- 逆に時間領域でSINC波形は、周波数領域では矩形状になる
⇔
- 時間領域で一定のデータは、周波数領域ではインパルス状になる
- 逆に時間領域のインパルスは、全周波数に均一に分布するものになる
⇔
- 工業数学の基礎
- Maximaの実験が参考になった。というか、そのままやってみた。
- 小野測器
- FFTアナライザの記事なんだけど、いろいろ詳しく解説されている
5この図は、GoogleChartのGraphVizで描いてるんだけど、日本語をうまくエンコード出来なかった(というより、日本語フォントが無いのかな?)ので、仕方なく怪しい英語になってる。
6自分の環境だと、残念ながらJavaがうまく動かなかった。
[top]
[プログラムの部屋に戻る]
⇒ Disqusの広告がうるさすぎるので基本は非表示にしました