02、cordic算法原理及verilog实现

发布时间:2021/11/25
发布版本:2021-02
一、cordic算法原理
cordic算法主要应用于三角函数计算,尽管现在随着大规模存储器的普及,设计人员可以将所需三角函数值全部存储在存储器件上,需要用时直接读取即可,但cordic算法能直击运算函数值。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、verilog实现,已经验证过
/*
1、计算0-90度范围内的sin,cos值
2、采用13级流水线,最小角度为0.1度
3、缩放因子为0.60725
4、计算其它象限的角度值可以移到第一象限来计算
正负号有区别
5、用这样的值计算正弦、余弦值存在一定误差,尤其是
0度,90度这类端点一定要注意
6、angle_13为0时,sin_out和cos_out除值以10000即为计算值
*/
module cordic(
//input signal
input sys_clk ,
input sys_clk_rst_n ,
input valid_in ,
input [14:0] angle , //0-90度,即0-9000(14’h2328),算上符号位
output valid_out , //output signal
output [14:0] sin_out , //0-10000,算上符号位,15bit
output [14:0]cos_out
);

//parameter
//angle 0:15’h0,90:15’h2328(16’d9000)
//MSB is symbol bit
parameter angle_step_1 = 15’h1194;//4500
parameter angle_step_2 = 15’hA61 ;//2657
parameter angle_step_3 = 15’h57B ;//1403
parameter angle_step_4 = 15’h2C9 ;//713
parameter angle_step_5 = 15’h166 ;//358
parameter angle_step_6 = 15’hB3 ;//179
parameter angle_step_7 = 15’h5A ;//90
parameter angle_step_8 = 15’h2D ;//45
parameter angle_step_9 = 15’h16 ;//22
parameter angle_step_10 = 15’hB ;//11
parameter angle_step_11 = 15’h6 ;//6
parameter angle_step_12 = 15’h3 ;//3
parameter angle_step_13 = 15’h1 ;//1
//由于迭代累加会导致x,y可能不断增大,增加1bit
parameter x0 = 16’h2710;//10000
parameter y0 = 16’h0 ;//0
//60725*0.65536 = 39796.736.由于Kn已确定且为正数,无须符号位
//parameter Kn = 16’h9b74;//0.60725
//wire
//reg
reg valid_1 ;
reg valid_2 ;
reg valid_3 ;
reg valid_4 ;
reg valid_5 ;
reg valid_6 ;
reg valid_7 ;
reg valid_8 ;
reg valid_9 ;
reg valid_10 ;
reg valid_11 ;
reg valid_12 ;
reg valid_13 ;

reg [15:0] x1 ;
reg [15:0] x2 ;
reg [15:0] x3 ;
reg [15:0] x4 ;
reg [15:0] x5 ;
reg [15:0] x6 ;
reg [15:0] x7 ;
reg [15:0] x8 ;
reg [15:0] x9 ;
reg [15:0] x10 ;
reg [15:0] x11 ;
reg [15:0] x12 ;
reg [15:0] x13 ;

reg [15:0] y1 ;
reg [15:0] y2 ;
reg [15:0] y3 ;
reg [15:0] y4 ;
reg [15:0] y5 ;
reg [15:0] y6 ;
reg [15:0] y7 ;
reg [15:0] y8 ;
reg [15:0] y9 ;
reg [15:0] y10 ;
reg [15:0] y11 ;
reg [15:0] y12 ;
reg [15:0] y13 ;

