Source code for stg._wrapper.downloadnet

# -*- coding: utf-8 -*-
from typing import List
from stg._wrapper.dll import (
    System,
    CURRENT,
    VOLTAGE,
    available,
    select,
    DeviceInfo,
    StreamingInterface,
    bitmap,
    STGX,
)


[docs]class STG4000(STGX): """ 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 :meth:`~STG4000.diagonalize_triggermap` to repeat this normalization. Example ------- .. code-block:: python 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 """
[docs] def stop_stimulation(self, triggerIndex: List[int] = []): """stops all trigger inputs or a selection based on a list args ---- 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]. """ if triggerIndex == []: triggerIndex = [c for c in range(self.channel_count)] with self.interface() as interface: interface.SendStop(System.UInt32(bitmap(triggerIndex)))
[docs] def start_stimulation(self, triggerIndex: List[int] = []): """starts all trigger inputs or a selection based on a list args ---- 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]. """ if triggerIndex == []: triggerIndex = [c for c in range(self.channel_count)] with self.interface() as interface: interface.SendStart(System.UInt32(bitmap(triggerIndex)))
[docs] def set_mode(self, channel_index: List[int] = [], mode: str = "current") -> int: """set a single or all channels to voltage or current mode args ---- 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 .. 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 :code:`stg.set_mode("current")` """ if mode == "current": self._set_current_mode(channel_index) return CURRENT elif mode == "voltage": self._set_voltage_mode(channel_index) return VOLTAGE else: # pragma no cover raise ValueError( f"Unknow mode {mode}. select either 'current' or ' 'voltage'" )
[docs] def diagonalize_triggermap(self): """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 | +----------+---+---+---+---+---+---+---+---+ """ channelmap = [] syncoutmap = [] repeat = [] for chan_idx in range(0, self.channel_count): repeat.append(1) # every trigger only once syncoutmap.append(1 << chan_idx) # diagonal triggerout channelmap.append(1 << chan_idx) # diagonal triggerin with self.interface() as interface: interface.SetupTrigger(0, channelmap, syncoutmap, repeat)
[docs] def download( self, channel_index: int = 0, amplitudes_in_mA: List[float,] = [0], durations_in_ms: List[float,] = [0], mode="current", ): """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 args ---- 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 ------- .. code-block:: python stg.download(channel_index = 0, amplitudes_in_mA = [1, -1, 0], durations_in_ms = [.1, .1, .488]) """ if len(amplitudes_in_mA) != len(durations_in_ms): raise ValueError("Every amplitude needs a duration and vice versa!") amplitudes = [System.Int32(a * 1000_000) for a in amplitudes_in_mA] durations = [System.UInt64(s * 1000) for s in durations_in_ms] MODE = self.set_mode([channel_index], mode) with self.interface() as interface: interface.PrepareAndSendData( System.UInt32(channel_index), amplitudes, durations, MODE )