详解CORDIC算法以及Verilog实现并且调用Xilinx CORDIC IP核进行验证

news2024/12/23 2:37:59

系列文章目录

文章目录

  • 系列文章目录
  • 一、什么是CORDIC算法?
  • 二、CORDIC算法原理推导
  • 三、CORDIC模式
    • 3.1 旋转模式
    • 3.2 向量模式
  • 四、Verilog实现CORDIC
    • 4.1 判断象限
    • 4.2 定义角度表
    • 4.3 迭代公式
  • 五、仿真验证
    • 5.1 matlab打印各角度的正余弦值
    • 5.2 Verilog仿真结果观察
  • 六、Xilinx CORDIC IP核介绍
    • 6.1 Xilinx CORDIC IP 特点
    • 6.2 端口说明
    • 6.3 AXI4_stream握手信号
    • 6.4 数据传输模式
    • 6.5 数据结构
      • 6.5.1 输入数据结构
      • 6.5.2 输出数据结构
    • 6.6 各种功能描述
      • 6.6.1 矢量旋转(Rotate)
      • 6.6.2 坐标转换(Translate)
      • 6.6.3 sin 和cos
      • 6.6.4 Sinh and Cosh
      • 6.6.5 ArcTan
      • 6.6.6 ArcTanh
      • 6.6.7 Square Root
    • 6.7 输出输入数据的表示
  • 七、例化IP
    • 7.1 仿真代码
    • 7.2 仿真结果


一、什么是CORDIC算法?

  CORDIC(COordinate Rotation DIgital Computer)算法是一种用于计算三角函数、双曲函数、对数、指数和平方根等数学函数的迭代算法。对于硬件电路来说,计算三角函数不像CPU那样方便,如果使用大量的乘法器和加法器,那么整个硬件电路会消耗很多资源,因此cordic算法就有效地解决了乘法器和加法器的问题,它的主要优点是:可以使用简单的加法和位移操作,而不需要乘法和除法,从而适合在硬件中实现三角函数的计算,特别是数字信号处理(DSP)和嵌入式系统中。

二、CORDIC算法原理推导

  CORDIC算法的基本原理是:将旋转角度 θ θ θ分成多个连续的小偏转角,通过逐次摇摆逼近目标旋转角度来完成旋转过程。

