March 9, 2018What Makes a DDS Engine?Design Guidelines - Sample TableThe Sample Table is going to contain all the possible outputs for the DDS engine. The Sample Table is represented by a Memory item in an FPGA project. If the LabVIEW version is old enough, it may be necessary to use a fixed length array instead. At the start of the FPGA application, initialize the Sample Table with a known waveform. For the purposes of this article, it's presumed that the data in the Sample Table will be 1 cycle of a sinusoid with 1 Volt amplitude. This waveform will need to be sampled to the size of the Sample Table. This is an important decision point. The size of the Sample Table, in conjunction with some other parameters, dictates the maximum precision of the output data. The DDS engine is only capable of outputting samples that can be found in the Sample Table. A small table is more resource efficient, but may result in poor waveform shape and features when attempting to produce a high-frequency output. To select an effective Sample Table size, review the customer documentation to determine precision requirements, the minimum number of samples per cycle, and the Source Clock rate. A proper understanding of these properties will assist in selecting a proper Sample Table size. Typically the Sample Table is prefilled with data, but external mechanisms may modify the Sample Data content as necessary to further customize the output generation.Example: Basic Sinusoid OutputRequirements: Output up to 100kHz waveform (sinusoid) with at least 64 samples per cycle.Source Clock: 10MHzSample Table Size: At least 64 SamplesRationale: In this case, we know the upper limit for representable frequencies. We can just assume that we will never need to go faster than 64 samples for a 100kHz waveform. However, one important takeaway, a 10MHz Source Clock will only allow for for a maximum samples/cycle of 100 for a 100kHz frequency requirement. The Source Clock rate would need to be increased to allow for more precise output generation. See the Source Clock section for more information.Figure 1. Sample Table Memory Configuration DialogFigure 2. Sample Table Memory Data Type DialogAlways make the Sample Table data type match the actual analog output type.Figure 3. Sample Tables Are Just Memory ItemsSelect the index and write the data output to the target analog output.Design Guidelines - Source ClockThe Source Clock is responsible for clocking the DDS engine. Every time the Source Clock ticks, the DDS engine will execute once. During a single execution, the DDS engine will increment the Accumulator by the Tuning Word value, select a new output value from the Sample Table, and output that value on hardware. Additionally, the Source Clock will dictate the maximum precision an output waveform can achieve through the DDS engine. The Sample Clock should be set to the highest necessary value to fulfill the documented signal generation requirements. Selection of a Source Clock is usually fairly strict, compared to selecting a Sample Table. Most National Instruments FPGAs have an inherent limit of 40MHz clocking, without using a clock multiplier (which is generally inadvisable to use for a DDS engine). This limitation means that it's best to set the Source Clock to a high rate and adjust the Sample Table as necessary to achieve the minimum sampling requirements.Example: Basic Sinusoid OutputRequirements: Output up to a 50kHz waveform (sinusoid) with at least 100 samples/cycle.Sample Table: 100 SamplesSource Clock: At least 5MHzRationale: In this example, the Sample Table is fixed. The Source Clock needs to be set to a particular rate to achieve the desired waveform output. Simply take the samples/cycle requirement and multiply it against the maximum required frequency. That will produce the minimum required rate for the Source Clock.Figure 4. The Source Clock Synchronization is Maintained in the First Frame of a Sequence StructureThis should always be defined in tick counts for maximum flexibility.Design Guidelines - Tuning WordThe Tuning Word is what allows a DDS engine to produce an exceptionally wide variety of waveforms, using only a single Sample Table. The Tuning Word dictates how many samples are transitioned during single execution of the DDS engine. When the value of the Tuning Word is set to a variety of values, different basic behaviors can be classified:Tuning Word equals 1: The DDS engine should visit every sample in the Sample Table once as it executes. Essentially, each tick of the Source Clock will produce a new output value every time. This will always produce a fixed output frequency based on the size of the Sample Table and therate of the Source Clock.Tuning Word greater than 1: The DDS engine will routinely skip samples to produce a higher frequency output. The Tuning Word may be a decimal value. The Accumulator will handle that decimal to account for drift.Tuning Word less than 1: The DDS engine will routinely revisit the same sample on consecutive executions of the DDS engine to produce a lower frequency waveform. The Tuning Word may be a decimal value. The Accumulator will handle that decimal to account for drift.To generalize, adjusting the Tuning Word will result in various different output frequencies, assuming a single cycle of a sinusoid is present in the Sample Table. The tuning word should always be a floating point or fixed point value to allow for precise frequency selection. Please note that a fixed point value that is not sufficiently accurate will result in unmanaged frequency inaccuracies, but may allow for higher operating speeds.Example: Basic Sinusoid OutputRequirements: Output any sinusoidal frequency from 10kHz to 50kHz with at least 100 samples/cycle.Sample Table: 100 SamplesSource Clock: 10MHzTuning Word Range:10kHz = 0.133kHz = 0.3350kHz = 0.5Math: TuningWordValue = (TargetFrequency * SampleTableSize) / (SourceClockRate)Rationale: This is just simple execution of the equation in the math section. Due to the high Source Clock rate, the Tuning Word is always smaller than 1. If the Source Clock was set slower or the Sample Table was larger, the Tuning Word could go above 1.Figure 5. The Tuning Word is Literally Just a Value That Allows the Controller Software to Adjust the Output Behavior of the DDS EngineIt can be replaced with a register in the event that the DDS behavior is in subVI.Design Guidelines - AccumulatorAs seen in prior sections, the Tuning Word is designed to accept floating-point and fixed-point values. This is an intentional design choice. If the Tuning Word was an integer, it would cause serious long-term issues with the flexibility of the DDS engine (I strongly suggest trying this at a later point and seeing what happens). Regardless, the addition of a decimal place will cause some serious issues when trying to access Sample Table entries. Without handling the error accrued by that decimal place, the DDS engine will only produce specific frequencies that can be represented by the coerced integer indexes on every iteration. Additionally, the DDS engine would never be able to represent output waveform frequencies that are represented by Tuning Words that are less than 1. Since that would be completely unacceptable, the Accumulator is introduced as the final component of the DDS engine. The Accumulator exists to accumulate the current value of the Tuning Word every execution of the DDS engine. In other words, it's a value that has the Tuning Word added to it over and over again. Using the prior example at 10kHz, a couple DDS engine executions would look like this:Execution 0: Accumulator(t) = 0 + TuningWord = 0.1Execution 1: Accumulator(t+1) = Accumulator(t) + TuningWord = 0.2Execution 2: Accumulator(t+2) = Accumulator(t+1) + TuningWord = 0.3Execution 3: Accumulator(t+3) = Accumulator(t+2) + TuningWord = 0.4... and so on... note that all the above values will still access index 0 in the Sample Table. All discussion here will assume a floor operation to reach integer values. Samples are output after each accumulation.As the Accumulator increments, a copy of the Accumulator value is coerced to an integer value, which will be used to access an index in the Sample Table. The retrieved sample is then output. Once the Accumulator reaches the maximum representable sample in the Sample Table, it needs to handle a rollover event. To explain this further, the current value of the Accumulator represents an index for a value in the Sample Table. If it represents an index that doesn't exist, there will be a runtime error or an incorrect value will be output. To prevent this from happening, the Accumulator is aware of the maximum size of the Sample Table. Once it reaches a value that will exceed the maximum size of the Sample Table, it will subtract the size of the table from the current Accumulator value, retain the remaining decimal (we cannot lose this value or the engine will drift). For example:Execution 999: Accumulator(t+999) = Accumulator(t+998) + TuningWord = 100Rollover event triggered: Accumulator(t+999) = Accumulator(t+999) - 100 = 0Sample is output from index 0 in Sample TableExecution 1000: Accumulator(t+1000) = Accumulator(t+999) + TuningWord = 0.1The behavior of rollover events is critical to ensuring the DDS engine does not drift and represent an incorrect output frequency.Figure 6. A Working AccumulatorThe false case of the case structure will just pass the current accumulator value through.Advantages/disadvantagesDDS Engines are extremely useful and powerful, however they are also very expensive to implement and debug. It's important to realize the strengths and pitfalls of this tool before attempting to leverage in an application:AdvantagesExtremely accurate output generationAllows for seamless sample transitionsSupports linear and non-linear frequency sweepingNo need to operate around zero-crossing points.DisadvantagesExpensive to implement. Can use a lot of FPGA resources.Difficult to d