Stimuli
Electrical stimulation is completely described using electrodes that can deliver stimuli, which is the object of present chapter.
Electrical stimuli are electrical signals, mostly current quantities, that are applied in the extracellular (marginaly to the intracellular) to trigger cell reactions. In NRV, a special class has been designed to handle stimuli.
A stimulus is described as an asynchronous signal: there is no need for a regular clock to describe the stimulus changes in time. As a consequence, the stimulus is based on two lists:
a first list called ‘s’ contains the signal values,
a second list called ‘t’ contains the time stamps for the different values.
The class constructor takes no positional arguments, however there is one optional argument: - s_init: the initial value of the stimulus at time t=0.
At the instantiation, a stimulus only gets its initial value at time t=0, and lists ‘s’ and ‘t’ have a length of 1. Here is a minimal example of instatiation of a stimulus:
import nrv
stim1 = nrv.stimulus()
print(len(stim1.s))
print(len(stim1.t))
1
1
It is possible to plot the stimulus instance using the plot method, taking as arguments, matplotlib axes. An example is performed with more consistant stimuli bellow in this chapter.
Stimuli generators
In order to ease the user experience, commonly used signals can be automatically generated by invoking pre-implemented methods:
constant
: a simple constant signal. Parameters are:value
(float): Value of the constant signalstart
(float): starting time of the constant signal, by default set to 0.
pulse
: pulse shape signal. Parameters are:value
(float): value of the pulsestart
(float): starting time of the pulseduration
(float): duration of the pulse, optional and by default equal to zero, if non zero value, a point is added at the end of the pulse with the previous value
biphasic_pulse
: conventional automatically charged-balanced biphasic pulse waveform. Parameters are:start
(float): starting time of the waveform, in mss_cathod
(float): cathodic (negative stimulation value) current, in uA WARNING: always positive, the user give here the absolute valuet_stim
(float): stimulation time, in mss_anod
(float): anodic (positive stimulation value) current and, in uAt_inter
(float): inter pulse timing, in msanod_first
(bool): if true, stimulation is anodic and begins with the anodic value and is balanced with cathodic value, else stimuation is cathodic and begins with the cathodic value and is balances with anodic value, by default set to False (cathodic first as most stimulation protocols)
sinus
: sinusoidal waveform. Parameters are:start
(float): starting time of the waveform, in msduration
float duration of the waveform, in msamplitude
(float): amplitude of the waveform, in uAfreq
(float): frequency of the waveform, in kHzoffset
(float): offset current ofthe waveform, in uA, by default set to 0phase
(float): initial phase of the waveform, in rad, by default set to 0dt
(float): sampling time period to generate the sinusoidal shape. If equal to 0, dt is automatically set to match 100 samples per sinusoid period by default set to 0
harmonic_pulse
: pulse waveform based on N harmonic. Parameters are:start
(float): starting time of the waveform, in mst_pulse
(float): pulse duration, in msamplitude
(float): finaln amplitude of the pulse, in uA WARNING: always positive, the user give here the absolute value - amp_list (list): list of relative sine amplitude, between 0 and 1phase_list
(list): list of sine pulse phasesdt
(float): sampling time period to generate the sinusoidal shape. If equal to 0, dt is automatically set to match 100 samples per sinusoid period by default set to 0
square
: repetitive (periodic) square waveform. Parameters are:start
(float): starting time of the waveform, in msduration
(float): duration of the waveform, in msamplitude
(float): amplitude of the waveform, in uAfreq
(float): frequency of the waveform, in kHzoffset
(float): offset current of the waveform, in uA, by default set to 0anod_first
(bool): if true, stimulation is anodic and begins with the anodic value and is balanced with cathodic value, else stimuation is cathodic and begins with the cathodic value and is balances with anodic value, by default set to False (cathodic first as most stimulation protocols)
ramp
: ramp waveform with slope value. Parameters are:slope
(float): slope of the waveform, in uA.ms-1start
(float): starting time of the waveform, in msduration
(float): duration of the waveform, in msdt
(float): sampling time period to generate the sinusoidal shapebounds
(tuple): boundary vaues of the ramp signalprintslope
(bool, optional): if True, the value of the slope is printed on the prompt
ramp_lim
: ramp waveform with bounds values. Parameters are:ampstart
(float): initiale amplitude of the waveform, in uAampmax
(float): final amplitude of the waveform, in uAtstart
(float): starting time of the waveform, in mstmax
(float): starting time of the waveform, in msduration
(float): duration of the waveform, in msdt
(float): sampling time period to generate the sinusoidal shapeprintslope
(bool, optional): if True, the value of the slope is printe on the prompt.
As an example, let’s create a biphasic signal (\(50\mu s\) of cathodic time, cathodic value of 1, \(40\mu s\) deadtime between cathodic and anodic and a ratio of 5 betwen cathodic and anodic values) and a sinusoidal signal at \(1kHz\) and of amplitude 0.5
import matplotlib.pyplot as plt
t_start = 1
V_cat = 1
t_cat = 60e-3 # recall, NRV's units are in ms
t_dead = 40e-3
ca_ratio = 5
biphasic_stim = nrv.stimulus()
biphasic_stim.biphasic_pulse(t_start, V_cat,t_cat, V_cat/ca_ratio, t_dead)
f_stim = 1 # recall, NRV's units are in ms
duration = 10
amp = 0.5
sinus_stim = nrv.stimulus()
sinus_stim.sinus(t_start, duration, amp, f_stim)
#print(dir(biphasic_stim))
fig, axs = plt.subplots(1, 2, layout='constrained', figsize=(10, 4))
biphasic_stim.plot(axs[0])
axs[0].set_title('Biphasic stimulus')
sinus_stim.plot(axs[1])
axs[1].set_title('Biphasic stimulus')
Text(0.5, 1.0, 'Biphasic stimulus')
Note that the last value (here always 0) is not further ploted on the picture, however, the value is present in the table and in simulations, the last value of the stimuli is effectively applied to the electrode up untill the end of simulation.
Mathematical operations with stimuli
The asynchronous description of stimulus is convinient for pulsed signal such as used on electrodes, and is also interesting for handling simulations: ‘simulate’ methods are paused and stimulation is updated thanks to the time stamps of the involved stimuli.
However, it can be seen also as restricting operations with stimuli. In order to limit such restrictions, basic mathematical operations between stimuli objects have been implemented:
+
,-
,\*
operators are implemented with numerical values or between to stimulus objects. The end used do not have to worry about time stamps combinations. It is worth mentioning that the division has not been implemented as this operation is ambiguous and can lead to divisions by zero. For dividing by a scalar value, we envourage to multiply by the inverse of the scalar,absolute value (
abs
) and negation of a stimulus are implemented.a length method (
len
) is implemented,(in-)equality comparaison operators (
==
,!=
) are implemented, if stimuli are equal but not of the same length (successive equal values with multiple time stamps), the the result is still straigthforward, but compared stimuli are not altered (redondancy of values is not removed) - <, > operators are not implemented as the are ambiguous.
Here below is an example of constant sinusoidal stimulation with envelope modulation by a ramp signal, to demonstrate the use of operations:
stim1, stim2 = nrv.stimulus(),nrv.stimulus()
f_stim = 1
t_start = 1
duration = 99
amp = 0.5
t_ramp_stop = 90
amp_start = 0
amp_max = 1
stim1.sinus(t_start, duration, amp, f_stim)
stim2.ramp_lim(t_start, t_ramp_stop, amp_start, amp_max, duration, dt=1)
stim3 = stim1*stim2
fig, axs = plt.subplots(1, 2, layout='constrained', figsize=(10, 4))
stim1.plot(axs[0])
stim2.plot(axs[0])
axs[0].set_title('arguments of the product')
stim3.plot(axs[1])
axs[1].set_title('product result')
Text(0.5, 1.0, 'product result')
Low level access
To develop new methods or functions, the user also has access to:
append
method, taking as argument a couple of value and time stamp,concatenate
method, taking as argument a couple of list (or iterable, also numpy arrays), with a optional argumentt_shift
that shifts all timte stamps with an offset (by default set at zero). This is especially usefull to create repetitive patterns.