FPGA学习笔记---Verilog实现CORDIC算法——FPGA求sin函数和cos函数——FPGA求actan函数——FPGA开平方

9 篇文章 3 订阅

 

参考资料:

 

https://blog.csdn.net/qq_39210023/article/details/77456031 

 

https://blog.csdn.net/messi_cyc/article/details/77966457

 

https://wenku.baidu.com/view/6c623aa8910ef12d2bf9e732.html?sxts=1521614036184(Xilinx CORDIC,值得参考)

 

http://blog.sina.com.cn/s/blog_b906c1070102ve1l.html  (本篇的C语言程序很有参考价值)

 

 

CORDIC算法涉及3种坐标系、2种模式,共计6这个组合,其中在圆周坐标系下利用旋转模式实现sin和cos的文章和资料较多,其他5种较少,利用FPGA实现的更少。本文实现圆周坐标系下的向量模式,对输入的一对(x,y),求得actan(y/x)和 sqrt(x^2+y^2) ,具体原理以上资料均已很清楚,如有不清楚的可在评论区提出,文中不再赘述。文章侧重于Verilog程序的设计。 

(1)输入、输出位宽32,设为signed有符号数,这样便于下面的操作,通过判断y的最高位y[31]为1还是为0即可判断正负,对于移位操作也可以直接运用“>>>”,而不需要进行位拼接操作

 

 

//输入
input                       clk;
input                       rst_n;
input   signed    [31:0]    x;
input   signed    [31:0]    y;

//输出
output reg signed [31:0]    sqrt;
output reg signed [31:0]    actan;

 

(2)定义旋转角度常量和中间寄存器,此处借鉴了参考资料1中的定义(几乎是照抄,特别感谢@善良的一休君,文章给了我很多启发)

 

//以下为了避免浮点运算,对每个变量θi都放大了2^16倍
`define rot0  32'd2949120     //45度*2^16
`define rot1  32'd1740992     //26.5651度*2^16
`define rot2  32'd919872      //14.0362度*2^16
`define rot3  32'd466944      //7.1250度*2^16
`define rot4  32'd234368      //3.5763度*2^16
`define rot5  32'd117312      //1.7899度*2^16
`define rot6  32'd58688       //0.8952度*2^16
`define rot7  32'd29312       //0.4476度*2^16
`define rot8  32'd14656       //0.2238度*2^16
`define rot9  32'd7360        //0.1119度*2^16
`define rot10 32'd3648        //0.0560度*2^16
`define rot11 32'd1856        //0.0280度*2^16
`define rot12 32'd896         //0.0140度*2^16
`define rot13 32'd448         //0.0070度*2^16
`define rot14 32'd256         //0.0035度*2^16
`define rot15 32'd128         //0.0018度*2^16
//全部定义为有符号型数据
reg signed  [31:0]      x0=0,y0=0,z0=0;
reg signed  [31:0]      x1=0,y1=0,z1=0;
reg signed  [31:0]      x2=0,y2=0,z2=0;
reg signed  [31:0]      x3=0,y3=0,z3=0;
reg signed  [31:0]      x4=0,y4=0,z4=0;
reg signed  [31:0]      x5=0,y5=0,z5=0;
reg signed  [31:0]      x6=0,y6=0,z6=0;
reg signed  [31:0]      x7=0,y7=0,z7=0;
reg signed  [31:0]      x8=0,y8=0,z8=0;
reg signed  [31:0]      x9=0,y9=0,z9=0;
reg signed  [31:0]      x10=0,y10=0,z10=0;
reg signed  [31:0]      x11=0,y11=0,z11=0;
reg signed  [31:0]      x12=0,y12=0,z12=0;
reg signed  [31:0]      x13=0,y13=0,z13=0;
reg signed  [31:0]      x14=0,y14=0,z14=0;
reg signed  [31:0]      x15=0,y15=0,z15=0;
reg signed  [31:0]      x16=0,y16=0,z16=0;

(3)数据预处理,将输入数据x,y赋值给对应的x0,y0,而z0初值设为0,进行16级迭代,最后可得到z16=z0+actan(y/x)=actan(y/x)

//数据预处理
always @ (posedge clk or negedge rst_n)
begin
    if( !rst_n )  begin
        x0 <= 1'b0;                         
        y0 <= 1'b0;
        z0 <= 1'b0;
    end
    else  begin
        x0 <= x;           //x0赋初值
        y0 <= y;				//y0赋初值0
        z0 <= 32'd0;			//z0赋初值0
    end
end

//第一级迭代
always @ (posedge clk or negedge rst_n)
begin
    if( !rst_n )  begin
        x1 <= 1'b0;                         
        y1 <= 1'b0;
        z1 <= 1'b0;
    end
    else if( !y0[31] )  begin	//有符号数,最高位为符号位,是1表示<0
      x1 <= x0 + y0;
      y1 <= y0 - x0;
      z1 <= z0 + `rot0;
    end
    else  begin					//有符号数,最高位为符号位,是0表示>0
      x1 <= x0 - y0;
      y1 <= y0 + x0;
      z1 <= z0 - `rot0;
    end
end

......依次迭代

 

(4)将所得值赋给输出信号sqrt、actan,此处应该注意x16=K*sqrt(x^2+y^2),输出复数模值时需要除以K或乘以1/K,直接使用除法或乘法器都是非常消耗硬件资源的,因此采用移位的方式除以K(K为常数,具体得出的方式见上面的参考文献),因为输入的数据为了避免浮点运算,均扩大了2^16倍,所以输出的数据也扩大了2^16倍,右移16位的得到输出(但是应注意,这样得到的输出是整数,而无法得到小数的输出,只是为了便于特定数据仿真结果的验证,实际输出时不能采用这种移位方式)

 

always @ (posedge clk or negedge rst_n)
begin
    if( !rst_n )  begin
        sqrt <= 1'b0;
		  actan <= 1'b0;
    end
    else  begin  
      ppp <= (x16 >>> 1) + (x16 >>> 3) - (x16 >>> 6) - (x16 >>> 9);  //相当于x16/0.607523
       sqrt <= ppp >>> 16;
		 aaa <= z16;
		 actan <= aaa >>> 16;
	//	 sqrt <= x16;
    end
end

 

 

输入x=y=(2√2)*2^16=185364,预计输出sqrt=4,actan=45  (sqrt(8+8) = 4,tan45 = 1)



 



  • 5
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值