Waveform Generation (App Note) | LabJack
« Close

Datasheets and User Guides

App Notes

Software & Driver


Free Shipping for U.S. Orders $150+   |   5-year Warranty   |   Try Our Devices & Support for 60 Days, Risk Free  |   50 of 54 Products In-Stock Now

Waveform Generation (App Note)

This application note is about creating analog or digital output waveforms with the U3, U6, UE9, or T-series (T4 or T7).

Hardware Bandwidth Limitations

Before we talk about how to get output updates to happen when desired, first consider whether the hardware can handle the signal frequency you want.

Digital output is pretty simple (very fast), but for analog output first determine if the bandwidth of the DAC (digital to analog converter, or analog output) hardware can handle your desired maximum signal frequency.  As of this writing, -3 dB cutoff frequencies are as follows:

       -3 dB cutoff frequency
U3 16 Hz
U6 500 Hz
T4 159 kHz *
T7 40 kHz

*The T4 cannot output a signal this quickly. The cutoff frequency was calculated by measuring the time constant.

If the hardware can handle the signal frequency you want, the next question is whether you can update the DAC fast enough to build your desired waveform.  You need to determine your required DAC update rate.  Take the max signal frequency you want to make, and multiply it by how many updates per cycle you require (i.e. how "smooth" you need the signal to be).  For example, if you want to build a 10 Hz sine wave using 50 updates per cycle, that would require 500 updates per second.

Software Timing, Command-Response Updates

The basic method of updating an output is command/response mode.  Typical timing information can be found in the documentation for the U3, U6, UE9, or T-series.  For example, in Section 3.1 of the U3 User's Guide it says that with a USB high-high connection it takes about 0.6 ms to update one or both DACs, which is about 1600 updates/second.  Whether you can make a software program that can iterate a loop at that interval has to do with many factors.

WAIT Technique (U3, U6, T4, and T7)

The idea of the WAIT technique is to send a single packet to the device with multiple commands that are executed in sequence.  Typical commands would be write DO, write DAC, read AIN, and WAIT, where WAIT is a user-controllable delay.  Using this technique you have the normal command-response delay to send the packet and read the response (on the order of 1 millisecond), but the multiple commands within the packet are executed in hardware without any communication delays.

The U3 and U6 have low-level IOTypes WaitShort (U3/U6) and WaitLong (U3/U6).  These can be combined with other commands in a low-level Feedback packet.  The UD driver uses both of these, but to the user presents a single IOType LJ_ioPUT_WAIT (U3/U6).  This IOType can be combined with others in a single packet using the Add/Go/Get technique (U3/U6).  The value range you can pass to LJ_ioPUT_WAIT is 0-4000000 microseconds, and the resolution is 128 µs on a U3 and 64 µs on a U6.  To determine how many commands can be fit in a single packet on the U3/U6, consider that the low-level Feedback packet has room for 57 bytes of data in the command and 55 bytes of data in the response.  Section 5.2.5 of either User's Guide (U3/U6) specifies the command and response bytes needed for each IOType.

The T4 and T7 have a register WAIT_US_BLOCKING (UINT32 starting at address 61590).  Pass a value to wait, in microseconds, from 0-100000.  The resolution is 1 µs, but there can be a few µs of occasional jitter due to other higher priority things happening in the processor.  If this wait is placed between 2 other commands, which is typical, there will be an extra ~10 µs of delay between the commands due to the normal time to process each command.  Writes to this register can be combined with writes/reads of other registers in a single Modbus TCP packet.  With the LJM Library, you would typically use LJM_eWriteNames() or LJM_eNames(), but either way LJM will send a Modbus Feedback function to the device.  The maximum packet size of a single packet for a T-series device is 64/1040/500 bytes for USB/Ethernet/WiFi, respectively.  You can combine multiple WAITs to get more than 100 ms delay, but keep each packet to less than 250 ms total to avoid a device reset caused by the internal watchdog timer.  This technique might also be useful within a Lua script.

Stream Output

The UE9 has a feature called Stream-DAC that allows DAC channels to be updated in stream mode.  You specify a buffer of 1-128 update values, and the UE9 will step through this buffer (continuously rolling back to the start) sending each value to a DAC at the stream scan rate (which can be up to 50 kscans/second or even more).

The T4 and T7 have a similar but more powerful feature called Stream-Out.

Square or Rectangular Output with Timers or DIO-EF

For continuous square or rectangular waveforms you would typically use a timer on a U3/U6/UE9 or DIO-EF on a T-series device.  If a sinusoid is needed, but fixed frequency and amplitude is sufficient, you can output a square wave and use a simple RC filter to create a decent sinusoid.

To get a specific number of pulses from a U3/U6/UE9 timer, rather than continuous output, you can use another timer in Stop mode.  On the T4 or T7, simply use the Pulse Out type.

Square or Rectangular Output at Voltages other than 3.3V

They way to achieve this is to use one of the digital output techniques above to create a 0/3.3V waveform, and use that waveform to control some sort of switch that is gating the desired voltage.  You could gate 5V from VS or a variable voltage from a DAC output, among others.  For the specific case of getting a 5V digital output, there is information on Section 2.8 of the U3 User's Guide.

Scripting (T4 and T7)

On the T4 or T7 you can write a Lua script.  This is code that runs on the hardware, without communication overhead, and thus can be much faster.





The UE9 has a feature called Stream-DAC


How about U6?

The U6's hardware is not setup for Stream-DAC.

I would like to post your application note and example code on our web site, so I have tried to find example code, but I cannot find.


Can you please let us know where it is?

Looks like the only example right now is for LabVIEW.  We will work on an example for VC6, as that is where we usually make the most core examples that can be adapted to other languages.


The appnote says:

As of this writing, the -3 dB cutoff frequency of U3 and U6 is about 16 Hz and 500 Hz respectively.

Should it be 1600 Hz? It is because the appnote also says:

For example, in Section 3.1 of the U3 User's Guide it says that with a USB high-high connection it takes about 0.6 ms to update one or both DACs, which is about 1600 updates/second.

Can you post sample code for C/C++?


Two different things.  For the U3, you might be able to update the value of the DAC 1600 times per second, but the bandwidth of the output hardware is only 16Hz.  So, for example, if you update it 1000 times per second to make a 10Hz waveform it will work well, but if you update it 1000 times to try to make a 100Hz waveform you will not get much output.

For examples start here.

About the WAIT technique (on T7):

Are only the commands within one packet sequenced with hardware timing, or can a final wait hide the transmission of the next packet (so it's already there when due)?

E.g., could I in one command packet write 10 SPI bytes, read the SPI response, measure a line level, change another and finally wait for the rest of 5ms? Meanwhile send the next such command, so they are nicely paced at 5ms interval?

(Poor man's streaming, so to speak...)


No, WAIT_US_BLOCKING simply blocks execution of the list of commands.  If you put a wait at the end of the list, it will just take that much longer for the T7 to send the response and that much longer for the function call you make in software to return.  Seems like Lua Scripting might be an option for you.

can you post sample python  code for displaying waveform output for sample voltages.

The code to output a waveform would depend on which technique above you are using and which device.  For example, if you are using the "Software Timing, Command-Response Updates" method on a T7 to update DAC0 at 200Hz, you would simply make a loop with a 5ms iteration interval and call eWriteName in that loop to update DAC0 with your new value each iteration.  If you run into difficulty, I suggest you post a code snippet on our forums.