开平方_复数有效值+角度的verilog代码

2023-05-16

1、逐位比较法-二进制

《 FPGA篇(一) 基于verilog的定点开方运算(1)-逐次逼近算法 》该篇文章中有详细描述
在这里插入图片描述
假设被开方数rad_i[7:0],则结果qout[3:0]位宽为4位,从最高位到最低位依次置1,用乘法器平方后与被开方数比较,>rad_i则当前位=0,<rad_i则当前位=1;详细说明见原文。
总结:该算法在计算大数据时占用大量乘法器,时间为位宽一半,可流水计算
二进制思维:依次改变的每一个bit的值,下方的sqrt_shift中并不关心bit的0,1,以十进制参考.

/*
逐次逼近算法,逐位变1,平方后与被开方数比较,当前位是否可以为1;
可以流水计算,被开方数位宽时占用大量乘法器。
*/
module sqrt_1
	#( 	
			parameter  		 							  d_width = 58,
			parameter       							q_width = d_width/2 - 1,
			parameter       							r_width = d_width/2)
	(
	input			wire									clk,
	input			wire									rst,
	input			wire									i_vaild,
	input			wire		[d_width-1:0]			data_i, //输入
	
	
	output		reg											o_vaild,
	output		reg			[q_width:0]			data_o, //输出
	output		reg			[r_width:0]			data_r  //余数
	
    );
//--------------------------------------------------------------------------------
	reg 							[d_width-1:0] 		D			[r_width:1]; //被开方数
	reg 							[q_width:0] 		Q_z			[r_width:1]; //临时
	reg	 						  [q_width:0] 		Q_q			[r_width:1]; //确认
	reg 													ivalid_t		[r_width:1]; //杈撳叆鏁版嵁鏈夋晥
//--------------------------------------------------------------------------------
	always@(posedge	clk or posedge	rst)
		begin
			if(rst)
				begin
					D[r_width] 				<= 0;
					Q_z[r_width] 			<= 0;
					Q_q[r_width] 			<= 0;
					ivalid_t[r_width] <= 0;
				end
			else	if(i_vaild)
				begin
					D[r_width] 	 			<= data_i;  								//被开方数进入缓存
					Q_z[r_width] 			<= {1'b1,{q_width{1'b0}}};  //实验值设置,开方值的一半,从最高位依次向下;
					Q_q[r_width] 			<= 0; 											//实际计算结果
					ivalid_t[r_width] <= 1;												// 有效
				end
			else
				begin
					D[r_width] 				<= 0;
					Q_z[r_width] 			<= 0;
					Q_q[r_width] 			<= 0;
					ivalid_t[r_width] <= 0;
				end
		end
//-------------------------------------------------------------------------------
//		迭代计算过程
//-------------------------------------------------------------------------------
		generate
			genvar i;
				for(i=r_width-1;i>=1;i=i-1)//从最高位开始向下比较
					begin:U
						always@(posedge clk or posedge	rst)
							begin
								if(rst)
									begin
										D[i] 				<= 0;
										Q_z[i] 			<= 0;
										Q_q[i] 			<= 0;
										ivalid_t[i] <= 0;
									end
								else	if(ivalid_t[i+1])
									begin
										if(Q_z[i+1]*Q_z[i+1] > D[i+1])//注意此处有平方的乘运算,被开方数位宽时占用大量乘法器。
											begin
												Q_z[i] <= {Q_q[i+1][q_width:i],1'b1,{{i-1}{1'b0}}};
												Q_q[i] <=  Q_q[i+1];//试验平方大于被开方数,当前实验值不可确认,确认值不变,并将第i bit置1进行下一次试验比较 
											end
										else
											begin
												Q_z[i] <= {Q_z[i+1][q_width:i],1'b1,{{i-1}{1'b0}}};
												Q_q[i] <=  Q_z[i+1]; //试验平方小于被开方数,当前实验值可确认,并将第i bit置1进行下一次试验比较
											end
										D[i] 				<= D[i+1];//流水移动
										ivalid_t[i] <= 1;
									end
								else
									begin
										ivalid_t[i] <= 0;
										D[i] 				<= 0;
										Q_q[i] 			<= 0;
										Q_z[i] 			<= 0;
									end
							end
					end
		endgenerate
//--------------------------------------------------------------------------------
//	计算余数与最终平方根
//--------------------------------------------------------------------------------
		always@(posedge	clk or posedge	rst) 
			begin
				if(rst)
					begin
						data_o <= 0;
						data_r <= 0;
						o_vaild <= 0;
					end
				else	if(ivalid_t[1])
					begin
						if(Q_z[1]*Q_z[1] > D[1])//  Q_z比Q_q提前变化一位用于对比测试
							begin
								data_o <= Q_q[1];
								data_r <= D[1] - Q_q[1]*Q_q[1];//余数
								o_vaild <= 1;
							end
						else
							begin
								data_o <= {Q_q[1][q_width:1],Q_z[1][0]};//试验值的[0]有效补给确认确认值
								data_r <= D[1] - {Q_q[1][q_width:1],Q_z[1][0]}*{Q_q[1][q_width:1],Q_z[1][0]};
								o_vaild <= 1;
							end
					end
				else
					begin
						data_o <= 0;
						data_r <= 0;
						o_vaild <= 0;
					end
			end
endmodule
//--------------------------------------------------------------------------------

2、逐位比较-十进制

十进制思维:
把结果按照位宽拆分为多份,以每一位的十进制结果为参考,通过由大块到小块的叠加减,从最高位粗调,低位细调得到最终精确的十进制值。并不以二进制方式逐位确定0、1.
求rad_i[51:0],把结果[25:0]的每个bit依次从高到低查询,(以十进制方式)并累加减得到最终结果。
结果可以拆分为
2^25      ± 224±...±21 ±2^0    ±   ±    2^25 ± 2
关键算式:
b_2是b的平方,b表示对应bit的十进制值;
r0_2是r0的平方,r0表示当前结果的十进制值;
(r0 + b)^2 = r0^2 + b^2 + r0b2 = r0_2 + b_2 + r0<<c,r0 + b表示当前结果与下一个要判断的bit代表值的和。
在调整结果和的同时,调整和的平方值,用于与被开方数比较。
总结:
sqrt_shift从开方值一半开始移位相加比较;当前代码不可流水,可修改设计为流水。


