2
\$\begingroup\$

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

\$\endgroup\$
9
  • \$\begingroup\$ Which chip are you using at the moment? \$\endgroup\$
    – Oli Glaser
    Commented Jan 10, 2013 at 9:26
  • \$\begingroup\$ What "timing limitations"? What's the shape of the signal (sine, square)? \$\endgroup\$
    – pjc50
    Commented Jan 10, 2013 at 9:28
  • \$\begingroup\$ 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 \$\endgroup\$
    – Daniel
    Commented Jan 10, 2013 at 9:39
  • \$\begingroup\$ According to your EDIT the signal is not shifted by 40 kHz (as you wrote twice before) but by just 49 Hz (no kilo). \$\endgroup\$
    – Curd
    Commented Jan 10, 2013 at 10:17
  • \$\begingroup\$ @Daniel - a PIC16F isn't going to be very good for this, a DSP (Digital Signal Processor) is a far better option. If you are familiar with the 16FPICs, then it wouldn't be too much of a leap to the dsPICs, which are 16-bit, faster, have more ram, etc. \$\endgroup\$
    – Oli Glaser
    Commented Jan 10, 2013 at 10:23

4 Answers 4

4
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ @Daniel This is the path to the best answer. To elaborate a bit more, very high frequency accuracy can be achieved by having a wide phase accumulator word, but only using a practical number of its higher bits for the table lookup. The samples at a given instant in time will be somewhat approximate, but over time they will average to the desired sinusoid(s), leading to extremely precise frequency control. \$\endgroup\$ Commented Jan 10, 2013 at 18:53
  • \$\begingroup\$ This is a good answer if you can dedicate your PIC to the signal generation. If it has other thing to do, especially time critical things, it would be difficult to implement. I would go for a hardware solution. \$\endgroup\$
    – Blup1980
    Commented Jan 11, 2013 at 7:04
  • \$\begingroup\$ It'll work as a SW solution if: (a) it's on a timer interrupt (b) it takes only about half the cycles available (c) it saves/restore context properly (d) it's the only time-critical thing (and I would say, the only interrupt). If the PIC has much more to do, I suggest the simplest (not necessarily best) HW solution is ... another PIC. \$\endgroup\$
    – user16324
    Commented Jan 11, 2013 at 9:47
3
\$\begingroup\$

Use a DDS chip (Direct Digital Synthesis). Analog Devices has some, for instance.

Usually controlled by SPI or I2C, you can configure its output frequency using your microcontroller.

But if you want to generate theses different frequencies at the same time in the same signal, then a DDS is not the way to go.

The easiest way to do it, is to generate the different signals, one at 16.4kHz, one at 16.7khZ,... and sum them (not multiply) using an OPAMP.

You can generate them using simple XTAL oscillators.

Another method is compute your signal in advance. sample it at something like 20 times the highest frequency. Then you store the sample in a external ram, flash or eeprom. Then you can use a simple logic design (discreet, CPLD, FPGA etc..) to send the sample to a DAC. Don't forget to filter the DAC output remove the higher frequency content that appears.

\$\endgroup\$
5
  • \$\begingroup\$ I do need to generate them at the same time. I'm computing the samples in advance and sample it 4 the max frequency... unfortunately I've never used XTAL oscillators before, can you recommend of any specific kind for my needs? thanks again \$\endgroup\$
    – Daniel
    Commented Jan 10, 2013 at 9:47
  • \$\begingroup\$ You will not generate these frequencies from individual crystal oscillators! That would involve custom cut crystals - prohibitively expensive. Normally, there would be one crystal oscillator (external 8MHz crystal, the oscillator is part of the PIC) and you would use DDS or other technique in software to generate the actual tones. \$\endgroup\$
    – user16324
    Commented Jan 10, 2013 at 13:46
  • \$\begingroup\$ This is NOT the best answer. It overlooks the possibility of software DDS in the existing chip, mistakenly claims that a DDS can't generate multiple frequencies, and throws in an entirely spurious recommendation of an OMAP. \$\endgroup\$ Commented Jan 10, 2013 at 18:51
  • 1
    \$\begingroup\$ Not at all. If you read carefully, I said that generating multiple frequency at the same time is a NO GO for a DDS. And I never talked about software DDS, I recommended using an external chip. Where did you read any recommendation for an OMAP? I recommend to use an OPAMP (operational amplifier) to sum the generated signals. \$\endgroup\$
    – Blup1980
    Commented Jan 11, 2013 at 6:57
  • \$\begingroup\$ @Blup1980 - that is precisely why this is a poor answer. Generating multiple frequencies at the same time is very easy for "a DDS" - you impose the limitation only by suggesting an off the shelf hardware version of DDS, instead of the more flexible software path the poster was already on and which would do the job if implemented correctly. Sorry about the OPAMP/OMAP confusion though. \$\endgroup\$ Commented Jan 14, 2013 at 21:20
2
\$\begingroup\$

Blup1980's answer is a good one, and pretty easily (assuming you have done this ort of thing before) achieved with an FPGA/DAC setup, or a couple of DDS chips.

On the uC front, there are DSPs with multiple DAC peripherals which may be worth looking at, e.g. the dsPIC33FJ64GP802 (and variants) runs at 40 MIPS, has a 16-bit dual DAC peripheral capable of up to 100kHz output IIRC. There are also far more powerful DSPs, this is just food for thought.

\$\endgroup\$
0
\$\begingroup\$

If this problem is simply a matter of your LUT storage being too small the simple solution is to only store a 90 degree segment of the waveform and then obtain the correct sample through indexing offsets (Phase), polarity inversions (quadrant III and IV) and count direction (Quadrants II, IV). It's important that the samples be symmetrical about reflection and NOT contain "O" or peak (which can be inserted if needed).

\$\endgroup\$
1
  • \$\begingroup\$ That can help. However, the real issue is more likely the mistaken (but understandable) assumption that the phase resolution has to be limited by the table size. It does not - good DDS implementations have a phase accumulator which is wider than the table size, so that the integrated phase is more accurate. Even though the output at any particular instant is more crudely approximate in the resolution of the phase used as an index into a short table, measured over time the frequency is quite accurate as the "remainder" bits which cannot be indexed into the table still count in the phase sum. \$\endgroup\$ Commented Jan 14, 2013 at 21:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.