reg [13:0] angle_1 ;
reg [13:0] angle_2 ;
reg [13:0] angle_3 ;
reg [13:0] angle_4 ;
reg [13:0] angle_5 ;
reg [13:0] angle_6 ;
reg [13:0] angle_7 ;
reg [13:0] angle_8 ;
reg [13:0] angle_9 ;
reg [13:0] angle_10 ;
reg [13:0] angle_11 ;
reg [13:0] angle_12 ;
reg [13:0] angle_13 ;
//------------contrl state machine--------------------
//1step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_1 <= 1’b0 ;
x1 <= 16’h0;
y1 <= 16’h0;
angle_1 <= 14’h0;
end
else begin
valid_1 <= valid_in ;
x1 <= x0 - y0 ;
y1 <= y0 + x0 ;
angle_1 <= angle - angle_step_1;
end
end
//2step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_2 <= 1’b0 ;
x2 <= 16’h0;
y2 <= 16’h0;
angle_2 <= 14’h0;
end
else begin
if(angle_1[13] == 1’b0) begin//判断正负数
valid_2 <= valid_1 ;
x2 <= x1 - {y1[15],y1[15:1]} ;
y2 <= y1 + {x1[15],x1[15:1]} ;
angle_2 <= angle_1 - angle_step_2 ;
end else begin
valid_2 <= valid_1 ;
x2 <= x1 + {y1[15],y1[15:1]} ;
y2 <= y1 - {x1[15],x1[15:1]} ;
angle_2 <= angle_1 + angle_step_2 ;
end
end
end
//3step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_3 <= 1’b0 ;
x3 <= 16’h0;
y3 <= 16’h0;
angle_3 <= 14’h0;
end
else begin
if(angle_2[13] == 1’b0) begin
valid_3 <= valid_2 ;
x3 <= x2 - {{2{y2[15]}},y2[15:2]} ;
y3 <= y2 + {{2{x2[15]}},x2[15:2]} ;
angle_3 <= angle_2 - angle_step_3 ;
end else begin
valid_3 <= valid_2 ;
x3 <= x2 + {{2{y2[15]}},y2[15:2]} ;
y3 <= y2 - {{2{x2[15]}},x2[15:2]} ;
angle_3 <= angle_2 + angle_step_3 ;
end
end
end
//4step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_4 <= 1’b0 ;
x4 <= 16’h0;
y4 <= 16’h0;
angle_4 <= 14’h0;
end
else begin
if(angle_3[13] == 1’b0) begin
valid_4 <= valid_3 ;
x4 <= x3 - {{3{y3[15]}},y3[15:3]} ;
y4 <= y3 + {{3{x3[15]}},x3[15:3]} ;
angle_4 <= angle_3 - angle_step_4 ;
end else begin
valid_4 <= valid_3 ;
x4 <= x3 + {{3{y3[15]}},y3[15:3]} ;
y4 <= y3 - {{3{x3[15]}},x3[15:3]} ;
angle_4 <= angle_3 + angle_step_4 ;
end
end
end
//5step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_5 <= 1’b0 ;
x5 <= 16’h0;
y5 <= 16’h0;
angle_5 <= 14’h0;
end
else begin
if(angle_4[13] == 1’b0) begin
valid_5 <= valid_4 ;
x5 <= x4 - {{4{y4[15]}},y4[15:4]} ;
y5 <= y4 + {{4{x4[15]}},x4[15:4]} ;
angle_5 <= angle_4 - angle_step_5 ;
end else begin
valid_5 <= valid_4 ;
x5 <= x4 + {{4{y4[15]}},y4[15:4]} ;
y5 <= y4 - {{4{x4[15]}},x4[15:4]} ;
angle_5 <= angle_4 + angle_step_5 ;
end
end
end

