为什么会出现CORDIC算法呢?
对于三角函数计算,理论接触较多的应该就是级数展开的方法 ,通过逼近的方式进行计算,比如泰勒级数。但是因为这种多项式函数在计算的过程中需要大量使用到浮点数计算,而对于缺乏硬件乘法器的器件而言这种计算方式的实现是很困难的。有了问题,自然就会有人出来解决,1959年J. Volder就首次提出了CORDIC算法,只需要进行移位和加减运算的快速算法。
CORDIC算法能干什么?
这里只介绍关于三角函数方面CORDIC的作用:
1、得到坐标轴上一点的角度(相位信息);
2、得到坐标轴上一点对应的
ps:使用cordic计算幅值的方法不好,可以选择更好的,比如查找表的方法,因此这里不再过多介绍计算幅值的方法。
CORDIC算法的原理是什么?
对于坐标轴上点的相位,就是和x轴正半轴(后面统称x轴)的夹角。求一个点的相位也就是将要求的点进行旋转,当点旋转到与x轴第一次重合时,旋转过的相位大小就是这个点的相位。CORDIC算法通俗来讲就是把这个旋转过程变成了“离散”旋转,每次旋转特定的角度,旋转N次。在旋转过程中不停的判断,如果落在x轴就停止,如果发现在x轴上方就逆时针旋转(相位增加),如果发现在x轴下方就顺时针旋转(相位减小),将旋转过程中的相位变化进行累加,最终就可以得到一个点的相位。这里可以总结这个旋转过程有两点要求:
1、旋转过程中能够实时得到y的值,因为我们需要y的值来判断我们旋转的点是否到达了x轴(点在第一象限的话,y=0则表明点落在了x轴上);
2、每次旋转需要知道旋转的角度,以便于计算相位。
有了上面的原理,现在需要做的就是得到一个点在坐标轴上旋转和相位的关系式。
首先假设坐标轴上有任意一点
因为是旋转,幅值相等,则可以推导公式:
ps:这里介绍一种方便的方法推导,使用复变函数推导相位旋转,有兴趣化简一下即可对应上面的公式:
这里可以把(
1、对于
2、对于任意的
3、既然
ps:CORDIC算法只是一个近似计算,也就是说15次迭代后点不一定是落在x轴上的。转化精度也高,迭代次数越多,结果越准确。
有了上面的推论,相位旋转公式可以写成:
对于旋转过程中相位累加的公式可以写成:
这里的z是有初始值的,初始值和象限有关,第一象限和第四就是z=0(x>0),第二象限就是z=90(y>0),第三象限就是z=-90(y<>在下面给出的示例代码中,是默认输入值x>0的。如果想将程序扩展到四个象限,判断输入点的象限,然后取z的不同初始值和对输入点进行象限变换(比如输入点在第二象限(x0,y0),则将点逆时针旋转90°得到新点(y0,-x0))即可,有兴趣的可以进行添加。
以下是示例代码:
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;
联系客服