```c
-------------------------------------------------------------------------------
--
-- Project:	<Floating Point Unit Core>
--  	
-- Description: square-root entity for the square-root unit
-------------------------------------------------------------------------------

-- 	Author:		 Jidan Al-eryani 
-- 	E-mail: 	 jidan@gmx.net
--
--  Copyright (C) 2006
--
--	This source file may be used and distributed without        
--	restriction provided that this copyright statement is not   
--	removed from the file and that any derivative work contains 
--	the original copyright notice and the associated disclaimer.
--                                                           
--		THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     
--	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   
--	TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   
--	FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      
--	OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         
--	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    
--	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   
--	GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        
--	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  
--	LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  
--	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  
--	OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         
--	POSSIBILITY OF SUCH DAMAGE. 


--把结果[25:0]的每个bit依次从高到低查询,并累加得到最终结果。 结果可以拆分为[25]*2^25 + [24]*2^24 +... +[0]*2^0
--关键算式:b_2是b的平方,b表示对应bit的十进制值;r0_2是r0的平方,r0表示当前结果的十进制值;(r0   + b)^2 = r0^2 + b^2 + r0*b*2 = r0_2 + b_2 + r0<<c,r0   + b表示当前结果与下一个要判断的bit代表值的和。

library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity sqrt_shift is
	generic	(RD_WIDTH: integer:=52; SQ_WIDTH: integer:=26); -- SQ_WIDTH = RD_WIDTH/2 (+ 1 if odd)
	port(
			 clk_i 			 : in std_logic;
			 rad_i			: in std_logic_vector(RD_WIDTH-1 downto 0); -- hidden(1) & fraction(23)
			 start_i			: in std_logic;
			 ready_o			: out std_logic;
			 sqr_o			: out std_logic_vector(SQ_WIDTH-1 downto 0);
			 ine_o			: out std_logic
		);
end sqrt_shift;

architecture rtl of sqrt_shift is

signal s_rad_i: std_logic_vector(RD_WIDTH-1 downto 0);
signal s_start_i, s_ready_o : std_logic;
signal s_sqr_o: std_logic_vector(RD_WIDTH-1 downto 0);
signal s_ine_o : std_logic;

constant ITERATIONS : integer:= RD_WIDTH/2; -- iterations = N/2
constant WIDTH_C : integer:= 5; -- log2(ITERATIONS)
                            							  --0000000000000000000000000000000000000000000000000000
constant CONST_B : std_logic_vector(RD_WIDTH-1 downto 0) :="0000000000000000000000000010000000000000000000000000"; -- b = 2^(N/2 - 1) 最大开方值的一半 0x2000000 * 2 = 0x4000000
constant CONST_B_2: std_logic_vector(RD_WIDTH-1 downto 0):="0100000000000000000000000000000000000000000000000000"; -- b^2 最大开方值的一半 的平方
constant CONST_C : std_logic_vector(WIDTH_C-1 downto 0):= "11010"; -- c = N/2


signal s_count : integer range 0 to ITERATIONS;

type t_state is (waiting,busy);
signal s_state : t_state;

signal b, b_2, r0, r0_2 : std_logic_vector(RD_WIDTH-1 downto 0);
signal c : std_logic_vector(WIDTH_C-1 downto 0);

	signal s_op1, s_op2, s_sum1a, s_sum1b, s_sum2a, s_sum2b : std_logic_vector(RD_WIDTH-1 downto 0);
	
begin


	-- Input Register
	process(clk_i)
	begin
		if rising_edge(clk_i) then	
			s_rad_i <= rad_i;
			s_start_i <= start_i;
		end if;
	end process;	
	
	-- Output Register
	process(clk_i)
	begin
		if rising_edge(clk_i) then	
			sqr_o <= s_sqr_o(SQ_WIDTH-1 downto 0);
			ine_o <= s_ine_o;
			ready_o <= s_ready_o;
		end if;
	end process;


	-- FSM
	process(clk_i)
	begin
		if rising_edge(clk_i) then
			if s_start_i ='1' then
				s_state <= busy;
				s_count <= ITERATIONS; --26 迭代次数为被开方数宽度的一半
			elsif s_count=0 and s_state=busy then
				s_state <= waiting;
				s_ready_o <= '1';--计算完成
				s_count <=ITERATIONS; 
			elsif s_state=busy then
				s_count <= s_count - 1;--长度0~26
			else
				s_state <= waiting;
				s_ready_o <= '0';
			end if;
		end if;	
	end process;

	process(clk_i)
	begin
		if rising_edge(clk_i) then
				if s_start_i='1' then
					b    <= CONST_B;  -- "0000000000000000000000000010000000000000000000000000"; -- b = 2^(N/2 - 1) = 2^25
					b_2  <= CONST_B_2;-- "0100000000000000000000000000000000000000000000000000"; -- b^2 = 2^50    b_2一直是b的平方         
					c    <= CONST_C;  --  26
				else
					b   <= '0' &b  (RD_WIDTH-1 downto 1);-- shr 1 每个clk右移1= /2
					b_2 <= "00"&b_2(RD_WIDTH-1 downto 2);-- shr 2	每个clk右移2= /4
					c   <= c - '1';
				end if;
		end if;
	end process;
	

	-- (r0   + b)^2 = r0^2 + b^2 + r0*b*2 = r0_2 + b_2 + r0<<c
	s_op1 <= r0_2 + b_2;
	s_op2 <= shl(r0, c);--r0左移c位   因为b = 2^(位号 - 1),所以r0*b*2 =r0*2^c 
		
		
	--	r0
	s_sum1a <= "00000000000000000000000000"& (r0(25 downto 0) - b(25 downto 0));
	s_sum2a <= "00000000000000000000000000"& (r0(25 downto 0) + b(25 downto 0));		

  --  r0_2 	> s_rad_i 取	s_sum1b
	s_sum1b <= s_op1 - s_op2;		
	s_sum2b <= s_op1 + s_op2;	



	process(clk_i)
--		variable v_r1, v_r1_2 : std_logic_vector(RD_WIDTH-1 downto 0);
	begin
		if rising_edge(clk_i) then
				if s_start_i='1' then
					r0   <= (others =>'0');
					r0_2 <= (others =>'0');
				elsif s_state=busy then
					
					if r0_2 > s_rad_i then--与被开方数比较,被开方数是一个平方值  平方的乘法运算转换为移位,节省乘法器
						r0   <= s_sum1a;--r0   <= r0   - b
						r0_2 <= s_sum1b;--r0_2 <= r0_2 + b_2 - r0<<c
					else
						r0   <= s_sum2a;--r0   <= r0   + b                                             (r0   + b)^2 = r0^2 + b^2 + r0*b*2 = r0_2 + b_2 + r0<<c
						r0_2 <= s_sum2b;--r0_2 <= r0_2 + b_2 + r0<<c	  初始值为b_2的初值	CONST_B_2		  r0_2是r0的平方值r0<<c = r0*b*2
					end if;
						
						
--					r0   <= v_r1;
--					r0_2 <= v_r1_2;
--					r0   <= v_r1;
--					r0_2 <= v_r1_2;
				end if;
		end if;
	end process;
	
	process(clk_i)
	begin
		if rising_edge(clk_i) then
			if s_start_i = '1' then
				s_sqr_o <= (others =>'0');
			elsif s_count=0 then
						if r0_2 > s_rad_i then--判定最后一个[0]bit
							s_sqr_o <= r0 - '1';
						else
							s_sqr_o <= r0;--最终结果
						end if;		
			end if;
		end if;
	end process;
	
	
	-- check if result is inexact. In this way we saved 1 clk cycle!
	process(clk_i)
		variable v_r1_2 : std_logic_vector(RD_WIDTH-1 downto 0);
	begin
		if rising_edge(clk_i) then
			v_r1_2 := r0_2 - (r0(RD_WIDTH-2 downto 0)&"0") + '1';-- = r0_2 + 1^2 - (r0(RD_WIDTH-2 downto 0)&"0") = ( r0 - 1)^2
			if s_count=0 then				
				if r0_2 = s_rad_i or v_r1_2=s_rad_i then--r0^2( r0 - 1)^2
					s_ine_o <= '0';--正好开方完,没有余数
				else
					s_ine_o <= '1';
				end if;
			end if;
			
		end if;
	end process;				
	
end rtl;

仿真时序如下:
在这里插入图片描述

3、安路TD软件自带的开方IP

精度准确,可流水计算。其原理与逐位比较-十进制 相同,改进为流水计算。
在这里插入图片描述

4、安路TD软件自带的CORDIC算复数有效值、角度

极坐标方式计算膜误差很大,当膜本身很大时,误差小,角度值计算误差也小。

在这里插入图片描述
角度=scaled_radians_angle/2^32*180。
当角度的模式选择为radians时,值是scaled的π倍。1064850062/338952294=3.14159
在这里插入图片描述
在这里插入图片描述

5、开源CORDIC算法

《基于FPGA的CORDIC算法实现——Verilog版》 本文对CORDIC算法的原理做了详细的介绍
基本原理是坐标旋转,把角度分为16份,从45°开始通过16次迭代逼近,最终结果用系数做校正。
(采用20次迭代与16次精度相差不大,个别情况误差更大,可能因为在终点的震荡导致)
在这里插入图片描述在这里插入图片描述

/*
角度增加小数点后位数,对结果影响不大,按四舍五入,都能保证结果的小数点后4位正确。

结果延时18个clk出现,如cnt=1出现输入,则cnt=19时出现结果

优化原理:将旋转角θ细化成若干分固定大小的角度θi,并且规定θi满足tanθi = 2-i,因此∑θi的值在[-99.7°,99.7°]范围内,
          如果旋转角θ超出此范围,则运用简单的三角运算操作即可(加减π)
          
旋转方向:如果旋转角已经大于θ,则di为-1,表示下次旋转为顺时针,即向θ靠近;如果旋转角已经小于θ,则di为1,表示下次旋转为逆时针,即也向θ靠近


tanθi = 2-i,

xi+1 = xi – di yi 2-i,提取了cosθi,2-i等效替换了tanθi之后  
yi+1 = yi + di xi 2-i,提取了cosθi,2-i等效替换了tanθi之后  
zi+1 = zi - di θi    ,表示旋转后剩余的角度值

计算cos.sin:
     di 与 zi符号相同,同为负号,或正号; di取值+1,或-1。
     设置x0 = ∏cosθi,y[0] = 0,z[0] = phase,则根据等式,xn = cosθ,yn = sinθ。其中∏cosθi表示余弦值的累乘,并预先存入系统中。
 
 
     
计算角度、膜时:
		di 符号与 yi不同。
		设置迭代次数为16,则x0 = x,y[0] = y,z[0] = 0,di与yi的符号相反。表示,经过n次旋转,使Pn靠近x轴
		就算出了反正切函数zn = θ = arctan(y/x),以及向量OP0(x,y)的长度 d = xn * ∏cosθi。  
    yn越来越小逼近0,xn越来越大逼近膜, zn越来越大逼近真实角度。

根据精度需要,对角度值放大2^n,设置迭代次数(满足tanθi = 2-i即可)


>>> 算数右移,有符号数的高位自动补符号位。


*/

module Cordic_Sqrt
(
    CLK_50M,RST_N,
    Phase,Quadrant_in,
    Sin,Cos,Error,
    x_in,y_in,angle,length
);

input                       CLK_50M;
input                       RST_N;
input       [31:0]          Phase;//[15:0]表示角度
input       [1:0]           Quadrant_in;//表示象限
output      [31:0]          Sin;
output      [31:0]          Cos;
output      [31:0]          Error;//剩余的角度误差

input      [31:0]          x_in;
input      [31:0]          y_in; 
output  reg   [31:0]          angle; //          最终要 /2^16
output  reg   [31:0]          length;// 向量的膜,最终要 *∏cosθi

/*
  `define rot0  32'd2949120       //45度*2^16

