2.2 拡張離散 Fourier 変換

 ここでの拡張 DFT は,時間方向または周波数方向の点をずらした 変換のことで,

          N-1      (j+δ1)(k+δ2)   
    A  =  Σ   a   W               
     k    j=0  j   N              

で定義します.この逆変換も拡張 DFT で

          1   N-1      -(j+δ2)(k+δ1)   
    a  = ---  Σ   A   W                
     k    N   j=0  j   N               

となります.もし,δ1, δ2 が有理数ならば,拡張 DFT は通常の DFT を 適当な間隔で点をとばして計算したものに相当します.たとえば,δ1=1/2, δ2=0 の場合は長さ 2N の奇数点上での DFT になります.

この拡張 DFT は,通常の FFT の変換前のデータに W^δ2 j を掛けて, 変換後のデータに W^δ1 k を掛ければ計算できることになります. しかし,δ1 または δ2 のどちらかがゼロのこの変換は,通常の FFT の 三角関数データをずらすだけで容易に実行できます [参考文献].したがって,これらの乗算の 片方は簡単に省略することができます.

 例えば,時間方向に δ1 シフトした拡張 DFT は周波数間引き FFT の 三角関数を δ1 だけずらすことで計算できます.具体的なルーチンは 次のようになります.

リスト2.2-1. 周波数間引きによる拡張 FFT
/*
  F[k]=Σ_j=0^n-1 a[j]*exp(±2*pi*i*(j+delta1)*k/n),0<=k<n を計算する.
  n はデータ数で 2 の整数乗, theta は ±2*PI/n, 
  ar[0...n-1], ai[0...n-1], はデータの実部, 虚部.
*/
#include <math.h>

void gfft1(int n, double theta, double delta1, double ar[], double ai[])
{
    int m, mh, i, j, k;
    double wr, wi, xr, xi;

    for (m = n; (mh = m >> 1) >= 1; m = mh) {
        for (i = 0; i < mh; i++) {
            wr = cos(theta * (i + delta1));
            wi = sin(theta * (i + delta1));
            for (j = i; j < n; j += m) {
                k = j + mh;
                xr = ar[j] - ar[k];
                xi = ai[j] - ai[k];
                ar[j] += ar[k];
                ai[j] += ai[k];
                ar[k] = wr * xr - wi * xi;
                ai[k] = wr * xi + wi * xr;
            }
        }
        theta *= 2;
    }
    /* ---- unscrambler ---- */
    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;
        }
    }
}
 

同様に,周波数方向に δ2 だけシフトした拡張 DFT は時間間引き FFT の 三角関数を δ2 だけずらすことで計算できます.これらの拡張 DFT に対する FFT を,拡張 FFT と呼ぶことにします.

 次に実数データに対する拡張 FFT の計算について 考えます.これは, 実数専用の FFT ルーチンを用いる方法の第二の方法 を用いて計算できます.例えば,実数データの時間 1/2 シフト拡張 FFT は 三角関数データを 1/2 だけずらすことで計算できます.このルーチンは 次のようになります.

リスト2.2-2. 実数データの時間 1/2 シフト拡張 FFT
/*
  実数データの時間 1/2 シフト拡張 DFT :
  F[k]=Σ_j=0^n-1 a[j]*exp(-2*pi*i*(j+1/2)*k/n),0<=k<n を計算する.
  出力 a[0...n/2-1], a[n/2...n-1] はそれぞれ F[0...n/2-1] の実部, 
  F[n/2...n-1] の符号を付けかえた虚部に相当する.
*/
#include <math.h>

void grfft1h(int n, double a[])
{
    int m, mh, mq, i, j, k, irev, jr, ji, kr, ki;
    double theta, 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 = a[j];
            a[j] = a[i];
            a[i] = xr;
        }
    }
    theta = -8 * atan(1.0) / n;
    for (mh = 1; (m = mh << 1) <= n; mh = m) {
        /* ---- real to real butterflies ---- */
        for (jr = 0; jr < n; jr += m) {
            kr = jr + mh;
            xr = a[jr] - a[kr];
            a[jr] += a[kr];
            a[kr] = xr;
        }
        if (mh == 1) continue;
        /* ---- real to complex butterflies ---- */
        mq = mh >> 1;
        irev = mq;
        for (ji = mq; ji < n; ji += m) {
            wr = cos(0.5 * theta * irev);
            wi = sin(0.5 * theta * irev);
            for (k = n >> 2; k > (irev ^= k); k >>= 1);
            ki = ji + mh;
            xr = a[ji];
            xi = a[ki];
            a[ji] = wr * xr + wi * xi;
            a[ki] = wr * xi - wi * xr;
        }
        if (mh == 2) continue;
        /* ---- complex to complex butterflies ---- */
        irev = mq;
        for (i = 0; i < n; i += m) {
            wr = cos(theta * irev);
            wi = sin(theta * irev);
            for (k = n >> 2; k > (irev ^= k); k >>= 1);
            for (j = 1; j < mq; j++) {
                jr = i + j;
                kr = jr + mh;
                ki = i + mh - j;
                ji = ki + mh;
                xr = a[jr] - a[kr];
                xi = a[ji] - a[ki];
                a[jr] += a[kr];
                a[ji] += a[ki];
                a[ki] = wr * xr + wi * xi;
                a[kr] = wr * xi - wi * xr;
            }
        }
    }
}
 

この実数データの時間 1/2 シフト拡張 FFT は,離散コサイン変換 DCT-II と 離散サイン変換 DST-II を同時に計算していることになります.したがって, このルーチンを二つに分離すれば,DCT-II と DST-II のルーチンが 作成できることになります.これは 次の 2.3.3で示します.


目次へ戻る