みんな大好きFFTのお話です
以前MaximaのFFT関数を紹介しましたが,そもそもMaximaは数式処理システムなので大量の数値計算は苦手です(´・ω・`)
なので今回はC言語で組んだFFTプログラムを使ってみたいと思います
FFT本体のサブルーチンは奥村晴彦著「C言語による最新アルゴリズム事典」に記載のものを使わせて頂きました
サポートサイトでサブルーチンのソースコードを配布されています(make_sintbl, make_bitrev, fftの3つです)
- FFTにはCooley-Tukey型FFTアルゴリズムを用いています
- 入力データのサンプル数は2のべき乗として下さい
- 計算結果をパイプ処理でgnuplotに出力します
- gnuplotフォルダはc:\直下に置かれていることを前提とします(それ以外はpathを通して下さい)
- gnuplot-win32のver4.4.3で動作確認しました
以下にソースコードを示します(make_sintbl, make_bitrev, fftについては省略します)
【fft.c】
#include <stdio.h> #include <stdlib.h> #include <math.h> #define PI 3.14159265358979323846 #define NMAX 65536 #define SMAX 1024 #define GNUPLOT_PATH "c:/gnuplot/binary/pgnuplot.exe" FILE *fp1, *fp2, *fp3, *gp; int N; float X1[NMAX], Y1[NMAX]; float X2[NMAX], Y2[NMAX]; float DT, DF; void output_fft(void); void gnuplot(void); int main(void) { if(!input_fft()) return EXIT_FAILURE; else if(fft(N, X2, Y2)) return EXIT_FAILURE; else{ output_fft(); gnuplot(); return EXIT_SUCCESS; } } int input_fft(void) { int i = 0, j; char buff[SMAX], *tok; /* fft.dat */ if((fp1 = fopen("fft.dat", "r")) == NULL){ printf("can't open input data file\n"); getch(); exit(1); } fgets(buff, SMAX, fp1); tok = strtok(buff, "\n"); DT = atof(tok); while(!feof(fp1)){ fgets(buff, SMAX, fp1); tok = strtok(buff, "\t"); if(tok != NULL) X1[i] = atof(tok); else break; tok = strtok(NULL, "\n"); if(tok != NULL) Y1[i] = atof(tok); else break; i++; } fclose(fp1); /* error check */ if((i & (i-1))){ printf(" error : %d is not powers of 2\n", i); getch(); return 0; } N = i; for(j = 0; j < i; j++) { X2[j] = X1[j]; Y2[j] = Y1[j]; } DF = 1/(i*DT); return 1; } void output_fft(void) { int i; char *s[7]; s[0] = "\n FFT : fast Fourier transform with Cooley-Tukey algorithm\n\n"; s[1] = " number of samples\t: %d\n"; s[2] = " sampling interval\t: %g [s]\n"; s[3] = " sampling time\t\t: %g [s]\n"; s[4] = " sampling rate\t\t: %g [Hz]\n"; s[5] = " nyquist frequency\t: %g [Hz]\n"; s[6] = " resolution of freq\t: %d\n"; s[7] = " minimum frequency\t: %g [Hz]\n\n"; /* stdout */ printf(s[0]); printf(s[1], N); printf(s[2], DT); printf(s[3], N*DT); printf(s[4], 1/DT); printf(s[5], 0.5/DT); printf(s[6], N/2); printf(s[7], DF); /* fft.out */ fp2 = fopen("fft.out", "w"); fprintf(fp2, s[0]); fprintf(fp2, s[1], N); fprintf(fp2, s[2], DT); fprintf(fp2, s[3], N*DT); fprintf(fp2, s[4], 1/DT); fprintf(fp2, s[5], 0.5/DT); fprintf(fp2, s[6], N/2); fprintf(fp2, s[7], DF); fprintf(fp2, " TIME\tINPUT\t\t\t\t\tFFT\n"); fprintf(fp2, "\t\t real\t\timage\t\t real\t\timage\n"); for (i = 0; i < N; i++) fprintf(fp2, "%5d | %10.3e %10.3e | %10.3e %10.3e\n", i, X1[i], Y1[i], X2[i], Y2[i]); fclose(fp2); } void gnuplot(void) { int i, n = N/2; float x2, y2; /* gnu.out */ fp3 = fopen("gnu.out", "w"); fprintf(fp3, "%10.3e\t%10.3e\n", 0., 0.); for (i = 1; i < n; i++){ x2 = pow(X2[i], 2); y2 = pow(Y2[i], 2); fprintf(fp3, "%10.3e\t%10.3e\n", i*DF, 2*sqrt(x2 + y2)); } fclose(fp3); /* gnuplot */ if((gp = _popen(GNUPLOT_PATH, "w")) == NULL){ fprintf(stderr,"can't open gnuplot\n"); exit(1); } fprintf(gp, "set logscale xy\n"); fprintf(gp, "set xlabel \"Hz\"\n"); fprintf(gp, "set ylabel \"amp\"\n"); fprintf(gp, "plot \"%s\" with lines linetype 1\n","gnu.out"); fflush(gp); printf("\n press any key to exit...\n"); getch(); _pclose(gp); }
C言語による最新アルゴリズム事典 (ソフトウェアテクノロジー)
- 作者: 奥村晴彦
- 出版社/メーカー: 技術評論社
- 発売日: 1991/03/01
- メディア: 単行本
- 購入: 20人 クリック: 396回
- この商品を含むブログ (95件) を見る