利用 Cordic 计算浮点三角函数

1. 前言

当前 STM32G4 系列以及 STM32H723 中虽然有专门计算三角函数的硬件 CORDIC,但目前是定点的 CORDIC 硬件,很多实际应用,比如电机控制,数字电源,客户整个软件代码是基于浮点的运算,因此有必要对如何利用 CORDIC 计算浮点的三角函数(本文计算正弦和余弦),以及计算时间的评估做下说明文档,给客户一定的参考示例,本文使用 STM32G474 为例来进行。

2. 使用 CORDIC 计算定点三角函数

这边不做具体的说明,详细信息请参考 STM32G4 的培训文档。实际上就三个步骤,写入CSR 寄存器,写入角度以及模值,读取计算结果。注意这边没有等待标志位的操作,实际上是CORDIC 特有的零开销单次模式 (Zero overhead single shot mode) ,这种是最快的运算方式。输入角度在[-1,1]
图1. Sin/Cos 计算参数说明
在这里插入图片描述
数据是按照 q1.15 或者 q1.31 格式输入和输出,下面是角度对应的数据范围:
图2. 输入角度值数据范围

输入角度范围(角度)输入角度范围(弧度)输入角度范围输入角度 q1.31范围输入角度 q1.15 范围
[-180, 180][-π, π][-1, 1]0x80000000 ~ 0x7FFFFFFF0x8000 ~ 0x7FFF

图3. Cordic 计算定点 Sin/Cos 步骤
在这里插入图片描述

3. 用 CORDIC 浮点计算正余弦量

浮点的计算要做的就是输入和输出对浮点转定点,定点转浮点的操作,同时需要根据角度的周期性,对角度做限制,把角度范围控制在[-π, π]。
图4. 浮点三角函数 Cordic 使用流程
在这里插入图片描述

3.1. 浮点三角函数角度限制

将输入角度范围缩小到[-π, π],用于后面数据输入到 CORDIC 的操作,这边利用了 Sin,Cos 的三角函数的周期性,因此可以直接对数据进行限制,如果能够保证输入角度数据在[-π, π],那么这个限制的操作可以忽略。
图5. 角度限制函数
在这里插入图片描述

3.2. 浮点与定点之间在使用 STM32 Cordic 的转换

角度限制后,按照弧度为单位的数据在输入到 STM32 Cordic 单元时候,需要进行数据q1.31 的变换,输入 Cordic 角度数据与浮点输入角度有以下关系:
𝐴𝑛𝑔𝑙𝑒𝐼𝑛 = 𝐴𝑛𝑔𝑙𝑒𝐹𝑙𝑜𝑎𝑡 ∗ 231/𝜋
在这里插入图片描述

同样的 Cordic 输出数据与浮点输出数据有以下关系:

4. 浮点三角函数计算程序

结合上面的分析,我们可以将几个操作步骤整合起来进行编程。
单独计算浮点正弦 Sin 的函数如下:

/* Define PI */
#define PI 3.1415926536f
/* Define Q31 */
#define Q31 0x80000000
/* Define Q31 to float unit in RADIAN = Q31/PI */
#define RADIAN_Q31_f 683565275.6f
/**
 * @brief Calculate sin value in float unit
 * @param angle in, sin value out
 * @retval None
 */
void Calculate_Float_Sin(float angle,float *sin)
{
	/* Q31,two write, one read, sine calculate, 6 precision */
	CORDIC->CSR = 0x00100061;
	/* Write data into WDATA */
	CORDIC->WDATA = (int32_t )(angle * RADIAN_Q31_f);
	/* Modulus is m=1 */
	CORDIC->WDATA = 0x7FFFFFFF;
	/* Get sin value in float */
	*sin = ((int32_t)CORDIC->RDATA)*1.0f/Q31;
}

计算浮点正余弦 Sin/Cos 函数,同时计算两个函数会更节省时间。

/**
 * @brief Calculate sin/cos value in float unit
 * @param angle in, sin/cos value out
 * @retval None
 */
