Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

CORDIC ベクトル モード カーネルを使用した直交座標から極座標への変換

この例では、MATLAB® で CORDIC ベクトル モード カーネル アルゴリズムを使用して直交座標を極座標に変換する方法を説明します。CORDIC ベースのアルゴリズムは、モーター制御、ナビゲーション、信号処理、ワイヤレス通信などのさまざまな組み込みアプリケーションにとって重要です。

はじめに

CORDIC は、COordinate Rotation DIgital Computer の略語です。ギブンス回転に基づく CORDIC アルゴリズム ([1] および [2] を参照) は、反復的なシフト加算演算だけが必要であるため、ハードウェア効率が最も高いアルゴリズムのうちの 1 つです。CORDIC アルゴリズムは、明示的な乗数を必要とせず、正弦関数、余弦関数、逆正弦関数、逆余弦関数、逆正接関数、ベクトル振幅関数、除算関数、平方根関数、双曲線関数、対数関数など、さまざまな関数の計算に適しています。

固定小数点 CORDIC アルゴリズムには次の演算が必要です。

  • 反復あたり 1 回のテーブル ルックアップ

  • 反復あたり 2 回のシフト

  • 反復あたり 3 回の加算

ベクトル計算モードを使用した CORDIC カーネル アルゴリズム

CORDIC ベクトル計算モード アルゴリズムを使用して、atan(y/x) の計算、直交座標から極座標への直交座標変換およびその他の演算を実行できます。ベクトル モードでは、CORDIC 回転子が入力ベクトルを正の X 軸に対して回転させて、残差ベクトルの $$ y $$ 成分を最小化します。残差ベクトルの $$ y $$ 座標が正である場合、CORDIC 回転子は反復ごとに時計回りに (負の角度を使って) 回転し、それ以外の場合は反時計回りに (正の角度を使って) 回転します。各回転は徐々に小さい角度の値を使用します。反復の終了時に、角度のアキュムレータが 0 に初期化された場合、累計された回転角は元の入力ベクトルの角度です。

ベクトル モードでは、CORDIC 方程式は次のようになります。

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

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

$$ z_{i+1} = z_{i} + d_{i}*\mbox{atan}(2^{-i}) $$ は角度のアキュムレータです。

ここで、$$ y_{i} < 0 $$ の場合は $$ d_{i} = +1 $$、それ以外の場合は $$ -1 $$ です。

$$ i = 0, 1, ..., N-1 $$ および $$ N $$ は、反復の総数です。

$$ N $$$$ +\infty $$ に近づくにつれて、次のようになります。

$$ x_{N} = A_{N}\sqrt{x_{0}^2+y_{0}^2} $$

$$ y_{N} = 0 $$

$$ z_{N} = z_{0} + \mbox{atan}(y_{0}/x_{0}) $$

ここで、

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

一般的には、$$ N $$ には大きな定数値が選ばれます。そのため、$$ A_{N} $$ は事前に計算できる場合があります。

MATLAB での CORDIC ベクトル モード カーネル アルゴリズムの効率的な実装

CORDIC ベクトル モード カーネル アルゴリズムを MATLAB コードに実装する例は、スカラー xy および z の場合、次のようになります。固定小数点と浮動小数点の演算の両方にこの同じコードを使用できます。

CORDIC ベクトル モード カーネル

function [x, y, z] = cordic_vectoring_kernel(x, y, z, inpLUT, n)
% Perform CORDIC vectoring kernel algorithm for N iterations.
xtmp = x;
ytmp = y;
for idx = 1:n
    if y < 0
        x(:) = accumneg(x, ytmp);
        y(:) = accumpos(y, xtmp);
        z(:) = accumneg(z, inpLUT(idx));
    else
        x(:) = accumpos(x, ytmp);
        y(:) = accumneg(y, xtmp);
        z(:) = accumpos(z, inpLUT(idx));
    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 ベクトル カーネルを使用した直交座標から極座標への計算

適切な初期値を選択することにより、CORDIC カーネル ベクトル モード アルゴリズムで振幅 $$ R = \sqrt{x_{0}^2+y_{0}^2} $$ と角度 $$ \theta = \mbox{atan}(y_{0}/x_{0}) $$ を直接計算できます。

