目录
Written by @hzj
//JinXing Project
#2021.11.26 V1.0
#2021.11.27 V1.1
#2021.11.27 V1.2
CORDIC算法详解
cordic算法的FPGA实现中,对于cordic算法的理解非常重要,下面对整个算法的流程进行详解:
1、cordic的算法表示式
也有上述的表示式:
x
2
=
x
1
c
o
s
θ
−
y
1
s
i
n
θ
x_2 = x_1cos\theta - y_1sin\theta
x2=x1cosθ−y1sinθ
y
2
=
y
1
c
o
s
θ
+
x
1
s
i
n
θ
y_2 = y_1cos\theta + x_1sin\theta
y2=y1cosθ+x1sinθ
2、提取cordic的算法表示式中的cos分量
将式子右边提出一个cos分量之后,可以得到如下的变换过程:
x
2
=
x
1
c
o
s
θ
−
y
1
s
i
n
θ
=
c
o
s
θ
(
x
1
−
y
1
t
a
n
θ
)
x_2 = x_1cos\theta - y_1sin\theta =cos\theta (x_1- y_1tan\theta)
x2=x1cosθ−y1sinθ=cosθ(x1−y1tanθ)
y
2
=
y
1
c
o
s
θ
+
x
1
s
i
n
θ
=
c
o
s
θ
(
y
1
+
x
1
t
a
n
θ
)
y_2 = y_1cos\theta + x_1sin\theta = cos\theta(y_1 + x_1tan\theta)
y2=y1cosθ+x1sinθ=cosθ(y1+x1tanθ)
以上为旋转分量。
3、去掉cordic的算法表示式中的cos分量
由于被一次的变换都需要乘以一个cos分量,因此,可以利用这个规律进行简化。
由此我们有:
X
2
=
x
1
−
y
1
t
a
n
θ
=
x
2
/
c
o
s
θ
X_2 = x_1 - y_1tan\theta =x_2/cos\theta
X2=x1−y1tanθ=x2/cosθ
Y
2
=
y
1
+
x
1
t
a
n
θ
=
y
2
/
c
o
s
θ
Y_2 = y_1 +x_1tan\theta = y_2/cos\theta
Y2=y1+x1tanθ=y2/cosθ
此刻可以发现:现在的X2,Y2相对于x2,y2,放大了
c
o
s
θ
cos\theta
cosθ倍。
通往在一般的情况下,我们这个地方有:
x
n
=
x
n
−
1
c
o
s
θ
n
−
1
−
y
n
−
1
s
i
n
θ
n
−
1
=
c
o
s
θ
n
−
1
(
x
n
−
1
−
y
n
−
1
t
a
n
θ
n
−
1
)
x_n = x_{n-1}cos\theta_{n-1} - y_{n-1}sin\theta_{n-1} = cos\theta_{n-1} (x_{n-1}- y_{n-1}tan\theta_{n-1} )
xn=xn−1cosθn−1−yn−1sinθn−1=cosθn−1(xn−1−yn−1tanθn−1)
y
n
=
y
n
−
1
c
o
s
θ
n
−
1
+
x
n
−
1
s
i
n
θ
n
−
1
=
c
o
s
θ
n
−
1
(
y
n
−
1
+
x
n
−
1
t
a
n
θ
n
−
1
)
y_n = y_{n-1}cos\theta_{n-1} + x_{n-1}sin\theta_{n-1} = cos\theta_{n-1} (y_{n-1}+x_{n-1}tan\theta_{n-1} )
yn=yn−1cosθn−1+xn−1sinθn−1=cosθn−1(yn−1+xn−1tanθn−1)
同理去掉cos函数有:
X
n
=
X
n
−
1
−
Y
n
−
1
t
a
n
θ
n
−
1
X_n = X_{n-1} - Y_{n-1}tan\theta_{n-1}
Xn=Xn−1−Yn−1tanθn−1
Y
n
=
Y
n
−
1
+
X
n
−
1
t
a
n
θ
n
−
1
Y_n = Y_{n-1} + X_{n-1}tan\theta_{n-1}
Yn=Yn−1+Xn−1tanθn−1
以上称之为伪旋转分量。
4、将去掉cordic的算法表示式中的cos分量进行累成成系数K
由于每一次都要进行一次乘法运算,因此可以有:
K
n
=
c
o
s
θ
1
∗
c
o
s
θ
2
∗
c
o
s
θ
3
∗
.
.
.
∗
c
o
s
θ
n
K_n = cos\theta_1* cos\theta_2* cos\theta_3*...* cos\theta_n
Kn=cosθ1∗cosθ2∗cosθ3∗...∗cosθn
因此就可以有,可以配合原始式子有:
x
n
=
K
n
∗
X
n
x_n = K_n*X_n
xn=Kn∗Xn
y
n
=
K
n
∗
Y
n
y_n = K_n*Y_n
yn=Kn∗Yn
5、设置一个控制算子
引入一个控制算子,用来控制旋转的方向,若是顺时针旋转,则这个地方d=-1,反而若是逆时针旋转,则应该为d=1。因此,上述的式子应该为:
X
n
=
X
n
−
1
−
d
n
−
1
∗
Y
n
−
1
∗
t
a
n
θ
n
−
1
X_n = X_{n-1} - d_{n-1}*Y_{n-1}*tan\theta_{n-1}
Xn=Xn−1−dn−1∗Yn−1∗tanθn−1
Y
n
=
Y
n
−
1
+
d
n
−
1
∗
X
n
−
1
∗
t
a
n
θ
n
−
1
Y_n = Y_{n-1} + d_{n-1}*X_{n-1}*tan\theta_{n-1}
Yn=Yn−1+dn−1∗Xn−1∗tanθn−1
其中d = 1或-1
6、设置一个误差系数
虽然这个地方只需要求得sin以及cos值的输出,但是还需要一个误差系数,来保存当前的误差值。误差系数设为z,误差输入的初始值为z=angle_in,也就是角度输入值,最终在不断的计算下,这个误差值趋近于0。而z的运算如下所示:
Z
n
=
Z
n
−
1
−
d
n
−
1
θ
Z_n = Z_{n-1} - d_{n-1}\theta
Zn=Zn−1−dn−1θ
7、简化运算
令
t
a
n
θ
n
=
2
−
n
tan\theta_n = 2^{-n}
tanθn=2−n,其中i=0,1,…,n-1。由此可以得到,上述式子有:
X
n
=
X
n
−
1
−
d
n
−
1
∗
Y
n
−
1
∗
2
n
−
1
X_n = X_{n-1} - d_{n-1}*Y_{n-1} *2^{n-1}
Xn=Xn−1−dn−1∗Yn−1∗2n−1
Y
n
=
Y
n
−
1
+
d
n
−
1
∗
X
n
−
1
∗
2
n
−
1
Y_n = Y_{n-1} + d_{n-1}*X_{n-1} *2^{n-1}
Yn=Yn−1+dn−1∗Xn−1∗2n−1
Z
n
=
Z
n
−
1
−
d
n
−
1
∗
a
r
c
t
a
n
2
(
n
−
1
)
Z_n = Z_{n-1} - d_{n-1}*arctan2^{(n-1)}
Zn=Zn−1−dn−1∗arctan2(n−1)
8、FPGA运算实现逻辑
实现方式以30°输入为例子,输出对应的sin以及cos值。同时观察每时每刻的误差值z的大小。首先输入x,y,z的值为x = K 16 K_{16} K16,y=1
计算次数 | 2 n − 1 2^{n-1} 2n−1 | 角度值 θ \theta θ( a r c t a n 2 n − 1 arctan2^{n-1} arctan2n−1) | x | y | z |
---|---|---|---|---|---|
0 | \ | \ | 0.60724 | 0 | 30 |
1 | 2 0 2^{0} 20 | 45° | 0.60724 | 0.60724 | -15 |
2 | 2 1 2^{1} 21 | 26.5654° | 0.91086 | 0.30362 | 11.5651 |
3 | 2 2 2^{2} 22 | 14.036° | 0.83496 | 0.5313 | -2.4711 |
4 | 2 3 2^{3} 23 | 7.125° | 0.9014 | 0.42696 | 4.6539 |
5 | 2 4 2^{4} 24 | 3.576° | 0.87469 | 0.4833 | 1.0776 |
6 | 2 5 2^{5} 25 | 1.79° | 0.8596 | 0.5106 | -0.7123 |
7 | 2 6 2^{6} 26 | 0.8955° | 0.8676 | 0.49719 | 0.1829 |
8 | 2 7 2^{7} 27 | 0.4473° | 0.86369 | 0.50397 | -0.2647 |
9 | 2 8 2^{8} 28 | 0.2236° | 0.8657 | 0.5006 | -0.0409 |
10 | 2 9 2^{9} 29 | 0.1123° | 0.8666 | 0.4989 | 0.071 |
11 | 2 10 2^{10} 210 | 0.05566° | 0.8662 | 0.4998 | 0.015 |
12 | 2 11 2^{11} 211 | 0.02832° | 0.8659 | 0.5002 | -0.013 |
13 | 2 12 2^{12} 212 | 0.0137° | 0.8661 | 0.49997 | 0.001 |
14 | 2 13 2^{13} 213 | 0.0068° | 0.8660 | 0.5001 | -0.006 |
15 | 2 14 2^{14} 214 | 0.0039° | 0.86604 | 0.50002 | -0.0025 |
16 | 2 15 2^{15} 215 | 0.00195° | 0.86606 | 0.5 | -0.0007 |
整个FPGA对于cordic的实现流程采用的是状态机实现法,因此,整个过程的实现代码如下所示:
/* cordic算法的实现 */
/* 输入一个角度值(拓展了2^16次大小),进行16次运算之后,输出一个对应的sin值以及cos值,同时获得每一次运算的时候的误差大小z*/
/* 整个模块的运算宽度范围大小为45 + 26.5654 + 14.036 + 7.125 + 3.576 + 1.79 + 0.8955 + 0.4473 + 0.2236 + 0.1123 + 0.05566 + 0.02832 + 0.0137 + 0.0068 + 0.0039 + 0.00195 = 99.88*/
`timescale 1ns / 1ps
module cordic_top(
input clk ,//设置系统时钟clk
input rst_n ,//设置复位电平,电平的低电平位有效
input [31:0]angle_in ,//通过控制testbench中的角度输入,来达到不同角度输入一个值,并且同时输出对应的sin值以及cos值
output reg signed[31:0] sin_value ,//输出对应的sin值输出通道
output reg signed[31:0] cos_value //输出对应的cos值输出通道
);
parameter U_DLY = 1 ;//设置延迟的时限
parameter angle_2_0 = 32'd2949120 ; //45°
parameter angle_2_1 = 32'd1740992 ; //26.5654°
parameter angle_2_2 = 32'd919872 ; //14.036°
parameter angle_2_3 = 32'd466944 ; //7.125°
parameter angle_2_4 = 32'd234368 ; //3.576°
parameter angle_2_5 = 32'd117312 ; //1.79°
parameter angle_2_6 = 32'd58688 ; //0.8955°
parameter angle_2_7 = 32'd29312 ; //0.4473°
parameter angle_2_8 = 32'd14656 ; //0.2236°
parameter angle_2_9 = 32'd7360 ; //0.1123°
parameter angle_2_10 = 32'd3648 ; //0.05566°
parameter angle_2_11 = 32'd1856 ; //0.02832°
parameter angle_2_12 = 32'd896 ; //0.0137°
parameter angle_2_13 = 32'd448 ; //0.0068°
parameter angle_2_14 = 32'd256 ; //0.0039°
parameter angle_2_15 = 32'd128 ; //0.00195°
parameter K16 = 32'd39796 ; //作为初始的cos分值变量之积,总共是16次分值变量之积
//保留每一次变量的的寄存器值,一共是17组,分别保存计算的sin值、cos值以及对应的误差值z。
reg signed [31:0] x_inital ;
reg signed [31:0] y_inital ;
reg signed [31:0] z_inital ;
reg signed [31:0] x1 ;
reg signed [31:0] y1 ;
reg signed [31:0] z1 ;
reg signed [31:0] x2 ;
reg signed [31:0] y2 ;
reg signed [31:0] z2 ;
reg signed [31:0] x3 ;
reg signed [31:0] y3 ;
reg signed [31:0] z3 ;
reg signed [31:0] x4 ;
reg signed [31:0] y4 ;
reg signed [31:0] z4 ;
reg signed [31:0] x5 ;
reg signed [31:0] y5 ;
reg signed [31:0] z5 ;
reg signed [31:0] x6 ;
reg signed [31:0] y6 ;
reg signed [31:0] z6 ;
reg signed [31:0] x7 ;
reg signed [31:0] y7 ;
reg signed [31:0] z7 ;
reg signed [31:0] x8 ;
reg signed [31:0] y8 ;
reg signed [31:0] z8 ;
reg signed [31:0] x9 ;
reg signed [31:0] y9 ;
reg signed [31:0] z9 ;
reg signed [31:0] x10 ;
reg signed [31:0] y10 ;
reg signed [31:0] z10 ;
reg signed [31:0] x11 ;
reg signed [31:0] y11 ;
reg signed [31:0] z11 ;
reg signed [31:0] x12 ;
reg signed [31:0] y12 ;
reg signed [31:0] z12 ;
reg signed [31:0] x13 ;
reg signed [31:0] y13 ;
reg signed [31:0] z13 ;
reg signed [31:0] x14 ;
reg signed [31:0] y14 ;
reg signed [31:0] z14 ;
reg signed [31:0] x15 ;
reg signed [31:0] y15 ;
reg signed [31:0] z15 ;
reg signed [31:0] x16 ;
reg signed [31:0] y16 ;
reg signed [31:0] z16 ;
/*计数器寄存器,用来保存整体的时序次数*/
reg [4:0] count ;
/*状态机实现方式,用来控制状态机的整体逻辑,循环次数控制到17次,第0次的时候因为没有上升沿,因此*/
/*可能会出问题,所以这个地方采用的是1-18,当值的大小位18的时候,执行复位的操作*/
always@(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
count <= #U_DLY 32'b0 ;
end
else if(count == 5'd18)begin
count <= 1'b0 ;
end
else begin
count <= count + 1'b1 ;
end
end
/*进入状态机的主模块*/
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)begin //如果复位信号出现使能,所有寄存器的值置1
x_inital <= #U_DLY 32'b0 ;
y_inital <= #U_DLY 32'b0 ;
z_inital <= #U_DLY 32'b0 ;
x1 <= #U_DLY 32'b0 ;
y1 <= #U_DLY 32'b0 ;
z1 <= #U_DLY 32'b0 ;
x2 <= #U_DLY 32'b0 ;
y2 <= #U_DLY 32'b0 ;
z2 <= #U_DLY 32'b0 ;
x3 <= #U_DLY 32'b0 ;
y3 <= #U_DLY 32'b0 ;
z3 <= #U_DLY 32'b0 ;
x4 <= #U_DLY 32'b0 ;
y4 <= #U_DLY 32'b0 ;
z4 <= #U_DLY 32'b0 ;
x5 <= #U_DLY 32'b0 ;
y5 <= #U_DLY 32'b0 ;
z5 <= #U_DLY 32'b0 ;
x6 <= #U_DLY 32'b0 ;
y6 <= #U_DLY 32'b0 ;
z6 <= #U_DLY 32'b0 ;
x7 <= #U_DLY 32'b0 ;
y7 <= #U_DLY 32'b0 ;
z7 <= #U_DLY 32'b0 ;
x8 <= #U_DLY 32'b0 ;
y8 <= #U_DLY 32'b0 ;
z8 <= #U_DLY 32'b0 ;
x9 <= #U_DLY 32'b0 ;
y9 <= #U_DLY 32'b0 ;
z9 <= #U_DLY 32'b0 ;
x10 <= #U_DLY 32'b0 ;
y10 <= #U_DLY 32'b0 ;
z10 <= #U_DLY 32'b0 ;
x11 <= #U_DLY 32'b0 ;
y11 <= #U_DLY 32'b0 ;
z11 <= #U_DLY 32'b0 ;
x12 <= #U_DLY 32'b0 ;
y12 <= #U_DLY 32'b0 ;
z12 <= #U_DLY 32'b0 ;
x13 <= #U_DLY 32'b0 ;
y13 <= #U_DLY 32'b0 ;
z13 <= #U_DLY 32'b0 ;
x14 <= #U_DLY 32'b0 ;
y14 <= #U_DLY 32'b0 ;
z14 <= #U_DLY 32'b0 ;
x15 <= #U_DLY 32'b0 ;
y15 <= #U_DLY 32'b0 ;
z15 <= #U_DLY 32'b0 ;
x16 <= #U_DLY 32'b0 ;
y16 <= #U_DLY 32'b0 ;
z16 <= #U_DLY 32'b0 ;
sin_value <= #U_DLY 32'b0 ;
cos_value <= #U_DLY 32'b0 ;
end
else begin
case(count)
5'd1: begin //由于需要将K16的值放入运算,这里直接设置初始值的大小就为K16,方便我们的运算
x_inital <= #U_DLY K16 ;
y_inital <= #U_DLY 32'd0 ;
z_inital <= #U_DLY angle_in ;
end
5'd2: begin
if(z_inital[31] == 1'b1)begin
x1 <= #U_DLY x_inital + y_inital ;
y1 <= #U_DLY y_inital - x_inital ;
z1 <= #U_DLY z_inital + angle_2_0 ;
end
else begin
x1 <= #U_DLY x_inital - y_inital ;
y1 <= #U_DLY y_inital + x_inital ;
z1 <= #U_DLY z_inital - angle_2_0 ;
end
end
5'd3:begin
if(z1[31] == 1'b1)begin
x2 <= #U_DLY x1 + (y1>>>1) ;
y2 <= #U_DLY y1 - (x1>>>1) ;
z2 <= #U_DLY z1 + angle_2_1 ;
end
else begin
x2 <= #U_DLY x1 - (y1>>>1) ;
y2 <= #U_DLY y1 + (x1>>>1) ;
z2 <= #U_DLY z1 - angle_2_1 ;
end
end
5'd4:begin
if(z2[31] == 1'b1)begin
x3 <= #U_DLY x2 + (y2>>>2) ;
y3 <= #U_DLY y2 - (x2>>>2) ;
z3 <= #U_DLY z2 + angle_2_2 ;
end
else begin
x3 <= #U_DLY x2 - (y2>>>2) ;
y3 <= #U_DLY y2 + (x2>>>2) ;
z3 <= #U_DLY z2 - angle_2_2 ;
end
end
5'd5:begin
if(z3[31] == 1'b1)begin
x4 <= #U_DLY x3 + (y3>>>3) ;
y4 <= #U_DLY y3 - (x3>>>3) ;
z4 <= #U_DLY z3 + angle_2_3 ;
end
else begin
x4 <= #U_DLY x3 - (y3>>>3) ;
y4 <= #U_DLY y3 + (x3>>>3) ;
z4 <= #U_DLY z3 - angle_2_3 ;
end
end
5'd6:begin
if(z4[31] == 1'b1)begin
x5 <= #U_DLY x4 + (y4>>>4) ;
y5 <= #U_DLY y4 - (x4>>>4) ;
z5 <= #U_DLY z4 + angle_2_4 ;
end
else begin
x5 <= #U_DLY x4 - (y4>>>4) ;
y5 <= #U_DLY y4 + (x4>>>4) ;
z5 <= #U_DLY z4 - angle_2_4 ;
end
end
5'd7:begin
if(z5[31] == 1'b1)begin
x6 <= #U_DLY x5 + (y5>>>5) ;
y6 <= #U_DLY y5 - (x5>>>5) ;
z6 <= #U_DLY z5 + angle_2_5 ;
end
else begin
x6 <= #U_DLY x5 - (y5>>>5) ;
y6 <= #U_DLY y5 + (x5>>>5) ;
z6 <= #U_DLY z5 - angle_2_5 ;
end
end
5'd8:begin
if(z6[31] == 1'b1)begin
x7 <= #U_DLY x6 + (y6>>>6) ;
y7 <= #U_DLY y6 - (x6>>>6) ;
z7 <= #U_DLY z6 + angle_2_6 ;
end
else begin
x7 <= #U_DLY x6 - (y6>>>6) ;
y7 <= #U_DLY y6 + (x6>>>6) ;
z7 <= #U_DLY z6 - angle_2_6 ;
end
end
5'd9:begin
if(z7[31] == 1'b1)begin
x8 <= #U_DLY x7 + (y7>>>7) ;
y8 <= #U_DLY y7 - (x7>>>7) ;
z8 <= #U_DLY z7 + angle_2_7 ;
end
else begin
x8 <= #U_DLY x7 - (y7>>>7) ;
y8 <= #U_DLY y7 + (x7>>>7) ;
z8 <= #U_DLY z7 - angle_2_7 ;
end
end
5'd10:begin
if(z8[31] == 1'b1)begin
x9 <= #U_DLY x8 + (y8>>>8) ;
y9 <= #U_DLY y8 - (x8>>>8) ;
z9 <= #U_DLY z8 + angle_2_8 ;
end
else begin
x9 <= #U_DLY x8 - (y8>>>8) ;
y9 <= #U_DLY y8 + (x8>>>8) ;
z9 <= #U_DLY z8 - angle_2_8 ;
end
end
5'd11:begin
if(z9[31] == 1'b1)begin
x10 <= #U_DLY x9 + (y9>>>9) ;
y10 <= #U_DLY y9 - (x9>>>9) ;
z10 <= #U_DLY z9 + angle_2_9 ;
end
else begin
x10 <= #U_DLY x9 - (y9>>>9) ;
y10 <= #U_DLY y9 + (x9>>>9) ;
z10 <= #U_DLY z9 - angle_2_9 ;
end
end
5'd12:begin
if(z10[31] == 1'b1)begin
x11 <= #U_DLY x10 + (y10>>>10) ;
y11 <= #U_DLY y10 - (x10>>>10) ;
z11 <= #U_DLY z10 + angle_2_10 ;
end
else begin
x11 <= #U_DLY x10 - (y10>>>10) ;
y11 <= #U_DLY y10 + (x10>>>10) ;
z11 <= #U_DLY z10 - angle_2_10 ;
end
end
5'd13:begin
if(z11[31] == 1'b1)begin
x12 <= #U_DLY x11 + (y11>>>11) ;
y12 <= #U_DLY y11 - (x11>>>11) ;
z12 <= #U_DLY z11 + angle_2_11 ;
end
else begin
x12 <= #U_DLY x11 - (y11>>>11) ;
y12 <= #U_DLY y11 + (x11>>>11) ;
z12 <= #U_DLY z11 - angle_2_11 ;
end
end
5'd14:begin
if(z12[31] == 1'b1)begin
x13 <= #U_DLY x12 + (y12>>>12) ;
y13 <= #U_DLY y12 - (x12>>>12) ;
z13 <= #U_DLY z12 + angle_2_12 ;
end
else begin
x13 <= #U_DLY x12 - (y12>>>12) ;
y13 <= #U_DLY y12 + (x12>>>12) ;
z13 <= #U_DLY z12 - angle_2_12 ;
end
end
5'd15:begin
if(z13[31] == 1'b1)begin
x14 <= #U_DLY x13 + (y13>>>13) ;
y14 <= #U_DLY y13 - (x13>>>13) ;
z14 <= #U_DLY z13 + angle_2_13 ;
end
else begin
x14 <= #U_DLY x13 - (y13>>>13) ;
y14 <= #U_DLY y13 + (x13>>>13) ;
z14 <= #U_DLY z13 - angle_2_13 ;
end
end
5'd16:begin
if(z14[31] == 1'b1)begin
x15 <= #U_DLY x14 + (y14>>>14) ;
y15 <= #U_DLY y14 - (x14>>>14) ;
z15 <= #U_DLY z14 + angle_2_14 ;
end
else begin
x15 <= #U_DLY x14 - (y14>>>14) ;
y15 <= #U_DLY y14 + (x14>>>14) ;
z15 <= #U_DLY z14 - angle_2_14 ;
end
end
5'd17:begin
if(z14[31] == 1'b1)begin
x16 <= #U_DLY x15 + (y15>>>15) ;
y16 <= #U_DLY y15 - (x15>>>15) ;
z16 <= #U_DLY z15 + angle_2_15 ;
end
else begin
x16 <= #U_DLY x15 - (y15>>>15) ;
y16 <= #U_DLY y15 + (x15>>>15) ;
z16 <= #U_DLY z15 - angle_2_15 ;
end
end
5'd18:begin //进行完成16次的运算之后,进行sin以及cos值的输出,转而进入下一次的角度运算
sin_value <= #U_DLY y16 ;
cos_value <= #U_DLY x16 ;
end
default:begin
x_inital <= 0 ;
y_inital <= 0 ;
z_inital <= 0 ;
x1 <= #U_DLY 32'b0 ;
y1 <= #U_DLY 32'b0 ;
z1 <= #U_DLY 32'b0 ;
x2 <= #U_DLY 32'b0 ;
y2 <= #U_DLY 32'b0 ;
z2 <= #U_DLY 32'b0 ;
x3 <= #U_DLY 32'b0 ;
y3 <= #U_DLY 32'b0 ;
z3 <= #U_DLY 32'b0 ;
x4 <= #U_DLY 32'b0 ;
y4 <= #U_DLY 32'b0 ;
z4 <= #U_DLY 32'b0 ;
x5 <= #U_DLY 32'b0 ;
y5 <= #U_DLY 32'b0 ;
z5 <= #U_DLY 32'b0 ;
x7 <= #U_DLY 32'b0 ;
y7 <= #U_DLY 32'b0 ;
z7 <= #U_DLY 32'b0 ;
x8 <= #U_DLY 32'b0 ;
y8 <= #U_DLY 32'b0 ;
z8 <= #U_DLY 32'b0 ;
x9 <= #U_DLY 32'b0 ;
y9 <= #U_DLY 32'b0 ;
z9 <= #U_DLY 32'b0 ;
x10 <= #U_DLY 32'b0 ;
y10 <= #U_DLY 32'b0 ;
z10 <= #U_DLY 32'b0 ;
x11 <= #U_DLY 32'b0 ;
y11 <= #U_DLY 32'b0 ;
z11 <= #U_DLY 32'b0 ;
x12 <= #U_DLY 32'b0 ;
y12 <= #U_DLY 32'b0 ;
z12 <= #U_DLY 32'b0 ;
x13 <= #U_DLY 32'b0 ;
y13 <= #U_DLY 32'b0 ;
z13 <= #U_DLY 32'b0 ;
x14 <= #U_DLY 32'b0 ;
y14 <= #U_DLY 32'b0 ;
z14 <= #U_DLY 32'b0 ;
x15 <= #U_DLY 32'b0 ;
y15 <= #U_DLY 32'b0 ;
z15 <= #U_DLY 32'b0 ;
x16 <= #U_DLY 32'b0 ;
y16 <= #U_DLY 32'b0 ;
z16 <= #U_DLY 32'b0 ;
sin_value <= #U_DLY 32'b0 ;
cos_value <= #U_DLY 32'b0 ; end
endcase
end
end
endmodule
对应cordic的的testbench的实现代码如下所示:
`timescale 1ns / 1ps
module tb_cordic_top;
// cordic_top Parameters
parameter PERIOD = 10 ;
parameter angle_2_0 = 32'd2949120;
parameter angle_2_1 = 32'd1740992;
parameter angle_2_2 = 32'd919872 ;
parameter angle_2_3 = 32'd466944 ;
parameter angle_2_4 = 32'd234368 ;
parameter angle_2_5 = 32'd117312 ;
parameter angle_2_6 = 32'd58688 ;
parameter angle_2_7 = 32'd29312 ;
parameter angle_2_8 = 32'd14656 ;
parameter angle_2_9 = 32'd7360 ;
parameter angle_2_10 = 32'd3648 ;
parameter angle_2_11 = 32'd1856 ;
parameter angle_2_12 = 32'd896 ;
parameter angle_2_13 = 32'd448 ;
parameter angle_2_14 = 32'd256 ;
parameter angle_2_15 = 32'd128 ;
parameter K16 = 32'd39796 ;
// cordic_top Inputs
reg clk = 0 ;
reg rst_n = 0 ;
reg [31:0] angle_in = 0 ;
// cordic_top Outputs
wire signed[31:0] sin ;
wire signed[31:0] cos ;
initial
begin
forever #(PERIOD/2) clk=~clk;
end
initial
begin
#(PERIOD*4) rst_n = 1;
end
initial begin
#(PERIOD*2) angle_in = 32'd1966080; //30°
// #(PERIOD*2) angle_in = 32'd2949120; //45°
end
cordic_top #(
.angle_2_0 ( angle_2_0 ),
.angle_2_1 ( angle_2_1 ),
.angle_2_2 ( angle_2_2 ),
.angle_2_3 ( angle_2_3 ),
.angle_2_4 ( angle_2_4 ),
.angle_2_5 ( angle_2_5 ),
.angle_2_6 ( angle_2_6 ),
.angle_2_7 ( angle_2_7 ),
.angle_2_8 ( angle_2_8 ),
.angle_2_9 ( angle_2_9 ),
.angle_2_10 ( angle_2_10 ),
.angle_2_11 ( angle_2_11 ),
.angle_2_12 ( angle_2_12 ),
.angle_2_13 ( angle_2_13 ),
.angle_2_14 ( angle_2_14 ),
.angle_2_15 ( angle_2_15 ),
.K16 ( K16 ))
u_cordic_top (
.clk ( clk ),
.rst_n ( rst_n ),
.angle_in ( angle_in ),
.sin_value ( sin ),
.cos_value ( cos )
);
endmodule
仿真效果图如下图:
从最终的结果可以看到,最终输出的结果
s
i
n
o
u
t
p
u
t
=
32768
sin_{output} =32768
sinoutput=32768,
c
o
s
o
u
t
p
u
t
=
56758
cos_{output} = 56758
cosoutput=56758 ,
z
o
u
t
p
u
t
=
64
z_{output} = 64
zoutput=64,根据放大倍数65536的关系,这个地方可以得出,
s
i
n
=
32768
/
65536
=
0.5
sin =32768/65536=0.5
sin=32768/65536=0.5,
c
o
s
=
56758
/
65536
=
0.866
cos = 56758/65536=0.866
cos=56758/65536=0.866 ,
z
=
64
/
65536
=
0.00098
z = 64/65536 = 0.00098
z=64/65536=0.00098