0

我正在研究cordic。我发现了cordic的收获。K=0.607XXX。

根据 CORDIC,K_i = cos(tan^-1(2^i))。

据我所知,K 接近 0.607xxx。当我要去无穷大时

这个值是从所有 K 乘法中得出的。

我理解每个 k 存在的原因。但我很好奇它在哪里使用?为什么我们使用这个值 K=0.607xx?

4

1 回答 1

3

CORDIC 圆形变体的旋转模式的比例因子可以很容易地从第一原理建立。CORDIC 背后的想法是在单位圆上取一个点并逐步旋转它通过我们想要确定其正余弦的角度u 。

为此,我们定义了一组增量角 a 0 , ..., a n-1,使得 a k = atan(0.5 k )。我们将这些增量角度适当地求和为角度 s k的部分和,例如 s n ~= u。设 y k = cos(s k ) 和 x k = sin(s k )。如果在给定的步骤k我们旋转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( ak ) = sin( ak )/cos( ak ),我们得到:

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( ak )
x k+1 = x ± y k * tan( ak )

由于我们选择了k ,如果我们在定点算术中计算,与 tan( ak ) 的乘法将变成简单的右移。因为我们省略了因子 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 (a n ))

如前所述,因子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;
}
于 2015-06-19T04:35:57.830 回答