//`define rot1  32'd1740992       //26.5651度*2^16
	`define rot1  32'd1740967       //26.5650511771度*2^16
	
//`define rot2  32'd919872        //14.0362度*2^16
	`define rot2  32'd919879        //14.0362434679度*2^16
	
//`define rot3  32'd466944        //7.1250度*2^16
	`define rot3  32'd466945        //7.1250163489度*2^16
	
//`define rot4  32'd234368        //3.5763度*2^16
	`define rot4  32'd234379        //3.5763343750度*2^16
	
//`define rot5  32'd117312        //1.7899度*2^16
	`define rot5  32'd117304        //1.7899106082度*2^16
	
//`define rot6  32'd58688         //0.8952度*2^16
	`define rot6  32'd58666         //0.8951737102度*2^16
	
//`define rot7  32'd29312         //0.4476度*2^16
	`define rot7  32'd29335         //0.4476141709度*2^16
	
//`define rot8  32'd14656         //0.2238度*2^16
	`define rot8  32'd14668         //0.2238105004度*2^16
	
//`define rot9  32'd7360          //0.1119度*2^16
	`define rot9  32'd7334          //0.1119056771度*2^16
	
//`define rot10 32'd3648          //0.0560度*2^16
	`define rot10 32'd3667          //0.05595289189度*2^16

//`define rot11 32'd1856          //0.0280度*2^16
	`define rot11 32'd1833          //0.02797645262度*2^16

//`define rot12 32'd918           //0.0140度*2^16      原来的896计算错误应为918
	`define rot12 32'd917           //0.01398822714度*2^16

//`define rot13 32'd448           //0.0070度*2^16
	`define rot13 32'd458           //0.006994113675度*2^16

//`define rot14 32'd256           //0.0035度*2^16
	`define rot14 32'd229           //0.003497056851度*2^16

//`define rot15 32'd118           //0.0018度*2^16        原来的128计算错误应为118
	`define rot15 32'd115           //0.001748528427度*2^16

	`define rot16 32'd57            //0.0008742642137度*2^16
	`define rot17 32'd29            //0.00043713210687度*2^16
	`define rot18 32'd14            //0.000218566053439度*2^16
	`define rot19 32'd7           //0.00010928302672度*2^16	
			
*/
  `define rot0  32'd2949120       //45度*2^16

 
	`define rot1  32'd1740967       //26.5650511771度*2^16
	
 
	`define rot2  32'd919879        //14.0362434679度*2^16
	
 
	`define rot3  32'd466945        //7.1250163489度*2^16
	
 
	`define rot4  32'd234379        //3.5763343750度*2^16
	

	`define rot5  32'd117304        //1.7899106082度*2^16
	

	`define rot6  32'd58666         //0.8951737102度*2^16
	

	`define rot7  32'd29335         //0.4476141709度*2^16
	
	`define rot8  32'd14668         //0.2238105004度*2^16
	
	`define rot9  32'd7334          //0.1119056771度*2^16
	
	`define rot10 32'd3667          //0.05595289189度*2^16

	`define rot11 32'd1833          //0.02797645262度*2^16

	`define rot12 32'd917           //0.01398822714度*2^16

	`define rot13 32'd458           //0.006994113675度*2^16

	`define rot14 32'd229           //0.003497056851度*2^16

	`define rot15 32'd115           //0.001748528427度*2^16

	`define rot16 32'd57            //0.0008742642137度*2^16
	`define rot17 32'd29            //0.00043713210687度*2^16
	`define rot18 32'd14            //0.000218566053439度*2^16
	`define rot19 32'd7           //0.00010928302672度*2^16	
	
parameter Pipeline = 16;//20
parameter K = 32'h09b75;    //K=0.6072529351*2^16,32'd39797, 16次迭代,20次迭代都一样	

reg signed  [31:0]      Sin;
reg signed  [31:0]      Cos;
reg signed  [31:0]      Error;
reg signed  [31:0]      x[0:Pipeline];
reg signed  [31:0]      y[0:Pipeline];
reg signed  [31:0]      z[0:Pipeline];

//reg signed  [31:0]      x[0]=0,y[0]=0,z[0]=0;
//reg signed  [31:0]      x[1]=0,y[1]=0,z[1]=0;
//reg signed  [31:0]      x[2]=0,y[2]=0,z[2]=0;
//reg signed  [31:0]      x[3]=0,y[3]=0,z[3]=0;
//reg signed  [31:0]      x[4]=0,y[4]=0,z[4]=0;
//reg signed  [31:0]      x[5]=0,y[5]=0,z[5]=0;
//reg signed  [31:0]      x[6]=0,y[6]=0,z[6]=0;
//reg signed  [31:0]      x[7]=0,y[7]=0,z[7]=0;
//reg signed  [31:0]      x[8]=0,y[8]=0,z[8]=0;
//reg signed  [31:0]      x[9]=0,y[9]=0,z[9]=0;
//reg signed  [31:0]      x[10]=0,y[10]=0,z[10]=0;
//reg signed  [31:0]      x[11]=0,y[11]=0,z[11]=0;
//reg signed  [31:0]      x[12]=0,y[12]=0,z[12]=0;
//reg signed  [31:0]      x[13]=0,y[13]=0,z[13]=0;
//reg signed  [31:0]      x[14]=0,y[14]=0,z[14]=0;
//reg signed  [31:0]      x[15]=0,y[15]=0,z[15]=0;
//reg signed  [31:0]      x[16]=0,y[16]=0,z[16]=0;
//
//reg signed  [31:0]      x[17]=0,y[17]=0,z[17]=0;
//reg signed  [31:0]      x[18]=0,y[18]=0,z[18]=0;
//reg signed  [31:0]      x[19]=0,y[19]=0,z[19]=0;
//reg signed  [31:0]      x[20]=0,y[20]=0,z[20]=0;


reg         [ 1:0]      Quadrant [Pipeline:0];

always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
    begin
        x[0] <= 1'b0;                         
        y[0] <= 1'b0;
        z[0] <= 1'b0;
    end
    else
    begin
//计算 cos sin的初值    	
//        x[0] <= K;
//        y[0] <= 32'd0;
//        z[0] <= Phase[15:0] << 16;

//计算角度,膜的初值
        x[0] <= x_in;
        y[0] <= y_in;
        z[0] <= 0;

    end
end

always @ (posedge CLK_50M or negedge RST_N)//0
begin
    if(!RST_N)
    begin
        x[1] <= 1'b0;                         
        y[1] <= 1'b0;
        z[1] <= 1'b0;
    end
//    else if(z[0][31])//1为负数 di 符号同 zi   剩余角度<0,+
	  else if(!y[0][31])// di 符号不同 yi
    begin
      x[1] <= x[0] + y[0];
      y[1] <= y[0] - x[0];
      z[1] <= z[0] + `rot0;
    end
    else
    begin  //剩余角度>0,继续- 逼近0
      x[1] <= x[0] - y[0];
      y[1] <= y[0] + x[0];
      z[1] <= z[0] - `rot0;
    end
end

always @ (posedge CLK_50M or negedge RST_N)//1
begin
    if(!RST_N)
    begin
        x[2] <= 1'b0;                         
        y[2] <= 1'b0;
        z[2] <= 1'b0;
    end
//    else if(z[1][31])
    else if(!y[1][31])
   begin
        x[2] <= x[1] + (y[1] >>> 1);//设计中使用了移位,当输入越大时,计算误差越小
        y[2] <= y[1] - (x[1] >>> 1);
        z[2] <= z[1] + `rot1;
   end
   else
   begin
       x[2] <= x[1] - (y[1] >>> 1);
       y[2] <= y[1] + (x[1] >>> 1);
       z[2] <= z[1] - `rot1;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//2
begin
    if(!RST_N)
    begin
        x[3] <= 1'b0;                         
        y[3] <= 1'b0;
        z[3] <= 1'b0;
    end
//    else if(z[2][31])
    else if(!y[2][31])
   begin
       x[3] <= x[2] + (y[2] >>> 2);
       y[3] <= y[2] - (x[2] >>> 2);
       z[3] <= z[2] + `rot2;
   end
   else
   begin
       x[3] <= x[2] - (y[2] >>> 2);
       y[3] <= y[2] + (x[2] >>> 2);
       z[3] <= z[2] - `rot2;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//3
begin
    if(!RST_N)
    begin
        x[4] <= 1'b0;                         
        y[4] <= 1'b0;
        z[4] <= 1'b0;
    end
//    else if(z[3][31])
    else if(!y[3][31])
   begin
       x[4] <= x[3] + (y[3] >>> 3);
       y[4] <= y[3] - (x[3] >>> 3);
       z[4] <= z[3] + `rot3;
   end
   else
   begin
       x[4] <= x[3] - (y[3] >>> 3);
       y[4] <= y[3] + (x[3] >>> 3);
       z[4] <= z[3] - `rot3;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//4
begin
    if(!RST_N)
    begin
        x[5] <= 1'b0;                         
        y[5] <= 1'b0;
        z[5] <= 1'b0;
    end
//    else if(z[4][31])
    else if(!y[4][31])
   begin
       x[5] <= x[4] + (y[4] >>> 4);
       y[5] <= y[4] - (x[4] >>> 4);
       z[5] <= z[4] + `rot4;
   end
   else
   begin
       x[5] <= x[4] - (y[4] >>> 4);
       y[5] <= y[4] + (x[4] >>> 4);
       z[5] <= z[4] - `rot4;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//5
begin
    if(!RST_N)
    begin
        x[6] <= 1'b0;                         
        y[6] <= 1'b0;
        z[6] <= 1'b0;
    end
//    else if(z[5][31])
    else if(!y[5][31])
   begin
       x[6] <= x[5] + (y[5] >>> 5);
       y[6] <= y[5] - (x[5] >>> 5);
       z[6] <= z[5] + `rot5;
   end
   else
   begin
       x[6] <= x[5] - (y[5] >>> 5);
       y[6] <= y[5] + (x[5] >>> 5);
       z[6] <= z[5] - `rot5;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//6
begin
    if(!RST_N)
    begin
        x[7] <= 1'b0;                         
        y[7] <= 1'b0;
        z[7] <= 1'b0;
    end
//    else if(z[6][31])
    else if(!y[6][31])
   begin
       x[7] <= x[6] + (y[6] >>> 6);
       y[7] <= y[6] - (x[6] >>> 6);
       z[7] <= z[6] + `rot6;
   end
   else
   begin
       x[7] <= x[6] - (y[6] >>> 6);
       y[7] <= y[6] + (x[6] >>> 6);
       z[7] <= z[6] - `rot6;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//7
begin
    if(!RST_N)
    begin
        x[8] <= 1'b0;                         
        y[8] <= 1'b0;
        z[8] <= 1'b0;
    end
//    else if(z[7][31])
    else if(!y[7][31])
   begin
       x[8] <= x[7] + (y[7] >>> 7);
       y[8] <= y[7] - (x[7] >>> 7);
       z[8] <= z[7] + `rot7;
   end
   else
   begin
       x[8] <= x[7] - (y[7] >>> 7);
       y[8] <= y[7] + (x[7] >>> 7);
       z[8] <= z[7] - `rot7;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//8
begin
    if(!RST_N)
    begin
        x[9] <= 1'b0;                         
        y[9] <= 1'b0;
        z[9] <= 1'b0;
    end
//    else if(z[8][31])
    else if(!y[8][31])
   begin
       x[9] <= x[8] + (y[8] >>> 8);
       y[9] <= y[8] - (x[8] >>> 8);
       z[9] <= z[8] + `rot8;
   end
   else
   begin
       x[9] <= x[8] - (y[8] >>> 8);
       y[9] <= y[8] + (x[8] >>> 8);
       z[9] <= z[8] - `rot8;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//9
begin
    if(!RST_N)
    begin
        x[10] <= 1'b0;                        
        y[10] <= 1'b0;
        z[10] <= 1'b0;
    end
//    else if(z[9][31])
    else if(!y[9][31])
   begin
       x[10] <= x[9] + (y[9] >>> 9);
       y[10] <= y[9] - (x[9] >>> 9);
       z[10] <= z[9] + `rot9;
   end
   else
   begin
       x[10] <= x[9] - (y[9] >>> 9);
       y[10] <= y[9] + (x[9] >>> 9);
       z[10] <= z[9] - `rot9;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//10
begin
    if(!RST_N)
    begin
        x[11] <= 1'b0;                        
        y[11] <= 1'b0;
        z[11] <= 1'b0;
    end
//    else if(z[10][31])
    else if(!y[10][31])
   begin
       x[11] <= x[10] + (y[10] >>> 10);
       y[11] <= y[10] - (x[10] >>> 10);
       z[11] <= z[10] + `rot10;
   end
   else
   begin
       x[11] <= x[10] - (y[10] >>> 10);
       y[11] <= y[10] + (x[10] >>> 10);
       z[11] <= z[10] - `rot10;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//11
begin
    if(!RST_N)
    begin
        x[12] <= 1'b0;                        
        y[12] <= 1'b0;
        z[12] <= 1'b0;
    end
//    else if(z[11][31])
    else if(!y[11][31])
   begin
       x[12] <= x[11] + (y[11] >>> 11);
       y[12] <= y[11] - (x[11] >>> 11);
       z[12] <= z[11] + `rot11;
   end
   else
   begin
       x[12] <= x[11] - (y[11] >>> 11);
       y[12] <= y[11] + (x[11] >>> 11);
       z[12] <= z[11] - `rot11;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//12
begin
    if(!RST_N)
    begin
        x[13] <= 1'b0;                        
        y[13] <= 1'b0;
        z[13] <= 1'b0;
    end
//    else if(z[12][31])
    else if(!y[12][31])
   begin
       x[13] <= x[12] + (y[12] >>> 12);
       y[13] <= y[12] - (x[12] >>> 12);
       z[13] <= z[12] + `rot12;
   end
   else
   begin
       x[13] <= x[12] - (y[12] >>> 12);
       y[13] <= y[12] + (x[12] >>> 12);
       z[13] <= z[12] - `rot12;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//13
begin
    if(!RST_N)
    begin
        x[14] <= 1'b0;                        
        y[14] <= 1'b0;
        z[14] <= 1'b0;
    end
//    else if(z[13][31])
    else if(!y[13][31])
   begin
       x[14] <= x[13] + (y[13] >>> 13);
       y[14] <= y[13] - (x[13] >>> 13);
       z[14] <= z[13] + `rot13;
   end
   else
   begin
       x[14] <= x[13] - (y[13] >>> 13);
       y[14] <= y[13] + (x[13] >>> 13);
       z[14] <= z[13] - `rot13;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//14
begin
    if(!RST_N)
    begin
        x[15] <= 1'b0;                        
        y[15] <= 1'b0;
        z[15] <= 1'b0;
    end
//    else if(z[14][31])
    else if(!y[14][31])
   begin
       x[15] <= x[14] + (y[14] >>> 14);
       y[15] <= y[14] - (x[14] >>> 14);
       z[15] <= z[14] + `rot14;
   end
   else
   begin
       x[15] <= x[14] - (y[14] >>> 14);
       y[15] <= y[14] + (x[14] >>> 14);
       z[15] <= z[14] - `rot14;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//15
begin
    if(!RST_N)
    begin
        x[16] <= 1'b0;                        
        y[16] <= 1'b0;
        z[16] <= 1'b0;
    end
//    else if(z[15][31])
    else if(!y[15][31])
   begin
       x[16] <= x[15] + (y[15] >>> 15);
       y[16] <= y[15] - (x[15] >>> 15);
       z[16] <= z[15] + `rot15;
   end
   else
   begin
       x[16] <= x[15] - (y[15] >>> 15);
       y[16] <= y[15] + (x[15] >>> 15);
       z[16] <= z[15] - `rot15;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//16
begin
    if(!RST_N)
    begin
        x[17] <= 1'b0;                        
        y[17] <= 1'b0;
        z[17] <= 1'b0;
    end
//    else if(z[16][31])
    else if(!y[16][31])
   begin
       x[17] <= x[16] + (y[16] >>> 16);
       y[17] <= y[16] - (x[16] >>> 16);
       z[17] <= z[16] + `rot16;
   end
   else
   begin
       x[17] <= x[16] - (y[16] >>> 16);
       y[17] <= y[16] + (x[16] >>> 16);
       z[17] <= z[16] - `rot16;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//17
begin
    if(!RST_N)
    begin
        x[18] <= 1'b0;                        
        y[18] <= 1'b0;
        z[18] <= 1'b0;
    end
//    else if(z[17][31])
    else if(!y[17][31])
   begin
       x[18] <= x[17] + (y[17] >>> 17);
       y[18] <= y[17] - (x[17] >>> 17);
       z[18] <= z[17] + `rot17;
   end
   else
   begin
       x[18] <= x[17] - (y[17] >>> 17);
       y[18] <= y[17] + (x[17] >>> 17);
       z[18] <= z[17] - `rot17;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//18
begin
    if(!RST_N)
    begin
        x[19] <= 1'b0;                        
        y[19] <= 1'b0;
        z[19] <= 1'b0;
    end
//    else if(z[18][31])
    else if(!y[18][31])
   begin
       x[19] <= x[18] + (y[18] >>> 18);
       y[19] <= y[18] - (x[18] >>> 18);
       z[19] <= z[18] + `rot18;
   end
   else
   begin
       x[19] <= x[18] - (y[18] >>> 18);
       y[19] <= y[18] + (x[18] >>> 18);
       z[19] <= z[18] - `rot18;
   end
end

always @ (posedge CLK_50M or negedge RST_N)//19
begin
    if(!RST_N)
    begin
        x[20] <= 1'b0;                        
        y[20] <= 1'b0;
        z[20] <= 1'b0;
    end
//    else if(z[19][31])
    else if(!y[19][31])
   begin
       x[20] <= x[19] + (y[19] >>> 19);
       y[20] <= y[19] - (x[19] >>> 19);
       z[20] <= z[19] + `rot19;
   end
   else
   begin
       x[20] <= x[19] - (y[19] >>> 19);
       y[20] <= y[19] + (x[19] >>> 19);
       z[20] <= z[19] - `rot19;
   end
end




always @ (posedge CLK_50M or negedge RST_N)//out
begin
    if(!RST_N)
    begin
        Quadrant[0] <= 1'b0;
        Quadrant[1] <= 1'b0;
        Quadrant[2] <= 1'b0;
        Quadrant[3] <= 1'b0;
        Quadrant[4] <= 1'b0;
        Quadrant[5] <= 1'b0;
        Quadrant[6] <= 1'b0;
        Quadrant[7] <= 1'b0;
        Quadrant[8] <= 1'b0;
        Quadrant[9] <= 1'b0;
        Quadrant[10] <= 1'b0;
        Quadrant[11] <= 1'b0;
        Quadrant[12] <= 1'b0;
        Quadrant[13] <= 1'b0;
        Quadrant[14] <= 1'b0;
        Quadrant[15] <= 1'b0;
        Quadrant[16] <= 1'b0;
        
        Quadrant[17] <= 1'b0;
        Quadrant[18] <= 1'b0;
        Quadrant[19] <= 1'b0;
        Quadrant[20] <= 1'b0;
    end
    else
    begin
//        Quadrant[0] <= Phase[17:16];
        Quadrant[0] <= Quadrant_in;
        Quadrant[1] <= Quadrant[0];
        Quadrant[2] <= Quadrant[1];
        Quadrant[3] <= Quadrant[2];
        Quadrant[4] <= Quadrant[3];
        Quadrant[5] <= Quadrant[4];
        Quadrant[6] <= Quadrant[5];
        Quadrant[7] <= Quadrant[6];
        Quadrant[8] <= Quadrant[7];
        Quadrant[9] <= Quadrant[8];
        Quadrant[10] <= Quadrant[9];
        Quadrant[11] <= Quadrant[10];
        Quadrant[12] <= Quadrant[11];
        Quadrant[13] <= Quadrant[12];
        Quadrant[14] <= Quadrant[13];
        Quadrant[15] <= Quadrant[14];
        Quadrant[16] <= Quadrant[15];
        
        Quadrant[17] <= Quadrant[16];
        Quadrant[18] <= Quadrant[17];
        Quadrant[19] <= Quadrant[18];
        Quadrant[20] <= Quadrant[19];               
        
    end
end

/*
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
    begin
        Cos <=  0;
        Sin <=  0;
        Error <=  0;
    end
    else
    begin
        Error <= z[Pipeline];
        case(Quadrant[Pipeline])//16
            2'b00: //if the Phase is in first Quadrant,the Sin(X)=Sin(A),Cos(X)=Cos(A)
                begin
                    Cos <= x[Pipeline];
                    Sin <= y[Pipeline];
                end
            2'b01: //if the Phase is in second Quadrant,the Sin(X)=Sin(A+90)=CosA,Cos(X)=Cos(A+90)=-SinA
                begin
                    Cos <= ~(y[Pipeline]) + 1'b1;//-Sin
                    Sin <= x[Pipeline];//Cos
                end
            2'b10: //if the Phase is in third Quadrant,the Sin(X)=Sin(A+180)=-SinA,Cos(X)=Cos(A+180)=-CosA
                begin
                    Cos <= ~(x[Pipeline]) + 1'b1;//-Cos
                    Sin <= ~(y[Pipeline]) + 1'b1;//-Sin
                end
            2'b11: //if the Phase is in forth Quadrant,the Sin(X)=Sin(A+270)=-CosA,Cos(X)=Cos(A+270)=SinA
                begin
                    Cos <= y[Pipeline];//Sin
                    Sin <= ~(x[Pipeline]) + 1'b1;//-Cos
                end
        endcase
    end
end
*/

always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
    begin
        angle <=  0;
        length     <=  0;
        Error <=  0;
    end
    else
    begin
        Error  <= y[Pipeline];
        length <= x[Pipeline];//最终要 *∏cosθi
        angle  <= z[Pipeline];
//        case(Quadrant[Pipeline])//20
//            2'b00: //if the Phase is in first Quadrant,the Sin(X)=Sin(A),Cos(X)=Cos(A)
//                begin
//                    angle  <= z[Pipeline]; //最终/2^16                   
//                end
//            2'b01: //if the Phase is in second Quadrant,the Sin(X)=Sin(A+90)=CosA,Cos(X)=Cos(A+90)=-SinA
//                begin
//                    angle <= z[Pipeline] + 32'd90<<16;//-Sin
//                end
//            2'b10: //if the Phase is in third Quadrant,the Sin(X)=Sin(A+180)=-SinA,Cos(X)=Cos(A+180)=-CosA
//                begin
//                    angle <= z[Pipeline] + 32'd180<<16;//-Cos
//                end
//            2'b11: //if the Phase is in forth Quadrant,the Sin(X)=Sin(A+270)=-CosA,Cos(X)=Cos(A+270)=SinA
//                begin
//                    angle <= z[Pipeline] + 32'd270<<16;//Sin
//                end
//        endcase
    end
end
endmodul

6、仿真 对比TD CORDIC与开源CORDIC精度

结论:在被开方数在百万级时,两者误差率都不超过1/1000,开源精度更高。角度计算值两者基本相等,相差大约0.01°左右。两者的计算结果都与TD的开方IP结果对比。
开源算法的误差检查代码:
在这里插入图片描述
TD CORDIC误差检查:
在这里插入图片描述
误差仿真:TD的误差稍大一些。
在这里插入图片描述
开源CORDIC算法的细节:
在这里插入图片描述
TD CORDIC的算法细节:
在这里插入图片描述
角度计算值两者对比:
在这里插入图片描述

`timescale 1 ns/ 1 ns

