Вычислите синус и косинус Используя ядро вращения CORDIC

В этом примере показано, как вычислить синус и косинус с помощью ядра вращения CORDIC в MATLAB®. Основанные на CORDIC алгоритмы очень важны для многих встраиваемых приложений, включая блоки управления приводом, навигацию, обработку сигналов и радиосвязи.

Введение

CORDIC является акронимом для Координатного Компьютера Вращения. Основанный на вращении алгоритм CORDIC Givens (см. [1,2]) является одним из большей части оборудования эффективные алгоритмы, потому что это только требует итеративных операций shift-add. Алгоритм CORDIC избавляет от необходимости явные множители и подходит для вычисления множества функций, таков как синус, косинус, arcsine, arccosine, арктангенс, векторная величина, разделитесь, квадратный корень, гиперболические и логарифмические функции.

Фиксированная точка алгоритм CORDIC требует следующих операций:

  • 1 поиск по таблице на итерацию

  • 2 сдвига на итерацию

  • 3 сложения на итерацию

Алгоритм ядра CORDIC Используя режим расчета вращения

Можно использовать вращение CORDIC вычислительный алгоритм режима, чтобы вычислить синус и косинус одновременно, вычислить полярные-к-декартову преобразования, и для других операций. В режиме вращения векторная величина и угол вращения известны и координата (X-Y), компоненты вычисляются после вращения.

Алгоритм режима вращения CORDIC начинается путем инициализации углового аккумулятора желаемым углом поворота. Затем решение вращения в каждой итерации CORDIC сделано способом, который уменьшает величину остаточного углового аккумулятора. Решение вращения основано на знаке остаточного угла в угловом аккумуляторе после каждой итерации.

В режиме вращения уравнения CORDIC:

$$ z_{i+1} = z_{i} - d_{i}*\mbox{atan}(2^{-i}) $$

$$ x_{i+1} = x_{i} - y_{i}*d_{i}*2^{-i} $$

$$ y_{i+1} = y_{i} + x_{i}*d_{i}*2^{-i} $$

где$$ d_{i} = -1 $$, если$$ z_{i} < 0 $$, и$$ +1 $$ в противном случае;

$$ i = 0, 1, ..., N-1 $$, и$$ N $$ общее количество итераций.

Это обеспечивает следующий результат как$$ N $$ подходы$$ +\infty $$:

$$ z_{N} = 0 $$

$$ x_{N} = A_{N}(x_{0}\cos{z_{0}} - y_{0}\sin{z_{0}}) $$

$$ y_{N} = A_{N}(y_{0}\cos{z_{0}} + x_{0}\sin{z_{0}}) $$

Где:

$$ A_{N} = \prod_{i=0}^{N-1}{\sqrt{1+2^{-2i}}} $$.

Обычно$$ N $$ выбирается, чтобы быть достаточно большим постоянным значением. Таким образом,$$ A_{N} $$ может быть предварительно вычислен.

В режиме вращения алгоритм CORDIC ограничивается углами поворота между$$ -\pi/2 $$ и$$ \pi/2 $$. Чтобы поддержать углы за пределами той области значений, квадрантная коррекция часто используется.

Эффективная реализация MATLAB алгоритма ядра вращения CORDIC

Пример реализации кода MATLAB алгоритма Ядра Вращения CORDIC следует (для случая скалярного xY, и z). Этот тот же код может использоваться и для фиксированной точки и для операции с плавающей точкой.

Ядро вращения CORDIC

function [x, y, z] = cordic_rotation_kernel(x, y, z, inpLUT, n)
% Perform CORDIC rotation kernel algorithm for N iterations.
xtmp = x;
ytmp = y;
for idx = 1:n
    if z < 0
        z(:) = accumpos(z, inpLUT(idx));
        x(:) = accumpos(x, ytmp);
        y(:) = accumneg(y, xtmp);
    else
        z(:) = accumneg(z, inpLUT(idx));
        x(:) = accumneg(x, ytmp);
        y(:) = accumpos(y, xtmp);
    end
    xtmp = bitsra(x, idx); % bit-shift-right for multiply by 2^(-idx)
    ytmp = bitsra(y, idx); % bit-shift-right for multiply by 2^(-idx)
end

Синус CORDIC-Based и расчет косинуса Используя нормированные входные параметры

Синус и расчет косинуса Используя ядро вращения CORDIC

Разумный выбор начальных значений позволяет алгоритму режима вращения ядра CORDIC непосредственно вычислять и синус и косинус одновременно.

