Sum of sines sound wave using microcontroller

I need to produce a signal which contains only several frequencies, for example, 17KHz, 17.2 kHz,17.6 kHz. The components I'm using are microcontroller (PIC16F1783 by microchip) which works at 80 kHz frequency, and produces an analog signal, which is then fed into an audio amplifier and then into a speaker.

First, I'm trying to output a single frequency, say 17 kHz. under timing and low memory constraints my algorithm is as follows:

1. I have an array of 400 elements which contains samples of a sine wave at constant intervals
2. Every clock cycle(80,000^-1 sec) I output sine_array[index] to the audio amplifier (and then to the speaker) where index starts at 0 and increased each cycle by: (17,000/80,000)*400=85.

However, for some reason, besides seeing the pure 17 kHz frequency, I also hear (and see on the oscilloscope) parasitic 5 kHz frequency! I've also noticed that for frequencies such as 16 kHz (index increased by 80), 8 kHz there are no parasitic frequencies.
So I though it may have something to do with the fact that 400/80 is an integer, whereas 400/85 isn't.

Can anyone please suggest a creative way to sort this issue? The final goal is, as stated, to produce a signal which is composed of several frequencies with a rather small difference (around 200 Hz).

• What you need is a numerically-controlled oscillator. Here are a couple previous questions that might be of use: 1, 2 Dec 31 '12 at 14:53
• Could it be that you are simply not handling index wrap-around correctly, e.g. that you always reset the index variable to 0 instead of subtracting 400? Jan 1 '13 at 17:36
• @SebastianReichelt.It's not it, I am substracting 400 each time I overflow. Jan 1 '13 at 23:16

To explain the problem (without solving it):

However, for some reason, besides seeing the pure 17KHz frequency, I also hear (and see on the oscilloscope) parasitic 5KHz frequency!

Your sampling rate is 80 kHz, so the Nyquist frequency is 40 kHz. Your generation method produces a distorted sine wave at 17 kHz, which produces harmonics at:

• 17×2 = 34 kHz
• 17×3 = 51 kHz
• 17×4 = 68 kHz
• 17×5 = 85 kHz
• ...

But everything above 40 kHz gets aliased, so

• 51 kHz becomes 40-(51-40) = 29 kHz
• 68 kHz becomes 40-(68-40) = 12 kHz
• 85 kHz becomes 40-(85-40) = -5 kHz, which then aliases off 0 Hz and becomes 5 kHz
• ...

I've also noticed that for frequencies such as 16KHz (index increased by 80) ,8KHz there are no parasitic frequencies.

Now you've got harmonics at 32, 48, 64, 80, ... These alias to 32 kHz, 32 kHz, 16 kHz, 0 kHz, etc. So they aren't as obvious, but they're still there unless your wavetable is lining up perfectly with the samples.

If you look at your output using an FFT analyzer, you should be able to see these aliased harmonics more clearly:

http://www.music.mcgill.ca/~gary/307/week4/wavetables.html

• What if I put an LPF (say Fc=20KHz), at the output of the microcontroller. should that remove the harmonics? Or should I put a HPF (say around 15KHz),considering that the speaker cannot produce above 20KHz? Dec 31 '12 at 17:24
• @Daniel: Nope, anything outside of the micro is too late. The distortion and aliasing are happening internally, before this. You need to generate the sine wave more smoothly so that the harmonics are not produced. I think there are several techniques, like cubic interpolation of the wavetable values, but I don't know which work best. The better the generation algorithm, the lower the harmonic amplitudes. crca.ucsd.edu/~msp/techniques/v0.11/book-html/node31.html Are your signal frequencies fixed forever, or do they need to be variable? Dec 31 '12 at 18:00
• @endolitht: thanks for that. Let's say that the frequencies are fixed; I fill a 400-sample array first and only then do I periodically output each sample at 80KHz. I thought I was covered Nyquist-wise... but I guess I'm not... Jan 1 '13 at 7:36
• @Daniel: I was thinking you could just generate a wavetable for each sine component and then generate them with no interpolation, but I guess not because they aren't perfect sub-multiples of the sampling frequency. Jan 1 '13 at 22:19
• I tried increasing the sampling frequency from 80kHz to 160Khz to reduce aliasing. I'm witnessing now that if I produce 18kHz I get a "harmonic" at 9kHz! Do you have any idea how that can be? thanks Jan 2 '13 at 9:20

Based on the previous post (3) I can add the following. You need to remove the distortion from your signal(s). I can think of 2 possible approaches for this...

1) You will have to approximation your frequencies so you can get exact periods that line up with your sampling rate. This may not be satisfactory because you will have to use frequencies that repeat over some number of samples exactly. I haven't tried to work out the numbers. If this isn't true, you will end up with discontinuities in you signal causing distortion. You can decrease the distortion by using longer tables to extend the signal past a single cycle. The longer the table (more cycles) the less energy you will have produced by the discontinuity. You can also choose the table length to minimize the discontinuity (the end of the table should line up as closely as possible with the start of the signal).

2) Generate the signals with the frequencies you want (as you tried) then filter the signal using a low pass filter with a sharp cut off just above the highest frequency of interest.

You can combine these two approaches to optimize your results. You can find low pass filter algorithms by searching on "discrete time low pass filter design".

There is a direct way to come up with a sequence that produces the desired frequencies. Basically you define the frequencies you want and then take the inverse discrete Fourier transform of the frequency definition. The result from taking the inverse discrete Fourier transform will be the table entries. The accuracy of the defined frequencies will depend on the chosen length of your table. The longer the table, the better the accuracy. A table with 80000 entries will have an accuracy of 1Hz. Longer tables will be required for the accuracy you want. This looks impractical, but once you have the desired table, you can shorten it using a windowing function (tapering the table off to shorten it at both ends). A tool to help with the math is highly recommended.

• @Daniel A low pass filter won't work because the low frequency spurs are already in the signal as a result of the method of generation; however, a bandpass filter centered around the middle of your two frequencies will work if it is sufficiently narrow. Jan 1 '13 at 9:29
• One other idea you can look into is using an digital oscillator algorithm to generate each frequency instead of using a table look up. The Goertzel algorithm is one such option. The complexity and memory requirement for such ossilators is quite low. Check www.dspguru.com/dsp/tricks/sine_tone_generator for a very clear example. Jan 1 '13 at 11:13