Basic Real-time Sequence Examples

Writing a real-time sequence

A Python real-time sequence is a Python function decorated with the niveristand.nivs_rt_sequence decorator. For example, the following sequence calls a function and checks the result.

1@nivs_rt_sequence
2def call_add_two_numbers_test():
3    result = DoubleValue(0)
4    result.value = add_two_numbers(1, 2)
5    if result.value != 3:
6        generate_error(-100, "Unexpected result", ErrorAction.ContinueSequenceExecution)

The function also takes in some parameters. You must define parameters using the niveristand.NivsParam decorator.

1@NivsParam("x", DoubleValue(0), NivsParam.BY_VALUE)
2@NivsParam("y", DoubleValue(0), NivsParam.BY_VALUE)
3@nivs_rt_sequence
4def add_two_numbers(x, y):
5    result = DoubleValue(0)
6    # There is an intentional mistake here. It multiplies when the function implies it adds.
7    result.value = x.value * y.value
8    return result.value

You can now run the test just like any other Python function. You can run it non-deterministically, as in the following example:

1    try:
2        call_add_two_numbers_test()
3    except RunError as run_error:
4        print("Something Non-deterministic went wrong:" + str(run_error))
5

Or, you can run the test deterministically on the VeriStand engine connected to your system.

1    try:
2        realtimesequencetools.run_py_as_rtseq(call_add_two_numbers_test)
3    except RunError as run_error:
4        print("Something Deterministic went wrong:" + str(run_error))

Combining the legacy API with real-time sequences

To create a fully-automated test environment, you can mix the Legacy API with Python real-time sequences.

 1import os
 2from examples.engine_demo.engine_demo_basic import run_engine_demo
 3from niveristand import run_py_as_rtseq
 4from niveristand.errors import RunError
 5from niveristand.legacy import NIVeriStand
 6
 7
 8def mix_legacy_and_rtseq_run():
 9    """Combines the legacy API with Python real-time sequences to run a deterministic test."""
10    # Ensures NI VeriStand is running.
11    NIVeriStand.LaunchNIVeriStand()
12    NIVeriStand.WaitForNIVeriStandReady()
13    # Uses the ClientAPI interface to get a reference to Workspace2
14    workspace = NIVeriStand.Workspace2("localhost")
15    engine_demo_path = os.path.join(
16        os.path.expanduser("~public"),
17        "Documents",
18        "National Instruments",
19        "NI VeriStand 2019",
20        "Examples",
21        "Stimulus Profile",
22        "Engine Demo",
23        "Engine Demo.nivssdf",
24    )
25    # Deploys the system definition.
26    workspace.ConnectToSystem(engine_demo_path, True, 120000)
27    try:
28        # Uses Python real-time sequences to run a test.
29        run_py_as_rtseq(run_engine_demo)
30        print("Test Success")
31    except RunError as e:
32        print("Test Failed: %d -  %s" % (int(e.error.error_code), e.error.message))
33    finally:
34        # You can now disconnect from the system, so the next test can run.
35        workspace.DisconnectFromSystem("", True)
36
37
38if __name__ == "__main__":
39    mix_legacy_and_rtseq_run()

Array operations example

 1@nivs_rt_sequence
 2def array_operations():
 3    """
 4    Shows operations you can perform with array data types in a real-time sequence.
 5
 6    An array can hold multiple values of the same data type. You cannot have arrays of arrays.
 7    Use arrays to pass buffers of data for playback or storage.
 8
 9    Returns:
10        float: sum of all values in the array.
11
12    """
13    var = DoubleValue(0)
14    arr_size = I64Value(0)
15    array = DoubleValueArray([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
16
17    # Indexes a value out of an array.
18    var.value = array[4].value + 100
19    # Updates a value in an array.
20    array[2].value = 6.0
21    # Gets the size of an array.
22    arr_size.value = arraysize(array)
23    # Loops over each element of an array. Each time the loop iterates a value from the array is copied into x.
24    var.value = 0.0
25    for x in array:
26        var.value += x
27    return var.value

Measuring elapsed time example

 1@nivs_rt_sequence
 2def measure_elapsed_time():
 3    """
 4    Shows different ways to measure elapsed time in a sequence.
 5
 6    You can measure time in milliseconds, microseconds, or seconds.
 7
 8    Returns:
 9        int: time, in milliseconds, it took to run this sequence.
10
11    """
12    seqtime_timer = DoubleValue(0)
13    seqtime_us_timer = I64Value(0)
14    tick_ms_timer = I64Value(0)
15    tick_us_timer = I64Value(0)
16
17    # The following steps demonstrate different ways you can capture an initial timestamp:
18    seqtime_timer.value = seqtime()
19    seqtime_us_timer.value = seqtimeus()
20    tick_ms_timer.value = tickcountms()
21    tick_us_timer.value = tickcountus()
22
23    # Simulates work to time.
24    while iteration() < 1000:
25        nivs_yield()
26
27    # Measures the elapsed time by subtracting the initial timestamp from the current time.
28    seqtime_timer.value = seqtime() - seqtime_timer.value
29    seqtime_us_timer.value = seqtimeus() - seqtime_us_timer.value
30    tick_ms_timer.value = tickcountms() - tick_ms_timer.value
31    tick_us_timer.value = tickcountus() - tick_us_timer.value
32
33    return tick_ms_timer.value

State machine

 1@nivs_rt_sequence
 2def state_machine_example():
 3    state = I32Value(0)
 4    iters = I32Value(0)
 5    amplitude = DoubleValue(1000)
 6    stop = BooleanValue(False)
 7    output = ChannelReference("Aliases/DesiredRPM")
 8
 9    while (
10        stop.value != True  # noqa: E712 NI recommends you use comparison instead of identity.
11        and iters.value < 10
12    ):
13        state.value = rand(7)
14        if state.value == 0:
15            wait(2)
16        elif state.value == 1:
17            sine_wave(output, amplitude, 1, 0, 0, 2)
18        elif state.value == 2:
19            square_wave(output, amplitude, 5, 0, 0, 50, 2)
20        elif state.value == 3:
21            triangle_wave(output, amplitude, 1, 0, 0, 2)
22        elif state.value == 4:
23            uniform_white_noise_wave(output, amplitude, tickcountus(), 2)
24        elif state.value == 5:
25            ramp(output, -amplitude.value, amplitude, 2)
26        elif state.value == 6:
27            sawtooth_wave(output, amplitude, 1, 0, 0, 2)
28        else:
29            stop.value = True
30        iters.value += 1
31        state.value = rand(7)