入力アキュムレータは入力の座標値に初期化されます。

  • $$ x_{0} = X $$

  • $$ y_{0} = Y $$

角度アキュムレータはゼロに初期化されます。

  • $$ z_{0} = 0 $$

$$ N $$ 回の反復の後、これらの初期値は $$ N $$$$ +\infty $$ に近づくときの以下の出力を導きます。

  • $$ x_{N} \approx A_{N}\sqrt{x_{0}^2+y_{0}^2} $$

  • $$ z_{N} \approx \mbox{atan}(y_{0}/x_{0}) $$

その他のベクトル モード カーネルベースの関数近似は、他の初期条件を使って前処理と後処理を行うと可能です ([1] および [2] を参照)。

[-1, 1) の範囲の値に正規化された直交座標 (X,Y) データの測定値があり、それを極座標 (振幅、角度) に変換するとします。また、加算、減算、シフトおよびメモリ演算を実行できる 16 ビットの整数演算器も利用するとします。このような演算器の場合、CORDIC ベクトル モード カーネルを実装すると、乗算や大きいルックアップ テーブルを使用せずに、入力 (X,Y) 座標値から振幅と角度を効率的に計算できます。

sumWL  = 16; % CORDIC sum word length
thNorm = -1.0:(2^-8):1.0; % Also using 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
xyCPNT = numerictype(1,16,15); % Using normalized X-Y range [-1.0, 1.0)
thetaRadians = pi/2 .* thNorm; % real-world range [-pi/2 pi/2] angle values
inXfix = fi(0.50 .* cos(thetaRadians), xyCPNT); % X coordinate values
inYfix = fi(0.25 .* sin(thetaRadians), xyCPNT); % Y coordinate values

niters = 13; % Number of CORDIC iterations
inpLUT = fi(atan(2 .^ (-((0:(niters-1))'))) .* (2/pi), z_NT); % Normalized
z_c2p  = fi(zeros(size(theta)), z_NT);   % Z array pre-allocation
x_c2p  = fi(zeros(size(theta)), xyCPNT); % X array pre-allocation
y_c2p  = fi(zeros(size(theta)), xyCPNT); % Y array pre-allocation

for idx = 1:length(inXfix)
    % CORDIC vectoring kernel iterations
    [x_c2p(idx), y_c2p(idx), z_c2p(idx)] = ...
        fidemo.cordic_vectoring_kernel(...
            inXfix(idx), inYfix(idx), fi(0, z_NT), inpLUT, niters);
end

% Get the Real World Value (RWV) of the CORDIC outputs for comparison
% and plot the error between the (magnitude, angle) values
AnGain       = prod(sqrt(1+2.^(-2*(0:(niters-1))))); % CORDIC gain
x_c2p_RWV    = (1/AnGain) .* double(x_c2p); % Magnitude (scaled by CORDIC gain)
z_c2p_RWV    =   (pi/2)   .* double(z_c2p); % Angles (in radian units)
[thRWV,rRWV] = cart2pol(double(inXfix), double(inYfix)); % MATLAB reference
magnitudeErr = rRWV - x_c2p_RWV;
angleErr     = thRWV - z_c2p_RWV;
figure;
subplot(411);
plot(thNorm, x_c2p_RWV);
axis([-1 1 0.25 0.5]);
title('CORDIC Magnitude (X) Values');
subplot(412);
plot(thNorm, magnitudeErr);
title('Error between Magnitude Reference Values and X Values');
subplot(413);
plot(thNorm, z_c2p_RWV);
title('CORDIC Angle (Z) Values');
subplot(414);
plot(thNorm, angleErr);
title('Error between Angle Reference Values and Z Values');

参考文献

  1. Jack E. Volder, The CORDIC Trigonometric Computing Technique, IRE Transactions on Electronic Computers, Volume EC-8, September 1959, pp330-334.

  2. Ray Andraka, A survey of CORDIC algorithm for FPGA based computers, Proceedings of the 1998 ACM/SIGDA sixth international symposium on Field programmable gate arrays, Feb. 22-24, 1998, pp191-200