任意の周期関数のフーリエ級数を計算し、再び元の関数を再現する(C言語)
1.任意の周期関数をシンプソン法による求積を用いて(複素数)、フーリエ級数を計算する。
2.求めたフーリエ級数を用いて、元の関数を再現する。
計算結果
先に解析的に求めたステップ関数のフーリエ級数と比較するために、同じステップ関数を用いる
κの値
元の関数を再現
ソース(ステップ関数のフーリエ級数)
注意点
1.前回のシンプソン法による求積は実数であったものを、今回は複素数で取り扱い可能なものに変更。
2.大きな m_max (例えば m_max =10000) の場合には、シンプソン法の kizami をその10倍以上の値にしなければならない。
3.被積分関数に不連続点があれば、積分範囲のとり方を気をつける
/* フーリエ級数をシンプソン法を用いて計算 計算例はステップ関数 F(x,m) 非積分関数 */ #include <math.h> #include <stdlib.h> #include <fstream> #include <sstream> #include <iostream> #include <string> #include <iomanip> #include <stdio.h> #include <complex> using namespace std; double PI = acos(-1.0); double e = 2.7182818284590452354; complex<double> I = complex<double>(0.0,1.0); int kizami= 10000; //積分分割回数 double a = 1.0; // ステップの高さ double L = 1.0; // 周期 double l = 0.5; // ステップの幅 double x_max =2.0; //描画範囲 complex<double> F(double);//被積分関数 complex<double> kappa_p[10000]; // m=[0, 10000]までをkappa の値を格納 complex<double> kappa_m[10000]; // m=[0,-10000]までのkappa の値を格納 complex<double> Simpson(double x0, double x1, int kizami, int m); int main (void){ for(int m_max = 2; m_max<=1024; m_max *= 2){ kappa_p[0] = Simpson(0.0,L,kizami,0); for(int m=1 ; m<=m_max ; m++ ){ int mm = -m; // 非積分関数が x = l で不連続なため、個別に計算する /* 0からlまでの積分 */ kappa_p[m] = Simpson(0.0,l,kizami,m); kappa_m[m] = Simpson(0.0,l,kizami,mm); /* lからLまでの積分 */ kappa_p[m] += Simpson(l,L,kizami,m); kappa_m[m] += Simpson(l,L,kizami,mm); } /* ---------kappaの書き出し-------------------- */ ostringstream fname2; fname2 << "kappa_2-" << m_max << ".data";//出力ファイル名 string fname2_s = fname2.str(); ofstream fout2; fout2.open(fname2_s.c_str()); for(int m=m_max ; m>0 ; m-- ){ complex<double> z = kappa_m[m]; fout2 << -m << " " << z.real() << " " << z.imag() << endl; } for(int m=0 ; m<=m_max ; m++ ){ complex<double> z = kappa_p[m]; fout2 << m << " " << z.real() << " " << z.imag() << endl; } fout2.close(); /*---------------------------------------------*/ ostringstream fname1; fname1 << "step_2-" << m_max << ".data";//出力ファイル名 string fname1_s = fname1.str(); ofstream fout; fout.open(fname1_s.c_str()); for(double x=0.0; x<=x_max ; x+=0.001){ complex<double> sum =complex<double>(0.0,0.0); for(int m=1 ; m<=m_max ; m++ ){ int mm = -m; sum += kappa_p[m] * exp( I*(2.0*PI*double(m)*x/L)); sum += kappa_m[m] * exp(-I*(2.0*PI*double(m)*x/L)); } complex<double> f = kappa_p[0] + sum; fout << x << " " << f.real() << " " << f.imag() << endl; } fout.close(); cout << m_max << endl; } return 0; } complex<double> F(double x ,int m) //非積分関数 { complex<double> ff; if(0<=x && x<l) ff = complex<double>(0.0,0.0); if(l<=x && x<L) ff = exp(-I*2.0*PI*double(m)*x/L) * a / L; return ff; } complex<double> Simpson(double x0 ,double x1 ,int N, int m) // 合成シンプソン法による求積 { complex<double> ss1 = complex<double>(0.0,0.0); for(int i=1; i<=N/2-1; i++){ double x = x0 + (x1-x0)/double(N) * double(2*i); ss1 += F(x,m); } complex<double> ss2 = complex<double>(0.0,0.0);; for(int i=1; i<=N/2; i++){ double x = x0 + (x1-x0)/double(N) * double(2*i-1); ss2 += F(x,m); } return (x1-x0)/(3.0*double(N)) * ( F(x0,m)+F(x1,m) + 2.0 * ss1 + 4.0 * ss2 ); }