Во-первых, выполняющие шаги инициализации выполняются:

  • Угол ввел интерполяционную таблицу inpLUT установлен в atan(2 .^ -(0:N-1)).

  • $$ z_{0} $$ установлен в$$ \theta $$ значение входного параметра.

  • $$ x_{0} $$ установлен в$$ 1 / A_{N} $$.

  • $$ y_{0} $$ обнуляется.

После$$ N $$ итераций эти начальные значения приводят к следующим выходным параметрам как$$ N $$ подходы$$ +\infty $$:

  • $$ x_{N} \approx cos(\theta) $$

  • $$ y_{N} \approx sin(\theta) $$

Другие основанные на вращении-ядром функциональные приближения возможны через пред - и последующая обработка и использование других начальных условий (см. [1,2]).

Алгоритм CORDIC обычно запускается через заданное (постоянное) количество итераций начиная с окончания итераций CORDIC, рано повредил бы конвейерный код, и усиление CORDIC$$ A_{n} $$ не будет постоянным, потому что$$ n $$ варьировался бы.

Для очень больших значений $$ n $$алгоритм CORDIC, как гарантируют, будет сходиться, но не всегда монотонно. Можно обычно достигать большей точности путем увеличения общего числа итераций.

Пример

Предположим, что у вас есть датчик угла поворота (e.g. в сервоприводе), который использует отформатированные целочисленные значения, чтобы представлять измеренные углы вращения. Также предположите, что у вас есть 16-битный целочисленный арифметический модуль, который может выполнить, добавляют, вычитают, переключают, и операции памяти. С таким устройством вы могли реализовать ядро вращения CORDIC, чтобы эффективно вычислить косинус, и синус (эквивалентно, декартовы координаты X и Y) от угловых значений датчика, без использования умножается или большие интерполяционные таблицы.

sumWL  = 16; % CORDIC sum word length
thNorm = -1.0:(2^-8):1.0; % Normalized [-1.0, 1.0] angle values
theta  = fi(thNorm, 1, sumWL); % Fixed-point angle values (best precision)

z_NT   = numerictype(theta);             % Data type for Z
xyNT   = numerictype(1, sumWL, sumWL-2); % Data type for X-Y
x_out  = fi(zeros(size(theta)), xyNT);   % X array pre-allocation
y_out  = fi(zeros(size(theta)), xyNT);   % Y array pre-allocation
z_out  = fi(zeros(size(theta)), z_NT);   % Z array pre-allocation

niters = 13; % Number of CORDIC iterations
inpLUT = fi(atan(2 .^ (-((0:(niters-1))'))) .* (2/pi), z_NT); % Normalized
AnGain = prod(sqrt(1+2.^(-2*(0:(niters-1))))); % CORDIC gain
inv_An = 1 / AnGain; % 1/A_n inverse of CORDIC gain

for idx = 1:length(theta)
    % CORDIC rotation kernel iterations
    [x_out(idx), y_out(idx), z_out(idx)] = ...
        fidemo.cordic_rotation_kernel(...
            fi(inv_An, xyNT), fi(0, xyNT), theta(idx), inpLUT, niters);
end

% Plot the CORDIC-approximated sine and cosine values
figure;
subplot(411);
plot(thNorm, x_out);
axis([-1 1 -1 1]);
title('Normalized X Values from CORDIC Rotation Kernel Iterations');
subplot(412);
thetaRadians = pi/2 .* thNorm; % real-world range [-pi/2 pi/2] angle values
plot(thNorm, cos(thetaRadians) - double(x_out));
title('Error between MATLAB COS Reference Values and X Values');
subplot(413);
plot(thNorm, y_out);
axis([-1 1 -1 1]);
title('Normalized Y Values from CORDIC Rotation Kernel Iterations');
subplot(414);
plot(thNorm, sin(thetaRadians) - double(y_out));
title('Error between MATLAB SIN Reference Values and Y Values');

Ссылки

  1. Джек Э. Волдер, Тригонометрический Вычислительный Метод CORDIC, Транзакции IRE на Электронно-вычислительных машинах, Volume EC 8, сентябрь 1959, pp330-334.

  2. Рэй Андрэка, обзор алгоритма CORDIC для основанных на FPGA компьютеров, Продолжений 1998 шестых международных симпозиумов ACM/SIGDA по Программируемым пользователем вентильным матрицам, 22-24 февраля 1998, pp191-200