ちょこちょこっと終わるかなと思っていたら思いのほか四苦八苦。
どこで計算がおかしくなっているのかがわかりにくかったです。
今回のポイント(?)は積分関数に関数ポインタを渡すところですか。
関数ポインタを使うのが今回が初めてだったので苦戦しました。
クラスのメンバ関数は引数として渡せないというのが大きな壁。
やむなく積分関数は冗長でわかりにくい関数になってしまいました。
しかし汎用性は一応キープ。
周期関数func()の内容だけ変えればすぐにフーリエ解析ができるようにしました。
今回の画像は半径1の円 です。
積分計算にsinなんかが入ってきてますので積分の分割dtが大きくなると発散します。
全体として級数の数nnとdtの積が1.9を超えると発散してしまいます。
以下フーリエ関数クラス(Fourier)と積分関数(integral())のコードです。
// Fourier.h
#include
#include
static const double PI = 3.1415926535897932384626;
double integral(double (*func)(double x), double dx, double begin, double x, double (*func2)(double x) = 0, double nn = 1);
class Fourier
{
public:
Fourier(double _T, int _n, double (*_func)(double), double _dx)
: T(_T), n(_n), func(_func), dx(_dx)
{
omg = 2 * PI / T;
calceff();
}
double T;
double (*func)(double);
double dx; // used in integral. not eccential for this class.
private:
int n;
double omg;
std::vector an;
std::vector bn;
public:
void Setn(int _n)
{
n = _n;
calceff();
}
// main
double calc(double x)
{
double sum = 0;
for(int i = 0; i < n + 1; i++)
{
sum += an[i] * cos(i * omg * x) + bn[i] * sin(i * omg * x);
}
return sum;
}
private:
double a(int m)
{
double aa = 2 / T * integral(func, dx, -T / 2, T / 2, cos, m * omg);
return m ? aa : aa / 2;
}
double b(int m)
{
return 2 / T * integral(func, dx, -T / 2, T / 2, sin, m * omg);
}
void calceff()
{
for(int i = 0; i < n + 1; i++)
{
an.push_back(a(i));
bn.push_back(b(i));
}
}
};
double integral(double (*func)(double x), double dx, double begin, double x, double (*func2)(double x), double nn)
{
bool flg = false;
if(x < begin)
{
double tmp = x;
x = begin;
begin = tmp;
flg = true;
}
int n = (int)((x - begin) / dx);
double sum = 0;
for(int i = 0; i < n; i++)
{
if(func2 != 0)
sum += func(begin + i * dx) * func2((begin + i * dx) * nn) * dx;
else
sum += func(begin + i * dx) * dx;
}
if(func2 != 0)
sum += func(begin + dx * n) * func2((begin + dx * n) * nn) * (x - begin - n * dx);
else
sum += func(begin + dx * n) * (x - begin - n * dx);
if(flg)
sum *= -1;
return sum;
}