LoginSignup
2
0

More than 3 years have passed since last update.

C言語による最新アルゴリズム事典 FFT 三角関数表の計算方法を調べた

Last updated at Posted at 2021-01-16

FFT向け三角関数表の作成

以下は 奥村 晴彦 著 "C言語による最新アルゴリズム事典"に記載のあるFFT計算のコードの一部です。
FFTを実行する際に利用する三角関数表(sinテーブル)を作成しています。
sinを一度求めたら、それを使って次々にcos,sinのn倍角の値を計算しています。
が、書籍中に特に説明はなく、なぜこれで計算できるのかすぐにはわかりません。
(FFTのソースコードはここにあります。)

/*
  関数{\tt fft()}の下請けとして三角関数表を作る.
*/
static void make_sintbl(int n, double sintbl[])
{
    int i, n2, n4, n8;
    double c, s, dc, ds, t;

    n2 = n / 2;  n4 = n / 4;  n8 = n / 8;
    t = sin(PI / n);
    dc = 2 * t * t;  ds = sqrt(dc * (2 - dc));
    t = 2 * dc;  c = sintbl[n4] = 1;  s = sintbl[0] = 0;
    for (i = 1; i < n8; i++) {
        c -= dc;  dc += t * c;
        s += ds;  ds -= t * s;
        sintbl[i] = s;  sintbl[n4 - i] = c;
    }
    if (n8 != 0) sintbl[n8] = sqrt(0.5);
    for (i = 0; i < n4; i++) {
        sintbl[n2 - i] = sintbl[i];
        sintbl[i + n2] = - sintbl[i];
    }
}

三角関数を計算している中心的な部分

上のコードの最も肝心なところを以下に抜粋しました。

    t = sin(PI / n);
    dc = 2 * t * t;  ds = sqrt(dc * (2 - dc));
    t = 2 * dc;  c = sintbl[n4] = 1;  s = sintbl[0] = 0;
    for (i = 1; i < n8; i++) {
        c -= dc;  dc += t * c; // cosに関する計算
        s += ds;  ds -= t * s; // sinに関する計算
        sintbl[i] = s;  sintbl[n4 - i] = c; // 求めたcos,sinの値をテーブルへ設定
    }

上の部分で$\theta =2\pi/N $ として
変数 c に$\cos(n\theta)$、変数 s に$\sin(n\theta)$ が計算されているようです。(実際計算できている)
これについて以下で示しました。

チェビシェフ多項式

$\cos(\theta)$ のn倍角の値はチェビシェフ多項式で表せる。

\begin{align}
\cos(1t) &= \cos(t) \\
\cos(2t) &= \cos(t)\cos(t) - \sin(t)\sin(t)=2(\cos(t))^2 - 1\\
\cos(3t) &= 4(\cos(t))^3-3\cos(t) \\
\vdots&
\end{align}

以下の式で$x = \cos(t)$ とすれば、

\begin{align}
T_0(x)& = 1 \\
T_1(x)& = x \\
T_2(x)& = 2x^2-1 \\
T_3(x)& = 4x^3-3x \\
\vdots&
\end{align}

$T_n(x)$を漸化式で表せば

T_{n+1}(x) = 2xT_n(x)-T_{n-1}(x)

と表せる。これを利用する。

cosのn倍角について

$k = 2\sin^2(\theta/2)$とすると
$\cos(\theta) = 1 - 2\sin^2(\theta/2) = 1 - k$
また、
$ T_n(\cos\theta) $ を $T_n$と書けばチェビシェフ多項式を使って

\begin{align}
T_0 &= 1 \\
T_1 &= 1 - k = \cos(\theta) \\
T_2 &= 2(1 - k)T_1 - T_0 \\
    &= 2T_1 - 2kT_1 - T_0 = T_1 - 2kT_1 + T_1 - T_0 \\
    &= T_1 - 2kT_1 - k \\
T_3 &= 2(1 - k)T_2 - T_1 \\
    &= 2T_2 - 2kT_2 - T_1 = T_2 - 2kT_2 + T_2 - T_1 \\
    &= T_2 - 2kT_2 - 2kT_1 - k \\
\vdots&
\end{align}

