Cordic IP核使用说明以及避坑记录

Cordic IP核使用说明以及避坑记录

参考文章:(140条消息) Vivado cordic IP核rotate和translate使用详解(附有代码)_cordic ip核 rotate_迎风打盹儿的博客-CSDN博客
(140条消息) VIVADO cordic IP核_卡布奇诺加勺糖的博客-CSDN博客



前言

项目需求使用了cordicIP核取相位然后旋转,这篇文章主要是记录一下学习IP核以及使用IP核过程中遇到的问题。


一、cordic算法的原理

推荐学习视频:FPGA:Cordic算法介绍与实现_哔哩哔哩_bilibili
视频清晰的讲述了cordic算法的原理以及硬件实现,视频下方还提供了代码和资料,其中有一份XILINX-CORDIC算法文档非常推荐一看。

二、cordic IP核主要功能:

CORDIC(Coordinate Rotation Digital Computer)算法即坐标旋转数字计算方法。该算法通过基本的加和移位运算代替乘法运算,使得矢量的旋转和定向的计算不再需要三角函数、乘法、开方、反三角、指数等函数。有以下功能模式:

  • rotate 旋转
  • translate 变换 ——直角坐标转极坐标
  • sin/cos
  • arctan
  • sinh/cosh
  • arc tanh
  • square root 平方根

这次实现主要关注的是:rotate、 translate

1.translate模式IP核配置和踩坑记录

在这里插入图片描述

  1. Functional Selection: 模式选择,此处选择Translate
  2. Architectural Configuration: CORDIC核心有两种架构配置,并行和串行。
  3. Pipelining Mode: CORDIC核心提供了三种流水线模式:无、最优和最大。流水线模式的选择基于功能配置和体系结构配置的选择。

None: CORDIC核心在没有流水线的情况下实现。
优化: CORDIC核心实现了尽可能多的流水线阶段,而不使用任何额外的lut。 最大:CORDIC核心在每个shift-add子阶段之后都有一个管道实现。 此处选择优化。

  1. Phase Format:

radians格式下就是输入正常的弧度制,输入范围是(-π,π) scale
radians则是输入归一化的弧度值,输入范围是(-1,1) 说明白点,radians格式下,你的输入就相当于在scale radians下输入再乘π。 此处选择Radians。

  1. Round Mode: CORDIC核心提供四种舍入模式。

Truncate截断: The X_OUT, Y_OUT, and PHASE_OUT outputs are truncated.

Positive Infinity向上取整: The X_OUT, Y_OUT, and PHASE_OUT outputs are
rounded such that 1/2 is rounded up (towards positive infinity). It is
equivalent to the MATLAB function floor(x + 0.5).

Pos Neg Infinity四舍五入: The outputs X_OUT, Y_OUT, and PHASE_OUT are rounded such that 1/2 is rounded up (towards positive infinity) and -1/2 is rounded down (towards negative infinity). It is equivalent to the MATLAB function round(x).

Nearest Even最近偶数: The X_OUT, Y_OUT, and PHASE_OUT outputs are rounded toward the nearest even number such that a 1/2 is rounded down and 3/2 is rounded up.
根据需要选择Round Pos Neg Inf。

  1. Iterations和 Precision: 不选设为0 IP核根据其他设置默认设置。
  2. Coarse Rotation:如果关闭粗旋转,输入/输出范围将限制在第一象限(-Pi/4,+ Pi/4)。所以应该勾上。
  3. 【坑】Compensation Scaling:补偿方式。cordic这个IP核在使用的时候他的输出是乘了倍数Z的,第一次用的时候没有勾选补偿方式,发现输出结果角度是对的,但是模值不正确,勾选补偿方式后cordic会自己把输出再乘一个Z的倒数,这样就对了。

No Scale Compensation: 输出X和Y没有补偿,并生成,按比例Z缩放。
LUT Based:输出X和Y补偿使用基于LUT的常系数乘法器。
BRAM: 输出X和Y使用块ram为基础的常系数乘法器进行补偿。
Embedded Multiplier: 输出X和Y使用DSP Slice进行补偿。
此处如果选No,不会补偿,输出结果不对。以保证结果正确,必须选择一项补偿方式。此处默认选LUT Based。

  1. 数据范围 需要注意,否则输出可能出错
    在这里插入图片描述
    在这里插入图片描述
    Translation的数据范围,fix格式下数据范围不能超过±1,此外要注意输出的模值会不会超位宽的问题,如果有超需要扩展位宽!!!Fix16_14实际上就是(signed [15:0])/2^14

    Fix16_14: 1(符号位)+1(整数位)+14(小数位)
    仿真器显示定点小数:
    【技巧】Vivado 仿真器simulation显示定点小数_LiangWF22的博客-CSDN博客
    在这里插入图片描述

  2. 输入PADDING:具体是否有补零和补零位数根据IP核配置页面为准。另外如果输入X/Y_IN位宽和IP核位宽不一致需要补符号位。

在这里插入图片描述

