ARM CMSIS DSP库函数arm_sin_cos_f32的BUG

news/2024/10/30 11:18:12/

ARM CMSIS DSP库函数arm_sin_cos_f32的BUG

 

王强

  2016-05-10

本人从事电力电子产品的研发,使用的是STM32F4系列的CPU,带浮点运行,进行park变换或逆变换的时候,需要用到sin和cos,为了方便就采用了arm_sin_cos_f32这个函数。

本文为原创,未经作者允许不得转载。

1. BUG发现

输出的电流会突然出现一个很大负向电流,已经在PC上通过C语言仿真,不会出现算法上的错误,把问题定位到角度到了,因为角度是反馈算出来的,可能会出问题,通过打印却看到sin和cos的值不在-1到1范围,判定是arm_sin_cos_f32这个函数造成的,并不是角度异常造成的,而且角度值为-720度。

 

2. 源代码分析

  遇到上面的问题后,在ARM CMSIS官网上下载了源代码,找到arm_sin_cos_f32这个函数的源代码如下:

 

void arm_sin_cos_f32(

  float32_t theta,

  float32_t * pSinVal,

  float32_t * pCosVal)

{

  float32_t fract, in;                             /* Temporary variables for input, output */

  uint16_t indexS, indexC;                         /* Index variable */

  float32_t f1, f2, d1, d2;                        /* Two nearest output values */

  int32_t n;

  float32_t findex, Dn, Df, temp;

 

  /* input x is in degrees */

  /* Scale the input, divide input by 360, for cosine add 0.25 (pi/2) to read sine table */

  in = theta * 0.00277777777778f;

 

  /* Calculation of floor value of input */

  n = (int32_t) in;

 

  /* Make negative values towards -infinity */

  if(in < 0.0f)

  {

    n--;

  }

  /* Map input value to [0 1] */

  in = in - (float32_t) n;

 

  /* Calculation of index of the table */

  findex = (float32_t) FAST_MATH_TABLE_SIZE * in;

  indexS = ((uint16_t)findex) & 0x1ff;

  indexC = (indexS + (FAST_MATH_TABLE_SIZE / 4)) & 0x1ff;

 

  /* fractional value calculation */

  fract = findex - (float32_t) indexS;

 

  /* Read two nearest values of input value from the cos & sin tables */

  f1 = sinTable_f32[indexC+0];

  f2 = sinTable_f32[indexC+1];

  d1 = -sinTable_f32[indexS+0];

  d2 = -sinTable_f32[indexS+1];

 

  Dn = 0.0122718463030f; // delta between the two points (fixed), in this case 2*pi/FAST_MATH_TABLE_SIZE

  Df = f2 - f1; // delta between the values of the functions

  temp = Dn*(d1 + d2) - 2*Df;

  temp = fract*temp + (3*Df - (d2 + 2*d1)*Dn);

  temp = fract*temp + d1*Dn;

 

  /* Calculation of cosine value */

  *pCosVal = fract*temp + f1;

  

  /* Read two nearest values of input value from the cos & sin tables */

  f1 = sinTable_f32[indexS+0];

  f2 = sinTable_f32[indexS+1];

  d1 = sinTable_f32[indexC+0];

  d2 = sinTable_f32[indexC+1];

 

  Df = f2 - f1; // delta between the values of the functions

  temp = Dn*(d1 + d2) - 2*Df;

  temp = fract*temp + (3*Df - (d2 + 2*d1)*Dn);

  temp = fract*temp + d1*Dn;

  

  /* Calculation of sine value */

  *pSinVal = fract*temp + f1;

}

 

当theta = -720时,in = 1, findex = 512.0,indexS = 0,fract = 512。

上面的函数采用的方法是线性插值的方法,所以fract应该只在0到1,所以产生了上面的BUG。

 

3. 对应方法

Arm_sin_cos_f32这个函数的输入范围是-180到180,但官网上也写了,如果超出这个范围,函数将自动调整回来,所以我的代码中没有对输入范围有限制,比较在-720度时出现了这个问题,仔细分析代码,如果在-180到180之间是不会出问题的。那么解决方法就是将输入限制在-180到180之间就可以了。

 

4. 总结

权威也不一定权威。

追加:

