基于cordic算法的小数开方及其FPGA实现

基于cordic算法的小数开方及其FPGA实现

目录

前言

一、坐标旋转公式推导

二、cordic算法简介

三、cordic IP核配置 

四、仿真

1.顶层代码

2.仿真代码

五、仿真结果分析

总结

扫描二维码关注公众号,回复: 15080286 查看本文章

参考文献


前言

        现实中很多算法本身就包含开方运算,硬件实现中很多时候也会涉及到开方运算,本次较为详细的介绍用cordic算法实现开方运算的基本原理以及如何使用xilinx公司提供的cordic IP核来完成无符号小数开方运算。


提示:以下是本篇文章正文内容,写文章实属不易,希望能帮助到各位,转载请附上链接。

一、坐标旋转公式推导

        欲明白cordic算法中如何实现开方运算,首先需要知道坐标旋转公式。

        如图1所示,在二维坐标系中,有一点A(x,y),其与原点之间连线的长度为r,连线和x轴正向夹角为\alpha,将其绕原点逆时针旋转\Theta可得到点A^{'}(x^{'},y^{'})

图1 坐标旋转图

 由图知:

x’=rcos(α+θ)=rcosαcosθ−rsinαsinθ    (1.1)

y’=rsin(α+θ)=rsinαcosθ+rcosαsinθ     (1.2)

x=rcosα                                            (1.3)

y=rsinα                                             (1.4)

将(1.3)和(1.4)代入(1.1)和(1.2)可知:

x’=xcosθ−ysinθ                                 (1.5)

y’=xsinθ+ycosθ                                 (1.6)

(1.5)和(1.6)组成的即为坐标旋转公式,写成矩阵形式即为:

 

 注:在word公式编辑器中编辑后复制过来居然有乱码,不兼容,所以以图片形式给出了。

那么如果是顺时针旋转我们由式(1.7)可知只需要将θ用-θ代替即可得到:

 

二、cordic算法简介

         CORDIC 算法最早是由 Volder 提出的,其有两种计算模式:旋转 (Rotation)模式和求模 (Vectoring)模式。它是一种迭代算法,只通过移位操作和加减操作就可以实现任意角度的坐标变换。假设坐标(x,y)旋转角度Ф后得到坐标(x',y'),则:
         如果限定旋转角度Ф ,使 tanФ= ±2^{-i} ,那么由tanФ引入的乘法运算就简化为移位操作。任意角度的旋转可通过一系列\phi =tan^{-1}(2^{-i}) 的角度旋转迭代完成,那么第 i+1 次角度旋转可表示为:
         其中,k_{i}=cos(tan^{-1}(2^{-i}))=\frac{1}{\sqrt{1+2^{-2i}}}di = ±1。如果去掉常数项Ki ,迭代方程(2)就只有移位和加减操作。而常数项可以在系统的其它地方进行补偿,或者直接当作系统的增益。当迭代次数趋于无穷时,常数项趋于0.6073,其倒数趋于1.6467。

        i+1 迭代旋转的角度为:

        d{_{i}}决定每次迭代旋转的方向(逆时针或顺时针),若 z{_{i}} < 0,d{_{i}} = -1;否则 d{_{i}} =1。当 z{_{i+1}} =0 时迭代结束,此时迭代的最终值为:

 

        CORDIC算法也可用于投影计算,即将向量 (x,y)投影到x轴或y轴,当投影到x轴时,迭代方
程为:

        
        若 y_{i}< 0 ,d{_{i}}=1;否则,d{_{i}}= -1,当 y_{i+1}= 0时,迭代结束,迭代的最终值为:  
 
        扩展迭代方程式(2)和式(5),CORDIC 算法可用于计算线形方程和双曲线方程,扩展后方程为:

         e_{i}是每次迭代中的旋转角度。当 m=1 时,e_{i}=tan^{-1}(2^{-i}),此时为正弦方程;当 m=0 时,e_{i}=2^{-i},此时为线性方程;当 m=-1 时, e_{i}=tanh^{-1}(2^{-i}),此时为双曲线方程。

        对于平方根运算采用的是双曲线方程,而且迭代模式为投影模式,迭代的最终值为:
        迭代中的方向 d{_{i}}的选取为,若 y_{i}< 0,d{_{i}}=1;否则, d{_{i}}= -1。
        如果要求值a 的平方根,只需将x_{0} 、y_{0} 分别赋值为:x_{0}=a+1/4,y_{0}=a-1/4,代入式(8),可得x_{n}=\sqrt{\alpha }
 

三、cordic IP核配置

四、仿真

1.顶层代码

`timescale 1ns / 1ps
//
// Company: cq university
// Engineer: clg
// Create Date: 2022/09/01 20:52:25
// Design Name: 
// Module Name: square_root
// Project Name: 
// Target Devices: 
// Tool Versions: 2017.4
// Description: 
// Dependencies: 
// Revision:1.0
// Revision 0.01 - File Created
// Additional Comments:
//

module square_root(
    input clk,                   
    input rst_n,
    input data_in_valid,
    input [31:0] data_in,
    output data_out_valid,
    output [31:0] data_out 
    );
    
cordic_square u1_cordic_square(     //ip核例化
    .aclk(clk), 
    .aresetn(rst_n), 
    .s_axis_cartesian_tvalid(data_in_valid), 
    .s_axis_cartesian_tdata(data_in),
    .m_axis_dout_tvalid(data_out_valid), 
    .m_axis_dout_tdata(data_out)
    );
    
endmodule

2.仿真代码

`timescale 1ns / 1ps
//
// Company: cq university
// Engineer: clg
// Create Date: 2022/09/01 21:07:29
// Design Name: 
// Module Name: square_root_tb
// Project Name: 
// Target Devices: 2017.4
// Tool Versions: 
// Description: 
// Dependencies: 
// Revision:1.0
// Revision 0.01 - File Created
// Additional Comments:
//

module square_root_tb();
reg clk;
reg rst_n;
reg data_in_valid;
reg [31:0] data_in;
wire data_out_valid;
wire [31:0] data_out;

square_root u1_square_root(
    .clk(clk),
    .rst_n(rst_n),
    .data_in_valid(data_in_valid),
    .data_in(data_in),
    .data_out_valid(data_out_valid),
    .data_out(data_out) 
    );

initial begin
        clk=1'b1;rst_n=1'b1;data_in_valid=1'b0;data_in=32'b0;
#10  rst_n=1'b0;
#10  rst_n=1'b1;
#10  data_in_valid=1'b1;data_in=32'b0_001_0000_0000_0000_0000_0000_0000_0000;
#10  data_in_valid=1'b1;data_in=32'b0_111_0000_0000_0000_0000_0000_0000_0000;

end
always #5 clk=!clk;
endmodule

五、仿真结果分析

         如上图所示,从数据输入到数据输出会有32个时钟周期延时(与数据位数长短有关),注意实际的data_in和data_out是图中显示的2倍,因为我是把二进制的结果用定点数显示了,它显示的其实是真实值的一半,(这个运算是正确的,这里的误差完全是为了显示方便带来的一个倍数误差)因为实际上这个IP核开方运算时数据并不是真真正正的定点数,它的第一位算作的是小数点前面的0,其格式如下图所示:

         所以图中仿真的输入为0.4375*2=0.875,输出为0.467707173200324*2=0.93541434346400648,我用计算器对0.875开方得到的结果是0.93541434346693485346,对比可知32位的精度挺高了,到小数点后第11位了,实际使用时完全可以自己根据需要的精度设置运算数据的位数。

总结

        以上就是此次介绍的cordic算法开方。

参考文献

利用 CORDIC 算法计算平方根及其 FPGA 实现

猜你喜欢

转载自blog.csdn.net/m0_66360845/article/details/126669872