STG4000

class STGX(serial=None)[source]

The STGX is the base class for the STG4000 and wraps the basic USB interface and reads all the properties that are determined by the specific STG connected to your PC. Additionally methods for downloading or streaming are implemented by subclasses. Ideally, just use from stg.api import STG4000, and you will get the class implementing all bells and whistles.

When initialized without arguments, i.e. stg = STG4000(), it looks through your USB ports and connects with the first STGs it finds. If you want to use a specific STG, initialize the class with the serial number of the device, e.g. using stg = STG4000(serial=12345).

Immediatly after the connection is established, we eagerly read all properties from the stimulator, e.g. the number of channels or the output resolution. This read-only properties are than cached, to prevent any later overhead. This means it might take a few seconds until the stg is initialized, but it saves you precious milliseconds when you later stimulate.

Because at any time, only one process can be connected with a specific STG the connection is implemented using a with ... as idiom. This should therefore be relatively safe. It is still possible that the STG can get into a weird state. In that case, try turning it off and on again.

Note

  • Properties are eagerly loaded and cached during initalization

property DAC_resolution: int

Return the DAC resolution in bits

property channel_count: int

returns the number of stimulation channels

property current_range_in_mA: float

Return the current range in mA

property current_range_in_uA: float

Return the current range in uA

property current_resolution_in_mA: float

Return the current resolution in mA

property current_resolution_in_uA: float

Return the current resolution in µA

property manufacturer: str

Returns the name of the manufacturer

property name: str

returns the model name, i.e. STG4002/4/8

property serial_number: int

Returns the serial number of the device

sleep(duration_in_ms)[source]

sleep for duration in milliseconds

property time_resolution_in_ms: float

Return the time resolution in ms

property time_resolution_in_us: float

Return the time resolution in µs

property trigin_count: int

returns the number of trigger inputs

property version: str

Returns the current hardware and software version

property voltage_range_in_uV: float

Return the voltage range in uV

property voltage_resolution_in_uV: float

Return the voltage resolution in µV

Download

class STG4000(serial=None)[source]

This class implements the interface to download, start and stop stimulation.

At this point, you should pay attention to two specific details. First, indexing starts at 0. That means, the first channel is channel 0. Second, there is a difference between channels and triggers for the STG. Triggers are mapped to channels according to a channelmap. That means a single trigger can start stimulation of a whole set of channels. During initialization of the STG, we give this a sensible default. That means, all triggers are mapped to the respective channels following diagonal identity, i.e. trigger 0 maps to channel 0. Use diagonalize_triggermap() to repeat this normalization.

Example

import time
from stg.api import STG4000

stg = STG4000()
stg.download(0,[1,-1, 0], [0.1, 0.1, 49.8])
while True:
    time.sleep(0.5)
    a.trigger()
    stg.start_stimulation([0])

Note

  • Indexing starts at zero

  • Differentiate triggers and channels

Warning

Please note, that in download mode, the Python object and the STG do not share states. More specifically, once a program is downloaded to the STG, it stays downloaded, even if you delete the object, instantiate a new one or reboot the PC. You can enforce a clean state by rebooting the STG or explicitly downloading and thereby overwriting the channels after instantiation. This behavior was kept for three reasons. First, this is also the behavior of the MCS GUI, and therefore less non-intuitive if you come from this direction. Second, it clearly shows that in download mode, PC and STG are not coupled, i.e. once downloaded, you can trigger without any USB connection. Third, clearing the downloaded programs during instantiation (or deletion of the object) would prevent the user from common use cases like recovering the STG after a restart of the kernel, deletion of the object or unplugging the USB cable.

diagonalize_triggermap()[source]

Give each trigger a sensible channel

Use this function to normalize the mapping of trigger to channel to a diagonal identity, i.e. trigger 0 maps to channel 0, so on.

Trigger

0

1

2

3

4

5

6

7

Channel

0

1

2

3

4

5

6

7

download(channel_index=0, amplitudes_in_mA=[0], durations_in_ms=[0], mode='current')[source]

Download a stimulation signal

Warning

Any previous data sent to that channel is erased. Other channels stay untouched.

The signal is compressed as amplitudes and their respective durations

Parameters
  • channel_index (int) – The index of the channel for which to download the signal. Indexing starts at 0

  • amplitudes_in_mA (List[float]) – a list of amplitudes in mA/mV delivered for the corresponding duration

  • durations_in_ms (List[float]) – a list of durations in ms determing how long each corresponding amplitude is delivered

  • mode (str) – defaults to current

Example

stg.download(channel_index = 0,
             amplitudes_in_mA = [1, -1, 0],
             durations_in_ms = [.1, .1, .488])
set_mode(channel_index=[], mode='current')[source]

set a single or all channels to voltage or current mode

Parameters
  • channel_index (list) – defaults to [], which sets the mode at all channels. Give it a list of integers to set the mode only for a specific subset of channels, e.g. [0,1].

  • mode (str ("current", "voltage")) – defaults to current

