I am sampling a sine wave at 48 kHz, the frequency range of my sine wave can vary from 0 to 20000 Hz with a step of about 100 Hz. I am using a lookup table approach. So I generate 4096 samples for a sine wave for 4096 different phases. I think the general idea behind this to increment the step size and use different step sizes for different frequncy. So I do the following (pseudo code). But I am not sure how the step size is going to be related to the frequency I want to generate the samples of the sine wave of? For example if my frequency is 15000 Hz what would be the step size that I have to traverse? Is my sample size (4096) too low for this?
// Pseudocode
uint16_t audio_sample[4096] = {...};
NSTEP = freq; //???How is the step size going to be related to the freq here
for(int i = 0; i < 4096; i = i+NSTEP)
{
sine_f(i) = audio_sample[i];
}
Thanks in advance.
Very good answer, this is classic software DDS. Facing the same problem these days. There is no need to use floats
Let phase wraparound LUT size as mask. And don't care about using quadrants since for my purpose I have a huge MIPS for this requirements already.
According to "http://en.wikipedia.org/wiki/X86_instruction_listings" if you have x80387 or newer there is a sine instruction, so just call it directly. You just have to figure out how to add some in-line assembly language to your program. This way you don't have to worry if your input value is not an exact match to what is in your table.
With look up table approach one may wish to use the memory efficiently and store only the first quadrant of the sine wave.
I would recommend linear interpolation, but there's also vector rotation based approach for sine generation (that produces both sine and cosine simultaneously)
where alpha=phase difference of the frequency == 2pi*fHz/Ts, with fHz is frequency to be produced (in Hertz) and Ts is sampling time (or 1/Ts = sampling frequenzy eg. 44100 Hz).
which leads to a resonating feedback filter approach, whose transfer function f(z) has two conjugate poles at unit circle (z=e^jomegaT).
The fun part is that one can change the alpha (cos(alpha)) on the fly. The downside of this IIR filter approach is that it's unstable by definition. Floating point and especially fixed point inaccuracies accumulate and lead to either exponential decay, or exponential growth of the magnitude. That can however be cured with allowing a slight phase distortion.
Instead of as in CORDIC rotation having a known per iteration amplification factor:
which doesn't produce perfect circles for (x', y'') but stable ellipses even with fixed point arithmetic. (Note that this assumes relatively small values of alpha, meaning also relatively low frequencies.)
You're on the right track - first we need to generate a sine wave LUT:
Note that we only need to generate this LUT once, e.g. during initialisation.
Now that we have a sine wave LUT we can use it to generate any frequency we wish to using a phase accumulator:
Note: for higher quality output you can use linear interpolation between the LUT values at
phase_i
andphase_i + 1
, but the above approach is good enough for most audio applications.If you want high precision, you can use a trig identities to have both a small LUT, and clean sine waves.