//6step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_6 <= 1’b0 ;
x6 <= 16’h0;
y6 <= 16’h0;
angle_6 <= 14’h0;
end
else begin
if(angle_5[13] == 1’b0) begin
valid_6 <= valid_5 ;
x6 <= x5 - {{5{y5[15]}},y5[15:5]} ;
y6 <= y5 + {{5{x5[15]}},x5[15:5]} ;
angle_6 <= angle_5 - angle_step_6 ;
end else begin
valid_6 <= valid_5 ;
x6 <= x5 + {{5{y5[15]}},y5[15:5]} ;
y6 <= y5 - {{5{x5[15]}},x5[15:5]} ;
angle_6 <= angle_5 + angle_step_6 ;
end
end
end
//7step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_7 <= 1’b0 ;
x7 <= 16’h0;
y7 <= 16’h0;
angle_7 <= 14’h0;
end
else begin
if(angle_6[13] == 1’b0) begin
valid_7 <= valid_6 ;
x7 <= x6 - {{6{y6[15]}},y6[15:6]} ;
y7 <= y6 + {{6{x6[15]}},x6[15:6]} ;
angle_7 <= angle_6 - angle_step_7 ;
end else begin
valid_7 <= valid_6 ;
x7 <= x6 + {{6{y6[15]}},y6[15:6]} ;
y7 <= y6 - {{6{x6[15]}},x6[15:6]} ;
angle_7 <= angle_6 + angle_step_7 ;
end
end
end
//8step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_8 <= 1’b0 ;
x8 <= 16’h0;
y8 <= 16’h0;
angle_8 <= 14’h0;
end
else begin
if(angle_7[13] == 1’b0) begin
valid_8 <= valid_7 ;
x8 <= x7 - {{7{y7[15]}},y7[15:7]} ;
y8 <= y7 + {{7{x7[15]}},x7[15:7]} ;
angle_8 <= angle_7 - angle_step_8 ;
end else begin
valid_8 <= valid_7 ;
x8 <= x7 + {{7{y7[15]}},y7[15:7]} ;
y8 <= y7 - {{7{x7[15]}},x7[15:7]} ;
angle_8 <= angle_7 + angle_step_8 ;
end
end
end
//9step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_9 <= 1’b0 ;
x9 <= 16’h0;
y9 <= 16’h0;
angle_9 <= 14’h0;
end
else begin
if(angle_8[13] == 1’b0) begin
valid_9 <= valid_8 ;
x9 <= x8 - {{8{y8[15]}},y8[15:8]} ;
y9 <= y8 + {{8{x8[15]}},x8[15:8]} ;
angle_9 <= angle_8 - angle_step_9 ;
end else begin
valid_9 <= valid_8 ;
x9 <= x8 + {{8{y8[15]}},y8[15:8]} ;
y9 <= y8 - {{8{x8[15]}},x8[15:8]} ;
angle_9 <= angle_8 + angle_step_9 ;
end
end
end
//10step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_10 <= 1’b0 ;
x10 <= 16’h0;
y10 <= 16’h0;
angle_10 <= 14’h0;
end
else begin
if(angle_9[13] == 1’b0) begin
valid_10 <= valid_9 ;
x10 <= x9 - {{9{y9[15]}},y9[15:9]} ;
y10 <= y9 + {{9{x9[15]}},x9[15:9]} ;
angle_10 <= angle_9 - angle_step_10 ;
end else begin
valid_10 <= valid_9 ;
x10 <= x9 + {{9{y9[15]}},y9[15:9]} ;
y10 <= y9 - {{9{x9[15]}},x9[15:9]} ;
angle_10 <= angle_9 + angle_step_10 ;
end
end
end
//11step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_11 <= 1’b0 ;
x11 <= 16’h0;
y11 <= 16’h0;
angle_11 <= 14’h0;
end
else begin
if(angle_10[13] == 1’b0) begin
valid_11 <= valid_10 ;
x11 <= x10 - {{10{y10[15]}},y10[15:10]} ;
y11 <= y10 + {{10{x10[15]}},x10[15:10]} ;
angle_11 <= angle_10 - angle_step_11 ;
end else begin
valid_11 <= valid_10 ;
x11 <= x10 + {{10{y10[15]}},y10[15:10]} ;
y11 <= y10 - {{10{x10[15]}},x10[15:10]} ;
angle_11 <= angle_10 + angle_step_11 ;
end
end
end
//12step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_12 <= 1’b0 ;
x12 <= 16’h0;
y12 <= 16’h0;
angle_12 <= 14’h0;
end
else begin
if(angle_11[13] == 1’b0) begin
valid_12 <= valid_11 ;
x12 <= x11 - {{11{y11[15]}},y11[15:11]} ;
y12 <= y11 + {{11{x11[15]}},x11[15:11]} ;
angle_12 <= angle_11 - angle_step_12 ;
end else begin
valid_12 <= valid_11 ;
x12 <= x11 + {{11{y11[15]}},y11[15:11]} ;
y12 <= y11 - {{11{x11[15]}},x11[15:11]} ;
angle_12 <= angle_11 + angle_step_12 ;
end
end
end
//13step
always @ (posedge sys_clk)
begin
if(!sys_clk_rst_n) begin
valid_13 <= 1’b0 ;
x13 <= 16’h0;
y13 <= 16’h0;
angle_13 <= 14’h0;
end
else begin
if(angle_12[13] == 1’b0) begin
valid_13 <= valid_12 ;
x13 <= x12 - {{12{y12[15]}},y12[15:12]} ;
y13 <= y12 + {{12{x12[15]}},x12[15:12]} ;
angle_13 <= angle_12 - angle_step_13 ;
end else begin
valid_13 <= valid_12 ;
x13 <= x12 + {{12{y12[15]}},y12[15:12]} ;
y13 <= y12 - {{12{x12[15]}},x12[15:12]} ;
angle_13 <= angle_12 + angle_step_13 ;
end
end
end
multi_kn u_multi_kn(
.sys_clk (sys_clk ),
.sys_clk_rst_n (sys_clk_rst_n ),
.valid_in (valid_13 ),
.sin_in (y13 ),
.cos_in (x13 ),
.valid_out (valid_out ),
.sin_out (sin_out ),
.cos_out (cos_out )
);

