Instructions#

Note

You need one AO card to run this tutorial.

Tip

We omit details to keep tutorials short. See API reference and docstrings for full descriptions.

# Minimal streamer setup for this tutorial
from nistreamer import NIStreamer
ni_strmr = NIStreamer()
ao_card = ni_strmr.add_ao_card(max_name='Dev2', samp_rate=1e6)  # <-- modify `Dev2` to match your setup
ao_chan = ao_card.add_chan(chan_idx=0)

Instruction contents#

NIStreamer stores pulse sequence as a collection of instructions. Each instruction contains start time, duration specification, and the waveform function to play:

  • t is a floating-point start time in seconds since the sequence beginning.

  • Duration spec can be of two types:

    • Fixed (dur, keep_val) - pulse of duration dur seconds. If keep_val is True, the last waveform value is maintained in the gap between this instruction and the next one. Otherwise channels returns to default.

    • Unspecified - actual duration is computed automatically when compiling to fill the full interval until the next instruction.

  • Waveform is a mathematical function from the library (Const, Sine, TanH, …) together with parameter values.

Pulse sequence is built by adding instructions to channels with a user script which computes start, duration, and waveform parameters for each pulse. Streamer compiles the full sequence by filling the remaining gaps according to duration specifications.

Waveform library#

Shortcuts#

A few common waveforms have “shortcuts” as direct channel methods:

ni_strmr.clear_edit_cache()

ao_chan.sine(t=0, dur=1.0e-3, amp=1, freq=10e3, keep_val=False)
ao_chan.go_sine(t=2e-3, amp=2, freq=20e3)  # unspecified duration version

# Helper methods for ramps:
ao_chan.linramp(t=3e-3, dur=1e-3, start_val=0, end_val=1)
ao_chan.sineramp(t=5e-3, dur=1e-3, start_val=0, end_val=1);

Library#

All waveform functions are stored in the library called std_fn_lib. Most of them don’t have shortcuts and need to be retrieved.

Let’s import the library and list all available waveforms:

from nistreamer import std_fn_lib
for fn_name in dir(std_fn_lib):
    if not fn_name.startswith('_'):
        print(fn_name)
ConstBool
ConstF64
Exp
Gaussian
LinFn
Lorentzian
Poly
Pow
Sine
TanH

Each waveform has a descriptive docstring:

std_fn_lib.Sine?
Signature: std_fn_lib.Sine(amp, freq, phase=0.0, offs=0.0)
Docstring:
Sine function:
    amp - amplitude (in Volts)
    freq - linear frequency (in Hz)
    phase - absolute phase (in radians)
    offs - offset (in Volts)
`Sine(t) = amp * sin(2Pi * freq * t + phase) + offs`
Type:      builtin_function_or_method

Waveforms from the library are added to the sequence with the following channel methods:

ni_strmr.clear_edit_cache()

# Fixed duration
ao_chan.add_instr(
    t=1, dur=2, keep_val=False,
    func=std_fn_lib.Poly([7, -8, 2])
)
ao_chan.add_instr(
    t=4, dur=2, keep_val=True,
    func=std_fn_lib.LinFn(slope=1, offs=-5)
)

# Unspecified duration
ao_chan.add_gothis_instr(
    t=7,
    func=std_fn_lib.Sine(amp=0.4, freq=4)
)

ni_strmr.compile(stop_time=9);

A schematic showing the computed waveform. One can see that there is indeed a parabolic pulse from 1 to 3 seconds, a linear function from 4 to 6 seconds, and then a sinusoidal wave spanning from 7 seconds through the requested stop time of 9 seconds.

ni_strmr.run()

Oscilloscope screenshot. The measured trace fully matches the expected waveform.

Note

If the built-in library does not contain the waveform you need, custom ones can be added through the user function library (see the tutorial).