Skip to content

Instantly share code, notes, and snippets.

@endolith
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save endolith/c184b0e8b27aa9eddc01 to your computer and use it in GitHub Desktop.
Save endolith/c184b0e8b27aa9eddc01 to your computer and use it in GitHub Desktop.
Quadratic approximation of sine

Tried converting this to fixed-point:

http://www.dspguru.com/dsp/tricks/parabolic-approximation-of-sin-and-cos

Don't bother with this; it's so distorted (-28 dB THD) you can tell it's not a sine wave by looking at it.

Uses slightly more CPU than AudioSynthWaveformSine, but I didn't bother trying to optimize it. Would need to break into octants instead of quadrants and use at least 5th order polynomial to get 16-bit quality? Doesn't seem like it would be any faster.

#include "quadratic.h"
#include "utility/dspinst.h"
void AudioSynthWaveformRes::update(void)
{
audio_block_t *block;
uint32_t i, inc;
int32_t ph, modph;
int32_t y, tmp;
uint32_t quadrant;
if (magnitude)
{
block = allocate();
if (block)
{
ph = phase_accumulator;
inc = phase_increment;
for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{
quadrant = ph bitand (3 << 30);
modph = ph bitand ~(3 << 30);
if (quadrant == (2 << 30)) // 1: -sin
{
y = (multiply_32x32_rshift32_rounded(modph, modph) << 1) - modph;
}
else if (quadrant == (3 << 30)) // 2: -cos
{
y = (multiply_32x32_rshift32_rounded(modph, modph) << 1) - (1 << 29);
}
else if (quadrant == (0 << 30)) // 3: sin
{
y = modph - (multiply_32x32_rshift32_rounded(modph, modph) << 1);
}
else if (quadrant == (1 << 30)) // 4: cos
{
y = (1 << 29) - (multiply_32x32_rshift32_rounded(modph, modph) << 1);
}
block->data[i] = multiply_32x32_rshift32_rounded(y, magnitude);
ph += inc;
}
phase_accumulator = ph;
transmit(block);
release(block);
return;
}
}
phase_accumulator += phase_increment * AUDIO_BLOCK_SAMPLES;
}
#ifndef quadratic_h_
#define quadratic_h_
#include "AudioStream.h"
#include "arm_math.h"
class AudioSynthWaveformRes : public AudioStream
{
public:
AudioSynthWaveformRes() : AudioStream(0, NULL), magnitude(16384) {}
void frequency(float freq)
{
if (freq < 0.0) freq = 0.0;
else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) freq = AUDIO_SAMPLE_RATE_EXACT / 2;
phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT);
}
void phase(float angle)
{
if (angle < 0.0) angle = 0.0;
else if (angle > 360.0)
{
angle = angle - 360.0;
if (angle >= 360.0) return;
}
phase_accumulator = angle * (4294967296.0 / 360.0);
}
void amplitude(float n)
{
if (n < 0) n = 0;
else if (n > 1.0) n = 1.0;
magnitude = n * 262139.0; // why does 262144 cause overflow??
}
virtual void update(void);
private:
uint32_t phase_accumulator;
uint32_t phase_increment;
int32_t magnitude;
};
#endif
#include <Audio.h>
#include <Wire.h>
#include <SD.h>
#include <SPI.h>
#include <math.h>
#include "quadratic.h"
AudioSynthWaveformRes waveform1; //xy=188,240
AudioOutputI2S i2s1; //xy=565,241
AudioConnection patchCord2(waveform1, 0, i2s1, 0);
AudioConnection patchCord3(waveform1, 0, i2s1, 1);
AudioControlSGTL5000 audioShield; //xy=586,175
void setup()
{
Serial.begin(9600);
AudioMemory(80);
audioShield.enable();
audioShield.volume(0.3);
waveform1.amplitude(1.0); // 1.26 Vpp for 1.0
waveform1.frequency(997.1);
}
void loop()
{
Serial.print(AudioProcessorUsage());
Serial.print(",");
Serial.println(AudioProcessorUsageMax());
delay(500);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment