8回目 課題 解説
#include <stdio.h> #include <math.h> struct Complex{ double re; /* 実部 */ double im; /* 虚部 */ }; void clear_array(double x[], int n); // 要素数 n の配列 x に,すべて 0 を代入する(初期化). void square_wave(double x[], int n); // 要素数 n の配列 x に,任意の周波数(例えば 5 )の矩形波を書き込む.振幅は任意,例えば -1 から 1 など. void sin_waves(double x[], int n, double f1, double f2, double f3); // 配列に周波数 f1, f2, f3,計3個の正弦波または余弦波の和を入れる. Complex ToComplex(double x, double y); Complex Cadd(Complex a, Complex b); Complex Cmul(Complex a, Complex b); Complex Cexp(Complex a); double Cabs(Complex a); void dft(const double in[], Complex out[], const int N); int main(){ const int n = 100; double x1[n] = {0}, x2[n] = {0}, x11[n] = {0}, x21[n] = {0}; Complex dx1[n], dx2[n]; FILE *fp; //配列の初期化 clear_array(x1, n); clear_array(x2, n); clear_array(x11,n); clear_array(x21,n); //配列に各波形の値を代入 square_wave(x1, n); sin_waves(x2, n, 1, 2, 5); //dftの計算 dft(x1, dx1, n); dft(x2, dx2, n); //スペクトルの計算 for(int i = 0; i < n; i++){ x11[i] = Cabs(dx1[i]) * Cabs(dx1[i]); x21[i] = Cabs(dx2[i]) * Cabs(dx2[i]); } //ファイル出力 fp = fopen("153R000000-08-1.csv", "w"); if(fp == NULL){ printf("file cannot be opened\n"); return -1; } fprintf(fp, "周波数,矩形波,合成波\n"); for(int i = 0; i < n/2; i++){ fprintf(fp, "%d,%f,%f\n", i, x11[i], x21[i]); } fclose(fp); printf("ファイル出力完了!\n"); return 0; } void clear_array(double x[], int n){ for(int i = 0; i < n; i++){ x[i] = 0; } } void square_wave(double x[], int n){ int freq = 10; //任意の半周波数をここで設定 for(int i = 0; i < n; i++){ if((i/freq)%2 == 0) x[i] = -1; //iを任意の半周期で割った解の整数の位が2の倍数なら-1を代入,それ以外で1を代入 else x[i] = 1; } } void sin_waves(double x[], int n, double f1, double f2, double f3){ for(int i = 0; i < n; i++){ x[i] = (2.0 * sin(2*M_PI*i/n * f1) //M_PIはmath.hに定義される円周率の定数 + 0.5 * cos(2*M_PI*i/n * f2) + 0.25 * sin(2*M_PI*i/n * f3)); } } Complex ToComplex(double x, double y){ /*複素数のパラメータを与える*/ Complex z; /*Complex型の変数を用意*/ z.re = x; z.im = y; return z; /*構造体として返す(実部,虚部をパラメータとして持つ)*/ } Complex Cadd(Complex a, Complex b){ /*複素数の足し算*/ Complex z; z.re = a.re + b.re;/*複素数aの実部と複素数bの実部を足す.*/ z.im = a.im + b.im; return z; } Complex Cmul(Complex a, Complex b){ /*複素数の掛け算*/ Complex z; z.re = (a.re * b.re) - (a.im * b.im); z.im = (a.re * b.im) + (b.re * a.im); return z; } Complex Cexp(Complex a){ /*指数関数*/ Complex z; z.re = exp(a.re) * cos(a.im); z.im = exp(a.re) * sin(a.im); return z; } double Cabs(Complex a){ /*絶対値*/ double x; x = sqrt(a.re * a.re + a.im * a.im); return x; } void dft(const double in[], Complex out[], const int N){ // // 離散フーリエ変換(DFT) // 元データは実数,変換後は複素数 // // in : 元データ.これは変更しない.実数の配列. // out : 計算結果.こちらは複素数. // N : データ個数.inもoutも同じデータ数でなければならない // int t; /* 出力用の配列を初期化 */ for(t=0; t<N; t++) { out[t].re = 0.0; out[t].im = 0.0; } for(int f=0; f<N; f++) { // 以下のループで 1個のF[omega]を計算する. double omega = 2 * M_PI * f; for(t=0; t<N; t++) { /* 積分の中身の計算 */ out[f] = Cadd(out[f], Cmul( ToComplex(in[t], 0.0), Cexp( ToComplex(0.0, -omega * t/N) ))); } } } |
構造体 関数の宣言 メイン関数 配列初期化 矩形波の関数 正弦波合成の関数 |
#include <stdio.h> #include <math.h> struct Complex{ double re; /* 実部 */ double im; /* 虚部 */ }; void clear_array(double x[], int n); // 要素数 n の配列 x に,すべて 0 を代入する(初期化). Complex ToComplex(double x, double y); Complex Cadd(Complex a, Complex b); Complex Cmul(Complex a, Complex b); Complex Cexp(Complex a); double Cabs(Complex a); void dft(const double in[], Complex out[], const int N); int main(){ const int N = 1000; //要素数 double data[N] = {0}, spdata[N] = {0}; //dataは元データ、spdataはパワースペクトルのデータ Complex dftdata[N] = {0}; //dftでの計算結果を格納するComplex型配列 FILE *ifp, *ofp; //FILE構造体へのポインタ,ifp:input, ofp:output char ifilename[] = "wave.txt", ofilename[] = "153R000000-08-2.csv"; /* ファイル名 */ ifp = fopen(ifilename, "r"); /* 読み込みモードで開く */ if(ifp == NULL){ printf("入力ファイルが開けない\n"); return -1; /* エラー終了 */ } for(int i=0; i<N; i++){ fscanf(ifp, "%lf", &data[i]); } fclose(ifp); /* 念のため画面に出力して確認 */ for(int i=0; i<N; i++){ printf("data[%d] = %lf\n", i, data[i]); } //spdataを初期化 clear_array(spdata, N); //dft演算 dft(data, dftdata, N); //パワースペクトルを計算 for(int i = 0; i < N; i++){ spdata[i] = Cabs(dftdata[i]) * Cabs(dftdata[i]); } //ファイル出力 ofp = fopen(ofilename, "w"); fprintf(ofp, "周波数,パワースペクトル\n"); if(ofp == NULL){ printf("出力ファイルが開けない\n"); return -1; } for(int i = 0; i < N/2; i++){ fprintf(ofp, "%d,%f\n", i, spdata[i]); } fclose(ofp); printf("ファイル出力完了\n"); return 0; } void clear_array(double x[], int n){ for(int i = 0; i < n; i++){ x[i] = 0; } } Complex ToComplex(double x, double y){ /*複素数のパラメータを与える*/ Complex z; /*Complex型の変数を用意*/ z.re = x; z.im = y; return z; /*構造体として返す(実部,虚部をパラメータとして持つ)*/ } Complex Cadd(Complex a, Complex b){ /*複素数の足し算*/ Complex z; z.re = a.re + b.re;/*複素数aの実部と複素数bの実部を足す.*/ z.im = a.im + b.im; return z; } Complex Cmul(Complex a, Complex b){ /*複素数の掛け算*/ Complex z; z.re = (a.re * b.re) - (a.im * b.im); z.im = (a.re * b.im) + (b.re * a.im); return z; } Complex Cexp(Complex a){ /*指数関数*/ Complex z; z.re = pow(exp(1), a.re) * cos(a.im); z.im = pow(exp(1), a.re) * sin(a.im); return z; } double Cabs(Complex a){ /*絶対値*/ double x; x = sqrt(a.re * a.re + a.im * a.im); return x; } void dft(const double in[], Complex out[], const int N){ // // 離散フーリエ変換(DFT) // 元データは実数,変換後は複素数 // // in : 元データ.これは変更しない.実数の配列. // out : 計算結果.こちらは複素数. // N : データ個数.inもoutも同じデータ数でなければならない // int t; /* 出力用の配列を初期化 */ for(t=0; t<N; t++) { out[t].re = 0.0; out[t].im = 0.0; } for(int f=0; f<N; f++) { // 以下のループで 1個のF[omega]を計算する. double omega = 2 * M_PI * f; for(t=0; t<N; t++) { /* 積分の中身の計算 */ out[f] = Cadd(out[f], Cmul( ToComplex(in[t], 0.0), Cexp( ToComplex(0.0, -omega * t/N) ))); } } } |
構造体 関数の宣言 メイン関数 配列初期化 |