[sdiy] Approximating sine with plain integer math
Richie Burnett
rburnett at richieburnett.co.uk
Thu Apr 7 01:27:48 CEST 2016
Neat. It's got quite a high distortion for a sinewave as you said, and has
only odd harmonics present. The waveform you have actually generated is the
integral of a triangle waveform.
As a triangle is the integral of a squarewave and has a steeper spectral
roll-off, your waveform is the integral of the triangle waveform, and has an
even steeper spectral roll-off:
Square has odd harmonics only and -6dB/oct rolloff
Triangle has odd harmonics only and -12dB/oct rolloff
"John Ames' sinewave approx" has odd harmonics only and -18dB/oct rolloff.
You can play similar tricks with generating successive integrals of a
sawtooth waveform, to get from sawtooth to parabola and then to something
that looks sine-like and has a -18dB/oct rolloff, but has both odd and even
harmonics present. Technically inferior to your approximation because the
THD is higher, but might sound nicer with even harmonics present!?!?
Did you consider a lookup-table with linear interpolation? ...that would be
my method of choice for sinewave generation if I wanted low distortion. You
can also get excellent results with low-order polynomial approximations with
or without range-reduction techniques to exploit the inherent symmetries of
the sine function. These can all be implemented with fixed-point
arithmetic. No need to go to floating point.
Good luck with your project!
-Richie,
-----Original Message-----
From: John Ames
Sent: Wednesday, April 06, 2016 11:55 PM
To: synthdiy diy
Subject: [sdiy] Approximating sine with plain integer math
I'm working on a softsynth for a project, and one of my goals is to
avoid floating-point math (no particular reason other than just to see
if I can, but there's still architectures out there where it makes a
significant difference, so what the hey.) Initially I had compromised
on that when I needed a sine waveform for my oscillators, but today,
while playing around with a way to make the sawtooth less of a plain
linear ramp, I stumbled onto a way to generate what I think is quite a
satisfactory sine waveform using only a few integer operations. Since
I'm rather pleased with it and it might prove useful to somebody,
here's the algorithm:
1. Generate a sawtooth in the range -max to +max (i.e. -32768 to 32767
for a 16-bit integer.)
2. Square it.
3. Divide by +max (i.e. 32767.)
4. Multiply by the sign of the original value.
5. Subtract the original value.
6. Multiply by 4.
7. The result is inverted (or 180 degrees out-of-phase, if you want to
look at it that way,) so re-invert it if this is a problem for you. Or
just multiply by -4 in step 6.
There's probably a few different ways to implement this depending on
what kind of architecture you're doing it on, but here's a basic C
implementation:
#include <stdlib.h>
#include <limits.h>
/* sawToSine - takes a sawtooth sample as a signed integer and returns
the equivalent sine sample. */
int sawToSine(int saw)
{
return ((((saw * saw) / INT_MAX) * (saw / abs(saw))) - saw) * -4;
}
>From a quick check with a graphing calculator (paste:
\left(\left(\left(x^2\cdot
\operatorname{sign}\left(x\right)\right)-x\right)\cdot -4\right)-\sin
\left(x\cdot \pi \right)
into https://www.desmos.com/calculator to see,) it looks like has a
maximum distortion of ~5.5% compared to a true sine, and it's actually
a little "fuller" and rounder, which I like. From a quick code test,
it maintains almost full peak-to-peak range and never overflows.
Whether this is any faster than using floating-point probably depends
on how expensive integer multiplies and divides are on your target
architecture, but I just thought it was interesting and wanted to
share :)
_______________________________________________
Synth-diy mailing list
Synth-diy at dropmix.xs4all.nl
http://dropmix.xs4all.nl/mailman/listinfo/synth-diy
-----
No virus found in this message.
Checked by AVG - www.avg.com
Version: 2016.0.7497 / Virus Database: 4545/11975 - Release Date: 04/06/16
More information about the Synth-diy
mailing list