Return type

int

Warning

Because we primarily use current-mode, voltage mode is relatively untested. Additionally, i so far have not tested the behavior when different channels are in different modes. Be safe, and just set all channels to current-mode with stg.set_mode("current")

start_stimulation(triggerIndex=[])[source]

starts all trigger inputs or a selection based on a list

Parameters

triggerIndex (List[int]) – defaults to [], which starts stimulation at all channels. Give it a list of integers to start a specific subset of triggers, e.g. [0,1].

stop_stimulation(triggerIndex=[])[source]

stops all trigger inputs or a selection based on a list

Parameters

triggerIndex (List[int]) – defaults to [], which stops stimulation at all channels. Give it a list of integers to start a specific subset of triggers, e.g. [0,1].

Stream

class STG4000Streamer(serial=None)[source]

This class implements the interface to stream data.

Quote from the documentation of the DLL:

The Streaming mode works by use of two ring buffers which hold data. One is in PC memory and managed by the DLL, and one is in on-board STG memory. Data is transfered from PC memory to the STG via the USB bus in time slices of one millisecond.

The user can define both the size of the ring buffer in DLL memory and in the STG memory. Once the Streaming mode is started, the STG request data from the PC. The data rate from PC to STG is variable and controlled by the STG. The STG request data from the PC at a rate to keep its internal ringbuffer at about half full.

It is the responsibility of the user to keep the ring buffer in the memory of the PC filled, so the DLL can supply sufficient data to the STG. To do so, the Windows DLL allows to define a “callback” function which is called whenever new data is needed, or more precise, as soon as the ring buffer in the memory of the PC falls below the user defined threshold.

Small buffers have the advantage of a low latency between data generation in the callback funtion and its output as a analog signal from the STG. However for low latency to work, the user-written callback function has to be fast and to produce a steady flow of data.

For you, that means you have to set two parameters carefully when you initialize the streaming mode with start_streaming(). These parameters are the buffer_in_s, which defines the size of the buffer in the DLL, and the capacity_in_s, which defines the size of the buffer on the STG. Both buffers need to be at least as large the the signal you want to buffer. Yet, larger buffer means that the latency when updating it becomes larger, too. Too short buffers will fail without error, and too large buffers might cause

Streaming is implemented by constantly reading the stimulation signal you have set with set_signal() for each channel, and pushing this signal into the DLL-buffer as soon as there is enough space. This is done within its own thread, and if you use set_signal() it is thread-safe. Yet, space in the DLL becomes available at the speed the STG pulls data from the DLL. That means not only that there is a natural jitter, but there are also racing conditions if you update your signal faster than data is actually being pulled from the STG.

Note

  • Uncontrolled racing conditions when adapting stimulation online

  • Extensively test the optimal buffer sizes for your stimulation signal

Example

import time
from stg.api import STG4000

buffer_in_s=0.05 # how large is the buffer in the DLL?
capacity_in_s=.1 # how large is the buffer on the STG?

stg = STG4000()
stg.start_streaming(capacity_in_s=capacity_in_s,
                    buffer_in_s=buffer_in_s)
while True:
    stg.set_signal(0, amplitudes_in_mA=[0], durations_in_ms=[.1])
    time.sleep(0.5)
    stg.set_signal(0, amplitudes_in_mA=[1, -1, 0], durations_in_ms=[.1, .1, 49.7])
    time.sleep(buffer_in_s / 2)

Warning

This class inherits from STG4000 and therefore you can use this class also to download, start, and stop stimulation. How these two modes mix has not been tested so far. Be safe and use either or.

property output_rate_in_hz: int

Constant at 50 kHz.

Type

the rate at which the stg will send out data

set_signal(channel_index=0, amplitudes_in_mA=[0], durations_in_ms=[0])[source]

sets the signal to be continually appended to the buffer

Parameters
  • channel_index (int = 0) – the channel for which the new signal is to be defined

  • amplitudes_in_mA (List[float,] = [0]) – a list of amplitudes in mA

  • durations_in_ms (List[float,] = [0]) –

  • ms (a list of durations in) –

The amplitudes and durations are decompressed (decompress()) to the sampling rate defined in output_rate_in_hz.

start_streaming(capacity_in_s=1, buffer_in_s=0.1, callback_percent=10)[source]

start streaming

sets the STG into streaming mode and creates buffers of the respective sizes within the DLL and on the STG. After the thread has initalized, it starts pushing data as set by set_signal() as soon as space is left in the DLL buffer.

Parameters
  • capacity_in_s (float = 1) – the size of the buffer in the DLL

  • buffer_in_s (float = 0.1) – the size of the buffer on the STG

  • callback_percent (int = 10) – at what state of the DLL-buffer the DLL should request new data. Should have no effect in this implementation, because we constanly push data into the buffer as soon as there is enough space.

stop_streaming()[source]

closes the thread started when calling start_streaming() gracefully