[C言語]初心者でもできる離散フーリエ変換、逆変換の実装[オイラーの公式]

C言語コード

はい今日はフーリエ変換を実装していきます

フーリエ変換自体の仕組みについては割愛します。

まあ数学のブログではないしね

あくまでフーリエ変換をC言語で実装することをメインに書いていくのでよろしくお願いします。
一応今回は1次元の離散フーリエ変換をやっていきます。
有限長の信号のデータセットを扱う感じです。

フーリエ変換、逆変換の計算式

信号の個数をNとして
xを信号の値、
Xを離散フーリエ変換とします

つまり周波数も0からNまでの整数です。

その時の離散フーリエ変換がこちら

逆変換がこちら

小文字と大文字の違いに注意ですね


この計算のコードを書いていきます。

コードの実装

虚数の部分どうするか問題

まあ計算のシグマの部分はforループでおk

問題は虚数が出ていることですね

C言語には標準で虚数を扱う関数がないからなぁ… どうしよう…

と思ったのですが、

今回、虚数が出ているのがeの係数ですね。
なのでオイラーの公式を使って分解できます

オイラーの公式

これで虚数iをただの係数に落とし込めるので計算できそうですね。

オイラーまじ感謝

まあオイラーの公式についての詳しいことは調べてください。

離散フーリエ変換の関数

void Fourier(void){ //フーリエ変換
    
    double xr[N];
   
    char r_r[NAME];
    printf("どのファイルから読み込みますか?:");
    scanf("%s",r_r);
    SCAN(xr,r_r);
    
    int n,k;
        
    double X_R[N];
    double X_I[N];
    double r;
    double i;
                 
        
    for(k=0; k<N; k++){
        r=0;
        i=0;
        for(n=0; n<N; n++){
            r += xr[n] * cos((2*M_PI*k*n)/N);
            i -= xr[n] * sin((2*M_PI*k*n)/N);
        }
        X_R[k] = r;

        X_I[k] = i;
    }
        
    writeru(X_R, X_I);
    
}

信号はファイルに入っているものとします。
SCANはファイルの中身を配列に入れる関数です。
で、X_RとX_Iがフーリエ変換の結果の実部と虚部を入れる配列です。

内側for文の中で、フーリエ変換の式とオイラーの公式に従って計算しています。
内側ループが終わったらX_R,X_Iに格納して外側ループに戻るって感じです。

最後に配列をファイルに格納します。writeruがそれ。

離散フーリエ逆変換

void r_Fourier(void){ //フーリエ逆変換
   
    double X_R[N];
    double X_I[N];
    scanru(X_R, X_I);
        
    int n,k;
    double x_r[N];
    
    for(n=0; n<N; n++){
        double r=0;
            
        for(k=0; k<N; k++){
            r += X_R[k] * cos((2*M_PI*k*n)/N) - X_I[k] * sin((2*M_PI*k*n)/N);
        }
            
        x_r[n] = r/N;
    }
    
    char r_w[NAME];
    printf("どのファイルに書き込みますか?:");
    scanf("%s",r_w);
    WRITE(x_r, r_w);
}

こちらも同様ですね。
こっちは普通の信号に戻るので返す配列は1つです。
あと式の1/Nの場所を間違えないように。

ゆーてどちらも計算式がややこしいだけですね。

終わり

今回はこれだけですね。
そのうちフィルタを掛けてみる実験の記事を書いても良いかも。

ではまた〜


コメント

タイトルとURLをコピーしました