module Cordic_Sqrt_tb;
glbl glbl();
// Inputs
reg                         CLK_50M;
reg                         RST_N;
reg             [31:0]      cnt;
reg             [31:0]      cnt_n;
reg             [31:0]      Phase;
reg             [31:0]      Phase_n;
wire            [31:0]      Sin;
wire            [31:0]      Cos;
wire            [31:0]      Error;

reg            [33:0] x;
reg            [33:0] y;
reg            [1:0] Quadrant_in;
wire           [31:0] angle;
wire           [31:0] length;

wire           [33:0]  rout_td;
wire           [34:0]  angle_td;
wire                   done_td	;
reg                   start_td =0 ;




			 wire  [51:0]	rad_i	   	;//: in std_logic_vector(RD_WIDTH-1 downto 0); -- hidden(1) & fraction(23)
			 wire          start_i	 ;
			 wire         ready_o	;
			 wire [25:0]  sqr_o		;
			 wire         ine_o		;

			 wire         done_o	;
			 wire [48:0]  sqrt_o		;
			 reg   [51:0]	rad_ishift;
			 reg          start_ishift	 ;

//TD 软件自带的开方IP,精度准确			--------------------------------------------------------------------- 

tdcordic_sqrt  tdcordic_sqrt
(
    .clk 	  (CLK_50M),
    .num	  (rad_i),//  input [48:0] num;
    .rst		(!RST_N),
    .start  (start_td),
    .done   (done_o),
    .sqrt	  (sqrt_o)//  output [48:0] sqrt;[48:24]为整数值,[23:0]可能为小数

);