第二页不用修改使用默认值即可:
在这里插入图片描述

2. rotate模式IP核配置和踩坑记录

配置和translate模式基本一致,这里我采的一个坑是,我是把translate的输出模值和相位经过一定处理后送到rotate里面,translate的输出位宽是16位,相位是fix16_13,但是我的rotate的输入phase是fix17_14(为了避免rotate输出的模值溢出多给了一位)我刚开始是直接补的符号位,这样子==实际上rotate收到的phase变成原来的一半了!!!==导致一个数据也不对,后来改成低位补一个0就解决了。

在这里插入图片描述


3. 代码参考

参考: (140条消息) Vivado cordic IP核rotate和translate使用详解(附有代码)_cordic ip核 rotate_迎风打盹儿的博客-CSDN博客

1.	`timescale 1ns / 1ps
2.	
3.	 
4.	module cordic_test_tb();
5.	 
6.	// cordic_translate_test Parameters
7.	parameter PERIOD  = 2;
8.	 
9.	// cordic_translate_test Inputs
10.	reg   clk                                  = 0 ;
11.	reg   start                                = 0 ;
12.	reg   [15:0]  x_in                         = 0 ;
13.	reg   [15:0]  y_in                         = 0 ;
14.	reg   [15:0]  pha_in                       = 0 ;
15.	 
16.	// cordic_translate_test Outputs
17.	wire  over1                                 ;
18.	wire  over2                                 ;
19.	wire  [15:0]  x_out1                        ;
20.	wire  [16:0]  x_out2                        ;
21.	wire  [16:0]  y_out2                        ;
22.	wire  [15:0]  pha_out                      ;
23.	 
28.	 
29.	cordic_translate_test  u_cordic_translate_test (
30.	    .clk                     ( clk             ),
31.	    .start                   ( start           ),
32.	    .x_in                    ( x_in     [15:0] ),
33.	    .y_in                    ( y_in     [15:0] ),
34.	 
35.	    .over                    ( over1            ),
36.	    .x_out                   ( x_out1    [15:0] ),
37.	    .pha_out                 ( pha_out   [15:0] )
38.	);
39.	 
40.	 
41.	initial
42.	begin
43.		forever #(PERIOD/2)  clk=~clk;
44.	    #5  start<=1;
45.	    x_in<=16'b0011000000000000;
46.	    y_in<=16'b0011000000000000;
47.	    pha_in<=16'b0011001001000011;
48.	    #2     
49.	    x_in<=16'b1110000000000000;
50.	    y_in<=16'b1110000000000000;
51.	    pha_in<=16'b1001101101111000;
52.	    
53.	    #10
54.	    x_in<=16'b0110000000000000;
55.	    y_in<=16'b1010000000000000;
56.	    pha_in<=16'b0110010010000111;
57.	end
58.	
59.	
60.	
61.	cordic_rotate_test  u_cordic_rotate_test (
62.	    .clk                     ( clk            ),
63.	    .start                   ( start          ),
64.	    .x_in                    ( x_in           ),
65.	    .y_in                    ( y_in           ),
66.	    .pha_in                  ( pha_in         ),
67.	 
68.	    .over                    ( over2           ),
69.	    .x_out                   ( x_out2          ),
70.	    .y_out                   ( y_out2          )
71.	);
72.	 
73.	
74.	
75.	 
76.	endmodule

module cordic_rotate_test(
input clk,                    //输入时钟信号
input start,                  //输入开始计算信号
input [15:0] x_in,            //输入坐标x
input [15:0] y_in,            //输入坐标y
input [15:0] pha_in,          //输入相角
output wire over,             //输出计算完成标志
output wire [16:0] x_out,     //输出坐标x
output wire [16:0] y_out      //输出坐标y
    );
wire [16:0]phase ;
wire [40:0] rotate_out;
//assign phase = {pha_in[15],pha_in};
assign phase = {pha_in,1'b0};
wire [16:0] x_in_1;
wire [16:0] y_in_1;
assign y_in_1 = {y_in[15],y_in};
assign x_in_1 = {x_in[15],x_in};
cordic_rotate u_cordic_rotate_ip (
  .aclk(clk),                                        // input wire aclk
  .s_axis_phase_tvalid(start),          // input wire s_axis_phase_tvalid
  .s_axis_phase_tdata(phase),            // input wire [17 : 0] s_axis_phase_tdata
  .s_axis_cartesian_tvalid(start),  // input wire s_axis_cartesian_tvalid
  .s_axis_cartesian_tdata({y_in_1,7'b0000000,x_in_1}),    // input wire [41 : 0] s_axis_cartesian_tdata
  .m_axis_dout_tvalid(over),            // output wire m_axis_dout_tvalid
  .m_axis_dout_tdata(rotate_out)              // output wire [41 : 0] m_axis_dout_tdata
);
assign  x_out = rotate_out[16:0];
assign  y_out = rotate_out[40:24];
endmodule
module cordic_translate_test(
input clk,                    //输入时钟信号
input start,                  //输入开始计算信号
input [15:0] x_in,            //输入坐标x
input [15:0] y_in,            //输入坐标y
output wire over,              //输出计算完成标志
output wire [15:0] x_out,      //输出坐标x
output wire [15:0] pha_out     //输出相角
);
 
 
cordic_translate cordic_translate_inst(
  .aclk(clk),                                        // input wire aclk
  .s_axis_cartesian_tvalid(start),  // input wire s_axis_cartesian_tvalid
  .s_axis_cartesian_tdata({y_in,x_in}),    // input wire [63 : 0] s_axis_cartesian_tdata
  .m_axis_dout_tvalid(over),            // output wire m_axis_dout_tvalid
  .m_axis_dout_tdata({pha_out,x_out})              // output wire [63 : 0] m_axis_dout_tdata
  
);
 
endmodule
### 回答1: Cordic IP是一种用于计算正弦和余弦函数的数学运算IP。在进行Cordic IP的sin/cos测试之前,我们需要编写一个测试台(testbench)来进行测试。 测试台的设计目标是在输入一组角度值后,计算出对应的正弦和余弦值,并与预期值进行对比,以确保Cordic IP的功能正确性。 首先,我们需要确定测试的角度值范围。我们可以选择一个角度的正弦和余弦值是已知的,并以这个角度为中心,测试一定范围内的角度值。例如,我们可以选择0°到360°之间的某个角度值进行测试。 测试台的流程如下: 1. 定义输入信号和预期输出信号。 2. 将输入信号传递给Cordic IP,并接收其计算得到的结果。 3. 将Cordic IP计算的结果与预期输出进行对比,检查它们之间的误差是否在可接受范围内。 4. 如果误差在可接受范围内,则测试通过,输出测试结果。 5. 如果误差不在可接受范围内,则测试失败,输出测试结果。 在测试台中,我们可以通过生成随机角度值的方法,对Cordic IP进行多组测试,以覆盖更广泛的角度范围。 测试台设计中需要考虑的几个重要因素包括输入输出数据的精度、测试角度的覆盖范围和测试结果的判定标准。通过合理设置这些参数,我们可以编写一个有效的Cordic IPsin/cos测试台,以确保IP的正确性。 ### 回答2: Cordic IP是一种用于计算三角函数的硬件心,通过使用迭代方法来实现高效的计算。为了测试Cordic IP的sin/cos功能,我们可以编写一个Testbench。 Testbench的目的是验证Cordic IP的输出结果是否正确。在Testbench中,我们首先需要生成一系列的输入值作为测试用例,这些输入值可以按照一定的步长递增或随机生成。然后,将这些输入值送入Cordic IP进行计算,得到对应的sin和cos值。 接下来,我们需要知道这些测试用例的预期输出值。我们可以使用软件或数学库函数计算标准的sin和cos值作为参考。然后,将Cordic IP的输出结果与预期输出值进行比较。如果两者非常接近,即可认为Cordic IP的sin/cos功能正确。 在Testbench中,我们可以使用assert语句对比Cordic IP的输出结果和预期输出值。如果两者不匹配,assert语句会给出错误提示。此外,我们还可以输出测试结果是否通过的信息,以便于判断Cordic IP的性能和准确性。 最后,在Testbench中我们还可以记录测试的运行时间以及任何其他有用的信息,以便于分析和评估Cordic IP的性能。 总结起来,通过编写一个完善的Testbench,我们可以对Cordic IP的sin/cos功能进行全面的测试和评估,确保其在实际应用中的正确性和可靠性。 ### 回答3: Cordic是一种数字算法,通常用于计算三角函数(如sin和cos函数)。Cordic IP是一种可以在FPGA中实现Cordic算法的IP。 进行Cordic IP的sin/cos测试需要编写一个测试平台,也就是所谓的testbench。测试平台主要用于验证Cordic IP的正确性和性能。 测试平台的第一步是生成输入信号,即角度(或弧度)的值。可以使用随机数生成器来生成不同的角度输入。然后将这些角度值提供给Cordic IP进行计算。 下一步是为Cordic IP建立期望输出。可以使用系统级建模(System-Level Modeling)来计算期望的sin和cos值。使用已知的数学公式,将输入的角度值代入,计算出对应的sin和cos值。 然后,将输入信号提供给Cordic IP,将计算结果与期望输出进行比较。可以使用assert语句来进行比较。如果计算结果与期望输出相差很小,可以认为测试通过。否则,可能需要检查IP的实现是否存在问题。 在测试过程中,还可以记录每个输入角度和对应的计算结果,以便后续分析和调试。可以将这些记录在一个文件中,或者将其显示在仿真工具的波形窗口中。 测试完所有的输入角度后,可以进行一些统计分析,如计算平均误差、最大误差等。这些分析可以用于评估Cordic IP的性能和准确性。 总之,Cordic IP的sin/cos测试需要编写一个测试平台,生成输入信号,计算期望输出,并将计算结果与期望输出进行比较。通过分析比较结果,可以评估IP的性能和准确性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值