iwiwi 備忘録

学んだことを殴り書きます。自分向けのメモです。

FFT (高速フーリエ変換) で信号の高周波数の部分をカットする

信号処理は専門じゃない(どころかそういう授業を受けたりするような環境ですら無かった)ので全然わからないが,ひょんなことからちょっと信号を処理することになった.

FFT は普段からたまに使うのだけれど,いつもただ畳込みを計算するばかりで,周波数がどうのみたいなことをやったことがなかった.以下がプログラミングコンテストでいつも使っている FFT のコード.(a の長さは 2 の累乗にする.)

#include <complex>
typedef complex<double> c_t;

void fft(vector<c_t> &a, int dir = 1) {
  int n = a.size(), i = 0;
  rep (j, n) {
    if (j < i) swap(a[i], a[j]);
    for (int k = n >> 1; k > (i ^= k); k >>= 1);
  }

  for (int s = 0; 1 << s < n; s++) {
    int m = 1 << s;
    c_t wm = polar(1.0, M_PI / m * dir), w(1.0);
    rep (j, m) {
      for (int k = j; k < n; k += m * 2) {
        c_t s = a[k], t = w * a[k + m];
        a[k] = s + t;
        a[k + m] = s - t;
      }
      w *= wm;
    }
  }
}

これにぶち込んだあと,配列のある部分を 0 にして,またぶち込む(dir = -1 にして呼び出し,さらに全てを a.length() で割り,実数部を取る)と,高周波数領域がカットできる.

これでどこを 0 にすればよいかというと,配列の真ん中の部分である.これはちょっと意外な感じがする(最初の部分とか後半の部分というのがよくある感じがする)が,まぁよく考えたらそうである.