void Calculate_Float_Sin_Cos(float angle,float *sin, float *cos)
{
	/* Q31,two write, two read, sine calculate, 6 precision */
	CORDIC->CSR = 0x00180061;
	/* Write data into WDATA */
	CORDIC->WDATA = (int32_t )(angle * RADIAN_Q31_f);
	/* Modulus is m=1 */
	CORDIC->WDATA = 0x7FFFFFFF;
	/* Get sin value in float */
	*sin = ((int32_t)CORDIC->RDATA)*1.0f/Q31;
	/* Get cos value in float */
	*cos = ((int32_t)CORDIC->RDATA)*1.0f/Q31;
}

5. 利用 Cordic 计算浮点三角函数时间测试

可以通过对汇编指令的查看,看是否在 STM32G4 上有效的执行了浮点指令 FPU。
图6. 计算浮点正弦函数
在这里插入图片描述
图7. 汇编代码
在这里插入图片描述
这边使能了 TIM3 做时间测试,测试在不同的 IDE 和配置选项下的计算时间。
图8. 时间测试程序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. 结论

从上面的执行浮点 CORDIC 运算程序以及测试结果来看,浮点的三角函数会消耗些时间,主要时间耗在浮点转定点、定点转浮点的过程中,好在 STM32G4 和 STM32H7 系列都带浮点 FPU单元,可减少计算时间,其他影响因素可以考虑 IDE 的配置,程序是否运行在紧耦合 RAM 等配置,以便得到更快的计算速度。


本文档参考ST官方的《【应用笔记】LAT1357+利用Cordic计算浮点三角函数》文档。
参考下载地址:https://download.csdn.net/download/u014319604/88969379

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Xilinx提供了CORDIC IP核,可以用于实现三角函数计算CORDIC(Coordinate Rotation Digital Computer)是一种通过旋转坐标轴来计算三角函数的算法,它具有高精度、低功耗、低面积等优点,在数字信号处理、通信、图像处理等领域得到广泛应用。 以下是实现正弦函数计算的示例代码: ```verilog `timescale 1ns / 1ps module cordic_sin ( input signed [31:0] angle, output reg signed [31:0] sin_out ); wire signed [31:0] x, y, z; reg signed [31:0] x_buf, y_buf, z_buf; reg [31:0] i; CORDIC #( .DATA_WIDTH(32), .MODE(1), // Mode 1: Compute sin and cos .ITERATIONS(16), // Number of iterations .ANGLE_PRECISION(32), // Angle precision .PIPELINE_STAGE(0) // Pipeline stage ) cordic_inst ( .x(x), .y(y), .z(z) ); // Initial values assign x = angle; assign y = 0; assign z = 0; always @ (posedge cordic_inst.clk) begin if (cordic_inst.done) begin sin_out <= y_buf; x_buf <= x; y_buf <= y; z_buf <= z; i <= 0; end else begin // Shift x, y, z for next iteration x_buf <= x; y_buf <= y; z_buf <= z; x <= cordic_inst.x_out >> i; y <= cordic_inst.y_out >> i; z <= cordic_inst.z_out >> i; i <= i + 1; end end endmodule ``` 在上面的代码中,我们使用CORDIC IP核计算输入角度的正弦值。输入角度为一个有符号的32位整数,输出正弦值也是一个有符号的32位整数。我们使用MODE 1来计算正弦和余弦,ITERATIONS为16,ANGLE_PRECISION为32(表示输入角度的精度为32位),PIPELINE_STAGE为0(表示不使用流水线)。 我们将输入角度直接赋值给x,y和z的初始值都为0。每次CORDIC IP核完成一次计算后,我们将得到下一次计算的x、y和z值,同时将当前计算得到的y值存储在sin_out寄存器中。 需要注意的是,CORDIC IP核是一个带有时钟的模块,因此我们需要在时钟上升沿时检查计算是否完成。如果计算完成,我们将存储下一次计算所需的x、y和z值,并将i重置为0,以便进行下一轮迭代。 值得注意的是,CORDIC IP核支持流水线操作,可以在可接受的延迟范围内提高性能。如果您需要更快的计算速度,可以尝试调整PIPELINE_STAGE参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值