私はコルディックを勉強しています。そして、コーディックゲインを見つけました。K=0.607XXX.
CORDIC から、K_i = cos(tan^-1(2^i))。
私が知っているように、私が無限大に行くとき、K は 0.607xxx に近づきます。
この値は、すべての K 乗算から得られます。
それぞれのkが存在する理由がわかりました。しかし、私は興味があります。どこで使用されますか? なぜその値 K=0.607xx を使用するのでしょうか?
CORDIC の円形バリアントの回転モードのスケール係数は、第一原理から簡単に確立できます。CORDIC の背後にある考え方は、単位円上の点を取り、正弦と余弦を求めたい角度uだけ段階的に回転させることです。
そのために、a k = atan(0.5 k ) となるように一連の増分角度 a 0 , ..., a n-1を定義します。これらの増分角度を、s n ~= uなどの角度 s kの部分和に適切に合計します。y k = cos(s k ) および x k = sin(s k ) とする。与えられたステップkで a kだけ回転すると、次のようになります。
y k+1 = cos (s k+1 ) = cos (s k + a k )
x k+1 = sin (s k+1 ) = sin (s k + a k )
次のように、x kと y kから x k+1と y k+ 1を計算できます。
y k+1 = y k * cos (a k ) - x k * sin (a k )
x k+1 = x k * cos (a k ) + y k * sin (a k )
a kの加算と減算の両方が可能であり、tan(a k ) = sin(a k )/cos(a k ) であることを考慮すると、次のようになります。
y k+1 = cos (a k ) * (y k ∓ x k * tan(a k )) = cos (s k+1 )
x k+1 = cos (a k ) * (x k ± y k * tan(a k )) = sin (s k+1 )
この計算を単純化するために、すべてのステップで cos(a k ) の乗算を省略できます。これにより、CORDIC 反復スキームが得られます。
y k+1 = y ∓ x k * tan(a k )
x k+1 = x ± y k * tan(a k )
a kを選択したため、固定小数点演算で計算すると、tan(a k ) による乗算は単純な右シフトになります。因数 cos(a k ) を省略したため、次のようになります。
y n ~= cos( u ) * (1 / (cos (a 0 ) * cos (a 1 ) * ... * cos (a n ))
x n ~= sin( u ) * (1 / (cos ( a 0 ) * cos (a 1 ) * ... * cos (an ) )
係数f = cos (a 0 ) * cos (a 1 ) * ... * cos (a n ) は、既に述べたように 0.607... です。開始値を設定して計算に組み込みます
y 0 = f * cos(0) = f
x 0 = f * sin(0) = 0
以下は、16 ビットの固定小数点演算を使用して、計算全体の動作を示す C コードです。入力角度は 360 度が 2 16に対応するようにスケーリングされ、正弦および余弦出力は 1 が 2 15に対応するようにスケーリングされます。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* round (atand (0.5**i) * 65536/360) */
static const short a[15] =
{
0x2000, 0x12e4, 0x09fb, 0x0511,
0x028b, 0x0146, 0x00a3, 0x0051,
0x0029, 0x0014, 0x000a, 0x0005,
0x0003, 0x0001, 0x0001
};
#define swap(a,b){a=a^b; b=b^a; a=a^b;}
void cordic (unsigned short u, short *s, short *c)
{
short x, y, oldx, oldy, q;
int i;
x = 0;
y = 0x4dba; /* 0.60725 */
oldx = x;
oldy = y;
q = u >> 14; /* quadrant */
u = u & 0x3fff; /* reduced angle */
u = -(short)u;
i = 0;
do {
if ((short)u < 0) {
x = x + oldy;
y = y - oldx;
u = u + a[i];
} else {
x = x - oldy;
y = y + oldx;
u = u - a[i];
}
oldx = x;
oldy = y;
i++;
/* right shift of signed negative number implementation defined in C */
oldx = (oldx < 0) ? (-((-oldx) >> i)) : (oldx >> i);
oldy = (oldy < 0) ? (-((-oldy) >> i)) : (oldy >> i);
} while (i < 15);
for (i = 0; i < q; i++) {
swap (x, y);
y = -y;
}
*s = x;
*c = y;
}
int main (void)
{
float angle;
unsigned short u;
short s, c;
printf ("angle in degrees [0,360): ");
scanf ("%f", &angle);
u = (unsigned short)(angle * 65536.0f / 360.0f + 0.5f);
cordic (u, &s, &c);
printf ("sin = % f (ref: % f) cos = % f (ref: % f)\n",
s/32768.0f, sinf(angle/360*2*3.14159265f),
c/32768.0f, cosf(angle/360*2*3.14159265f));
return EXIT_SUCCESS;
}