endmodule
/*
1、1616乘法器
2、被乘数固定为Kn(缩放因子0.60725),Kn = 16’h9b74
// = 16’b1001_1011_0111_0100
//60725
0.65536 =39796.736
3、乘完后只保留15位(30-16bit),除掉2的16次方(65536)
得到真实值
*/
module multi_kn(
input sys_clk ,
input sys_clk_rst_n,
input valid_in ,
input [15:0] sin_in ,
input [15:0] cos_in ,
output valid_out ,
output [14:0] sin_out ,
output [14:0] cos_out
);
//reg
reg valid_1 ;
reg [31:0] sin_1 ;//bit2 bit4 bit5
reg [31:0] sin_2 ;//bit6 bit8 bit9
reg [31:0] sin_3 ;//bit11 bit12 bit15
reg [31:0] cos_1 ;//bit2 bit4 bit5
reg [31:0] cos_2 ;//bit6 bit8 bit9
reg [31:0] cos_3 ;//bit11 bit12 bit15

reg valid_2 ;
reg [31:0] sin_4 ;
reg [31:0] cos_4 ;
//-----------combination circuit-------------------
assign valid_out = valid_2 ;
assign sin_out = sin_4[30:16] ;
assign cos_out = cos_4[30:16] ;
//-----------control state machine------------------
//1step
//Kn = 16’h9b74
// = 16’b1001_1011_0111_0100
//sin_n = sin_inKn
//cos_n = cos_in
Kn
always @ (posedge sys_clk)
begin
if(~sys_clk_rst_n)
begin
valid_1 <= 1’b0 ;
sin_1 <= 32’b0;
sin_2 <= 32’b0;
sin_3 <= 32’b0;
cos_1 <= 32’b0;
cos_2 <= 32’b0;
cos_3 <= 32’b0;
end else begin
valid_1 <= valid_in;
sin_1 <= {{14{sin_in[15]}},sin_in[15:0],2’h0}
+ {{12{sin_in[15]}},sin_in[15:0],4’h0}
+ {{11{sin_in[15]}},sin_in[15:0],6’h0};
sin_2 <= {{10{sin_in[15]}},sin_in[15:0],6’h0}
+ {{8 {sin_in[15]}},sin_in[15:0],8’h0}
+ {{7 {sin_in[15]}},sin_in[15:0],9’h0};
sin_3 <= {{5 {sin_in[15]}},sin_in[15:0],11’h0}
+ {{4 {sin_in[15]}},sin_in[15:0],12’h0}
+ {{1 {sin_in[15]}},sin_in[15:0],15’h0};
cos_1 <= {{14{cos_in[15]}},cos_in[15:0],2’h0}
+ {{12{cos_in[15]}},cos_in[15:0],4’h0}
+ {{11{cos_in[15]}},cos_in[15:0],6’h0};
cos_2 <= {{10{cos_in[15]}},cos_in[15:0],6’h0}
+ {{8 {cos_in[15]}},cos_in[15:0],8’h0}
+ {{7 {cos_in[15]}},cos_in[15:0],9’h0};
cos_3 <= {{5 {cos_in[15]}},cos_in[15:0],11’h0}
+ {{4 {cos_in[15]}},cos_in[15:0],12’h0}
+ {{1 {cos_in[15]}},cos_in[15:0],15’h0};
end
end
//2step
always @ (posedge sys_clk)
begin
if(~sys_clk_rst_n) begin
valid_2 <= 1’b0 ;
sin_4 <= 32’b0;
cos_4 <= 32’b0;
end else begin
valid_2 <= valid_1 ;
sin_4 <= sin_1 + sin_2 + sin_3 ;
cos_4 <= cos_1 + cos_2 + cos_3;
end
end
endmodule
//仿真文件
module cordic_tb();
reg sys_clk ;
reg sys_clk_rst_n ;
reg valid_in ;
reg [14:0] angle ; //0-90度,即0-9000(14’h2328),算上符号位
wire valid_out ; //output signal
wire [14:0] sin_out ; //0-10000,算上符号位,15bit
wire [14:0] cos_out ;

