为什么我们使用 CORDIC 增益?
Why we use CORDIC gain?
我正在研究 cordic。我发现了可喜的收获。 K=0.607XXX.
来自 CORDIC,K_i = cos(tan^-1(2^i)).
据我所知,K 接近于 0。607xxx.when我要无穷大
这个值是所有K相乘得到的。
我明白每k个存在的原因。但我很好奇它用在哪里?为什么我们使用该值 K=0.607xx?
CORDIC 圆形变体的旋转模式的比例因子可以很容易地从第一原理建立。 CORDIC 背后的想法是在单位圆上取一个点并逐步旋转它 u 我们想要确定其正弦和余弦的角度。
为此我们定义了一组增量角 a0, ..., an-1,使得 a k = atan(0.5k)。我们将这些增量角度适当地求和为角度的部分和 sk,例如 sn ~= u.设 yk = cos(sk) 和 xk = sin(sk)。如果在给定的步骤 k 中我们旋转了 ak,我们有
yk+1 = cos (sk+1) = cos (sk + ak)
xk+1 = sin (sk+1) = sin (sk + ak)
我们可以从 xk 计算出 xk+1 和 yk+1和 yk 如下:
yk+1 = yk * cos (ak) - x k * sin (ak)
xk+1 = xk * cos (ak) + y k * sin (ak)
考虑到我们可以同时加减ak,tan(ak) = sin(ak)/cos(ak),我们得到:
yk+1 = cos (ak) * (yk ∓ xk * tan(ak)) = cos (sk+1)
xk+1 = cos (ak) * (xk ± yk * tan(ak)) = sin (sk+1)
为了简化这个计算,我们可以在每一步中省去与 cos(ak) 的乘法,这给出了我们的 CORDIC 迭代方案:
yk+1 = y ∓ xk * tan(ak)
xk+1 = x ± yk * tan(ak)
因为我们选择了 ak,如果我们计算定点运算。因为我们省略了因数 cos(ak),我们最终得到
yn ~= cos(u) * (1 / (cos (a0) * cos (a1) * ... * cos (an))
xn ~= sin(u) * (1 / (cos (a0) * cos (a1) * ... * cos (an))
因数f = cos(a0) * cos(a1) * ... * cos (an) 是 0.607...,如前所述。我们通过设置起始值
将其合并到计算中
y0 = f * cos(0) = f
x0 = f * sin(0) = 0
这是显示整个计算过程的 C 代码,使用 16 位定点算法。输入角度被缩放,使得 360 度对应于 216,而正弦和余弦输出被缩放,使得 1 对应于 215.
#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;
}
我正在研究 cordic。我发现了可喜的收获。 K=0.607XXX.
来自 CORDIC,K_i = cos(tan^-1(2^i)).
据我所知,K 接近于 0。607xxx.when我要无穷大
这个值是所有K相乘得到的。
我明白每k个存在的原因。但我很好奇它用在哪里?为什么我们使用该值 K=0.607xx?
CORDIC 圆形变体的旋转模式的比例因子可以很容易地从第一原理建立。 CORDIC 背后的想法是在单位圆上取一个点并逐步旋转它 u 我们想要确定其正弦和余弦的角度。
为此我们定义了一组增量角 a0, ..., an-1,使得 a k = atan(0.5k)。我们将这些增量角度适当地求和为角度的部分和 sk,例如 sn ~= u.设 yk = cos(sk) 和 xk = sin(sk)。如果在给定的步骤 k 中我们旋转了 ak,我们有
yk+1 = cos (sk+1) = cos (sk + ak)
xk+1 = sin (sk+1) = sin (sk + ak)
我们可以从 xk 计算出 xk+1 和 yk+1和 yk 如下:
yk+1 = yk * cos (ak) - x k * sin (ak)
xk+1 = xk * cos (ak) + y k * sin (ak)
考虑到我们可以同时加减ak,tan(ak) = sin(ak)/cos(ak),我们得到:
yk+1 = cos (ak) * (yk ∓ xk * tan(ak)) = cos (sk+1)
xk+1 = cos (ak) * (xk ± yk * tan(ak)) = sin (sk+1)
为了简化这个计算,我们可以在每一步中省去与 cos(ak) 的乘法,这给出了我们的 CORDIC 迭代方案:
yk+1 = y ∓ xk * tan(ak)
xk+1 = x ± yk * tan(ak)
因为我们选择了 ak,如果我们计算定点运算。因为我们省略了因数 cos(ak),我们最终得到
yn ~= cos(u) * (1 / (cos (a0) * cos (a1) * ... * cos (an))
xn ~= sin(u) * (1 / (cos (a0) * cos (a1) * ... * cos (an))
因数f = cos(a0) * cos(a1) * ... * cos (an) 是 0.607...,如前所述。我们通过设置起始值
将其合并到计算中y0 = f * cos(0) = f
x0 = f * sin(0) = 0
这是显示整个计算过程的 C 代码,使用 16 位定点算法。输入角度被缩放,使得 360 度对应于 216,而正弦和余弦输出被缩放,使得 1 对应于 215.
#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;
}