reg           [31:0] td_sqrt;
reg           [31:0] td_sqrt_temp [0:11];
//assign length_temp[0]=length * 0.6072529351;

always @ (posedge CLK_50M )	
	begin
		td_sqrt_temp[0] <= sqrt_o[48:24];//取整数
		td_sqrt_temp[1] <= td_sqrt_temp[0];
		td_sqrt_temp[2] <= td_sqrt_temp[1];
		td_sqrt_temp[3] <= td_sqrt_temp[2];
		td_sqrt_temp[4] <= td_sqrt_temp[3];
		td_sqrt         <= td_sqrt_temp[4];   //打拍与TD软件的输出对齐,便于对比    		
	end
	
	
//TD 软件自带的坐标旋转IP			--------------------------------------------------------------------- 	
 cordic cordic//TD 极坐标
(
    .clk 	  (CLK_50M),
    .xin	  (x),
    .yin    (y ),
    .rst(!RST_N),
    .start   (start_td),
    .done   (done_td),
    .rout	  (rout_td),
    .angle  (angle_td)

);   
//检查TD 极坐标 IP误差
 wire [31:0]tderror_rate,tderror_num;                 
wire       tderror_bit,tdnum_bit;                             
assign tderror_num =   (rout_td > td_sqrt) ? (rout_td - td_sqrt) : (td_sqrt - rout_td);//与TD 开方IP结果对比
assign tdnum_bit =     (tderror_num >= 6) ? 1 : 0;   //实际误差>6给出高电平,便于观察

