Programming interface
Overview
This section defines terminology used in this documentation and provides an overview of how signals can be generated with the Pulse Streamer API.
Pulse pattern
The pulse pattern is a sequence of levels, defining the signal to generate. It is defined as an array of (duration, level) tuples, in other words, using Run-Length Encoding (RLE). In contrast to defining pulse patterns as an array of values with equal time durations, the RLE encoded pattern is more memory efficient, especially for patterns that consist of levels of both short and long durations.
The duration is always specified in nanoseconds. The level is either 0 or 1 for digital output or a real number between -1 and +1 in Volt for analog outputs. See the Hardware section for more details on the electrical properties of the generated signals.
The following code shows how to define a pulse pattern similar to the one shown in the image above. In addition, it shows an example of an analog pattern definition.
Creating sequences
Before a pattern can be sent for streaming to the Pulse Streamer outputs, they have to be mapped to the output channels. All these steps are performed with the Sequence
object, which is created with PulseStreamer.createSequence()
. The digital and analog channel assignment is done with the setDigital()
and setAnalog()
methods, respectively.
from pulsestreamer import PulseStreamer
ps = PulseStreamer('pulsestreamer')
seq = ps.createSequence()
seq.setDigital(0, pulse_patt)
seq.setDigital(2, pulse_patt)
seq.setAnalog(0, analog_patt)
import PulseStreamer.PulseStreamer;
ps = PulseStreamer('pulsestreamer');
seq = ps.createSequence();
seq.setDigital(0, pulse_patt);
seq.setDigital(2, pulse_patt);
seq.setAnalog(0, analog_patt);
Sequence transformation
Sequence transformation methods enable the creation of complex sequences from simpler sub-sequences. The sequence data can be repeated or combined with another sequence. These operations, while inherently simple, have a few edge cases that are important to know. Concatenation and repetition operations are non-destructive. In other words, they preserve original sequence objects (immutability). The result is stored in a newly created sequence object. Internally, the sequence stores a map of the channel number and the pattern data with the pattern data unmodified. In general, this results in a sequence that consists of patterns having different durations. On concatenation or repetitions, however, it is intuitively expected that a sequence is treated as a solid unit with every pattern of the same duration. Therefore, before concatenating the sequence data, the pattern durations are padded to the common duration.
When two sub-sequences being concatenated have a different set of mapped channels, the resulting sequence will include them all. This is explained with the following example. Let’s assume we have two sequences, seq1 and seq2, which we want to concatenate. The seq1 has patterns mapped to channels (0,2), and seq2 has channels (0,1), as shown in the code below.
seq1 = ps.createSequence()
seq1.setDigital(0, patt1)
seq1.setDigital(2, patt2)
seq2 = ps.createSequence()
seq2.setDigital(0, patt3)
seq2.setDigital(1, patt4)
seq3 = seq1 + seq2 # concatenation
seq1 = ps.createSequence();
seq1.setDigital(0, patt1);
seq1.setDigital(2, patt2);
seq2 = ps.createSequence();
seq2.setDigital(0, patt3);
seq2.setDigital(1, patt4);
seq3 = [seq1, seq2]; % concatenation
During the concatenation, the channel lists of the two sequences are compared and the output sequence seq3 will include them all (0,1,2). As a first step, a new sequence object seq3 will be created as a copy of seq1, and an empty pattern will be assigned to the channel 1. Next, all patterns in seq3 will be padded to the duration of the longest one, which is essentially the sequence duration. Finally, the pattern data from seq2 will be appended to the corresponding patterns of the seq3.
The duration padding is always performed with the value of the last element in the pattern. When there is no previous element, the default value is used. The repetition process behaves similarly and can be qualitatively understood as multiple concatenations of the object with itself.
Streaming
Now, any of the sequence objects created before can be sent for streaming by calling the PulseStreamer.stream()
method, as shown in the following example for the sequence seq.
On streaming, the sequence object is converted to a hardware-specific run-length encoded data block, which can be understood as an array of Sequence steps. Every step defines the state of all channels and the duration to hold the state. Sequences support a number of useful methods, like repetition, concatenation, preview plotting, etc. With this basic set of methods, complex sequences can be built from smaller and simpler sub-sequences.
Note
Internally, the Pulse Streamer hardware is always splitting the sequence data into 8 nanosecond long chunks. When a sequence is shorter than 8 ns or its length is not an exact multiple of 8 ns the extra time will be padded to complete the last chunk. You can observe the effects of such padding if you try to stream a short pulse repetitively.
Example 1. Your sequence consists of 3 ns high-level and 2 ns low-level and you stream it with infinite repetitions, the resulting signal
will have 3 ns high-level but 5 ns low-level. Therefore, the actual pulse frequency will be 125 MHz instead of 200 MHz.
For continuous periodic signals, you can solve this problem by creating a sequence of repetitive pulses that has a duration which is multiple of 8 ns.
One easy way to guarantee that sequence duration is a multiple of 8 ns is to repeat it 8 times using Sequence.repeat()
method,
which will repeat the sequence data in PC memory before sending it to the Pulse Streamer hardware.
Example 2. You want to stream a sequence that is 12345 ns long and you want to repeat it infinitely by setting n_runs=-1. Since this sequence duration is not a multiple of 8 ns (12345 ns / 8 ns = 1543.125) the Pulse Streamer will allocate 1544 chunks, and the actual sequence duration will be 1544 * 8ns = 12352 ns, or 7 ns longer.
Sequence step
The sequence step is the smallest element of a sequence that contains information on the state of every output of the Pulse Streamer and the duration to hold this state. The image below explains the relation between Sequence step, Sequence
, and OutputState
objects.
Warning
In a typical use of the client API, the user does not have to care about how to create or operate on the sequence data directly. All necessary functionality is enclosed within the API presented in this article. The description of the Sequence data corresponds to the RAW data as it is required by the hardware. The internal API data structures are implemented slightly differently for each programming language, aiming at the optimization of the client performance. Furthermore, the RAW sequence data format is hardware-dependent and future Pulse Streamer models are likely to use a different format. See also: Low-level RPC interface.
Module level functions
- findPulseStreamers(search_serial='')
- Parameters:
search_serial (str) – Pulse Streamer serial number as a string.
- Returns:
List of
DeviceInfo
objects.
This function searches and returns basic information about discovered Pulse Streamers. If non-empty search_serial string is provided, then information is returned only for a specific Pulse Streamer unit.
The returned value is a list of
DeviceInfo
objects containing the IP address and basic information.- class DeviceInfo
This class contains read-only information about the discovered Pulse Streamer.
Property name
Example data
Description
ip
“192.168.0.2”
Device IP address
serial
“00:26:32:f0:3b:1b”
Device serial number
hostname
“pulsestreamer”
Pulse Streamer hostname
model
“Pulse Streamer 8/2”
Pulse Streamer model name
fpgaid
“123456789ABCD”
FPGA ID number
firmware
“1.2.0”
Firmware version
hardware
“1.3”
Hardware version
The discovery algorithm sends Pulse Streamer specific query packets overall available and active network interfaces and listens for responses from the connected Pulse Streamers.
Note
The
findPulseStreamers()
is capable of finding the devices and reporting their IP addresses even in the networks without dynamic IP assignment by a DHCP server or an improper IP address configuration. Therefore, it might happen that the reported Pulse Streamer IP is not accessible from your network. For example, when the reported IP is 169.254.8.2 (static fallback) and your PC is configured as 192.168.1.2, you will not be able to connect to the Pulse Streamer. This is because of the way how IP networks operate. However, you will still be able to discover this Pulse Streamer and learn its IP, which is very helpful for identifying network connection problems.
PulseStreamer
The PulseStreamer
class is a wrapper for the RPC interface provided by the Pulse Streamer hardware. It handles the connection to the hardware and exposes all available methods. This class is implemented in various supported programming languages with consistently named methods. However, in some languages, additional functionality common to that language is also implemented, like callback functions in MATLAB.
- class PulseStreamer
- PulseStreamer(ip)
The class constructor accepts a single string argument, which can be either the IP address or a hostname by which the Pulse Streamer can be reached in the network. The constructor fails when the ip has an incorrect value or the device is not reachable. The Pulse Streamer hardware has a static fallback address “169.254.8.2”. This allows operation when the Pulse Streamer is directly connected to a PC network card and without requiring any additional configuration.
- Parameters:
ip (str) – IP address or hostname of the Pulse Streamer.
- reset()
Reset the Pulse Streamer device to the default state. All outputs are set to 0V, and all functional configurations are set to default. The automatic rearm functionality is enabled, and the clock source is the internal clock of the device. No specific trigger functionality is enabled, which means that each sequence is streamed immediately when its upload is completed.
- reboot()
Perform a soft reboot of the device without power-cycling.
- createSequence()
Use this method to create a new hardware-specific
Sequence
object. A hardware-specific sequence object has the same functionality asSequence
and implements early checks for hardware limits. For example, an attempt to assign a pattern to a non-existing channel or setting analog voltage outside the DAC range will result in an error. The genericSequence
object’s normal behavior is to check hardware limits only on the call toPulseStreamer.stream()
method.- Returns:
Hardware-specific
Sequence
object.
Setting constant output state
- PulseStreamer.constant(state=OutputState.ZERO)
Set the outputs to a constant state. Calling the method without a parameter will result in the default output state with all output set to 0V. If you set the device to a constant output, an eventually currently streamed sequence is stopped. It is not possible to retrigger the last streamed sequence after setting the Pulse Streamer constant. OutputState.ZERO is a constant equal to
OutputState([],0,0)
.Alternatively, the state parameter can be specified as a tuple consisting of three elements
([],0,0)
.ps.constant(OutputState([1, 2, 5], 0, 0)) # or ps.constant(([1, 2, 5], 0, 0))ps.constant(OutputState([1, 2, 5], 0, 0)); % or ps.constant({[1, 2, 5], 0, 0});
- Parameters:
state (OutputState) –
OutputState
object that defines the state of outputs or a tuple.
Running pulse sequences
This section describes methods that allow to run sequences and configure trigger properties. You can repeat a pulse sequence infinitely or an integer number of times. If you want to stop a running sequence and force it to the final, specified in the function call, you can do this by calling the method
forceFinal()
.
- PulseStreamer.stream(sequence[, n_runs=PulseStreamer.REPEAT_INFINITELY[, final=OutputState.ZERO]])
Sends the sequence to the Pulse Streamer. After the sequence has been repeated the given n_runs, the constant state final will be reached. All parameters except sequence have default values and can be omitted. By default, the sequence is started immediately. Alternatively, you can select when the output of the sequence starts with
setTrigger()
to a software-based trigger started withstartNow()
or to an external hardware trigger.If the sequence is empty, then the final state will set immediately.
The sequence parameter of the
stream()
method also accepts an RLE sequence defined as a list of 4 element tuples of the following format: (duration_ns, [channels_to_set_HIGH], analogV_0, analogV_1)ps.stream([(100, [1, 2], 0, 0), (10, [2], 0, 0), (5, [], 0, 0)])ps.stream([{100, [1, 2], 0, 0}, {10, [2], 0, 0}, {5, [], 0, 0}]);
- Parameters:
sequence (Sequence) – Sequence object or a list of tuples.
n_runs (int) – Number of times to repeat the sequence. Infinite repetitions if n_runs<0. There is also a symbolic constant REPEAT_INFINITELY=-1
final (OutputState) – OutputState object, which defines the constant output after the sequence has finished.
- PulseStreamer.setTrigger(start[, rearm=TriggerRearm.AUTO])
Defines how the uploaded sequence is triggered.
If you want to trigger the Pulse Streamer by using the external trigger input of the device, you have to set the start parameter to one of the following values: start=
TriggerStart.HARDWARE_RISING
(rising edge on the trigger input), start=TriggerStart.HARDWARE_FALLING
(falling edge on the trigger input) or start=TriggerStart.HARDWARE_RISING_AND_FALLING
(both edges are active).If the automatic rearm functionality is enabled (rearm=
TriggerRearm.AUTO
), which is the default power-on state, you can re-trigger a sequence which is finished, by providing an appropriate trigger signal, depending on start argument. You can disable the automatic rearm by passing rearm=TriggerRearm.MANUAL
.If the automatic rearm functionality is disabled, you can manually rearm the Pulse Streamer by calling the method
rearm()
- Parameters:
start (TriggerStart) – Defines the source of the trigger signal
rearm (TriggerRearm) – Enables or disables trigger automatic rearm.
- PulseStreamer.getTriggerStart()
Queries the hardware for the currently active trigger start condition.
- Returns:
Returns
TriggerStart
value.
- PulseStreamer.getTriggerRearm()
Queries the hardware for the currently active rearming method.
- Returns:
Returns
TriggerRearm
value.
- PulseStreamer.startNow()
Starts streaming the sequence present in the Pulse Streamer’s memory. The behavior of this method depends on the trigger configuration performed with
setTrigger()
method.If the start is
TriggerStart.IMMEDIATE
, n_runs>=0, and the sequence has finished, thenstartNow()
will trigger the sequence again.If the start is
TriggerStart.SOFTWARE
then the sequence is started every time thestartNow()
is called. In case of the rearm=TriggerRearm.MANUAL
the methodstartNow()
will trigger the sequence only once. Callrearm()
to manually rearm the trigger.If the start is set to one of the hardware sources, then this method does nothing.
- PulseStreamer.rearm()
Rearm the trigger in case the Pulse Streamer has reached the final state of the current sequence and the trigger rearm method was set to
TriggerRearm.MANUAL
. Returns True on success.
- Returns:
bool True or False
- PulseStreamer.forceFinal()
Interrupts the sequence and sets the final state. This method does not modify the output state if the sequence has already finished and the Pulse Streamer is in the final state.
If no final state was declared in the current sequence, the output of Pulse Streamer will change to (or stay in) the last known constant state.
The recommended way to stop the Pulse Streamer streaming is to set its output to a constant value via the method
constant()
, described above.
- PulseStreamer.setCallbackFinished(callback_func) (MATLAB only)
Allows to set up a callback function, which will be called after the sequence streaming has finished. The callback function will be called with the following signature callbackFunction(pulseStreamer_obj). An example of such a function is shown below.
function callbackFunction(pulseStreamer) % this is an example of a callback function disp('hasFinishedCallback - Pulse Streamer finished.'); end
Requesting the streaming state
The following methods allow you to request whether the Pulse Streamer has a sequence in memory, whether a sequence is currently being streamed or if it has already finished.
- PulseStreamer.hasSequence()
Returns True if the Pulse Streamer memory contains a sequence.
- Returns:
True or False.
- PulseStreamer.isStreaming()
Returns True if the Pulse Streamer is currently streaming a sequence. When the sequence has finished and the device remains in the final state, this method returns False again.
- Returns:
True or False.
- PulseStreamer.hasFinished()
Returns True if the Pulse Streamer remains in the final state after having finished a sequence.
- Returns:
True or False.
Using an external clock
The Pulse Streamer can be clocked from three different clock sources. By default, the internal clock of the device is used. It is also possible use an external clock of 125MHz (sampling clock) or an external 10MHz reference signal. You can choose the clock source via
selectClock()
. For more information on the required electrical parameters of an external clock signal, please see the section Hardware.
- PulseStreamer.selectClock(source)
Set the hardware clock source.
- Parameters:
source (ClockSource) – Specifies the clock source for the Pulse Streamer hardware.
- PulseStreamer.getClock()
Returns a
ClockSource
element with the clock source currently used by the Pulse Streamer.
- Returns:
ClockSource
Current clock sourceAlso, you can apply a continuous square wave of 125MHz to the dedicated Pulse Streamer output channels as an external clock signal for other devices to be synchronized with the Pulse Streamer.
- PulseStreamer.setSquareWave125MHz(channels=[])
Set a persistent square wave with a frequency of 125 MHz to the selected digital outputs. The 125 MHz will remain and will not be affected by any other settings applied to this channel unless the corresponding channel is deselected via
setSquareWave125MHz()
or the methodreset()
is called. A call to this method without a parameter will disable the 125 MHz signal on all channels it was enabled before.
- Parameters:
channels (list) – defines to which channels the 125 MHz square wave should be applied.
Hardware identification
- PulseStreamer.getSerial()
- Returns:
String containing the serial number which is the same as MAC address of the Ethernet interface.
- PulseStreamer.getFPGAID()
- Returns:
String containing FPGA ID number.
- PulseStreamer.getFirmwareVersion()
- Returns:
String containing the firmware version number of the connected Pulse Streamer.
- PulseStreamer.getHardwareVersion()
- Returns:
String containing the hardware revision number of the connected Pulse Streamer.
- PulseStreamer.setHostname(hostname)
- Parameters:
hostname (str) – Hostname string to set for the connected Pulse Streamer.
Set hostname of the connected Pulse Streamer.
Note
Depending on your network environment, this setting may not affect how your Pulse Streamer is identified in the network. However, the stored hostname will be returned when you call
getHostname()
.
- PulseStreamer.getHostname()
- Returns:
String containing the hostname of the connected Pulse Streamer.
Calibrating the analog outputs
Pulse Streamer 8/2 devices shipped with firmware version v1.3.0 or later (published in July 2020) already include calibration data for analog outputs, and no further user action is required. Devices shipped with older firmware require analog output calibration in order to achieve specified accuracy, see Hardware. You can perform this calibration yourself by following the steps described below. The calibration requires a sufficiently accurate multimeter (not an oscilloscope) connected to the analog outputs (can be done one channel at a time).
Calibration procedure
Connect the multimeter to the analog output of the Pulse Streamer. The measurement has to be performed at 50 Ohm load, so you will need to attach 50 Ohm termination.
Using the Pulse Streamer API, set the analog output to several values and record multimeter readings. This has to be done at least for -0.9 and +0.9 output values.
Calculate the slope
Calculate the offset
Perform the steps 1 to 4 for each analog output.
Call the
setAnalogCalibration()
and specify both offsets and slopes.Reboot the Pulse Streamer to apply the new calibration data (from firmware v1.5.0 on, the device is rebooted automatically).
Warning
If you perform repeated calibration, you have to reset the slope and offset to values 1 and 0, respectively. Failing to do so will lead to invalid calibration data.
- PulseStreamer.setAnalogCalibration(dc_offset_a0=0, dc_offset_a1=0, slope_a0=1, slope_a1=1)
Sends the DC-offset and slope of each analog channel to the Pulse Streamer and stores it to internal memory. These values will be applied after reboot. With firmware version v1.5.0 or later, this is done automatically. If you use a former firmware of the Pulse Streamer 8/2, you will have to power cycle your device.
- Parameters:
dc_offset_a0 – The DC offset of analog channel 0
dc_offset_a1 – The DC offset of analog channel 1
slope_a0 – The gradient of the transfer function of analog channel 0
slope_a1 – The gradient of the transfer function of analog channel 1
If you need help during the calibration procedure, please contact support@swabianinstruments.com.
- PulseStreamer.getAnalogCalibration()
Returns the stored calibration values of your Pulse Streamer. These values will be rounded according to the DAC resolution. If you call this method immediately after
setAnalogCalibration()
, the returned data will not reflect the actual calibration state.
- Returns:
structure of the four calibration values rounded to the DAC resolution.
Modify the network configuration
By default, the Pulse Streamer 8/2 will attempt to acquire an IP address via DHCP. If you want to assign a specific IP address to your Pulse Streamer, you can disable DHCP and configure a static IP instead. We recommend using our graphical user interface (Windows only) to modify the Pulse Streamer 8/2 network configuration. For more information, please have a look at Network Connection. Alternatively, the following methods allow you to configure the device’s network settings via our client software interfaces.
- PulseStreamer.setNetworkConfiguration(dhcp, ip='', netmask='', gateway='', testmode=True)
Enables DHCP or sets static IP address, Netmask and Standard Gateway. If testmode=True, the configuration is applied temporarily. Power-cycling will restore the former configuration. If testmode=False, the configuration will be applied permanently and the device is rebooted.
- Parameters:
dhcp (bool) – DHCP enable/disable True/False
ip (str) – static IP address (If dhcp=True, this value is ignored)
netmask (str) – Netmask for static IP address configuration (If dhcp=True, this value is ignored)
gateway (str) – Standard gateway for static IP address configuration (If dhcp=True, this value is ignored)
testmode (bool) – If True, the configuration is applied temporarily. Power-cycling will restore the former configuration. If False, the configuration will be applied permanently and the device is rebooted.
- PulseStreamer.getNetworkConfiguration(permanent=False)
- Parameters:
permanent (bool) – If True, the method returns network settings stored in the device’s configuration file. If False, the method returns the current network settings of the device.
- Returns:
structure of the current or stored network settings
- PulseStreamer.applyNetworkConfiguration()
Applies current (and successfully tested) network configuration permanently and the device is rebooted.
Enumerations
- class ClockSource(enumeration)
This enumeration describes the selectable clock sources of the Pulse Streamer
- INTERNAL
Use internal clock generator (default)
- EXT_125MHZ
Use external 125 MHz clock signal
- EXT_10MHZ
Derive clock from external 10 MHz reference signal
- class TriggerStart(enumeration)
This enumeration describes the selectable start modes of the Pulse Streamer
- IMMEDIATE
Trigger immediately after a sequence is uploaded. (default)
- SOFTWARE
Trigger by calling
startNow()
method.
- HARDWARE_RISING
External trigger on the rising edge.
- HARDWARE_FALLING
External trigger on the falling edge.
- HARDWARE_RISING_AND_FALLING
External trigger on rising and falling edges.
Sequence
The Sequence contains information about the patterns and channel assignments. It also handles the mapping of patterns (see Pulse pattern) to output channels and has a number of built-in methods that operate on the whole sequence, like concatenation, repetitions, visualization, etc.
Warning
While the same pattern can be mapped to one or more channels, successive mappings to the same channel will replace the previous mapping.
- class Sequence
- Sequence()
Class constructor. The Sequence is a generic class without early hardware limit checks. Since this class is not aware of hardware-specific limitations, like available channels or analog range, the validation will be performed only during an attempt to stream this Sequence object.
Note
If you want to have early limit checks, channel number validation, please create a hardware-specific Sequence object with
PulseStreamer.createSequence()
method. This, however, requires an active connection to the hardware.
- setDigital(channels, pattern)
Assign a pattern to a digital output. The same pattern can be assigned to one or more channels simultaneously.
sequence.setDigital(0, patt1) sequence.setDigital([1,2,6], patt2)
- Parameters:
channels (list[int]) – Digital channel number(s) as labeled on the Pulse Streamer connectors panel.
pattern (list) – A pattern to be assigned to the channel.
- invertDigital(channels)
Inverts level values in the stored pattern for the specified channel.
sequence.setDigital(1, [(10, 0), (20, 1), (80, 0)]) sequence.invertDigital(1) # is equivalent to sequence.setDigital(1, [(10, 1), (20, 0), (80, 1)])
- Parameters:
channel (int) – Digital channel number.
- setAnalog(channels, pattern)
Assign a pattern to an analog output. The same pattern can be assigned to one or more channels simultaneously.
sequence.setAnalog([0,1], patt2)
- Parameters:
channels (list[int]) – Analog channel number(s) as labeled on the Pulse Streamer connectors panel.
pattern (list) – A pattern to be assigned to the channel.
- invertAnalog(channel)
Inverts level values in the pattern for the specified channel.
sequence.setAnalog(0, [(100, -0.1), (200, 0), (800, 0.5)]) sequence.invertAnalog(0) # is equivalent to sequence.setAnalog(0, [(100, 0.1), (200, 0), (800, -0.5)])
- Parameters:
channel (int) – Analog channel number.
Properties
- Sequence.getDuration()
Returns sequence duration in nanoseconds.
- Sequence.getLastState()
Returns the last state in the sequence as an
OutputState
object.
- Returns:
OutputState
Last state of the sequence.
- Sequence.getData()
Returns the run-length encoded (RLE) sequence data. This method is called automatically by the
PulseStreamer.stream()
method.
- Returns:
Run-length encoded data.
Transformation
- static Sequence.repeat(sequence, n_times)
Returns the sequence data duplicated n_times. The sequence data in the original object remains unmodified. In case the
Sequence
object consists of patterns with different durations, they will be padded to the longest one, which defines sequence duration as returned bySequence.getDuration()
method. In this context, a Sequence shall be understood as a set of patterns all of the same duration.In Python, you can repeat sequences similarly to lists by multiplying it by a number.
# The following three lines are fully equivalent seq1 = Sequence.repeat(seq, 5) seq1 = seq * 5 seq1 = 5 * seqseq1 = repeat(seq, 5)
- static Sequence.concatenate(sequence1, sequence2)
Creates a new
Sequence
object with a sequence of sequence2 object appended at the end of this sequence. Both object, sequence1 and sequence2, remain unmodified. In case the sequence1 sequence consists of patterns with different durations, they will be padded to the longest one, which defines sequence duration as returned bySequence.getDuration()
method. In this context, a Sequence shall be understood as a set of patterns all of the same duration.This method is exposed directly in LabVIEW. However, in MATLAB and Python, it is exposed only as the override of the concatenation operator. This allows for transparent use of any function of these languages that implicitly use concatenation. See the example code for each language.
- Returns:
Returns a new
Sequence
object with concatenated data.
Visualization
- Sequence.plotDigital()
Plots the sequence data for digital outputs. Plotting is done into the current axes. (Only in MATLAB and LabView)
- Sequence.plotAnalog()
Plots sequence data for analog outputs. Plotting is done into the current axes. (Only in MATLAB and LabView)
- Sequence.plot()
Calls
plotDigital()
andplotAnalog()
and shows the results as subplots in a single figure. Plotting is done in the current figure.An example of the
plot()
output is shown in the image below.Note
(Python only)
Since the Python Client release v1.6.1, importing the module matplotlib for
plot()
is optional. If you want to use visualization with Python, please ensure you have the package matplotlib installed.
OutputState
The OutputState is a simple value class that contains information on the state of every output of the Pulse Streamer.
- class OutputState
- OutputState(channels, A0, A1)
Class constructor. Input parameters specify the state of each output of the Pulse Streamer. Digital and analog output values are specified differently. In order to set a HIGH level at the digital channel, add the channel number to the channels list, for example
channels=[0,2,3]
will set HIGH level on the channels 0, 2 and 3. All other digital channels will be set to LOW. Output values at each of two analog outputs are specified with corresponding parameters A0 and A1.- Parameters:
channels (list) – List of digital channels to be set HIGH.
A0 (float) – Analog output 0 voltage in Volt.
A1 (float) – Analog output 1 voltage in Volt.
- ZERO
This is a helper constant equal to
OutputState([], 0, 0)
.
Advanced (Beta) features
Synchronized Pulse Streamer (Python only)
With our programming examples in Python, we provide the class SyncPulseStreamer as a wrapper class for the client interface of the Pulse Streamer 8/2. It combines two Pulse Streamer 8/2 (requires firmware version v1.4.0 or later) and is currently only available for the Python client.
Synchronization concept and setup
One Pulse Streamer master generates the clock signal and trigger for one Pulse Streamer slave. The only necessary preparation is that digital channel 6 of the master must be connected to the external clock input of the slave as well as digital channel 7 of the master must be connected to the trigger input of the slave. To avoid race conditions between the trigger and trigger-sampling clock-edge, we recommend using cables of equal length.
The features of the resulting SyncPulseStreamer object can be described as follows:
14 digital channels (6 of the master, 8 of the slave)
4 analog channels (2 in each case master/slave)
The slave is delayed by a constant time offset of ~70ns (internal + cable)
Increased RMS jitter of the 8 digital channels of the slave (< 75 ps)
In this configuration, devices with hardware Version 2.x (devices before 2021) have a 100mV ripple on the digital channels of the slave due to the external clock signal. The analog outputs are not affected.
Usage and sequence generation
The Pulse Streamer synchronization wrapper offers the same API-structure as the original Pulse Streamer client if possible. For a detailed description of the Pulse Streamer 8/2 API, please have a look at the Programming interface section and the provided Python example.
When it comes to sequence generation, unlike the original method createSequence()
, the equivalent method of the sync-wrapper returns two sequence objects, one for the Pulse Streamer master
and one for the Pulse Streamer slave. You can set the digital and analog channels of both sequences independently. Setting Channel 6 (clock signal) of the master will be ignored, and channel 7 (trigger)
of the master will be overwritten by the stream method).
If you want to use a parameter n_runs>1 with the stream()
function, you should ensure that the two sequences are of equal duration. Therefore the stream()
prints a warning message if the duration of
the two sequences differs.
To compensate for the delay of the Pulse Streamer slave, you can add an empty pulse as a first pulse to each channel of the master sequence, as it is shown in the Python code example. In that case, you have to take into account
that if you want to use n_runs>1, you have to subtract the delay from the last pulses of the master-sequence, or you can accordingly pad the slave-sequence. The drawback is that this either requires the same state at the beginning
and the end of the channel pattern, or you have to deal with the padding. Furthermore, you have to take into account that when a sequence is given to the method stream()
of the Pulse Streamer or to the
transformation-methods (see Transformation) of the Sequence
class, all channels are padded with the last value to the longest channel duration. For further information, please have a look at the sections Creating sequences and Sequence.
Just to give you the complete information of the padding issue: Due to the internal design of the Pulse Streamer, the device itself will pad the last sequence step to a duration that the sequence duration as a whole is a multiple of 8ns (which means a prolongation between 0 and 7ns). This step is executed before the parameter n_runs is applied (see Streaming).
Further Limitations
If you use the synchronized Pulse Streamer with a fast external trigger, it is possible that the Pulse Streamer master is ready for retriggering and the slave is not and vice versa. Therefore, you should always poll the method
hasFinished()
before retriggering the Pulse Streamer with the external trigger.If you stream a second pulse pattern into an already running sequence, you previously should set the Pulse Streamer to a constant state by using the methods
constant()
orreset()
. Otherwise, the new sequence of the Pulse Streamer slave might already be triggered by the still running stream of the Pulse Streamer master.