# Source code for neurodynex3.tools.input_factory


# This file is part of the exercise code repository accompanying
# the book: Neuronal Dynamics (see http://neuronaldynamics.epfl.ch)
# located at http://github.com/EPFL-LCN/neuronaldynamics-exercises.

# This free software: you can redistribute it and/or modify it under
# Free Software Foundation. You should have received a copy of the
# GNU General Public License along with the repository. If not,

# Should you reuse and publish the code for your own purposes,
# please cite the book or point to the webpage http://neuronaldynamics.epfl.ch.

# Wulfram Gerstner, Werner M. Kistler, Richard Naud, and Liam Paninski.
# Neuronal Dynamics: From Single Neurons to Networks and Models of Cognition.
# Cambridge University Press, 2014.

import brian2 as b2
import numpy as np
import matplotlib.pyplot as plt
import math
import numpy

###############
# Input Currents
###############
[docs]def get_step_current(t_start, t_end, unit_time, amplitude, append_zero=True):

"""Creates a step current. If t_start == t_end, then a single
entry in the values array is set to amplitude.

Args:
t_start (int): start of the step
t_end (int): end of the step
unit_time (Brian2 unit): unit of t_start and t_end. e.g. 0.1*brian2.ms
amplitude (Quantity): amplitude of the step. e.g. 3.5*brian2.uamp
append_zero (bool, optional): if true, 0Amp is appended at t_end+1.
Without that trailing 0, Brian reads out the last value in the array (=amplitude) for all indices > t_end.

Returns:
TimedArray: Brian2.TimedArray
"""

assert isinstance(t_start, int), "t_start_ms must be of type int"
assert isinstance(t_end, int), "t_end must be of type int"
assert b2.units.fundamentalunits.have_same_dimensions(amplitude, b2.amp), \
"amplitude must have the dimension of current e.g. brian2.uamp"
tmp_size = 1 + t_end  # +1 for t=0
if append_zero:
tmp_size += 1
tmp = np.zeros((tmp_size, 1)) * b2.amp
tmp[t_start: t_end + 1, 0] = amplitude
curr = b2.TimedArray(tmp, dt=1. * unit_time)
return curr

[docs]def get_ramp_current(t_start, t_end, unit_time, amplitude_start, amplitude_end, append_zero=True):
"""Creates a ramp current. If t_start == t_end, then ALL entries are 0.

Args:
t_start (int): start of the ramp
t_end (int): end of the ramp
unit_time (Brian2 unit): unit of t_start and t_end. e.g. 0.1*brian2.ms
amplitude_start (Quantity): amplitude of the ramp at t_start. e.g. 3.5*brian2.uamp
amplitude_end (Quantity): amplitude of the ramp at t_end. e.g. 4.5*brian2.uamp
append_zero (bool, optional): if true, 0Amp is appended at t_end+1.
Without that trailing 0, Brian reads out the last value in the
array (=amplitude_end) for all indices > t_end.

Returns:
TimedArray: Brian2.TimedArray
"""
assert isinstance(t_start, int), "t_start_ms must be of type int"
assert isinstance(t_end, int), "t_end must be of type int"
assert b2.units.fundamentalunits.have_same_dimensions(amplitude_start, b2.amp), \
"amplitude must have the dimension of current e.g. brian2.uamp"
assert b2.units.fundamentalunits.have_same_dimensions(amplitude_end, b2.amp), \
"amplitude must have the dimension of current e.g. brian2.uamp"
tmp_size = 1 + t_end  # +1 for t=0
if append_zero:
tmp_size += 1
tmp = np.zeros((tmp_size, 1)) * b2.amp
if t_end > t_start:  # if deltaT is zero, we return a zero current
slope = (amplitude_end - amplitude_start) / float((t_end - t_start))
ramp = [amplitude_start + t * slope for t in range(0, (t_end - t_start) + 1)]
tmp[t_start: t_end + 1, 0] = ramp

curr = b2.TimedArray(tmp, dt=1. * unit_time)
return curr

[docs]def get_sinusoidal_current(t_start, t_end, unit_time,
amplitude, frequency, direct_current, phase_offset=0.,
append_zero=True):
"""Creates a sinusoidal current. If t_start == t_end, then ALL entries are 0.

Args:
t_start (int): start of the sine wave
t_end (int): end of the sine wave
unit_time (Quantity, Time): unit of t_start and t_end. e.g. 0.1*brian2.ms
amplitude (Quantity, Current): maximum amplitude of the sinus e.g. 3.5*brian2.uamp
frequency (Quantity, Hz): Frequency of the sine. e.g. 0.5*brian2.kHz
direct_current(Quantity, Current): DC-component (=offset) of the current
phase_offset (float, Optional): phase at t_start. Default = 0.
append_zero (bool, optional): if true, 0Amp is appended at t_end+1. Without that
trailing 0, Brian reads out the last value in the array for all indices > t_end.

Returns:
TimedArray: Brian2.TimedArray
"""
assert isinstance(t_start, int), "t_start_ms must be of type int"
assert isinstance(t_end, int), "t_end must be of type int"
assert b2.units.fundamentalunits.have_same_dimensions(amplitude, b2.amp), \
"amplitude must have the dimension of current. e.g. brian2.uamp"
assert b2.units.fundamentalunits.have_same_dimensions(direct_current, b2.amp), \
"direct_current must have the dimension of current. e.g. brian2.uamp"
assert b2.units.fundamentalunits.have_same_dimensions(frequency, b2.Hz), \
"frequency must have the dimension of 1/Time. e.g. brian2.Hz"

