Electronic – Frequency shift

analogmicrocontrollersignal

I'm trying to generate a signal which contains only several specific frequencies I know of in advance, around (16.4kHz, 16.7khZ, 17kHz,…)

the signal is generated using a microcontroller, which then outputs an analog signal into a speaker.

The problem is that due to timing limitations of the chip, I'm unable to produce the exact frequencies I need, they are shifted by around 40Hz in some direction. I'm starting to thinks that maybe this method of generation is not the optimal.
my questions are:

  1. could you think of a different way, perhaps even completely analog (no microcontroller) to generate this kind of signal?

  2. I know that in order to shift the frequencies by say,40Hz, I need to multiply it by a cosine (modulate it), but then it will be shifted both "left" and "right" which will make things extremely incontinent. Is there another, sophisticated way to achieve this kind of frequency shifting?

Thanks!

EDIT:
I'm currently using microchip pic16F1783 @32MHz with 8 bit DAC. I'm creating a sum of "pure" sines at the desired frequencies and then produce the wave. the constraints are of the digital world: the sampling frequency is digitalized, it can be 8MHz/integer, say 8M/100 to get sampling freq of 80KhZ. another constraint is the RAM. I create the signal in advance and put into an array that cannot have more than 450 elements. Due to all of that my signal is't created 16.4 but at 16.351

Best Answer

In principle, DDS should be easy to achieve in software - fractional accumulator, then lookup sine or cos for each tone you want to generate, then sum. On a PIC, that's going to be a tight loop, though...

I am assuming a 256 element LUT containing a complete cycle of a sine wave.

Each sample period , for each frequency, we add a fraction to the position of its pointer in the LUT, and take the sample at the (integer) part of the position. To illustrate how simple this can be, I played with a spreadsheet:

Fs  =   80000   
Fout=   16400   16700   17000
Fout/Fs 0.205   0.20875 0.2125
*256    52.48   53.44   54.4
integer 52      53      54
rem     0.48    0.44    0.4
*256    122.88  112.64  102.4
rounded 123     113     102
actual  16400.146   16700.439   16999.511

The actual DDS operation translates into pseudo-assembler (not PIC!) as

add acc1L,123
adc acc1H,52
lookup LUT,acc1h
mov sum, lookup result

add acc2L,113
adc acc2H,53
lookup LUT,acc2h
add sum, lookup result

add acc3L,102
adc acc3H,54
lookup LUT,acc3h
add sum, lookup result

out DAC,sum
wait for next sample period

which will expand considerably from what I remember of PIC assembly language, but is starting to look feasible.

Remember that the values in the lookup table must be scaled down so that the addition result in "sum" will not overflow.