1.2.1 で説明した FFT は,周波数領域の添字 k を偶数と奇数とに分ける ことで,半分の長さの DFT に変換するという方法ですが,時間領域の 添字 j を偶数と奇数とに分けることでも半分の長さの DFT
N/2-1 jk k N/2-1 jk
A = Σ a W + W Σ a W
k j=0 2j N/2 j=0 2j+1 N/2
N/2-1 jk k N/2-1 jk
A = Σ a W − W Σ a W
N/2+k j=0 2j N/2 j=0 2j+1 N/2
に分解することができます.次に,この分解による時間間引き FFT ルーチンの 例を示します.
| リスト1.2.2-1. 基数 2 の時間間引き FFT |
|---|
#include <math.h>
void fft(int n, double theta, double ar[], double ai[])
{
int m, mh, i, j, k;
double wr, wi, xr, xi;
/* ---- scrambler ---- */
i = 0;
for (j = 1; j < n - 1; j++) {
for (k = n >> 1; k > (i ^= k); k >>= 1);
if (j < i) {
xr = ar[j];
xi = ai[j];
ar[j] = ar[i];
ai[j] = ai[i];
ar[i] = xr;
ai[i] = xi;
}
}
theta *= n;
for (mh = 1; (m = mh << 1) <= n; mh = m) {
theta *= 0.5;
for (i = 0; i < mh; i++) {
wr = cos(theta * i);
wi = sin(theta * i);
for (j = i; j < n; j += m) {
k = j + mh;
xr = wr * ar[k] - wi * ai[k];
xi = wr * ai[k] + wi * ar[k];
ar[k] = ar[j] - xr;
ai[k] = ai[j] - xi;
ar[j] += xr;
ai[j] += xi;
}
}
}
}
|
![]() |
| 図1.2.2-1. 基数 2 の時間間引き FFT のフローグラフ |
|---|
時間間引き FFT は,回転因子 W を掛けてからデータを足し引きするという バタフライ演算からなり,周波数間引きの FFT のデータフローを逆に たどったものに相当します.したがって,時間間引き FFT と周波数間引き FFT の計算量は全く同じで,複素数データの DFT ではどちらを使っても 結果はほぼ同じになります.しかし,拡張 DFT や離散コサイン変換などの 順方向の変換と逆方向の変換が異なる変換では,時間間引きの FFT と 周波数間引きの FFT は互いに逆変換として使われます. 離散コサイン変換では,DCT-II を周波数間引きで,DCT-III を時間間引きで 計算します.実数データの DFT では,順変換を時間間引きで,逆変換を 周波数間引きで計算します.ただし,工夫をすれば実数データの DFT は どちらの間引きでも計算は可能です.これらの設計法は後に示します.
また,畳み込みの計算では,時間間引きの FFT と周波数間引きの FFT の 使い分けによりビット反転並べ替えが省略できます.これは,変換後の データに対するビット反転を省略し,ビット反転の状態で乗算を行い, ビット反転を省略した逆変換でもとに戻すという方法になります.これで 多少の時間の節約ができます.