assign tderror_rate =   (tderror_num* 100000)/td_sqrt;
assign tderror_bit =    (tderror_rate >= 1) ? 1 : 0;   //误差率>   0.01/1000 给出标志

wire           [63:0]  angle_td_final,angle_td_final1,angle_td_final2;
assign angle_td_final1 = angle_td * 180 * 100    ;//IP 计算角度值 = angle_td * 180 * 100 /3.1415926 /2^32
assign angle_td_final2 = angle_td_final1/3.1415926  ;//合在一起写算式计算不正确,分开写。
assign angle_td_final  = angle_td_final2 >> 32;     	

// Instantiate the Unit Under Test (UUT) --------------------------------------------------------------------- 
Cordic_Sqrt                 uut //自研极坐标转换
(
    .CLK_50M                (CLK_50M    ),
    .RST_N                  (RST_N      ),
    .Phase                  (Phase      ),
    .Sin                    (Sin        ),
    .Cos                    (Cos        ),
    .Error                  (Error      ),
    .x_in(x),
    .y_in(y),
    .angle(angle),
    .length(length),
    .Quadrant_in(Quadrant_in)
);

reg           [31:0] real_length,real_angle;
reg           [31:0] length_temp [0:11];
reg           [31:0] angle_temp [0:11];

//assign length_temp[0]=length * 0.6072529351;

      always @ (posedge CLK_50M )	
      	begin
      		length_temp[0] <= length * 0.6072529351;
      		length_temp[1] <= length_temp[0];
      		length_temp[2] <= length_temp[1];
      		length_temp[3] <= length_temp[2];
      		length_temp[4] <= length_temp[3];
      		length_temp[5] <= length_temp[4];
      		length_temp[6] <= length_temp[5];
      		length_temp[7] <= length_temp[6];
      		length_temp[8] <= length_temp[7];
      		length_temp[9] <= length_temp[8];
      		real_length     <= length_temp[9]; //打拍与TD 结果sqrt_o 对齐
      		     		
       		angle_temp[0] <= angle*100 /   65536  ;//角度放大100倍,便于观察精度
      		angle_temp[1] <= angle_temp[0];
      		angle_temp[2] <= angle_temp[1];
      		angle_temp[3] <= angle_temp[2];
      		angle_temp[4] <= angle_temp[3];
      		angle_temp[5] <= angle_temp[4];
      		angle_temp[6] <= angle_temp[5];
      		angle_temp[7] <= angle_temp[6];
      		angle_temp[8] <= angle_temp[7];
      		angle_temp[9] <= angle_temp[8];
      		real_angle    <= angle_temp[9];  //打拍与TD 结果sqrt_o 对齐    		     		
      	end
      	
      	
//检查自研 极坐标IP误差
wire [31:0]error_rate,error_num;
wire       error_bit,num_bit;

assign error_num =   (real_length > sqrt_o[48:24]) ? (real_length - sqrt_o[48:24]) : (sqrt_o[48:24] - real_length);//实际误差
assign num_bit =      (error_num >= 6) ? 1 : 0; //实际误差>6给出高电平,便于观察

assign error_rate =   (error_num* 100000)/sqrt_o[48:24] ;//误差率放大100000倍
assign error_bit =    (error_rate >= 1) ? 1 : 0;				//误差率>   0.01/1000 给出标志

      	

//-移位累加减开方-------------------------------------------------------------------- 
sqrt_shift sqrt_shift
(
    .clk_i 	  (CLK_50M),
    .rad_i	  (rad_ishift),
    .start_i  (start_ishift),
    .ready_o  (ready_o),
    .sqr_o	  (sqr_o),
    .ine_o	  (ine_o)

);

//-------------------------------------------------------------------- 
initial
begin
    #0 CLK_50M = 1'b0;
       RST_N = 1'b0;
       x=34'd2_000_000;
       y=34'd  000_000;
       Quadrant_in=0;
		#6 RST_N = 1'b1;
//    #10000 $stop;
end 

always #10 
begin
    CLK_50M = ~CLK_50M;
end

always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        cnt <= 1'b0;
    else
        cnt <= cnt_n;
end

