為什么會(huì )出現CORDIC算法呢?
對于三角函數計算,理論接觸較多的應該就是級數展開(kāi)的方法 ,通過(guò)逼近的方式進(jìn)行計算,比如泰勒級數。但是因為這種多項式函數在計算的過(guò)程中需要大量使用到浮點(diǎn)數計算,而對于缺乏硬件乘法器的器件而言這種計算方式的實(shí)現是很困難的。有了問(wèn)題,自然就會(huì )有人出來(lái)解決,1959年J. Volder就首次提出了CORDIC算法,只需要進(jìn)行移位和加減運算的快速算法。
CORDIC算法能干什么?
這里只介紹關(guān)于三角函數方面CORDIC的作用:
1、得到坐標軸上一點(diǎn)的角度(相位信息);
2、得到坐標軸上一點(diǎn)對應的
ps:使用cordic計算幅值的方法不好,可以選擇更好的,比如查找表的方法,因此這里不再過(guò)多介紹計算幅值的方法。
CORDIC算法的原理是什么?
對于坐標軸上點(diǎn)的相位,就是和x軸正半軸(后面統稱(chēng)x軸)的夾角。求一個(gè)點(diǎn)的相位也就是將要求的點(diǎn)進(jìn)行旋轉,當點(diǎn)旋轉到與x軸第一次重合時(shí),旋轉過(guò)的相位大小就是這個(gè)點(diǎn)的相位。CORDIC算法通俗來(lái)講就是把這個(gè)旋轉過(guò)程變成了“離散”旋轉,每次旋轉特定的角度,旋轉N次。在旋轉過(guò)程中不停的判斷,如果落在x軸就停止,如果發(fā)現在x軸上方就逆時(shí)針旋轉(相位增加),如果發(fā)現在x軸下方就順時(shí)針旋轉(相位減?。?,將旋轉過(guò)程中的相位變化進(jìn)行累加,最終就可以得到一個(gè)點(diǎn)的相位。這里可以總結這個(gè)旋轉過(guò)程有兩點(diǎn)要求:
1、旋轉過(guò)程中能夠實(shí)時(shí)得到y的值,因為我們需要y的值來(lái)判斷我們旋轉的點(diǎn)是否到達了x軸(點(diǎn)在第一象限的話(huà),y=0則表明點(diǎn)落在了x軸上);
2、每次旋轉需要知道旋轉的角度,以便于計算相位。
有了上面的原理,現在需要做的就是得到一個(gè)點(diǎn)在坐標軸上旋轉和相位的關(guān)系式。
首先假設坐標軸上有任意一點(diǎn)
因為是旋轉,幅值相等,則可以推導公式:

ps:這里介紹一種方便的方法推導,使用復變函數推導相位旋轉,有興趣化簡(jiǎn)一下即可對應上面的公式:

這里可以把(


1、對于


2、對于任意的



3、既然



ps:CORDIC算法只是一個(gè)近似計算,也就是說(shuō)15次迭代后點(diǎn)不一定是落在x軸上的。轉化精度也高,迭代次數越多,結果越準確。
有了上面的推論,相位旋轉公式可以寫(xiě)成:

對于旋轉過(guò)程中相位累加的公式可以寫(xiě)成:

這里的z是有初始值的,初始值和象限有關(guān),第一象限和第四就是z=0(x>0),第二象限就是z=90(y>0),第三象限就是z=-90(y<>在下面給出的示例代碼中,是默認輸入值x>0的。如果想將程序擴展到四個(gè)象限,判斷輸入點(diǎn)的象限,然后取z的不同初始值和對輸入點(diǎn)進(jìn)行象限變換(比如輸入點(diǎn)在第二象限(x0,y0),則將點(diǎn)逆時(shí)針旋轉90°得到新點(diǎn)(y0,-x0))即可,有興趣的可以進(jìn)行添加。
以下是示例代碼:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_arith.all;
entity cordic is
generic(
w1 : integer := 16; --幅值位寬
w2 : integer := 16; --角度位寬
w3 : integer := 18 --中間變量
);
port(
clk : in std_logic;
rstn : in std_logic;
data_En : in std_logic;
x_In : in std_logic_vector(w1-1 downto 0);
y_In : in std_logic_vector(w1-1 downto 0);
zn : out std_logic_vector(w2-1 downto 0)
);
end cordic;
architecture beha of cordic is
type array15x8 is array(0 to 14) of std_logic_vector(w2-1 downto 0);
constant z : array15x8 := (x'2D00',x'1A91',x'0E09',x'0720',x'0394',x'01CA',x'00E5',
x'0073',x'0039',x'001D',x'000E',x'0007',x'0004',x'0002',x'0001');
signal phi : std_logic_vector(w2-1 downto 0) := (others => '0');
signal x0,y0 : std_logic_vector(w3-1 downto 0);
signal im,re : std_logic_vector(w3-1 downto 0);
signal n : integer range 0 to 14;
type state is (s0,s1);
signal Cstate : state := s0;
begin
process(n,y0,x0)
begin
im <> to_stdlogicvector(to_bitvector(y0) sra n);
re <> to_stdlogicvector(to_bitvector(x0) sra n);
end process;
process(clk,rstn)
begin
if rstn='0' then
phi <> (others => '0');
elsif rising_edge(clk) then
case Cstate is
when s0 =>
if data_En='1' then
Cstate <> s1;
n <> 0;
x0 <> sxt(x_In,w3);
y0 <> sxt(y_In,w3);
else
n <> n;
end if;
when s1 =>
if signed(y0)=0 then
x0 <> x0;
y0 <> y0;
elsif (y0(7))='1' then
x0 <> x0 - im;
y0 <> y0 + re;
phi <> phi - z(n);
else
x0 <> x0 + im;
y0 <> y0 - re;
phi <> phi + z(n);
end if;
if n14 then
n <> n + 1;
else
Cstate <> s0;
end if;
when others =>
Cstate <> s0;
end case;
zn <> phi;
end if;
end process;
end beha;聯(lián)系客服