Этот пример показывает, как вычислить синус и косинус с помощью ядра вращения CORDIC в MATLAB ®. Основанные на CORDIC алгоритмы имеют решающее значение для многих встраиваемых приложений, включая управление двигателем, навигацию, обработку сигналов и беспроводную связь.
CORDIC - это аббревиатура для COordinate Rotation DIgital Computer. Алгоритм CORDIC на основе вращения Givens (см. [1,2]) является одним из наиболее аппаратно эффективных алгоритмов, потому что он требует только итерационных операций shift-add. Алгоритм CORDIC устраняет необходимость в явных умножителях и подходит для вычисления множества функций, таких как синус, косинус, арксин, арксозин, арктангенс, векторные величины, деление, квадратный корень, гиперболические и логарифмические функции.
Алгоритм CORDIC с фиксированной точкой требует следующих операций:
Поиск по 1 таблице на итерацию
2 сдвиги на итерацию
3 сложения за итерацию
Можно использовать алгоритм CORDIC rotation computing mode, чтобы вычислять синус и косинус одновременно, вычислять полярно-декартовые преобразования и для других операций. В режиме вращения известны векторы величины и угол поворота, и компоненты координат (X-Y) вычисляются после поворота.
Алгоритм CORDIC режима вращения начинается с инициализации углового аккумулятора с желаемым углом поворота. Затем решение о повороте в каждой итерации CORDIC выполняется способом, который уменьшает величину аккумулятора остаточного угла. Решение о повороте основывается на знаке остаточного угла в аккумуляторе угла после каждой итерации.
В режиме вращения уравнения CORDIC:
где если и в противном случае;
, и общее количество итераций.
Это обеспечивает следующий результат при подходах:
Где:
.
Обычно выбирается как достаточно большое постоянное значение. Таким образом, могут быть предварительно вычислены.
В режиме вращения алгоритм CORDIC ограничивается углами поворота между и. Чтобы поддерживать углы за пределами этой области значений, часто используется квадрантная коррекция.
Пример реализации кода MATLAB алгоритма CORDIC Rotation Kernel следует (для случая скаляра x
, y
, и 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
Разумный выбор начальных значений позволяет алгоритму CORDIC rotation mode непосредственно вычислять синус и косинус одновременно.
Во-первых, выполняются следующие шаги инициализации:
Интерполяционная таблица входного угла inpLUT
установлено в atan(2 .^ -(0:N-1))
.
задается значение входного параметра.
установлено в.
установлено в нуль.
После итераций эти начальные значения приводят к следующим выходам как подходы:
Другие приближения функций, основанные на ядре вращения, возможны через предварительную и последующую обработку и с использованием других начальных условий (см. [1,2]).
Алгоритм CORDIC обычно запускается через заданное (постоянное) количество итераций, поскольку прекращение итераций CORDIC раньше приведет к нарушению конвейерного кода, и коэффициент усиления CORDIC не будет постоянным, потому что он будет варьироваться.
Для очень больших значений, алгоритм CORDIC гарантированно сходится, но не всегда монотонно. Обычно можно достичь большей точности, увеличив общее количество итераций.
Пример
Предположим, что у вас есть датчик угла поворота (например, в сервоприводе), который использует форматированные целочисленные значения, чтобы представлять измеренные углы поворота. Также предположим, что у вас есть 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');
Jack E. Volder, The CORDIC Trigonometric Computing Technique, IRE Transactions on Electronic Computers, Volume EC-8, September 1959, pp330-334.
Рэй Андрака, Обзор алгоритма CORDIC для компьютеров на основе FPGA, Труды 1998 ACM/SIGDA шестой международный симпозиум по программируемым массивам ворот для поля, 22-24, 1998 февраля, pp191-200