ここでは実際に離散的フーリエ変換を、簡単なのこぎり波に対して行ってみる。
- のこぎり波を生成するプログラム例
import java.io.*;
class Sawwave
{
public static void main(String arg[])
{
int i,n,m,max;
n=0;
max=100; //最大繰り返し回数
double x,y[]=new double[max];
//のこぎり波の一周期分の数値をつくる。
for(x=-10;x<=10;x+=1)
{
y[n]=x;
n++;
}
try
{
FileWriter fw=new FileWriter("function.data");
//のこぎり波の生成
for(i=0;i<max;i++)
{
for(m=0;m<n;m++)
{
fw.write(y[m] + "\n");
}
}
fw.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
これを GNUPLOT で出力すると、
- フーリエ変換のプログラム例
import java.io.*;
class Fourier
{
public static void main(String arg[])
{
int k,n,N,max;
N=0;
max=10000;
double f[]=new double[max+1],ReF,ImF;
try
{
//フーリエ変換したいデータをあらかじめファイル function.data に保存しておく
FileReader fr=new FileReader("function.data");
StreamTokenizer st=new StreamTokenizer(fr);
//データの読み込み(ただし実数の成分のみ)
while(st.nextToken()!=StreamTokenizer.TT_EOF)
{
if(N>max)
break;
f[N]=st.nval;
N++;
}
FileWriter fw=new FileWriter("fourier.data");
//実数部分と虚数部分に分けてフーリエ変換
for(n=0;n<N;n++)
{
ReF=ImF=0.0;
for(k=0;k<N;k++)
{
ReF+=f[k]*Math.cos(2*Math.PI*k*n/(N+1));
ImF+=-f[k]*Math.sin(2*Math.PI*k*n/(N+1));
}
fw.write(n + " " + ReF + " " + ImF + "\n");
}
fr.close();
fw.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
GNUPLOTで出力結果を見てみる。上の画像が実数成分、下の画像が虚数成分である。
横軸が周波数を表し、縦軸がその周波数の強さ(スペクトル)となる。
- 離散的逆フーリエ変換のプログラム例
import java.io.*;
import java.util.*;
class Reversefourier
{
public static void main(String arg[])
{
int k,n,N,max;
N=0;
max=10000; //配列の個数(データ数に応じて余裕を持たせておく)
String s="";
double Ref,Imf;
double ReF[]=new double[max+1],ImF[]=new double[max+1];
try
{
//逆フーリエ変換したいデータをあらかじめfourier.dataに保存しておく
FileReader fr=new FileReader("fourier.data");
BufferedReader br=new BufferedReader(fr);
FileWriter fw=new FileWriter("inversef.data");
while((s=br.readLine())!=null)
{
StringTokenizer st=new StringTokenizer(s," ");
N=Integer.parseInt(st.nextToken());
ReF[N]=Double.parseDouble(st.nextToken());
ImF[N]=Double.parseDouble(st.nextToken());
}
//フーリエ逆変換
for(k=0;k<N;k++)
{
Ref=Imf=0.0;
for(n=0;n<N;n++)
{
Ref+=(ReF[n]*Math.cos(2*Math.PI*k*n/N)-ImF[n]*Math.sin(2*Math.PI*k*n/N))/N;
Imf+=(ReF[n]*Math.sin(2*Math.PI*k*n/N)+ReF[n]*Math.sin(2*Math.PI*k*n/N))/N;
}
fw.write(k + " " + Ref + " " + Imf + "\n");
}
fr.close();
fw.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
GNUPLOTで出力してみる。理論的には元ののこぎり波に戻るはずである。
やや違うところがあるがほぼ元ののこぎり波に戻った。しかし、もっと周波数が大きい部分では大きなずれが見られる。これは近似を行ったから誤差の発生はまぬがれないせいもあるが、比較的近似を粗く行ったせいもある。
|