Streamer#

class nistreamer.streamer.NIStreamer[source]#

Represents the whole streamer

add_ao_card(max_name, samp_rate, nickname=None, proxy_class=<class 'nistreamer.card.AOCardProxy'>)[source]#

Add an analog output card.

Parameters:
  • max_name (str) – name of the card as shown in NI MAX

  • samp_rate (float) – sample rate in Hz

  • nickname (Optional[str]) – human-readable name (e.g. “Fast AO card”; used for visualizations)

  • proxy_class (Optional[Type[BaseCardProxy]]) – custom subclass of BaseCardProxy to use for the device proxy.

Returns:

proxy_class instance representing this card.

Raises:

KeyError – if a card with the same name already exists.

add_do_card(max_name, samp_rate, nickname=None, proxy_class=<class 'nistreamer.card.DOCardProxy'>)[source]#

Add a digital output card.

Parameters:
  • max_name (str) – name of the card as shown in NI MAX

  • samp_rate (float) – sample rate in Hz

  • nickname (Optional[str]) – human-readable name (e.g. “Fast DO card”; used for visualizations)

  • proxy_class (Optional[Type[BaseCardProxy]]) – custom subclass of BaseCardProxy to use for the device proxy.

Returns:

proxy_class instance representing this card.

Raises:

KeyError – if a card with the same name already exists.

property chunksize_ms: float#

Streaming chunk size in milliseconds.

Chunk size is the main unit of streaming - all signal samples within a single chunk are computed, stored in memory, and transferred to the hardware in one operation together, at the same time as the previous chunk is playing.

Optimal chunk size depends on the tradeoff. Larger size reduces the risk of buffer underflow at the cost of increased overhead - memory allocation and the initial chunk compute will take longer. The default value is 150 ms.

Notes

If chunk size exceeds the total sequence duration, no streaming actually happens - all samples are computed before generation starts. This could be used to eliminate the risk of underflows if sequence is sufficiently short. However, in-stream looping feature will be disabled, and trying to pre-sample a long waveform can overfill RAM.

property starts_last: str | None#

Specifies which card starts last.

Format:
  • dev_name: str - this card waits for all others to start first;

  • None (default) - each threads starts its task independently.

Typically, this is needed when start trigger or shared sample clock are used for hardware synchronisation. The card-provider of the signal should call ni_task.start() last, otherwise some “consumer” cards could start later and miss the signal.

property ref_clk_provider: Tuple[str, str] | None#

Specifies which card exports its 10 MHz reference clock signal during the run.

Format:
  • (card_name: str, term_name: str) - card card_name exports to terminal term_name

  • None - no card exports

Notes

(1) NIStreamer uses run-based static reference clock export - signal is statically exported during init_stream() and then automatically undone during close_stream() calls.

This export is static instead of being tied to NI tasks. As a result, any card supporting 10MHz export can serve as the provider. It does not have to be active (get some instructions) or even be registered in the streamer.

(2) If this mechanism is not sufficient, you can manually do a static export from any card by calling share_10mhz_ref(). However, such export will not be undone automatically - you should manually call unshare_10mhz_ref() or reset_dev().

Forgetting to undo manual export is very easy and dangerous - the exporter card will continue silently feeding the signal until the system is power-cycled. That can lead to physical double-driving and very confusing mis-triggering or mis-clocking errors. So only choose the manual export over the automatic method (1) if absolutely necessary.

got_instructions()[source]#

Returns True if there are some instructions in the edit cache, otherwise False.

Return type:

bool

last_instr_end_time()[source]#

Returns the last instruction end time or None if the edit cache is empty.

Return type:

Optional[float]

compile(stop_time=None)[source]#

Compiles the full pulse sequence from instructions in the current edit cache.

Parameters:

stop_time (Optional[float]) – If None (default), the compiled sequence stops at the last instruction end. Specifying a later stop time extends the sequence duration.

Return type:

float

Returns:

The actual compiled stop time.

Raises:

ValueError – if provided stop_time is below the last instruction end.

Notes

The actual stop times may vary between cards due to clock grid mismatch and extra ticks on the final closing edges. The returned value is the shortest run time across all cards.

If explicit stop_time is provided, the additional time at the sequence end will be filled according to the usual rules:

  • Constant values after finite-duration instructions.

  • Continued waveforms after “go-this” instructions.

validate_compile_cache()[source]#

Verifies that compile cache is up-to-date with the current edit cache.

Returns:

None if compile cache is up-to-date with the current edit cache.

Raises:

ValueError – If compile cache does not match edit cache (typical reason - users forgot to re-compile after adding more instructions).

init_stream()[source]#

Context-based stream initialization.

This function should only be used in the with context. The returned object is a StreamHandle instance providing full stream control.

Examples

>>> strmr = NIStreamer()
>>> # ... add cards/channels, add instructions, compile ...
>>> with strmr.init_stream() as stream_handle:
>>>     stream_handle.launch(instream_reps=10)
>>>     # Do some other logic while waiting ...
>>>     stream_handle.wait_until_finished()
Raises:

ValueError – if stream initialization fails due to invalid settings.

See also

StreamHandle for more details about stream controls;

run() - a more basic way of launching stream.

run(nreps=1)[source]#

Runs pulse sequence generation.

This method will block and only return after all nreps iterations have been generated. But it can be interrupted with KeyboardInterrupt - generation will stop between repetitions.

Parameters:

nreps (Optional[int]) – the number of times to play the sequence. Plays once by default.

Raises:
  • ValueError – if stream initialization fails due to invalid settings.

  • RuntimeError – if generation fails during streaming (underflow, timeout, overvoltage).

Notes

This method implements basic repeating by stopping and re-starting the stream every time. As a result, there is a fluctuating time gap between subsequent repetitions.

Repeating with no gap and rigid timing between iterations is possible with so-called in-stream looping. It is only accessible through the context-based interface. See init_stream() and StreamHandle for more details.

See also

init_stream() and StreamHandle for full stream control.

close_stream()[source]#

Closes the stream.

You typically do not need to use this method since context manager will automatically close the stream whenever exiting the context.

There is a small chance that a rapid succession of KeyboardInterrupt signals disrupts __exit__() logic and prevents automatic stream shutdown. But even then, the next call to init will automatically close it.

So this method is mostly exposed for completeness.

add_reset_instr(reset_time=None)[source]#

Helper method - adds a “go-reset-value” instruction on each channel.

Parameters:

reset_time (Optional[float]) – the time at which to add the reset instruction (the same for all channels). If None, the latest last instruction end time from across all channels is used.

Raises:

ValueError – if requested reset_time is below the last instruction end time.

clear_edit_cache()[source]#

Discards all instructions added so far.

reset_all()[source]#

Performs hardware reset on all cards that have been added to the streamer.