嵌入式系统上的三角函数

sincos函数很慢,需要大量资源才能在嵌入式系统上运行。 如何以更节省资源和更快速的方式计算sincos函数?

计算泰勒或傅里叶级数总是很费时间。

在嵌入式系统中,您应该考虑查找表 。

关于惠普如何在早期科学计算器中优化此类计算的网络上也可能有一些有趣的信息。

我记得当时看到这样的东西

毫无疑问,带插值的查找表是最有效的解决方案。 但是,如果您想使用更少的内存, CORDIC是一种非常有效的计算三角函数值的算法,通常在手持式计算器中实现。

作为一个侧面点,使用傅里叶级数表示这些函数没有任何意义,因为您只是创建了一个循环问题,即如何评估系列的sin / cos项。 泰勒级数是一种众所周知的近似方法,但在许多情况下,误差大得令人无法接受。

您可能还想查看这个问题及其答案 ,关于Java的快速三角函数(因此代码可以轻松移植)。 它提到了CORDIC和Chebyshev近似等。 其中一个无疑将满足您的需求。

取决于你需要它。 如果您对角度精度不太满意(例如,如果最接近的度数可以),那么只需使用值的查找表。 如果您没有FPU,请在定点工作。

计算正弦/余弦函数的一种简单方法是使用泰勒级数(如此处的三角函数所示)。 您使用的术语越少,值越不准确,但计算越快。

傅里叶级数计算需要知道一些正弦/余弦值。 但是,如果您在大多数时间将事物存储在频域中 ,则可以节省计算 – 取决于您正在做什么。

Dobb博士的文章: 使用定点算法优化数学密集型应用程序对CORDIC算法有很好的解释,并为本文中讨论的库提供了完整的源代码。

  1. 查找表
  2. 泰勒系列 ,就像你说的那样

请注意,对于查找表,您通常可以通过限制域来优化事物,例如将角度表示为无符号字符,在圆周围只有256步,但也是一个非常紧凑的表。 可以对值进行类似的操作,例如使用定点。

请参阅Stack Overflow问题Trigonometric函数如何工作? 接受的答案解释了如何进行范围缩减的一些细节,然后使用CORDIC,然后进行一些进一步的优化。

这里似乎有一个很好的伪代码示例和显式代码。

但是,正如@unwind建议的那样,您可能希望尝试在正常的计算机上预先计算这些表,并将表加载到嵌入式设备。

如果您的答案不一定非常精确,那么查找表会相当小,您将能够将其存储在设备的内存中。 如果您需要更高的精度,则需要在设备中进行计算。 这是记忆,时间和所需精度之间的权衡; 答案取决于项目的特定性质。

在某些情况下,可以使用IIR滤波器进行管理,调谐到所需频率的谐振。 看这里: http : //www.ee.ic.ac.uk/pcheung/teaching/ee3_Study_Project/Sinewave%20Generation(708).pdf

这可能是一些帮助/灵感: Quake III中神奇的平方根

我有点迟到了,但无论如何我想分享一个现成的高效解决方案,使用查找表(包括表生成器): DFTrig 。

DFTrig由两部分组成:

  • 查找表生成器tablegen (用Java编写,但无关紧要)接收多个选项并生成C代码(带查找表的const结构)
  • 小型C模块,与tablegen生成的查找表tablegen

当然,查找表只包含最少的信息:只有一个象限的正弦值,即[0, 90]度。 这相当于计算任何角度的正弦/余弦。

行为是可定制的。 您可以指定:

  • 查找表中每个项目乘以的因子(基于每个表);
  • 表中每个项目之间的度数(基于每个表格); 表中的项目类型(整个C项目通用)。

因此,根据您的需求,您可以:

  • 使用max factor为整个应用程序生成单个表,以便C项目的任何子系统可以使用该单个表,提供所需的因子,如果请求的因子不是表的因子,则将重新计算;
  • 生成多个表,每个表都有ad hoc因子,C项目的每个子系统都使用其专用表。 然后,可以按原样从表中返回值,而无需重新计算; 这工作得更快。

我在我的嵌入式项目中使用它,它工作得很好。

您可以查看这个用于8位AVR微控制器的任意定点库: https : //community.atmel.com/projects/afp-arbitrary-fixed-point-lib

编辑:链接已更新