A simple sin(x) approximation

Introduction

When implementing digital oscillators or filters, a simple way of calculating \sin(2\pi \cdot x) for x=[0..1) is needed. Efficiency, in terms of the number of CPU cycles or hardware complexity, is favoured above accuracy. Several methods are known that produce good approximations to \sin(\pi \cdot x). These methods can be divided into three categories: table-lookup algorithms, approximation functions and recursive resonator algorithms.

Table-lookup algorithms are cycle efficient and their accuracy can be easily increased by increasing the number of table entries. Accuracy can also be increased by introducing interpolation between table entries.

In some memory limited situations, such as small microcontroller and DSP targets, a table is undesirable and an approximation based on functions is preferred.

Here, I will show how to approximate \sin(2 \cdot \pi\cdot x) based on a simple polynomial.

Approximating sin(2*pi*x)

The well known Taylor series seems a good candidate for obtaining a polynomial that approximates \sin(2\pi \cdot x) well. However, the approximation gets worse the further away the function argument gets from the point from which the series was derived. This generates a discontinuity when \sin(2\pi \cdot x) “wraps around”. To avoid such discontinuities, the approximation must produce the same value for x=0 and x=1.

An interesting candidate is the polynomial -16x^2 + 8x, which approximates \sin(2\pi \cdot x) quite well for x=[0..\frac{1}{2}]. The other half of the sinusoid is simply generated by mirroring the polynomial and adjusting for the offset, resulting in 16x^2 - 24x + 8.

How good is it?

The approximation is accurate to within +/- 6% of the total amplitude as is shown by the graphs below:

In sound synthesis and radio applications it is desirable to have low spurious tones. The following graph shows the spectrum of the approximated sinusoidal wave. It was generated using an 65536-point FFT and 2129 sine wave periods.

The spectrum is free of all even harmonics as the approximation is point symmetrical and the “grass” is due to high frequency components aliasing to lower frequencies. The first major spurious response is the third harmonic, which is found at -28.6 dBc.

Show me the code!

/*
  Fast sin(2*pi*x) approximation.
  The caller must make sure that the argument lies
  within [0..1).

  Note: this can be optimized further by using Horner's
  rule for evaluating polynomials, see:
  
  http://en.wikipedia.org/wiki/Horner%27s_method
  
  Omitted here for clarity.
*/

float fast_sin(float x)
{
  if (x < 0.5f)
  {
    return -16.0f*x*x + 8.0f*x;
  }
  else
  {
    return 16.0f*x*x - 24.0f*x + 8.0f;
  }
};

Conclusion

This may not be the world’s best sin approximation, but it sure is simple. Next time we’ll look at a more accurate polynomial-based sin approximation.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s