HOME > natural science Laboratory > コンピュータ・シミュレーション講座 > 計算物理学

高速フーリエ変換の動作チェック(C++)

文責:遠藤 理平 (2018年5月 9日) カテゴリ:計算物理学(141)

以前、JavaScriptで作成した高速フーリエ変換用関数をC言語に書き直しました。 シュレディンガー方程式を数値的に解くためにこれを用いる予定です。

元の関数と逆変換の結果

展開係数

プログラムソース

////////////////////////////////////////////////////////////////////
// 高速フーリエ変換
////////////////////////////////////////////////////////////////////
#define _USE_MATH_DEFINES
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdio>
#include <iomanip>
#include <stdio.h>
#include <complex>
#include <direct.h>

/////////////////////////////////////////////////////////////////
//項数と空間距離
const int N = 128;
double L = 3.0;

//高速フーリエ変換
void FFT(double* an, double* bn, int N, bool Inverse) {
	/////////////////////////////////////////
	//参考:Javaで学ぶシミュレーションの基礎
	/////////////////////////////////////////
	// 入力
	// N  : 項数(2のべき乗)
	// an : 実数配列(順変換:実数空間データを項数Nで指定、逆変換:展開係数a(n))
	// bn : 実数配列(順変換:虚数空間データを項数Nで指定、逆変換:展開係数b(n))
	// Inverse : 逆変換の場合に true
	/////////////////////////////////////////
	// 出力
	// an : 実数配列(順変換:展開係数a(n)、逆変換:実数空間データ)
	// bn : 実数配列(順変換:展開係数b(n)、逆変換:虚数空間データ)
	/////////////////////////////////////////

	int ff = Inverse ? 1 : -1;

	int* rot = new int[N];

	for (int i = 0; i < N; i++) rot[i] = 0;

	int nhalf = N / 2, num = N / 2;
	double sc = 2.0 * M_PI / N;

	while (num >= 1) {

		for (int j = 0; j < N; j += 2 * num) {

			int phi = rot[j] / 2;
			int phi0 = phi + nhalf;
			double c = cos(sc * phi);
			double s = sin(sc * phi * ff);

			for (int k = j; k < j + num; k++) {

				int k1 = k + num;
				double a0 = an[k1] * c - bn[k1] * s;
				double b0 = an[k1] * s + bn[k1] * c;
				an[k1] = an[k] - a0;
				bn[k1] = bn[k] - b0;
				an[k] = an[k] + a0;
				bn[k] = bn[k] + b0;
				rot[k] = phi;
				rot[k1] = phi0;
			}
		}
		num = num / 2;
	}

	for (int i = 0; i < N; i++) {
		int j = rot[i];
		if (j > i) {

			double tmp = an[i];
			an[i] = an[j];
			an[j] = tmp;

			tmp = bn[i];
			bn[i] = bn[j];
			bn[j] = tmp;

		}
	}

	if (!Inverse) {
		for (int i = 0; i < N; i++) {
			an[i] = an[i] / N;
			bn[i] = bn[i] / N;

		}
	}

	delete[] rot;
}

//元の関数
double f( double x) {
	//	return Math.sin( 2 * Math.PI / L * 2 * x );
	if (L / 2 - L / 5 < x  &&  x < L / 2 + L / 5) return 1;
	else return 0;
}


/////////////////////////////////////////////////////////////////
std::string folder = "output";//作成するフォルダ名
std::string filename1 = "FFT.txt";//ファイル名
std::string filename2 = "FFT_.txt";//ファイル名
const int precision_N = 4;

int main() {

	//フォルダ生成
	_mkdir(folder.c_str());
	std::string filepath1 = folder + "/" + filename1;
	std::string filepath2 = folder + "/" + filename2;

	//展開係数
	double an[N], bn[N];

	for (int i = 0; i<N; i++) {
		double x = L / N * i;
		an[i] = f(x);
		bn[i] = 0;
	}

	//順変換の実行
	FFT(an, bn, N, false);

	//出力ストリームによるファイルオープン
	std::ofstream fout1;
	fout1.open(filepath1.c_str());
	fout1 << "#x:n" << std::endl;
	fout1 << "#y:展開係数" << std::endl;
	fout1 << "#legend: an bn" << std::endl;
	fout1 << "#showLines: true true true true" << std::endl;
	fout1 << "#showMarkers: true true false false" << std::endl;
	fout1 << "#fills: false false false false" << std::endl;
	fout1 << "#xrange:0 128 10" << std::endl;
	fout1 << "#yrange:-0.5 0.5 0.1 " << std::endl;
	for (int i = 0; i < N; i++) {
		fout1 << i << " " << an[i] << " " << bn[i] << std::endl;
	}
	fout1.close();


	//逆変換用
	double _an[N], _bn[N];

	for (int n = 0; n < N; n++) {
		_an[n] = an[n];
		_bn[n] = bn[n];
	}

	//逆変換の実行
	FFT(_an, _bn, N, true);

	//出力ストリームによるファイルオープン
	std::ofstream fout2;
	fout2.open(filepath2.c_str());
	fout2 << "#x:x" << std::endl;
	fout2 << "#y:f(x)" << std::endl;
	fout2 << "#legend: 元の関数 逆変換(実数部) 逆変換(虚数部)" << std::endl;
	fout2 << "#showLines: true true true true" << std::endl;
	fout2 << "#showMarkers: false false false false" << std::endl;
	fout2 << "#fills: false false false false" << std::endl;
	fout2 << "#xrange:0 3 0.2" << std::endl;
	fout2 << "#yrange:-0.1 1.1 0.1 " << std::endl;
	for (int i = 0; i < N; i++) {
		double x = L / N * i;
		fout2 << x << " " << f(x) << " " << _an[i] << " " << _bn[i] << std::endl;
	}
	fout2.close();

}

http://www.natural-science.or.jp/files/physics/FFT_test.cpp
※VisualStudio2017のソルーションファイルです。GCC(MinGW)でも動作確認しています。



▲このページのトップNPO法人 natural science トップ

関連記事

計算物理学

▲このページのトップNPO法人 natural science トップ