Почему мы используем усиление CORDIC?
Я изучаю кордик. И я нашел сердечный прирост. К =0.607XXX.
Из CORDIC K_i = cos(tan^-1(2^i)).
Как я знаю, К приближается 0,607хх. Когда я иду в бесконечность
это значение придумать из всех K умножения.
Я понимаю причину существования каждого к. Но мне любопытно, где он используется? Почему мы используем это значение K=0.607xx?
1 ответ
Масштабный коэффициент для режима вращения кругового варианта CORDIC может быть легко установлен из первых принципов. Идея, лежащая в основе CORDIC, состоит в том, чтобы взять точку на круге единицы и постепенно повернуть ее на угол u, синус и косинус которого мы хотим определить.
Для этого мы определим набор инкрементальных углов a0,..., an-1, такой, что ak = atan (0,5k). Мы суммируем эти инкрементальные углы соответствующим образом в частичную сумму углов sk, таких как sn ~ = u. Пусть yk = cos (sk) и xk = sin (sk). Если на данном шаге k мы вращаемся на ak, мы имеем
yk + 1 = cos (sk + 1) = cos (sk + ak)
xk + 1 = грех (sk + 1) = грех (sk + ak)
мы можем вычислить xk + 1 и yk + 1 из xk и yk следующим образом:
yk + 1 = yk * cos (ak) - xk * sin (ak)
xk + 1 = xk * cos (ak) + yk * 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 умножения с tan (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;
}