Conceptually, a DDS is extremely simple. A digital to analog converter (DAC) does just that: it converts numbers to a voltage. You could make a simple DDS that generated one frequency with a counter that went through the memory locations in a lookup table and fed each number to a DAC. You could construct a sine wave or any waveform with this technique. This isn’t very useful, though; it generates just one frequency or one waveform. Sometimes that’s all you need, though.
In real life, you’d need to lowpass or bandpass filter that DAC output and probably amplify it.
What made a DDS useful was when someone came up with a way to generate a wide range of frequencies with one part. In a way, radio frequencies are all the same. If you’ve seen one sine wave, you’ve seen them all, right? The only difference between higher and lower frequencies is the timing. That led to a trick.
Sine functions are perfectly defined by the angles; the sine of 30 degrees, say, is always the same. What if we made up a table for the voltage value depending on angle and ran those numbers through a DAC? If you think about it, there’s a symmetry here. The voltages change in a constant pattern, so we don’t need to store an entire sine wave in our look up table. We can just save ¼ of the cycle (zero to 90 degrees, say) and mathematically manipulate the result for the other ¾ of the cycle. In a sine, for example, as you go past 90 degrees, each angle gets smaller by exactly the same amount it got bigger in the zero to 90 interval. That wording is more complicated than it should be so think of it this way: the voltage increase from 85 to 90 degrees is exactly the same as the voltage decrease from 90 to 95 degrees. Or the increase from 89 to 90 is the same as the decrease from 90 to 91. What we create is a memory array, a register, that saves the voltage at each given phase angle, and then a smart counter that steps through the phase register, a look up that converts the phase data to the amplitude at that phase angle, and then pass that value to the DAC.
This leads to a DDS that looks like this:
Let’s switch from the “what is it?” to the “what to do with it” standpoint. A DDS has a data bus over which you select the desired frequency output and it has one or more analog outputs. The number you program is the desired output divided by the clock frequency. The advantages of a DDS over a PLL are usually very fine step sizes, lower noise around the output frequency, and how quickly they tune. The main disadvantage is that they tend to have far more spurious junk in their output than a PLL will have. As general rule, you’ll need to have a DDS with a clock (crystal) frequency that’s more than twice the maximum frequency you need. See that stair-step ugly output in the lower right of that figure? The (Sin(x)/x) dependence means the output amplitude rolls off with the frequency you’ve set the DDS to, so you’ll probably need to process that to keep the amplitude where you need it. Or use a faster clock if the DDS chip can handle it.
All DDS outputs come with errors. The DDS is estimating the phase angle at a few points in that block labeled Amplitude/Sine Conversion Algorithm. While the sine phase lookup has more bits internally (24 bits vs. 16 bits programming or less), that means your programmed frequency is truncated or shortened. This leads to an error term called the phase truncation error. The output from that block, now a numerical representation of the frequency, goes through the DAC and there’s an amplitude error as well. If there’s a 32 bit phase to amplitude representation, there are very few DACs with that resolution and even fewer fast enough to create radio frequencies. The DAC probably has something like 12 bits internal resolution; some are 10 bit. I like to explain that the digital signal is two approximations away from reality. Those approximations lead to the spurious signals in the output.
The phase noise performance of a DDS is generally better than a PLL synthesizer because the major noise sources, the free-running VCO at the output frequency and the multiplied clock noise (20*log(N)) mentioned last week aren’t there. In fact, the PLL is effectively dividing down the crystal used as its clock, reducing its noise contribution.
The spurious signals in the output lead to the major disadvantage of DDSes, and the 12th Commandment; Thou Shalt Not Multiply a DDS. Amplitude Truncation spurs get worse at a 10*Log(N) rate and Phase Truncation spurs get worse at that 20*Log(N) rate. A DDS output can get ugly pretty quickly as you pass through a few stages of multiplication. Yeah, you can multiply by two or four, but you’d better check carefully if you plan to use a DDS with large multiplication values.
If you search the web you’ll find many projects based on Analog Devices DDS chips, particularly the AD9850/9851 chip which is a reasonably economical part that uses a 180 MHz clock. The clock says you can get to 90 MHz, but the (Sin(x)/x) function says 60 “or so” MHz. They’re in the range of $30 each. If you're into the Arduino world, they're available built onto little boards for less than that. The AD9850 is an older part, but still in stock at Digi-Key and Mouser, my usual “go to” guys. To give you an idea of the parts available, here's Analog Devices' webpage showing their DDS product selector. In the years since I retired, AD has bought up their major competitors, but when I retired they were the major source for DDS chips.