在这里插入图片描述
  如上图所示:在直角坐标系内将点( x 1 , y 1 x_1,y_1 x1y1)逆时针旋转 θ θ θ至点( x 2 x_2 x2 y 2 y_2 y2),那么怎么计算 c o s θ cosθ cosθ s i n θ sinθ sinθ的值呢?
  我们知道:
{ x 1 = cos ⁡ φ y 1 = sin ⁡ φ \left\{ \begin{aligned} x_1 & = \cosφ \\ y_1 & = \sinφ \\ \end{aligned} \right. {x1y1=cosφ=sinφ

{ x 2 = cos ⁡ ( θ + φ ) y 2 = sin ⁡ ( θ + φ ) \left\{ \begin{aligned} x_2& = \cos(θ+φ) \\ y_2 & = \sin(θ+φ)\\ \end{aligned} \right. {x2y2=cos(θ+φ)=sin(θ+φ)

  根据三角函数和差公式,我们可以得到:
{ x 2 = cos ⁡ θ c o s φ − s i n θ s i n φ y 2 =   s i n θ c o s φ + c o s θ s i n φ \left\{ \begin{aligned} x_2& = \cosθcosφ - sinθsinφ\\ y_2 & = \ sinθcosφ + cosθsinφ\\ \end{aligned} \right. {x2y2=cosθcosφsinθsinφ= sinθcosφ+cosθsinφ

  再用 x 1 x_1 x1替换掉 c o s φ cosφ cosφ y 1 y_1 y1替换掉 s i n φ sinφ sinφ可以得到:
{ x 2 =   c o s θ ∗ x 1 − s i n θ ∗ y 1 y 2 =   s i n θ ∗ x 1 + c o s θ ∗ y 1 \left\{ \begin{aligned} x_2& = \ cosθ *x_1 - sinθ *y_1\\ y_2 & = \ sinθ*x_1 + cosθ *y_1\\ \end{aligned} \right. {x2y2= cosθx1sinθy1= sinθx1+cosθy1

  也可以写成矩阵形式:

[ x 2 y 2 ] = [ c o s θ − s i n θ s i n θ c o s θ ] [ x 1 y 1 ] \begin{gathered} \begin{bmatrix} x_2 \\ y_2 \end{bmatrix} = \quad \begin{bmatrix} cosθ & - sinθ \\ sinθ & cosθ \end{bmatrix} \begin{bmatrix} x_1 \\ y_1 \end{bmatrix} \quad \end{gathered} [x2y2]=[cosθsinθsinθcosθ][x1y1]
  提取公因子 c o s θ cosθ cosθ
[ x 2 y 2 ] = c o s θ [ 1 − t a n θ t a n θ 1 ] [ x 1 y 1 ] \begin{gathered} \begin{bmatrix} x_2 \\ y_2 \end{bmatrix} = cosθ \quad \begin{bmatrix} 1& - tanθ \\ tanθ & 1 \end{bmatrix} \begin{bmatrix} x_1 \\ y_1 \end{bmatrix} \quad \end{gathered} [x2y2]=cosθ[1tanθtanθ1][x1y1]

{ x 2 =   c o s θ ( x 1 − t a n θ ∗ y 1 ) y 2 =   c o s θ ( t a n θ ∗ x 1 + y 1 ) \left\{ \begin{aligned} x_2& = \ cosθ(x_1 - tanθ *y_1)\\ y_2 & = \ cosθ(tanθ*x_1 + y_1)\\ \end{aligned} \right. {x2y2= cosθ(x1tanθy1)= cosθ(tanθx1+y1)

  这个公式就能将点( x 1 , y 1 x_1,y_1 x1y1)逆时针旋转 θ θ θ至点( x 2 x_2 x2 y 2 y_2 y2)。因为旋转的θ是个固定值,因此 c o s θ cosθ cosθ是一个常数,我们暂时去掉 c o s θ cosθ cosθ可以得到伪旋转方程:
{ x 2 =   x 1 − t a n θ ∗ y 1 y 2 =   y 1 + t a n θ ∗ x 1 \left\{ \begin{aligned} x_2& = \ x_1 - tanθ *y_1\\ y_2 & = \ y_1 + tanθ*x_1 \\ \end{aligned} \right. {x2y2= x1tanθy1= y1+tanθx1

  伪旋转方程意思就是,通过伪旋转方程我们可以将点( x 1 , y 1 x_1,y_1 x1y1)逆时针旋转 θ θ θ角,但是模长不是我们想要的模长。简而言之就是伪旋转方程负责旋转到正确的角度,去掉的 c o s θ cosθ cosθ能使得模长为想要的长度,示意图如下所示:

在这里插入图片描述
  因此经过伪旋转后到了点 ( x 2 ^ , y 2 ^ ) (\hat{x_2},\hat{y_2}) (x2^,y2^),向量R的模值增加了 1 / c o s θ 1/cosθ 1/cosθ倍。即:向量旋转到了正确的角度,但是模值不对。CORDIC的核心思想就是:先旋转到正确的角度,最后再对模长进行补偿。 我们前面也说了硬件电路不擅长乘除法运算,但是擅长加减法运算。这个伪旋转方程里还是有乘法以及 t a n θ tanθ tanθ,我们就要做一种处理:
  如果 t a n θ tanθ tanθ刚好等于1/2,即θ角=45°,那么这个伪旋转方程就变成了
{ x 2 =   x 1 − y 1 / 2 y 2 =   y 1 + x 1 / 2 \left\{ \begin{aligned} x_2& = \ x_1 - y_1/2\\ y_2 & = \ y_1 + x_1/2 \\ \end{aligned} \right. {x2y2= x1y1/2= y1+x1/2
  在硬件电路里,÷2可以用右移一位表示。这样整个方程就变成了只有加减法和移位操作了,因此,我们可以让θ为一系列固定的角度,使得 t a n θ i tanθ^{i} tanθi = 2 − i 2^{-i} 2i,这样经过一系列旋转后,总能找到一个角度无限逼近与我们想要的角度,这就是CORDIC算法的最核心的思想,故伪旋转方程变为:
{ x 2 ^ =   x 1 − y 1 ∗ t a n θ = x 1 − y 1 ∗ 2 − i y 2 ^ =   y 1 + x 1 ∗ t a n θ = y 1 + x 1 ∗ 2 − i \left\{ \begin{aligned} \hat{x_2}& = \ x_1 - y_1*tanθ = x_1 - y_1*2^{-i}\\ \hat{y_2} & = \ y_1 + x_1*tanθ =y_1 + x_1* 2^{-i} \\ \end{aligned} \right. {x2^y2^= x1y1tanθ=x1y12i= y1+x1tanθ=y1+x12i

  其中 t a n θ i tanθ^{i} tanθi对应的角度值表如下所示:

在这里插入图片描述
  这里把旋转角度变换改成了迭代运算。将各种可能的旋转角度进行一些条件限制,可以使得对任意旋转角度都能够通过连续的小角度的迭代来完成。旋转迭代顺序为:

  1. 第一次迭代旋转的角度是45.0°
  2. 第二次迭代旋转的角度是26.555°
  3. 第三次迭代旋转的角度是14.036°
  4. 第四次迭代旋转的角度是7.125°
  5. 第五次迭代旋转的角度是3.576°
  6. 第六次迭代旋转的角度是1.789°
      以此类推,迭代次数越多,精度越高,越能逼近想要的角度θ。在迭代到一定次数后,我们角度已经旋转到正确位置了,现在回头来看我们舍掉的 c o s θ cos θ cosθ,这是确定我们模长的因子,由上表也能看出,当θ值越小时, c o s θ cosθ cosθ无限接近1。所以我们迭代过程中舍掉的 c o s θ 1 ∗ c o s θ 2 ∗ c o s θ 3 ∗ c o s θ 4 ∗ c o s θ 5 ∗ c o s θ 6 ∗ c o s θ 7 ∗ c o s θ 8 . . . . . . . . 一定是收敛某个数的 cosθ^{1}*cosθ^{2}*cosθ^{3}*cosθ^{4}*cosθ^{5}*cosθ^{6}*cosθ^{7}*cosθ^{8}........一定是收敛某个数的 cosθ1cosθ2cosθ3cosθ4cosθ5cosθ6cosθ7cosθ8........一定是收敛某个数的
      经过计算,在迭代16次以后,上面的乘积≈0.60725941;1/0.60725941 ≈1.64676024187 。;在进行伪旋转之后,需要对伪旋转后的幅度进行标定,所以伪旋转后的坐标还需要乘以一个系数0.60725941才能得到我们想要的正确坐标。

  最终CORDIC算法伪旋转的公式为:
{ x i + 1 =   x i − d i ∗ y i ∗ ∗ 2 − i y i + 1 =   y i + d i ∗ x i ∗ ∗ 2 − i z i + 1 =   z i − d i θ i \left\{ \begin{aligned} x^{i+1}& = \ x^{i} -d_{i}* y^{i}**2^{-i} \\ y^{i+1} & = \ y^{i} + d_{i} * x^{i}**2^{-i} \\ z^{i+1} & = \ z^{i} - d_{i}θ^{i} \\ \end{aligned} \right. xi+1yi+1zi+1= xidiyi2i= yi+dixi2i= zidiθi
  其中 d i d_{i} di表示旋转因子, d i d_{i} di=±1,+1表示逆时针旋转,-1表示顺时针旋转。因为伪旋转不是最终的旋转,还有前面的 c o s θ cosθ cosθ的累乘称为缩放因子,伪旋转后的坐标伸缩了目标坐标的Kn倍,其中Kn:

在这里插入图片描述

  当确定迭代次数n时,可以预先计算出缩放因子Kn。当n趋近于正无穷时,Kn趋近于1.64676024187,1/Kn趋近于0.60725941。前面通过省略 c o s θ cosθ cosθ来进行伪旋转,使得在n次迭代后得到
{ x 伪 =   K n ( x 0 c o s θ − y 0 s i n θ ) , x n = x 伪 ∗ 0.60725941 y 伪 =   K n ( y 0 c o s θ + x 0 s i n θ ) , y n = y 伪 ∗ 0.60725941 z n =   0 \left\{ \begin{aligned} x_{伪}& = \ K_{n}(x_0cosθ - y_{0}sinθ) ,x_{n} = x_{伪} *0.60725941\\ y_{伪} & = \ K_{n}(y_0cosθ + x_{0}sinθ) ,y_{n} = y_{伪} *0.60725941 \\ z_{n} & = \ 0 \\ \end{aligned} \right. xyzn= Kn(x0cosθy0sinθ)xn=x0.60725941= Kn(y0cosθ+x0sinθ)yn=y0.60725941= 0

  也可以设置 x 0 = 0.0.60725941 , y 0 = 0 x_0= 0.0.60725941,y_0= 0 x0=0.0.60725941y0=0,来消除伸缩因子,从而得到:
{ x n = c o s θ y n = s i n θ \left\{ \begin{aligned} x_{n} = cosθ\\ y_{n} = sinθ\\ \end{aligned} \right. {xn=cosθyn=sinθ

三、CORDIC模式

3.1 旋转模式

  旋转模式就是,给定一个角度θ和初始坐标,算出旋转后的坐标。旋转模式下,旋转方向是以剩余角度 z i + 1 z^{i+1} zi+1的符号作为每次迭代旋转方向的依据。在旋转模式下,等迭代完成后, z i + 1 趋近于 0 z^{i+1}趋近于0 zi+1趋近于0 , x i + 1 = c o s θ ,x^{i+1} = cosθ xi+1=cosθ y i + 1 = s i n θ y^{i+1} = sinθ yi+1=sinθ
  例如,输入向量为 ( x 0 , y 0 ) (x_0,y_0) (x0y0)输入角度为 z z z,经过迭代旋转后,剩余角度为0,则输出目标向量为 ( x c o s z − y s i n z ) / K n (xcosz-ysinz)/K_n (xcoszysinz)/Kn ( y c o s z + x s i n z ) / K n (ycosz+xsinz)/K_n (ycosz+xsinz)/Kn其中nK为缩放因子。当旋转角度为30°时,其迭代过程如下:

在这里插入图片描述
   s i n 30 ° = 0.5006 , c o s 30 ° = 0.8657 sin30° = 0.5006,cos30°=0.8657 sin30°=0.5006cos30°=0.8657

3.2 向量模式

  向量模式就是给一个坐标(x,y),让向量旋转到x轴上,当y趋近于0时候,向量就无限接近x轴,此时x的坐标就是向量的模长,θ等于arctan(y/x) 。CORDIC算法的向量模式可以计算出输入向量的幅度值。并且使用向量模式就是使旋转后的向量与x轴重合。因此,向量的幅度就是旋转向量的x值,幅度结果由Kn增益标定。向量模式主要是用来求反正切、反正弦、反余弦以及向量幅值等

四、Verilog实现CORDIC

4.1 判断象限

  由迭代公式可以看出,每次迭代的范围是±(45 + 26.6 + 14 +… )≈ ±99.8°,因此我们要将输入的象限通过三角变换到第一和第四象限,例如
c o s 150 ° = − c o s 30 ° , s i n 150 ° = s i n 30 ° cos150° = -cos30°, sin150° = sin30° cos150°=cos30°sin150°=sin30°
  所以首先要对输入的角度值判断:

always @(*) begin
    if((w_act == 1'b1) && (i_angle >=32'd0) && (i_angle < 32'd900000))      //[0:90]第一象限
        w_quadrant <= 2'd0;
    else if((w_act == 1'b1) && (i_angle >=32'd900000) && (i_angle <= 32'd1800000)) //[90:180]第二象限
        w_quadrant <= 2'd1;
    else if((w_act == 1'b1) && (i_angle >=-32'd1800000) && (i_angle < -32'd900000))[-180:-90]第三象限
        w_quadrant <= 2'd2;
    else if(w_act == 1'b1)  [-90:0]第四象限
        w_quadrant <= 2'd3;
end 

  然后再根据象限对角度进行处理,±180°:

		if(w_quadrant == 2'd1)  //第二象限就减180°
            r_zi <= i_angle - 32'd1800000;
        else if(w_quadrant == 2'd2) //第三象限就+180°
            r_zi <= i_angle + 32'd1800000;
        else
            r_zi <= i_angle;

  最后根据象限判断输出的正负值

assign  o_sin   =   ((w_quadrant == 2'd1)||(w_quadrant == 2'd2)) ? -ro_sin :  ro_sin;//根据象限输出正确的数值
assign  o_cos   =   ((w_quadrant == 2'd2)||(w_quadrant == 2'd3)) ? -ro_cos :  ro_cos;//根据象限输出正确的数值

4.2 定义角度表

  由上面公式可以知道,我们必须提前将45°,26.565°…等等存储起来,然后每次按照顺序旋转角度:

//角度扩大了10000倍
wire signed [31:0]  w_arctan[0:15]  ;  //角度值表

assign  w_arctan[0 ] = 32'd450000   ;   //arctan45°     = 1
assign  w_arctan[1 ] = 32'd265650   ;   //arctan26.565° = 1/2
assign  w_arctan[2 ] = 32'd140362   ;   //arctan14.036° = 1/4
assign  w_arctan[3 ] = 32'd71250    ;   //arctan7.1250° = 1/8
assign  w_arctan[4 ] = 32'd35763    ;   //arctan3.5763° = 1/16
assign  w_arctan[5 ] = 32'd17899    ;   //arctan1.7899° = 1/32
assign  w_arctan[6 ] = 32'd8951     ;   //arctan0.8951° = 1/64
assign  w_arctan[7 ] = 32'd4476     ;   //arctan0.4476° = 1/128
assign  w_arctan[8 ] = 32'd2238     ;   //arctan0.2238° = 1/256
assign  w_arctan[9 ] = 32'd1119     ;   //arctan0.1119° = 1/512
assign  w_arctan[10] = 32'd559      ;   //arctan0.0559° = 1/1024
assign  w_arctan[11] = 32'd279      ;   //arctan0.0279° = 1/2048
assign  w_arctan[12] = 32'd139      ;   //arctan0.0139° = 1/4096
assign  w_arctan[13] = 32'd69       ;   //arctan0.0069° = 1/8192    
assign  w_arctan[14] = 32'd34       ;   //arctan0.0034° = 1/16384
assign  w_arctan[15] = 32'd17       ;   //arctan0.0017° = 1/32768    

4.3 迭代公式

  最核心的迭代公式就是通过加减和右移实现:

assign w_xi_1 = (w_di == 1'b1) ? (r_xi - (r_yi >>> r_cal_cnt)) : (r_xi + (r_yi >>> r_cal_cnt));
assign w_yi_1 = (w_di == 1'b1) ? (r_yi + (r_xi >>> r_cal_cnt)) : (r_yi - (r_xi >>> r_cal_cnt));
assign w_zi_1 = (w_di == 1'b1) ? (r_zi - w_arctan[r_cal_cnt])  : (r_zi + w_arctan[r_cal_cnt]);

五、仿真验证

5.1 matlab打印各角度的正余弦值

  我们仿真从-180 ° 一直到180°,步进为5°,我们先来用matlab打印出 -180° 、-175°、-170°、、、、一直到180°的sin值和cos值,matlab代码如下:


% 创建一个从-90到90的角度数组
angles = -180:5:180;

% 计算正弦和余弦值
sine_values = sin(deg2rad(angles));  % 将角度转换为弧度
cosine_values = cos(deg2rad(angles));

% 打印结果
fprintf('角度\t正弦值\t\t余弦值\n');
fprintf('---------------------------\n');
for i = 1:length(angles)
    fprintf('%d\t%.4f\t%.4f\n', angles(i), sine_values(i), cosine_values(i));
end

  打印结果如下:
在这里插入图片描述

5.2 Verilog仿真结果观察

在这里插入图片描述
  先来看-175°,在第三象限,sin(-175°)= -0.0872,cos(-175°)= -0.9961
在这里插入图片描述
  与matlab一致。

在这里插入图片描述
  再来看-140°,在第三象限,sin(-140°)= -0.6427,cos(-140°)= -0.7659
在这里插入图片描述
  与matlab一致。

在这里插入图片描述
  再来看-55°,在第四象限,sin(-55°)= -0.8191,cos(-55°)= -0.5737
在这里插入图片描述
  与matlab一致。

在这里插入图片描述
  再来看45°,在第一象限,sin(45°)= 7069,cos(45°)= 7071
在这里插入图片描述
  与matlab一致。其他的角度值也是一致的,至此我们用verilog实现了CORDIC算法,接下来我们调用Xilinx 的 CORDIC IP核来使用验证一下。

六、Xilinx CORDIC IP核介绍

  本章参考《PG105》。支持七种运算:

  1. 矢量旋转(极坐标到直角坐标:给定一个xy坐标和一个角度,求旋转角度后的xy坐标)
  2. 矢量平移(直角坐标到极坐标:给一个xy坐标,求出此坐标的角度和x值,此时x值就是模长)
  3. sin 和 cos(就给一个角度值,求出xy的坐标,此时x值就是cos,y值就是sin)
  4. Sinh 和 Cosh(双曲正弦和双曲余弦,给一个角度值,出x和y值)
  5. Atan (arctan:给一个坐标xy值,出一个角度值,就是把此向量旋转到x轴上)
  6. Atanh (反双曲正切,给一个坐标xy值,出一个角度值)
  7. 平方根(给一个x值,出一个x值的平方根)

6.1 Xilinx CORDIC IP 特点

  • 可选粗旋转模块:将 CORDIC 的范围从第一象限(+Pi/4 至 -Pi/4 弧度)扩展到整圆
  • 可选幅度补偿缩放模块,用于补偿 CORDIC 算法的输出幅度比例因子
  • 可选择并行或者串行模式
  • 可以控制内部迭代次数以提供精度控制
  • X 和 Y 数据格式:有符号分数、无符号分数和无符号整数
  • 相位数据格式:弧度、圆周率弧度

  并行模式:CORDIC 算法大约需要对每个精度位执行一次移位加减运算; 具有 N 位输出宽度的并行 CORDIC 核心具有 N 个周期的延迟,并且每个周期都会产生一个新输出。
  串行模式:具有 N 位输出宽度的字串行 CORDIC 核心具有 N 个周期的延迟,并且每 N 个周期产生一个新输出。

6.2 端口说明

在这里插入图片描述
  CORDIC IP 所有的端口如上图显示,根据不同的配置端口的数量不同,以下是所有端口的说明:

端口名称方向 描述
aclk in 上升沿有效
ACLKEN in 时钟使能信号,高电平有效
ARESETn in同步复位。低电平有效。ARESETn 在置位时必须保持有效至少 2 个时钟周期。
s_axis_cartesian_tvalid in 直角坐标系的握手信号
s_axis_cartesian_tready out 直角坐标系的握手信号
s_axis_cartesian_tdata[A-1:0]in 根据功能配置,此端口有一个或两个子字段;X_IN 和 Y_IN。这些是笛卡尔操作坐标数。每个子字段的宽度为 Input_Width 位,在连接之前填充到下一个字节宽度
s_axis_cartesian_tuser[B-1:0] in 此端口上的数据延迟与 tdata 相同,并出现在 m_axis_dout_tuser 上
s_axis_cartesian_tlast in tlast 不被核心使用,而是与 s_axis_phase_tlast 结合,或者根据 TLAST_Behavior 不加改变地传递给 m_axis_dout_tlast
s_axis_phase_tvalid in 角度数据握手信号
s_axis_phase_tready out 角度数据准备信号
s_axis_phase_tdata[C-1:0] in此端口有一个子字段,即 PHASE_IN。它是极坐标操作数。子字段的宽度为 Input_Width 位,填充到下一个字节宽度
s_axis_cartesian_tlast in tlast 不被核心使用,而是与 s_axis_phase_tlast 结合,或者根据 TLAST_Behavior 不加改变地传递给 m_axis_dout_tlast
s_axis_phase_tuser[D-1:0] in 此端口上的数据延迟与 tdata 相同,并出现在 m_axis_dout_tuser 上
s_axis_phase_tlast intlast 不被核心使用,而是与 s_axis_cartesian_tlast 结合,或者根据 TLAST_Behavior 不加改变地传递给 m_axis_dout_tlast。
m_axis_dout_tvalid out 输出数据有效信号
m_axis_dout_tready in输出数据准备信号
m_axis_dout_tdata[E-1:0] out根据功能配置,此端口包含以下子字段:X_OUT、Y_OUT、PHASE_OUT。每个子字段的宽度为 Output_Width 位,在连接之前填充到下一个字节宽度。
m_axis_dout_tuser[F-1:0] out该端口包含输入到 s_axis_cartesian_tuser 和/或 s_axis_phase_tuser 的值,其延迟与 tdata 相同
m_axis_dout_tlast out该端口输出 s_axis_cartesian_tlast、s_axis_phase_tlast 或两者的某种组合,延迟与 tdata 相同的延迟

  许多引脚是可选的。如果所选函数不需要相关通道携带的操作数,则不存在输入通道。例如,平方根函数不需要 PHASE_IN,因此此功能不存在 S_AXIS_PHASE,以下是根据功能配置选择的端口列表:

在这里插入图片描述

6.3 AXI4_stream握手信号

在这里插入图片描述
  tvalid 由通道的源(主)端驱动,tready 由接收器(从)端驱动。tvalid 表示有效载荷字段(tdata、tuser 和 tlast)中的值有效。tready 表示从端已准备好接收数据。当 tvalid 和 tready 在一个周期内都为 TRUE 时,传输就会发生。

6.4 数据传输模式

  1. 非阻塞模式:用于表示一个输入通道上缺少数据不会导致另一个通道上的传入数据被缓冲;在 “非阻塞 ”模式下,输出通道没有 “tready ”信号。所有当前输入通道都收到激活的 tvalid 时(如果存在,tready 也被断言),操作将被验证,输出 tvalid(根据内核的延迟时间适当延迟)将被断言,以验证结果。这样做的目的是尽量避免从以前的版本迁移。如果一个通道收到 tvalid,而另一个通道没有收到,那么即使 tready 存在并被断言,操作也不会发生

在这里插入图片描述
  如上面红线所示,只有当所有通道都握手成功时,才会输出一个周期的tdata和tvalid,不用等下游握手成功。

  1. :阻塞模式:所谓 “阻塞”,是指每个通道都有待机缓冲数据以供使用。(tready)的存在可防止数据丢失,因此只有当下游数据通路准备好处理数据时,数据才会传播。如果输出通道因 m_axis_dout_tready 为低电平而无法卸载数据,数据就会累积到内核内部的输出缓冲器中。当输出缓冲区接近满时,内核将停止进一步的操作

在这里插入图片描述
  如上面红线所示每个通道的数据握手成功后都会缓存下来。例如坐标通道的A1,A2,A3在握手成功后都会缓存下来,直到相位通道的B1握手成功后,才会输出A1B1。如果下游的ready信号没有拉高输出的结果也会缓存下来,例如A3B3只有下游的ready信号拉高后,才会输出有效的结果。(输出有缓存,输出也有缓存)

6.5 数据结构

6.5.1 输入数据结构

  tdata 中每个可以独立使用的子字段首先进行扩展(如果需要),以适应 8 位倍数的位字段

在这里插入图片描述
   笛卡尔坐标下,X在低位,Y在高位。
在这里插入图片描述
   相位模式,就输入一个相位即可。

6.5.2 输出数据结构

在这里插入图片描述
  输出的数据结构根据功能不同,结构亦然不同。

6.6 各种功能描述

6.6.1 矢量旋转(Rotate)

  CORDIC 算法最初设计用于执行向量旋转,其中向量 (X,Y) 旋转一定角度产生一个新的向量 (X’,Y’),方程如下:
在这里插入图片描述
  实现的功能就是如下,给定一个(x,y)和角度θ,输出目标位置的坐标
在这里插入图片描述
  输入输出的范围如下:
在这里插入图片描述

  输入向量 (Xin, Yin) 和输出向量 (Xout, Yout) 表示为一对定点二进制补码,整数宽度为 2 位(1QN 格式)。输入旋转角度 Pin 弧度也表示为定点二进制补码,但整数宽度为 3 位(2QN 格式)
在这里插入图片描述

6.6.2 坐标转换(Translate)

  当选择坐标转换功能配置时,输入矢量 (X_IN,Y_IN) 使用 CORDIC 算法旋转,直到 Y 分量为零。这将生成缩放的输出幅度 Zi * Mag(X_IN,Y_IN) 和输出相位 Atan(Y_IN/X_IN)。给定一个坐标,使其旋转到X轴上,其输出的相位就是角度值,输出的x的值就是模长

在这里插入图片描述
在这里插入图片描述
  各个输入向量元素 (X_IN、Y_IN) 和输出幅度 X_OUT 表示为定点二进制补码数,整数宽度为 2 位(1QN 格式)。输出相位角 PHASE_OUT 弧度表示为定点二进制补码数,整数宽度为 3 位(2QN 格式)
在这里插入图片描述

6.6.3 sin 和cos

  当选择 Sin 和 Cos 函数配置时,使用 CORDIC 算法将单位向量旋转输入角度 。这将生成输出向量 (Cos( )、Sin( ))。
在这里插入图片描述

  输入角度 PHASE_IN 表示为定点二进制补码,整数宽度为 3 位(2QN 格式)。输出向量 (X_OUT, Y_OUT) 表示为一对定点二进制补码,整数宽度为 2 位(1QN 格式)。

在这里插入图片描述

6.6.4 Sinh and Cosh

  当选择 Sinh and Cosh 函数配置时,CORDIC 算法用于将向量 (1,0) 沿下图 所示的双曲曲线以双曲角 p 移动。双曲角表示向量 (X, Y) 下面积的对数,与三角角无关。这将生成输出向量 (X_OUT = Cosh(PHASE_IN), Y_OUT = Sinh(PHASE_IN))。

在这里插入图片描述
在这里插入图片描述
  输入双曲角度 Pin 表示为 3 位整数宽度的定点二进制补码(2QN 格式)。输出向量 (X_OUT, Y_OUT) 表示为一对 2 位整数宽度的定点二进制补码(1QN 格式)

在这里插入图片描述

6.6.5 ArcTan

  当选择 ArcTan 函数配置时,输入向量 (X_IN,Y_IN) 会旋转(使用 CORDIC 算法),直到 Y 分量为零。这样便会生成输出角度 Atan(Y_IN/X_IN)。

在这里插入图片描述
  输入向量 (X_IN, Y_IN) 表示为一对定点二进制补码,整数宽度为 2 位(1QN 格式)。输出角度 Pout 弧度表示为一对定点二进制补码,整数宽度为 3 位(2QN 格式)
在这里插入图片描述

6.6.6 ArcTanh

  当选择 ArcTanh 函数配置时,CORDIC 算法用于沿双曲线移动输入向量 (X_IN,Y_IN),直到 Y 分量达到零。这将生成双曲“角度”,Atanh(Y_IN/X_IN)。双曲角度表示向量 (X_IN,Y_IN) 下面积的对数,与三角角无关

在这里插入图片描述
在这里插入图片描述
  输入向量 (X_IN, Y_IN) 表示为一对定点二进制补码,整数宽度为 2 位(1QN 格式)。输出 Pout 表示为一个定点二进制补码,整数宽度为 3 位(2QN 格式)

在这里插入图片描述

6.6.7 Square Root

  当选择平方根功能配置时,将使用简化的 CORDIC 算法来计算输入的正平方根。输入 X_IN 和输出 X_OUT 始终为正数,并且均表示为无符号分数或无符号整数
在这里插入图片描述
  输入 X_IN 和输出 X_OUT 表示为无符号定点数,整数宽度为 1 位

在这里插入图片描述

6.7 输出输入数据的表示

  Q 数字格式:XQN 格式数字是 1+X+N 位二进制补码数;一个符号位后跟 X 个整数位,再跟一个 N 位尾数(分数)

在这里插入图片描述
  截位方式
在这里插入图片描述

七、例化IP

在这里插入图片描述

在这里插入图片描述

7.1 仿真代码

`timescale 1ns / 1ps



module tb_ip();

reg                                               aclk = 0    ;
reg                                                 rst ;
reg           [15:0]                              s_axis_phase_tdata =16'he000  ;
reg                                               s_axis_phase_tvalid  ;
wire    m_axis_dout_tvalid;
wire [31:0] m_axis_dout_tdata;

wire            [15:0]                               sin ;
wire            [15:0]                               cos ;
wire    s_axis_phase_tready;

assign  sin = m_axis_dout_tdata[31:16];
assign  cos = m_axis_dout_tdata[15:0];

initial begin
    rst = 1;
    #1000;
    rst = 0;
end

always #5 aclk= ~aclk;

always @(posedge aclk) begin
    if (rst)
        s_axis_phase_tdata <= 16'he000;     //初始为-1
    else if (s_axis_phase_tdata == 16'h2000)
         s_axis_phase_tdata <= 16'he001;   //到了+1后 又回到-1 + 16'd1
    else if(s_axis_phase_tready && s_axis_phase_tvalid)  //每次握手成功相位 + 1
        s_axis_phase_tdata <= s_axis_phase_tdata + 1'b1;
    else
        s_axis_phase_tdata <= s_axis_phase_tdata ;
end

always @(posedge aclk) begin
    if(rst)
        s_axis_phase_tvalid <= 1'b0;
    else if(s_axis_phase_tready && s_axis_phase_tvalid)
        s_axis_phase_tvalid <= 1'b0;
    else
        s_axis_phase_tvalid <= 1'b1;
end

test_cordic_ip u_test_cordic_ip(
    .aclk                 ( aclk                 ),
    .s_axis_phase_tdata   ( s_axis_phase_tdata   ),
    .s_axis_phase_tvalid  ( s_axis_phase_tvalid  ),
    .s_axis_phase_tready  (s_axis_phase_tready   ),
    .m_axis_dout_tvalid   ( m_axis_dout_tvalid   ),
    .m_axis_dout_tdata    ( m_axis_dout_tdata    )
);


endmodule

7.2 仿真结果

在这里插入图片描述
  我们可以看到 sin 和 cos波形已经出来了,我们放大看一些具体的角度看看计算是否正确。
在这里插入图片描述

  初始角度为-1 * 180 = -180°,得到的sin = 0,cos = -1 结果正确。

在这里插入图片描述
  角度为-0.5 * 180 = -90°,得到的sin = -1,cos = 0 结果正确。

在这里插入图片描述
  角度为0.75 * 180 = 135°,得到的sin = 70709,cos = -70709 =根号2 /2 结果正确。

在这里插入图片描述
  角度为0.1666259765625 * 180 = 29.99267578125°,得到的sin = 0.49957275390625,cos = 0.86627197265625 结果正确。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2157687.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大模型学习方向不知道的,看完这篇学习思路好清晰!!

入门大模型并没有想象中复杂&#xff0c;尤其对于普通程序员&#xff0c;建议采用从外到内的学习路径。下面我们通过几个步骤来探索如何系统学习大模型&#xff1a; 1️⃣初步理解应用场景与人才需求 大模型的核心应用涵盖了智能体&#xff08;AI Agent&#xff09;、微调&…

NodeFormer:一种用于节点分类的可扩展图结构学习 Transformer

人工智能咨询培训老师叶梓 转载标明出处 现有的神经网络&#xff08;GNNs&#xff09;在处理大规模图数据时面临着一些挑战&#xff0c;如过度平滑、异质性、长距离依赖处理、边缘不完整性等问题&#xff0c;尤其是当输入图完全缺失时。为了解决这些问题&#xff0c;上海交通大…

RK3588NPU驱动版本升级至0.9.6教程

RK3588NPU驱动版本升级至0.9.6教程 1、下载RK3588NPU驱动2、修改NPU驱动源码2.0 修改MONITOR_TPYE_DEV写错问题2.1 解决缺少函数rockchip_uninit_opp_table问题2.2 解决缺少函数vm_flags_set、vm_flag_clear的问题2.3 内核编译成功2.4 重新构建系统 3、注意事项4、其他问题处理…

故障诊断 | 基于双路神经网络的滚动轴承故障诊断

故障诊断 | 基于双路神经网络的滚动轴承故障诊断 目录 故障诊断 | 基于双路神经网络的滚动轴承故障诊断效果一览基本介绍程序设计参考资料效果一览 基本介绍 基于双路神经网络的滚动轴承故障诊断 融合了原始振动信号 和 二维信号时频图像的多输入(多通道)故障诊断方法 单路和双…

【原创】java+springboot+mysql党员教育网系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

【Linux】常用指令【更详细,带实操】

Linux全套讲解系列&#xff0c;参考视频-B站韩顺平&#xff0c;本文的讲解更为详细 目录 一、文件目录指令 1、cd【change directory】指令 ​ 2、mkdir【make dir..】指令​ 3、cp【copy】指令 ​ 4、rm【remove】指令 5、mv【move】指令 6、cat指令和more指令 7、less和…

【爬虫工具】小红书评论高级采集软件

用python开发的爬虫采集工具【爬小红书搜索评论软件】&#xff0c;支持根据关键词采集评论。 思路&#xff1a;笔记关键词->笔记链接->评论 软件界面&#xff1a; 完整文章、详细了解&#xff1a; https://mp.weixin.qq.com/s/C_TuChFwh8Vw76hTGX679Q 好用的软件一起分…

去除字符串或字符串数组中字符串左侧的空格或指定字符numpy.char.lstrip()

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 去除字符串或字符串数组中 字符串左侧的空格或指定字符 numpy.char.lstrip() [太阳]选择题 请问关于以下代码表述错误的选项是&#xff1f; import numpy as np print("【执行】np.cha…

2024/9/22

系列文章目录 文章目录 系列文章目录前言一、两条腿走路二、编程语言能力提升1.廖雪峰的python课2.Leetcode&#xff08;数据结构题&#xff09; 三、机器学习能力提升1.统计学习方法 李航2.kaggle竞赛 四、神经网络能力提升1.神经网络与深度学习 邱锡鹏2.一套自己的万金油模板…

寄存器与内存

第三课&#xff1a;寄存器与内存、中央处理器&#xff08;CPU&#xff09;、指令和程序及高级 CPU 设计-CSDN博客 锁存器 引入 ABO0&#xff08;开始状态&#xff09;001&#xff08;将A置1&#xff09;110&#xff08;将A置0&#xff09;11 无论怎么做&#xff0c;都没法从1变…

Windows PowerShell相关笔记

之前我写的一篇&#xff0c;把我的PS&#xff08;power shell&#xff09;该了配置文件 pyqt5vscode 配置坑笔记_vscode使用pyqt command failed-CSDN博客 文件里写的自动加载conda #region conda initialize # !! Contents within this block are managed by conda init !!…

[Python]一、Python基础编程(2)

F:\BaiduNetdiskDownload\2023人工智能开发学习路线图\1、人工智能开发入门\1、零基础Python编程 1. 文件操作 把⼀些内容 ( 数据 )存储存放起来,可以让程序下⼀次执⾏的时候直接使⽤,⽽不必重新制作⼀份,省时省⼒ 。 1.1 文件的基本操作 1. 打开文件 2. 读写操作 3. 关闭…

基于YOLOv5s的瓶装酒瑕疵检测(附数据集与操作步骤)

本文主要内容:详细介绍了瓶装酒瑕疵检测的整个过程&#xff0c;从创建数据集到训练模型再到预测结果全部可视化操作与分析。 文末有数据集获取方式&#xff0c;请先看检测效果 现状 在酒类生产领域&#xff0c;品质极为重要。瓶装酒的外观瑕疵&#xff0c;不仅影响消费者的购…

基于Ambari搭建hadoop生态圈+Centos7安装教程V2.0优化版(本篇博客写的较为详细,可能比较多,请耐心看)

当我们学习搭建hadoop的时候&#xff0c;未免也会遇见很多繁琐的事情&#xff0c;比如很多错误&#xff0c;需要解决。在以后公司&#xff0c;也不可能让你一个一个搭建hadoop&#xff0c;成千上万的电脑&#xff0c;你再一个个搭建&#xff0c;一个个报错&#xff0c;而且每台…

飞书获取用户及部门信息

1、进入企业后台管理&#xff0c;创建一个企业自建应用 &#xff0c;获取App ID&#xff0c;App Secret 2、 对应用设置api权限及数据权限 3、Java客户端获取用户&#xff0c;部门信息 有两种方式可以获取&#xff1a;1、api 2、sdk的方式 我这里采用sdk的方式&#xff0c;…

如何给文件夹里面的文件批量添加前缀和编号(利用C#写的小工具)

运行结果 将上面的文件编号效果 下载过后启动这个程序即可&#xff08;这个程序灵感来源是上次给美术资源分类和编号的时候给我干吐了&#xff0c;所以写了这个工具&#xff09; 体验链接&#xff1a;laozhupeiqia/批处理 --- laozhupeiqia/批处理 (github.com) 如果对你有帮助…

【C++】面向对象编程的三大特性:深入解析继承机制

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现容器适配器Stack与QueuePriori…

近几年来说最有效率的编程语言和市场最认可的编程语言分别是什么?

在过去的几年中&#xff0c;编程语言的效率和市场认可度在不断演变。不同的语言适用于不同的领域和场景&#xff0c;因而编程语言的“效率”和“市场认可”需要根据具体应用来分析。本文将从两个角度入手&#xff0c;分别探讨近几年中被认为最有效率和最受市场认可的编程语言。…

MISC - 第二天(wireshark,base64解密图片,zip文件伪加密,LSB二进制最低位,ARCHPR工具)

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解杂项 乌镇峰会种图 使用了stegsolve工具&#xff0c;查看更多信息 发现flag信息 更改为html后缀flag{97314e7864a8f62627b26f3f998c37f1} wireshark 看题目是 分析pacp数据包&#xff0c;通过网站登录…

模组差分包,可能是你远程升级失败的罪魁祸首!

也许我们已经习惯生活里的问题接连不断。。。但当收到客户的问题反馈&#xff0c;还是会心头一紧&#xff01; 最近有客户反馈在乡村里频繁出现掉线的情况。 我们赶紧排查&#xff1a;换货、换SIM卡&#xff0c;发现只有去年5月22号采购的那批模块在客户环境附近会出现掉线的…