以上のように書ける。これを見ると以下の式が成り立っているように見える。

T_{n+1} = T_n - \sum_{i=1}^{n} 2kT_i - k  \tag{1}

式(1)がn>=1で成り立つことの証明

式$(1)$は、$n=1$のとき成り立つ。
$n=p$のとき成り立つとすると、$n=p+1$は、

\begin{align}
T_{p+2} &= 2(1 - k)T_{p+1} - T_p \\
        &= 2T_{p+1} - 2kT_{p+1} - T_p \\
        &= T_{p+1} - 2kT_{p+1} + T_{p+1} - T_{p} \\
        &= T_{p+1} - 2kT_{p+1} + (T_p - \sum_{i=1}^{p} 2kT_i - k) - T_p \\
        &= T_{p+1} - \sum_{i=1}^{p+1} 2kT_i - k
\end{align}

つまり、$n=p+1$で成り立つ。

プログラム中のcos計算との関係

c -= dc;  dc += t * c;
T_{n+1} = T_n - \sum_{i=1}^{n} 2kT_i - k  \tag{1}

上記のコードの、変数 c は式$(1)$に従って計算されていて、$T_n$に相当する。
変数 t は$2k$に相当し、変数dcは

\sum_{i=1}^{n} 2kT_i + k

に相当することがわかる。

sinのn倍角について

sinについてもcosと同様に求める。
$k = 2\sin^2(\theta/2) $とし、
$l = \sqrt{k(2 - k)}$
とすると、

\begin{align}
l &= \sqrt{k(2 - k)} = \sqrt{2\sin^2(\theta/2)(2-2\sin^2(\theta/2)} \\
&=\sqrt{4\sin^2(\theta/2)-4\sin^4(\theta/2)} \\
&=2\sin(\theta/2)\cos(\theta/2) \\
&=\sin(\theta) \\
&=\cos(\pi/2-\theta)
\end{align}

ここで、チェビシェフ多項式$T_n$を使って$S_n$を

S_n = T_{N/4-n}

として、$\pi/2$から右回りに$\theta$角ごとの$\cos$を求める。
これはつまり、$\sin(n\theta)$を求めることになる。

\begin{align}
S_0 &= \cos(\pi/2) = 0 \\
S_1 &= \cos(\pi/2 - \theta) = \sin(\theta) = l \\
S_2 &= 2(1 - k)S_1 - S_0 \\
&= 2S_1 - 2kS_1 - S_0 = S_1-2kS_1+S_1-S_0 \\
&= S_1 - 2kS_1 + l \\
S_3&= 2(1-k)S_2-S1\\
&=2S_2-2kS_2-S_1 =S_2-2kS_2+S_2-S_1  \\
&= S_2-2kS_2-2kS_1+l \\
\vdots&
\end{align}

これを見ると以下の式が成り立っているように見える。

S_{n+1} = S_n + \sum_{i=1}^{n} -2kS_i + l  \tag{2}

式(2)がn>=1で成り立つことの証明

式$(2)$は$n=1$のときに成り立つ。$n=p$のときに成り立つとすると、
$n=p+1$について

\begin{align}
S_{p+2} &= 2(1 - k)S_{p+1} - S_p \\
        &= 2S_{p+1} - 2kS_{p+1} - S_p \\
        &= S_{p+1} - 2kS_{p+1} + S_{p+1} - S_{p} \\
        &= S_{p+1} - 2kS_{p+1} + (S_p + \sum_{i=1}^{p} -2kS_i + l) - S_p \\
        &= S_{p+1} + \sum_{i=1}^{p+1} -2kS_i + l
\end{align}

つまり、$n=p+1$で成り立つ。

プログラム中のsin計算との関係

s += ds;  ds -= t * s;
S_{n+1} = S_n + \sum_{i=1}^{n} -2kS_i + l  \tag{2}

上記のコードの、変数 s は式$(2)$に従って計算されていて、$S_n$に相当する。
変数 t は$2k$に相当し、変数 ds は式$(2)$で考えれば、

\sum_{i=1}^{n} -2kS_i + l

に相当することがわかる。

以上で三角関数テーブルの計算方法がわかった。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0