上面的应对方法还是会存在BUG,因为还有一个BUG点就是-0.000001,这个时候也会造成in = 1,从而使fract = 512。所以将输入角度设置为-180到180也是有问题的,必须检测0点附近,如果在0附近时,强制给一个0。但看代码发现,正数是都不会出问题,所以原则上把角度范围限制在[0~无穷大),也是可行的。以上的方法都是通过规避这个BUG来解决问题,当然也有修复的办法,这里给出一种,在下面这行代码

  /* Map input value to [0 1] */

  in = in - (float32_t) n;

在代码中找到这行代码,在代码下面加入以下代码,

if ( in >= 1 )

{

    in = 0;

}

这样应该可以彻底解决,而且对角度也没有限定了。大家可以把上面的代码直接放在自己的工程中,当然函数名需要修改下,比如my_sin_cos_f32,头文件也需要追加


#include "../../DSP_LIB/include/Arm_math.h"
#include "../../DSP_LIB/include/Arm_common_tables.h"

测试了下,0点附近不会再出问题了。


http://www.ppmy.cn/news/520371.html

相关文章

基于ARM 的neon介绍以及常用intrinsic函数总结

在介绍NEON前&#xff0c;必须要介绍一下SIMD。 1.什么是simd 众所周知&#xff0c;计算机程序需要编译成指令才能让 CPU 识别并执行运算。所以&#xff0c;CPU 指令处理数据的能力是衡量 CPU 性能的重要指标。为了提高 CPU 指令处理数据的能力&#xff0c;半导体厂商在 CPU …

【嵌入式】STM32利用arm-dsp库进行FIR滤波

目录 一、Matlab中的FIR实验1.搭建原始信号2.设计FIR滤波器3.FIR滤波4.滤波前后对比 二、嵌入式平台FIR滤波移植1.arm-dsp库移植2.获得FIR滤波系数3.基于arm-dsp的FIR程序4.滤波结果-与Matlab比对 三、总结 电力电子应用中&#xff0c;往往需要对电流、电压信号进行采样&#x…

【STM32H7的DSP教程】第30章 STM32H7复数浮点FFT(支持单精度和双精度)

完整版教程下载地址&#xff1a;http://www.armbbs.cn/forum.php?modviewthread&tid94547 第30章 STM32H7复数浮点FFT&#xff08;支持单精度和双精度&#xff09; 本章主要讲解复数浮点FTT&#xff0c;支持单精度和双精度。 目录 30.1 初学者重要提示 30.2 复…

【STM32H7的DSP教程】第32章 STM32H7的实数FFT的逆变换(支持单精度和双精度)

完整版教程下载地址&#xff1a;http://www.armbbs.cn/forum.php?modviewthread&tid94547 第32章 STM32H7的实数FFT的逆变换(支持单精度和双精度) 本章主要讲解实数FFT的逆变换实现。通过FFT变换将波形从时域转换到频域&#xff0c;通过IFFT逆变换实现从频域到时域…

【STM32H7的DSP教程】第31章 STM32H7实数浮点FFT(支持单精度和双精度)

完整版教程下载地址&#xff1a;http://www.armbbs.cn/forum.php?modviewthread&tid94547 第31章 STM32H7实数浮点FFT&#xff08;支持单精度和双精度&#xff09; 本章主要讲解实数浮点FTT&#xff0c;支持单精度和双精度。 目录 31.1 初学者重要提示 31.2 实…

STM32 实数FFT 极速配置

想要进行FFT操作就得配置DSP环境&#xff0c;操作如下 STM32 keil极速配置DSP环境 关于FFT&#xff0c;先上操作再讲含义 操作 添加定义 #define fftsize 256 //对256个数据进行FFT #define ifftFlag 0float32_t testInput_f32[256]{0}; float32_t testOutput_f32[256…

STM32 FFT算法实现

DSP 库运行环境搭建 在 MDK 里面搭建 STM32F4 的 DSP 运行环境(使用.lib 方式)是很简单的&#xff0c;分为 3 个步骤&#xff1a; 1&#xff0c; 添加文件。 首先&#xff0c;我们在例程工程目录下新建&#xff1a;DSP_LIB 文件夹&#xff0c;存放我们将要添加的文件&#xff…

STM32+CubeMX 通过RMS和FFT进行波形识别

波形识别 本文所展示的程序可以用于分辨正弦波、三角波、方波三种波形。 文章目录 波形识别思路可以判断波形的两个特点时域方面频域方面 外设配置 & DSP库配置代码部分串口重定向时域部分变量定义ADC采集求最大值&#xff0c;最小值&#xff0c;幅值取出波形的一个周期求…