views:

574

answers:

8

sin and cos functions are slow and need a lot of resources to run on embedded systems. How does one calculate sin and cos functions in a more resource-saving and faster way?

+14  A: 

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

pavium
A simple 256-element table will give you a small section of sine; everything else can be derived through simple symmetry rules.
S.Lott
Yes, I seem to recall seeing that kind of thing described in HP's explanation of their calculator algorithms.
pavium
To clarify, the problem with a Taylor series is not speed, but combined speed-accuracy. It's probably the quickest method for low-precision calculations, but doesn't do too well if you want many decimal places. Fourier series are irrelevant here.
Noldorin
Yes, lookup tables are ideal. +1
Floetic
If I remember right a 512 entry lookup table for 0..90°, normalized to 0..2^15 gives - with linear interpolation - up to 21 bits of precission. That's just two bits worses than a proper sine.
Nils Pipenbrinck
+1 without cpu power or time, lookups are it.
kenny
And there's of course no reason to stick to linear interpolation. sin(x) is rather well-behaved, so higher-order interpolation works too. In essence there's a whole continuum between "all data, no interpolation" and "sin(0)=0, sin(90)=1, interpolate everything else".
MSalters
You only need to cover 0 to 45° with a table. Everything else is symmetric to this. 256 entries in the table gives you 0.17° steps. How much resolution do you need?
S.Lott
There's a good chance with an embedded system that you won't need arbitrary inputs either. If it's coming from a mechanical encoder, how many unique angles might you get? A lookup table is the natural answer.
Mark Ransom
@S.Lott -- can you clarify the "0 to 45°" bit? I imagine you'd need either 0 to 45° for _both_ sine and cosine tables, or 0 to 90° for just a sine table.
Craig McQueen
A: 

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.

Adam Matan
+2  A: 
  1. Lookup-tables
  2. Taylor series, like you say

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.

unwind
+4  A: 

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.

Artelius
+8  A: 

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.

Noldorin
Is there a link missing for "check out this question"?
Craig McQueen
@Craig: You're right. Somehow managed to miss that...
Noldorin
+1  A: 

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.

John D. Cook
+2  A: 

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.

Clifford
A: 

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

Mtr