tmp_size = 1 + t_end  # +1 for t=0
if append_zero:
tmp_size += 1
tmp = np.zeros((tmp_size, 1)) * b2.amp
if t_end > t_start:  # if deltaT is zero, we return a zero current
phi = range(0, (t_end - t_start) + 1)
phi = phi * unit_time * frequency
phi = phi * 2. * math.pi + phase_offset
c = numpy.sin(phi)
c = (direct_current + c * amplitude)
tmp[t_start: t_end + 1, 0] = c
curr = b2.TimedArray(tmp, dt=1. * unit_time)
return curr

[docs]def get_zero_current():
"""
Returns a TimedArray with one entry: 0 Amp

Returns:
TimedArray
"""
return get_step_current(0, 0, b2.ms, 0 * b2.amp, append_zero=False)

[docs]def get_spikes_current(t_spikes, unit_time, amplitude, append_zero=True):
"""Creates a two dimensional TimedArray wich has one column for each value in t_spikes.
All values in each column are 0 except one, the spike time as specified in t_spikes is set to amplitude.
Note: This function is provided to easily insert pulse currents into a cable. For other use of
spike input, search the Brian2 documentation for SpikeGeneration.

Args:
t_spikes (int): list of spike times
unit_time (Quantity, Time): unit of t_spikes . e.g. 1*brian2.ms
amplitude (Quantity, Current):  amplitude of the spike. All spikes have the sampe amplitude
append_zero (bool, optional): if true, 0Amp is appended at t_end+1. Without that trailing 0,
Brian reads out the last value in the array for all indices > t_end.

Returns:
TimedArray: Brian2.TimedArray
"""
assert isinstance(t_spikes, list), "t_spikes must be of type list"
assert b2.units.fundamentalunits.have_same_dimensions(amplitude, b2.amp), \
"amplitude must have the dimension of current e.g. brian2.uamp"
nr_spikes = len(t_spikes)
t_max = max(t_spikes)
tmp_size = 1 + t_max  # +1 for t=0
if append_zero:
tmp_size += 1
tmp = np.zeros((tmp_size, nr_spikes)) * b2.amp
for i in range(nr_spikes):
tmp[t_spikes[i], i] = amplitude
curr = b2.TimedArray(tmp, dt=1. * unit_time)
return curr

[docs]def plot_step_current_example():
"""
Example for get_step_current.
"""
current = get_step_current(10, 30, b2.ms, amplitude=5. * b2.uA, append_zero=False)
data = current.values[:, 0] / b2.uamp
plt.plot(data, "ro", markersize=10, fillstyle="full")
plt.title("get_step_current(10, 30, b2.ms, amplitude=5.*b2.uA, append_zero=False")
plt.xlabel("index")
plt.ylabel("value")

[docs]def plot_ramp_current_example():
"""
Example for get_ramp_current
"""
current = get_ramp_current(10, 25, b2.ms, 20 * b2.uamp, 50 * b2.uamp, append_zero=True)
data = current.values[:, 0] / b2.uamp
plt.plot(data, lw=3)
plt.title("get_ramp_current(10, 25, b2.ms, 20*b2.uamp, 50*b2.uamp, append_zero=True)")
plt.xlabel("index")
plt.ylabel("value")

[docs]def plot_sinusoidal_current_example():
"""
Example for get_sinusoidal_current
"""
current = get_sinusoidal_current(
100, 1100, b2.us,
amplitude=2 * b2.uamp, frequency=1.5 * b2.kHz, direct_current=1.5 * b2.uamp, phase_offset=math.pi / 6,
append_zero=False)
data = current.values[:, 0] / b2.uamp
plt.plot(data, lw=3)
plt.title("get_sinusoidal_current(100, 1100, b2.us, amplitude=2*b2.uamp, frequency=1.5*b2.kHz, \n"
"direct_current=1.5*b2.uamp, phase_offset=pi/6, append_zero=False)")
plt.xlabel("index")
plt.ylabel("value")

[docs]def getting_started():
# plot examples
plot_step_current_example()
plt.show()
plot_ramp_current_example()
plt.show()
plot_sinusoidal_current_example()
plt.show()

if __name__ == "__main__":
getting_started()