Precise timing is essential to the operation of a real-time application. Jitter is a measure of the extent to which execution timing fails to meet deterministic expectations. Use the information in this topic to minimize jitter in your RT application.

Avoid Common Sources of Jitter

To minimize jitter, avoid including non-deterministic operations in time-sensitive loops. Common sources of jitter include:

  • Memory allocation—Preallocate arrays before using them in deterministic loops, and avoid variable-size data structures in deterministic loops. Use the Replace Array Subset function to operate on pre-allocated arrays within a deterministic loop. Use the Real-Time Trace Viewer to identify Wait for Memory system event flags, which indicate memory management operations.
  • Opening and closing references—Open references in an initialization phase, before entering a deterministic loop, then close the references in a shutdown phase, after the deterministic loop terminates. Opening and closing references can impact the determinism of a loop.
  • Communication—When communicating with a deterministic loop, use either the RT FIFO functions or shared variables with the Real-Time FIFO enabled. RT FIFOs buffer data so that a deterministic loop can access the data without being blocked by a lower-priority loop.
  • Shared resources—Avoid accessing shared resources, such as hardware resources, I/O channels, or non-reentrant VIs in both a deterministic loop and another loop. Contention over shared resources is a common cause of jitter. When a deterministic loop uses a hardware resource or non-reentrant VI also used by another loop, the deterministic loop might have to wait for the other loop to release the shared resource.
  • File I/O—Avoid file I/O operations within deterministic loops. Hard disk access can introduce unbounded jitter in a deterministic loop.
  • Asynchronous I/O—Avoid asynchronous I/O operations inside a Timed Loop or time-critical VI. LabVIEW polls asynchronous operations to determine whether the operation has finished. This polling contributes to jitter and can prevent lower-priority tasks from running. Use synchronous operations instead. Synchronous operations run to completion, which ensures the read/write operation finishes without polling. This distinction is important when using the GPIB Read, GPIB Write, VISA Read, VISA Write, and VISA Wait on Event functions. If you need to use these functions inside a Timed Loop or time-critical VI, switch the function to Synchronous I/O Mode by right-clicking the function and selecting Synchronous I/O Mode»Synchronous from the shortcut menu. Other functions also might require this configuration.
  • Networking—Avoid networking operations within deterministic loops. Networking can introduce unbounded jitter in a deterministic loop.
  • Unbounded algorithms—Certain algorithms are non-deterministic by nature. Do not include unbounded algorithms in a deterministic loop. If you are not sure about the jitter characteristics of a VI or function, benchmark it.

Create a Timing Scheme

To ensure precision timing for ongoing, repetitive loops, establish a consistent timing scheme for your application. The timing scheme of a LabVIEW Real-Time Module application consists of a loop structure and a timing source. The LabVIEW Real-Time Module includes a variety of timing methods and timing sources you can use to control the timing of your loops.

Select a Loop

In addition to the standard While Loop, LabVIEW includes a Timed Loop with built-in timing capabilities. The Timed Loop also includes a robust set of inputs and outputs that you can use to alter and verify the timing characteristics of your application. The following table summarizes the characteristics of these two loop structures:

Loop Structure Characteristics Advantages Disadvantages
While Loop Basic looping structure, multi-threaded Low CPU overhead No built-in timing abilities
Timed Loop Single-threaded looping structure designed for multi-rate applications Built-in timing control, timing data, CPU selection, and priority control; single-threaded to facilitate deterministic scheduling Slightly more CPU overhead than a While Loop

Select a Timing Source

Whether you use a Timed Loop or a While Loop, select an appropriate timing source to drive the iteration timing of the loop.

While Loop Timing Sources

To control the timing of a While Loop, place a timing VI or function inside the loop. The following table summarizes the built-in timing VIs and functions available with the LabVIEW Real-Time Module:

Use Case Timing Method Underlying Timing Source
Synchronizing a loop with hardware-timed I/O Hardware-timed I/O methods such as a DAQmx Read VI or a wait method on an FPGA I/O Method Node External (depends on the hardware platform)
Delaying loop execution for x milliseconds Wait CPU-derived millisecond or microsecond timer
Controlling loop execution rates and synchronize loops Wait Until Next Multiple CPU-derived millisecond or microsecond timer
Triggering a loop to run after each scan of the NI Scan Engine Synchronize to Scan Engine NI Scan Engine

Timed Loop Timing Sources

Refer to the Selecting a Timing Source for a Timed Structure topic for information about selecting a Timed Loop timing source.

Create a Time Budget

To prevent undesired timing behavior, create a time budget for your application. Time budgeting involves determining the amount of time required to execute each loop in the application and setting the rates of the loops accordingly. Creating and following a time budget helps ensure that your application performs as expected.

Measure Loop Execution Times

After separating your application into multiple loops, use RT benchmarking techniques to determine the duration of each loop in your application. Allow the benchmark to run for several thousand iterations and record the worst-case execution time as the loop duration.

Note Avoid using the Highlight Execution tool while analyzing execution times. Execution highlighting significantly slows execution.

Create a Time Budgeting Table

After you measure the execution times of your loops, create a time budgeting table for the application by recording the duration and period of each loop, as shown in the following example:

Task/Loop Duration (µS) Period (µS)
Control 400 1000
Monitor 3,000 10,000
Log 16,000 30,000

Keep CPU Usage Low

By targeting a CPU usage well below 100%, you can minimize jitter and ensure that the tasks in your application do not need to compete for CPU time. After you construct the time budgeting table, you can determine the theoretical CPU usage of the application using the following formula.

CPU Usage (%) = 100 * Sum[Loop 1, Loop 2,.., Loop n](Duration / Period)

By plugging the numbers from the table into this formula, you can see that the CPU usage in this example is 100 * (400/1,000 + 3,000/10,000 + 16,000/30,000) = 123%. Because the monitoring loop in this example is set to a higher priority than the logging loop, the RTOS schedules the monitoring task immediately after the control loop finishes its iteration. The RTOS schedules the logging loop only after the monitoring loop finishes an iteration, leaving insufficient time for the logging loop to meet the requested period.

In this case, you can increase the period of one or more loops to ensure that each loop executes at the requested rate. For example, by increasing the period of the monitoring loop to 25,000 µS and increasing the period of the logging loop to 80,000 µS, the theoretical CPU usage becomes 100 * (400/1,000 + 3,000/25,000 + 16,000/80,000) = 72%.

Note If you cannot increase the periods of your loops, you might be able to use additional techniques to minimize CPU usage on the RT target.