always @ ( * )
begin
    if(cnt == 16'd359)
        cnt_n = 1'b0;
    else
        cnt_n = cnt + 1'b1;
end

//生成相位0-359度,Phase[17:16]为相位的象限,Phase[15:0]为相位的值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        Phase <= 1'b0;
    else
        Phase <= Phase_n;
end

//assign      start_i = (cnt == 16'd3 ) ? 1 : 0;
assign rad_i = x*x + y*y;
always @ ( posedge CLK_50M )//在0~90度范围内测试精度
begin
	    if(cnt >= 16'd4 && cnt <= 16'd364) begin
      	start_td <= 1;    	
      
 //     	rad_i   <= (x + 34'd480)*(x + 34'd480) + (y + 34'd120)*(y + 34'd120);//准确开根号IP
  
        x <=  x - 34'd2857;//两种极坐标转换
        y <=  y + 34'd2243;
        Quadrant_in <= 2'b00;
      	end
      else
      		start_td <= 0; 
      		
     if(cnt == 16'd4) begin
    	
      rad_ishift   <= 52'd3988585193498;//sqrt_shift 模块专用
      start_ishift <= 1;
      end
    else
            start_ishift <= 0;
/* 
    if(cnt == 16'd4) begin
    	
      rad_i   <= 52'd1000_0000;
      start_i <= 1;
      start_td <= 1;
        x <= 34'd480;
        y <= 34'd120;
        Quadrant_in <= 2'b00;
      end
    else if(cnt == 16'd5) begin
    	
//    	  start_i <= 0;
      rad_i   <= 52'd41000000;
       start_td <= 1;//计算极坐标数据有效
        x <= 34'd1000;
        y <= 34'd3000;
        Quadrant_in <= 2'b01;
      end
    else if(cnt == 16'd6) begin
    	  start_i <= 0;  
    	   start_td <= 1;  	
        x <= 34'd5000;
        y <= 34'd4000;
        Quadrant_in <= 2'b10;
      end

    else if(cnt == 16'd7) begin
    	start_td <= 1;  
        x <= 34'h07ff_ffff;
        y <= 34'h07ff_ffff;
        Quadrant_in <= 2'b11;
      end
    else
     start_td <= 0;
     */
end

//always @ ( posedge CLK_50M )
//begin
//    if(cnt <= 16'd90) begin
//        x <= cnt<<4;
//        y <= cnt + 16'd90;
//        Quadrant_in <= 2'b00;
//      end
//    else if(cnt > 16'd90 && cnt <= 16'd180) begin
//        x <= cnt;
//        y <= cnt + 16'd180;
//        Quadrant_in <= 2'b01;
//      end
//    else if(cnt > 16'd180 && cnt <= 16'd270) begin
//        x <= cnt;
//        y <= cnt + 16'd270;
//        Quadrant_in <= 2'b10;
//      end
//    else if(cnt > 16'd270) begin
//        x <= cnt;
//        y <= cnt + 16'd360;
//        Quadrant_in <= 2'b11;
//      end
//end


/*
initial
begin
    #0 CLK_50M = 1'b0;
       RST_N = 1'b0;
//    #10000 RST_N = 1'b0;
//    #10000 RST_N = 1'b1;
		#6000 RST_N = 1'b1;
    #10000000 $stop;
end 

always #10000 
begin
    CLK_50M = ~CLK_50M;
end

always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        cnt <= 1'b0;
    else
        cnt <= cnt_n;
end

always @ ( * )
begin
    if(cnt == 16'd359)
        cnt_n = 1'b0;
    else
        cnt_n = cnt + 1'b1;
end

//生成相位0-359度,Phase[17:16]为相位的象限,Phase[15:0]为相位的值
always @ (posedge CLK_50M or negedge RST_N)
begin
    if(!RST_N)
        Phase <= 1'b0;
    else
        Phase <= Phase_n;
end

always @ ( * )
begin
    if(cnt <= 16'd90)
        Phase_n = cnt;
    else if(cnt > 16'd90 && cnt <= 16'd180)
        Phase_n = {2'b01,cnt - 16'd90};
    else if(cnt > 16'd180 && cnt <= 16'd270)
        Phase_n = {2'b10,cnt - 16'd180};
    else if(cnt > 16'd270)
        Phase_n = {2'b11,cnt - 16'd270};
end
*/
				

endmodule


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

开平方_复数有效值+角度的verilog代码 的相关文章

  • NVIDIA Jetson TX2使用笔记(一):开机设置

    0 写在前面 由于项目需要 xff0c 使用 NVIDIA Jetson TX2作为硬件开发平台 xff0c 在此记录使用方法和遇到的问题 NVIDIA Jetson TX2是英伟达的嵌入式开发套件 xff0c 可以进行视觉计算 xff0c
  • ORB-SLAM2的安装与运行

    0 背景简介 ORB SLAM是西班牙Zaragoza大学的Raul Mur Artal编写的视觉SLAM系统 他的论文 ORB SLAM a versatile andaccurate monocular SLAM system 34 发
  • Ubuntu14.04升级cmake版本的方法

    在Ubuntu14 04用以下命令默认安装的cmake版本为2 8 x xff0c 有时我们需要更高版本的cmake xff0c 所以需要升级 span class hljs built in sudo span apt get insta
  • 在TX2上配置ORB-SLAM2错误总结

    Pangolin 错误描述 usr lib gcc aarch64 linux gnu 5 aarch64 linux gnu libGL so undefined reference to 96 drmFreeDevice 解决方法 cd
  • docker镜像迁移/移植

    docker镜像迁移 移植 或者docker save 镜像名 版本号 o 路径 保存的包名 tar 通过这两个命令保存保存镜像 xff0c 下载到本地再上传到其他服务器 然后通过docker load lt 保存的包名 tar 完成镜像移
  • 安装并运行VINS-Mono

    0 A Robust and Versatile Monocular Visual Inertial State Estimator VINS Mono是单目视觉惯性系统的实时SLAM框架 它使用基于优化的滑动窗口配方来提供高精度的视觉惯性
  • 使用小觅双目-惯性相机运行VINS-Mono

    步骤 1 下载相机驱动MYNT EYE SDK 2 xff0c 然后make ros xff08 注意 xff1a 前面的Ubuntu安装也要操作 xff09 xff1b 2 安装VINS Mono xff1b 3 在MYNT EYE VI
  • 在TX2上安装VIINS-Mono——问题总结

    1 ceres solver 我们一般通过以下命令安装Eigen xff1a sudo apt get install libeigen3 dev 默认安装在 usr include eigen3 在CMakeList txt中一般用以下语
  • LeGO-LOAM初探:原理,安装和测试

    前言 最近要搞3D激光SLAM xff0c 先后测试了Autoware xff0c cartographer xff0c loam和LeGO LOAM 今天就带来LeGO LOAM的使用体验 Github xff1a https githu
  • IMU噪声标定——加速度计和陀螺仪的白噪声和零偏不稳定性

    前言 imu utils是一个用于分析IMU性能的ROS工具包 参考资料 Allan Variance Noise Analysis for Gyroscopesvectornav gyroscopeAn introduction to i
  • TF坐标变换

    文章目录 TF坐标变换TF功能包TF工具乌龟例程中的TF创建TF广播器创建TF监听器实现乌龟跟随运动 存在的问题总结参考 TF坐标变换 坐标变换是机器人学中一个非常基础 xff0c 同时也是非常重要的概念 机器人本体和机器人的工作环境中往往
  • Linux下目录文件的操作(opendir,readdir,closedir) 以及DIR,dirent,stat等结构体详解

    From http blog chinaunix net uid 27213819 id 3810699 html 注 xff1a 为什么要说 目录文件 xff1f 其实在linux中 目录也是一种 文件 xff0c 只是它的内容是上级的
  • 堆栈的工作原理

    声明 xff1a 以下均为个人收集的一些资料 xff0c 非原创 每一个使用c语言的都应该知道栈的重要性 xff0c 我们能够使用C C 43 43 语言写出诸多复杂的程序 xff0c 很大功劳一部分有归于栈的实现 xff0c 因为它可以帮
  • RTK+GPS提高定位精度原理解析(一个小白写给另一个小白系列)

    RTK 43 GPS提高定位精度原理解析 xff08 一个小白写给另一个小白系列 xff09 GPS定位原理回顾RTK基本概念RTK组成RTK传输差分示意RTK数据链接坐标转换RTK应用后记 我们在上一篇文章导航定位系统的原理解析 xff0
  • Python 嵌套函数中内部函数引用外部函数循环变量情况

    Python 嵌套函数中内部函数引用外部函数循环变量情况 Python中的嵌套函数也称为闭包 xff08 Closure xff09 有一个特点就是内部函数可以引用外部函数内的变量并且在外部函数返回后保存该引用变量的值 xff1b 但是如果
  • Git查看版本改动—— git diff

    HEAD 表示当前版本 xff0c 也就是最新的提交 上一个版本就是 HEAD xff0c 上上一个版本就是 HEAD xff0c 往上100个版本写100个 比较容易数不过来 xff0c 所以写成 HEAD 100 HEAD 2 相当于
  • PyQt5编程-鼠标事件

    处理鼠标事件的频率不低于键盘事件 包括按下 松开鼠标按键 xff1b 移动鼠标到特定区域或离开特定区域 xff1b 更改鼠标指针的形状 xff0c 等等 1 按下 松开鼠标按键 按下并释放鼠标按钮时 xff0c 将调用以下方法 xff1a
  • latex 正文设置为双栏,图片如何占两栏

    xff08 1 xff09 插入一栏图片时 xff0c 使用的是 xff1a begin figure end figure 96 xff08 2 xff09 插入双栏图片时 xff0c 需在figure的上标中加入星号 begin fig
  • VIO松耦合和紧耦合对比

    松耦合 xff08 结果级融合 xff09 xff1a 两个独立的运动估计过程中分别处理视觉和惯性测量的信息 xff0c 最终将他们的输出 xff08 位置和姿态 xff09 融合作为结果 紧耦合 xff08 特征级融合 xff09 xff
  • zed2相机运行VINS-mono

    zed2相机标定请参考专栏前面博文 xff01 一 zed2相机运行VINS mono 1 下载VINS mono mkdir p vins ws src cd vins ws src git clone https github com

随机推荐

  • C语言指针笔试题

    1 我们先来看第一段代码和它的输出 span class token keyword int span span class token function main span span class token punctuation spa
  • Gazebo 官网教程学习笔记--Model Editor

    终端打开Gazebo Gui 界面 然后快捷键CTRL 43 M 打开 Model Editor xff0c 或者在edit 下选择model editor 界面如下 1 工具栏 包含用于编辑模型的工具 2 调色板 也称为左面板 有两个选项
  • 《大厂算法面试》小书

    算法面试是大多数小伙伴的弱势 xff0c 但是大厂几乎都会考算法 xff0c 如果在面试过程中不刻意准备一下算法 xff0c 很大概率被挂 其实对于前端和移动端来说 xff0c 算法要求的并不是很高 xff0c 只要把一些常见的算法题刷完
  • ROS通信架构上——Topic和Msg

    Topic 异步通信方式 Node间通过publish subscribe机制通信 相关的命令 xff1a rostopic rostopic list 列出当前所有topicrostopic info topic name 显示某个top
  • Type-C显示器是什么,Type-C显示器的5大优势

    在显示器领域内 xff0c USB Type C接口还处于发展阶段 xff0c 目前已经在新推出的一些高端显示器和旗舰显示器中有配置 USB Type C接口的出现 xff0c 将会形成以显示器为核心的桌面解决方案 xff0c 用户可以把任
  • SLAM综述

    SLAM综述 前言一 概述二 Lidar SLAM激光雷达传感器激光雷达SLAM系统 xff08 Lidar SLAM System xff09 2D SLAM3D SLAM深度学习与激光雷达Feature amp Detection xf
  • VisionPro使用 C# 开发

    VisionPro 常用控件的说明 工具设置窗体 CogPMAlignEditV2 模版匹配设置窗体控件 CogPMAlignEditV2 Subject 工具关联对象 如 xff1a CogPMAlignEditV2 Subject 61
  • rosdep update 失败及解决办法

    一 问题 reading in sources list data from etc ros rosdep sources list d Hit https raw githubusercontent com ros rosdistro m
  • 在STM32上运行ROS节点——rosserial&stm32开发及调试方法

    近期接手了一些ROS机器人项目 xff0c 这里将开发中遇到的问题和解决方法记录下来 stm32强大的外设资源为机器人底层设备控制带来了极大的便利 xff0c 本文简述借助rosserial项目在stm32中运行ROS节点的方法 基本原理
  • 动态存储区、静态存储区、堆和栈的区别

    C c 43 43 程序经过编译连接后形成的二进制映像文件 xff0c 这文件包含 xff1a 栈 xff0c 堆 xff0c 数据段 xff08 只读数据段 xff0c 已经初始化读写数据段 xff0c 未初始化数据段即BBS xff09
  • kubemini-基础使用

    起始 minikube 是一个本地的 k8s 专注于为 k8s 创建一个简单的学习和开发环境 你只需要一个 Docker 或者类似兼容的 容器 xff0c 或者一个虚拟机环境 xff0c k8s 只需要一个单独的命令 xff1a minik
  • 详解信号量和互斥锁之间的区别和联系

    一 xff1a 信号量与互斥锁之间的区别 xff1a 1 xff1a 互斥量用于线程的互斥 xff0c 信号线用于线程的同步 这是互斥量和信号量的根本区别 xff0c 也就是互斥和同步之间的区别 2 xff1a 互斥量值只能为0 1 xff
  • python基础学习(十二)——python中代码的执行顺序以及if __name__ ==‘__main__‘作用和原理

    xff08 1 xff09 代码执行顺序 python程序是顺序执行的 xff0c Python中首先执行最先出现的非函数定义和非类定义的没有缩进的代码 python程序执行时 按照自上而下的顺序 xff1a 首先执行没有缩进的代码 xff
  • c学习--不同c文件中的同名全局变量及同名函数53

    如果在不同的c文件中定义了同名的全局变量 xff0c 则它们会占用相同的内存空间 xff0c 而且编译链接时不会报错 xff01 这可以参考全局变量的内存初始化顺序 对于局部变量而言 xff0c 内存分配的顺序和代码的顺序是一样的 全局变量
  • 基于STM32的FreeRTOS学习之任务基础知识(六)

    记录一下 xff0c 方便以后翻阅 RTOS系统的核心是任务管理 xff0c 初学RTOS系统必须先掌握任务的创建 删除 挂起和恢复等操作 1 什么是多任务系统 玩裸机一般都是在main函数里用while 1 做一个死循环完成所有处理 xf
  • git 推送出现 “fatal: The remote end hung up unexpectedly“ 解决方案

    https blog csdn net qq 41241767 article details 98181952 git 推送出现 34 fatal The remote end hung up unexpectedly 34 解决方案 h
  • 操作系统的设计指导思想——主奴机制

    在学习操作系统的过程中我们会发现一个问题 xff1a 应用程序是应用程序 xff0c 操作系统也是程序 xff0c 操作系统程序凭什么能对应用程序进行组织 管理和协调而不受应用程序损害呢 xff1f 我们认为凭的是特权机制 要想让操作系统做
  • VScode如何配置Git

    注意 xff1a 食用本篇博客的前提是你已经安装好了Git xff0c 并且也有一定的Git基础 因为有些git中比较常用的功能我会略过 第一步 xff1a 配置Git环境变量 右键 我的电脑 xff0c 选择 属性 xff0c 在弹出的对
  • FMC/FSMC/EXMC总线NORFlash/PSRAM接口(异步-复用-不突发/同步-复用-突发)

    请勿转载 目录 1 简介 1 1 框图 1 2 接口定义 1 3 读写时序图 时序配置参数 1 4 PSRAM控制器异步工作模式分类 1 5 PSRAM寄存器配置 1 5 1 控制寄存器BCR 1 5 2 片选时序寄存器BTR 1 5 3
  • 开平方_复数有效值+角度的verilog代码

    1 逐位比较法 二进制 FPGA篇 xff08 一 xff09 基于verilog的定点开方运算 1 逐次逼近算法 该篇文章中有详细描述 假设被开方数rad i 7 0 xff0c 则结果qout 3 0 位宽为4位 xff0c 从最高位到