cordic u_cordic(
.sys_clk (sys_clk ),
.sys_clk_rst_n (sys_clk_rst_n ),
.valid_in (valid_in ),
.angle (angle ),
.valid_out (valid_out ),
.sin_out (sin_out ),
.cos_out (cos_out )

);
always #10 sys_clk = ~sys_clk;
initial
begin
sys_clk = 1’b1 ;
valid_in = 1’b0 ;
angle = 16’d0 ;
sys_clk_rst_n = 1’b0 ;
#100
sys_clk_rst_n = 1’b1 ;
#20 valid_in = 1’b1 ;
angle = 15’d3000;
#20 angle = 15’d6000;
#20 angle = 15’d9000;
#20 valid_in = 1’b0 ;
angle = 15’d0 ;
#5000 $stop ;
end
endmodule
三、仿真截图
在这里插入图片描述

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cordic算法是一种高效的计算三角函数的方法,它可以在硬件中实现。以下是一个基于Verilog的16级流水线Cordic算法实现,可以计算余弦值。 ``` module cordic_cos( input signed [15:0] theta, output reg signed [15:0] cos, input clk, rst_n); parameter ITERATIONS = 16; parameter ANGLE_WIDTH = 16; parameter FRACTION_WIDTH = 16; wire signed [15:0] angle [0:ITERATIONS]; wire signed [15:0] x [0:ITERATIONS]; wire signed [15:0] y [0:ITERATIONS]; wire signed [15:0] z [0:ITERATIONS]; wire signed [15:0] d [0:ITERATIONS]; reg signed [15:0] cos_reg; reg signed [15:0] angle_reg; assign angle[0] = theta; assign x[0] = {16'd1, 16'd0}; assign y[0] = {16'd0, 16'd0}; assign z[0] = theta; generate genvar i; for (i = 0; i < ITERATIONS; i = i + 1) begin : CORDIC_ITERATION assign angle[i+1] = angle[i] - (angle_reg >> i); assign x[i+1] = x[i] - (d[i] >> i); assign y[i+1] = y[i] + (z[i] >> i); assign z[i+1] = z[i] - (d[i] >> i); assign d[i+1] = (angle[i] < 0) ? {d[i], z[i]} + (angle[i+1] >> i) : {d[i], -z[i]} - (angle[i+1] >> i); end endgenerate always @ (posedge clk or negedge rst_n) begin if (~rst_n) begin cos_reg <= 0; angle_reg <= 0; end else begin cos_reg <= x[ITERATIONS]; angle_reg <= angle[ITERATIONS]; end end assign cos = cos_reg >> (FRACTION_WIDTH - ANGLE_WIDTH); endmodule ``` 在这个Verilog模块中,输入是一个带符号的16位角度值`theta`,输出是一个带符号的16位余弦值`cos`。`ITERATIONS`参数指定了流水线级数,`ANGLE_WIDTH`和`FRACTION_WIDTH`参数指定了角度和小数部分的位宽。输出余弦值的精度由这两个参数决定。 在每个流水线阶段中,计算一个新的角度值和三个新的坐标值。`x`和`y`表示当前坐标,`z`表示当前角度,`d`是旋转因子,用于计算下一个坐标值和下一个角度值。最后,输出最终的余弦值。 该模块中的代码可以进一步优化,例如使用查找表来存储旋转因子,以提高计算速度。此外,该模块只能计算余弦值,如果需要计算正弦值或其他三角函数,则需要进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值