嵌入式系统上的三角函数
sin
和 cos
函数速度较慢,并且需要大量资源才能在嵌入式系统上运行。如何以更节省资源且更快的方式计算 sin
和 cos
函数?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
sin
和 cos
函数速度较慢,并且需要大量资源才能在嵌入式系统上运行。如何以更节省资源且更快的方式计算 sin
和 cos
函数?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(11)
计算 Taylor 或 傅里叶级数总是很耗时的。
在嵌入式系统中,您应该考虑查找表。
网上可能还有关于惠普如何在其早期科学计算器中优化此类计算的有趣信息。
我记得当时看到过这样的东西
To calculate a Taylor or Fourier series is always going to be time-consuming.
In an embedded system, you should think about lookup tables.
There might also be interesting information on the 'Net about how Hewlett-Packard optimised such calculations in their early scientific calculators.
I recall seeing such stuff at the time
带插值的查找表无疑是最有效的解决方案。但是,如果您想使用更少的内存,CORDIC 是计算三角函数值的非常有效的算法功能,并且通常在手持计算器中实现。
顺便说一句,使用傅里叶级数表示这些函数没有任何意义,因为您只是创建了一个如何评估级数的正弦/余弦项的循环问题。泰勒级数是一种众所周知的近似方法,但在许多情况下误差大得令人无法接受。
您可能还想查看关于快速三角函数的这个问题及其答案 Java 函数(因此代码可以轻松移植)。其中提到了 CORDIC 和切比雪夫近似等。其中之一无疑会满足您的需求。
A lookup table with interpolation would without doubt be the most efficient solution. If you want to use less memory however, CORDIC is a pretty efficient algorithm for calculating values of trig functions, and is commonly implemented in handheld calculators.
As a side point, it doesn't make any sense to represent these functions using fourier series, since you're just creating a circular problem of how you then evaluate the sin/cos terms of series. A Taylor series is a well-known approximation method, but the error turns out to be unacceptably large in many cases.
You may also want to check out this question and its answers, regarding fast trigonometric functions for Java (thus the code could be ported easily). It mentions both the CORDIC and Chebyshev approximations, among others. One of them will undoubtedly suit your needs.
取决于你需要它做什么。如果您对角度精度不是很在意(例如,如果精确到最接近的度数就可以),那么只需使用值查找表即可。如果您没有 FPU,请使用定点。
计算 sin/cos 函数的一种简单方法是使用泰勒级数(如三角函数
傅里叶级数计算需要知道一些正弦/余弦值。不过,如果大多数时候您将内容存储在频域中,那么您可能可以节省计算 - 取决于您正在做什么。
Depends on what you need it for. If you are not very fussed about your angle accuracy (e.g. if to the nearest degree is OK) then just use a lookup table of values. If you don't have an FPU, work in fixed-point.
One simple way to calculate sin/cos functions is with Taylor series (as shown under Trigonometric Functions here). The fewer terms you use, the less accurate the values but the faster the calculations.
Fourier series calculations require some sin/cos values to be known. If you store things in the frequency domain most of the time, though, you can potentially save on calculations - depending on what it is you are doing.
Dobb 博士的这篇文章:用定点算术优化数学密集型应用 有很好的解释CORDIC 算法的一部分,并为本文讨论的库提供完整的源代码。
This Dr. Dobb's article: Optimizing Math-Intensive Applications with Fixed-Point Arithmetic has a good explanation of CORDIC algorithms and provides complete source code for the library discussed in the article.
注意,使用查找表,你通常可以优化通过限制域,例如将角度表示为无符号字符,只为您提供围绕圆的 256 步,但也是一个非常紧凑的表格。可以对值执行类似的操作,例如使用定点。
Note that with lookup-tables, you can often optimize things by limiting the domain, e.g. represent the angle as an unsigned char, giving you only 256 steps around the circle but also a very compact table. Similar things can be done to the value, like using fixed-point.
请参阅 Stack Overflow 问题三角函数如何工作? 已接受的答案其中解释了如何缩小范围,然后使用 CORDIC,然后进行一些进一步优化的一些细节。
See the Stack Overflow question How do Trigonometric functions work? The accepted answer there explains some details of how to do range reduction, then use CORDIC, then do some further optimizations.
似乎有一个很好的伪代码示例这里和显式代码此处。
但是,正如 @unwind 所建议的,您可能希望尝试在一台像样的计算机上预先计算这些表并将这些表加载到嵌入式设备。
如果您的答案不必非常精确,则查找表会相当小,您可以将其存储在设备的内存中。如果您需要更高的精度,则需要在设备内进行计算。这是内存、时间和所需精度之间的权衡;答案取决于您项目的具体性质。
There seems to be an nice pseudocode example here and explicit code here.
However, as @unwind suggested, you might want to try to precalculate these tables on a decent computer and load the tables to the embedded device.
If your answer doesn't have to be very exact, the lookup table would be rather small, and you'll be able to store it in your device's memory. If you need higher accuracy, you'll need to calculate it within the device. It's a tradeoff between memory, time and required precision; the answer relies on the specific nature of your project.
在某些情况下,只需使用 IIR 滤波器即可进行管理,并在所需频率上调谐到谐振。
请看这里:http://www. ee.ic.ac.uk/pcheung/teaching/ee3_Study_Project/Sinewave%20Generation(708).pdf
In some cases one can manage with just IIR filter, tuned to resonance on needed frequency.
Look here: http://www.ee.ic.ac.uk/pcheung/teaching/ee3_Study_Project/Sinewave%20Generation(708).pdf
这可能会有所帮助/启发:
雷神之锤 III 中的神奇平方根
This may be of some help / inspiration:
Magical square root in Quake III
我参加聚会有点晚了,但无论如何我想分享一个使用查找表(包括表生成器)的现成的高效解决方案:DFTrig。
DFTrig 由两部分组成:
tablegen
(用 Java 编写,但这并不重要),它接收多个选项并生成 C 代码(带有查找表的 const 结构) 可以tablegen
生成的查找表。当然,查找表仅包含最少的信息:仅单个象限的正弦值,即
[0, 90]
度。这足以计算任何角度的正弦/余弦。该行为是完全可定制的。您可以指定:
表中项目的类型(整个 C 项目通用)。
因此,根据您的需要,您可以:
我在我的嵌入式项目中使用它,效果很好。
I'm a bit late to the party, but anyway I want to share a ready-made efficient solution that uses lookup table (table generator included) : DFTrig.
DFTrig consists of two parts:
tablegen
(written in Java, but that doesn't matter much) that receives several options and produces C code (const struct with lookup table)tablegen
.Of course, lookup table contains only minimal information: sine values for just a single quadrant, i.e.
[0, 90]
degrees. That is fairly enough to calculate sine / cosine for any angle.The behavior is quite customizable. You may specify:
Type of items in the table (common for the whole C project).
So, depending on your needs, you may:
I use it in my embedded projects, it works nicely.
您可以看一下这个 8 位 AVR 微控制器的任意定点库:
https://community.atmel.com/projects/afp- Arbitrary-定点库
编辑:链接已更新
You can take a look at this arbitrary fixed point library for 8-bit AVR microcontrollers:
https://community.atmel.com/projects/afp-arbitrary-fixed-point-lib
EDIT: link updated