基于cordic算法的小数开方及其FPGA实现
目录
前言
现实中很多算法本身就包含开方运算,硬件实现中很多时候也会涉及到开方运算,本次较为详细的介绍用cordic算法实现开方运算的基本原理以及如何使用xilinx公司提供的cordic IP核来完成无符号小数开方运算。
提示:以下是本篇文章正文内容,写文章实属不易,希望能帮助到各位,转载请附上链接。
一、坐标旋转公式推导
欲明白cordic算法中如何实现开方运算,首先需要知道坐标旋转公式。
如图1所示,在二维坐标系中,有一点A(x,y),其与原点之间连线的长度为r,连线和x轴正向夹角为,将其绕原点逆时针旋转
可得到点
。

由图知:
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算法简介


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

是每次迭代中的旋转角度。当 m=1 时,
,此时为正弦方程;当 m=0 时,
,此时为线性方程;当 m=-1 时,
,此时为双曲线方程。

三、cordic IP核配置
四、仿真
1.顶层代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
// 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:
// 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 实现