debug and add unittests 1
This commit is contained in:
@@ -19,10 +19,10 @@ class LifacNoiseModel(AbstractModel):
|
||||
"v_offset": 50,
|
||||
"input_scaling": 1,
|
||||
"delta_a": 0.4,
|
||||
"tau_a": 40,
|
||||
"tau_a": 0.04,
|
||||
"a_zero": 0,
|
||||
"noise_strength": 3,
|
||||
"step_size": 0.01}
|
||||
"step_size": 0.00005}
|
||||
|
||||
def __init__(self, params: dict = None):
|
||||
super().__init__(params)
|
||||
@@ -36,26 +36,31 @@ class LifacNoiseModel(AbstractModel):
|
||||
def simulate(self, stimulus: AbstractStimulus, total_time_s):
|
||||
|
||||
self.stimulus = stimulus
|
||||
output_voltage = []
|
||||
adaption = []
|
||||
time = np.arange(0, total_time_s, self.parameters["step_size"])
|
||||
output_voltage = np.zeros(len(time), dtype='float64')
|
||||
adaption = np.zeros(len(time), dtype='float64')
|
||||
spiketimes = []
|
||||
|
||||
current_v = self.parameters["v_zero"]
|
||||
current_a = self.parameters["a_zero"]
|
||||
output_voltage[0] = current_v
|
||||
adaption[0] = current_a
|
||||
|
||||
for time_point in np.arange(0, total_time_s*1000, self.parameters["step_size"]):
|
||||
for i in range(1, len(time), 1):
|
||||
time_point = time[i]
|
||||
# rectified input:
|
||||
stimulus_strength = fu.rectify(stimulus.value_at_time_in_ms(time_point))
|
||||
stimulus_strength = fu.rectify(stimulus.value_at_time_in_s(time_point))
|
||||
|
||||
v_next = self._calculate_voltage_step(current_v, stimulus_strength - current_a)
|
||||
a_next = self._calculate_adaption_step(current_a)
|
||||
|
||||
if v_next > self.parameters["threshold"]:
|
||||
v_next = self.parameters["v_base"]
|
||||
spiketimes.append(time_point/1000)
|
||||
a_next += self.parameters["delta_a"] / (self.parameters["tau_a"] / 1000)
|
||||
spiketimes.append(time_point)
|
||||
a_next += self.parameters["delta_a"] / (self.parameters["tau_a"])
|
||||
|
||||
output_voltage.append(v_next)
|
||||
adaption.append(a_next)
|
||||
output_voltage[i] = v_next
|
||||
adaption[i] = a_next
|
||||
|
||||
current_v = v_next
|
||||
current_a = a_next
|
||||
@@ -66,33 +71,6 @@ class LifacNoiseModel(AbstractModel):
|
||||
|
||||
return output_voltage, spiketimes
|
||||
|
||||
def simulate_fast(self, stimulus: AbstractStimulus, total_time_s, time_start=0):
|
||||
|
||||
v_zero = self.parameters["v_zero"]
|
||||
a_zero = self.parameters["a_zero"]
|
||||
step_size = self.parameters["step_size"]
|
||||
threshold = self.parameters["threshold"]
|
||||
v_base = self.parameters["v_base"]
|
||||
delta_a = self.parameters["delta_a"]
|
||||
tau_a = self.parameters["tau_a"]
|
||||
v_offset = self.parameters["v_offset"]
|
||||
mem_tau = self.parameters["mem_tau"]
|
||||
noise_strength = self.parameters["noise_strength"]
|
||||
|
||||
stimulus_array = stimulus.as_array(time_start, total_time_s, step_size)
|
||||
rectified_stimulus = rectify_stimulus_array(stimulus_array)
|
||||
|
||||
parameters = np.array([v_zero, a_zero, step_size, threshold, v_base, delta_a, tau_a, v_offset, mem_tau, noise_strength])
|
||||
|
||||
voltage_trace, adaption, spiketimes = simulate_fast(rectified_stimulus, total_time_s, parameters)
|
||||
|
||||
self.stimulus = stimulus
|
||||
self.voltage_trace = voltage_trace
|
||||
self.adaption_trace = adaption
|
||||
self.spiketimes = spiketimes
|
||||
|
||||
return voltage_trace, spiketimes
|
||||
|
||||
def _calculate_voltage_step(self, current_v, input_v):
|
||||
v_base = self.parameters["v_base"]
|
||||
step_size = self.parameters["step_size"]
|
||||
@@ -109,6 +87,31 @@ class LifacNoiseModel(AbstractModel):
|
||||
step_size = self.parameters["step_size"]
|
||||
return current_a + (step_size * (-current_a)) / self.parameters["tau_a"]
|
||||
|
||||
def simulate_fast(self, stimulus: AbstractStimulus, total_time_s, time_start=0):
|
||||
|
||||
v_zero = self.parameters["v_zero"]
|
||||
a_zero = self.parameters["a_zero"]
|
||||
step_size = self.parameters["step_size"]
|
||||
threshold = self.parameters["threshold"]
|
||||
v_base = self.parameters["v_base"]
|
||||
delta_a = self.parameters["delta_a"]
|
||||
tau_a = self.parameters["tau_a"]
|
||||
v_offset = self.parameters["v_offset"]
|
||||
mem_tau = self.parameters["mem_tau"]
|
||||
noise_strength = self.parameters["noise_strength"]
|
||||
|
||||
rectified_stimulus = rectify_stimulus_array(stimulus.as_array(time_start, total_time_s, step_size))
|
||||
parameters = np.array([v_zero, a_zero, step_size, threshold, v_base, delta_a, tau_a, v_offset, mem_tau, noise_strength, time_start])
|
||||
|
||||
voltage_trace, adaption, spiketimes = simulate_fast(rectified_stimulus, total_time_s, parameters)
|
||||
|
||||
self.stimulus = stimulus
|
||||
self.voltage_trace = voltage_trace
|
||||
self.adaption_trace = adaption
|
||||
self.spiketimes = spiketimes
|
||||
|
||||
return voltage_trace, spiketimes
|
||||
|
||||
def min_stimulus_strength_to_spike(self):
|
||||
return self.parameters["threshold"] - self.parameters["v_base"]
|
||||
|
||||
@@ -159,8 +162,8 @@ class LifacNoiseModel(AbstractModel):
|
||||
"""
|
||||
base_stimulus = SinusAmplitudeModulationStimulus(base_stimulus_freq, 0, 0)
|
||||
_, spiketimes = self.simulate_fast(base_stimulus, 30)
|
||||
|
||||
baseline_freq = hF.mean_freq_of_spiketimes_after_time_x(spiketimes, 5)
|
||||
time_x = 5
|
||||
baseline_freq = hF.mean_freq_of_spiketimes_after_time_x(spiketimes, self.get_sampling_interval(), time_x)
|
||||
|
||||
relative_spiketimes = np.array([s % (1 / base_stimulus_freq) for s in spiketimes])
|
||||
eod_durations = np.full((len(spiketimes)), 1 / base_stimulus_freq)
|
||||
@@ -179,13 +182,10 @@ class LifacNoiseModel(AbstractModel):
|
||||
f_infinities = []
|
||||
for contrast in contrasts:
|
||||
stimulus = SinusAmplitudeModulationStimulus(base_freq, contrast, modulation_frequency)
|
||||
_, spiketimes = self.simulate_fast(stimulus, 0.5)
|
||||
_, spiketimes = self.simulate_fast(stimulus, 1)
|
||||
|
||||
if len(spiketimes) < 2:
|
||||
f_infinities.append(0)
|
||||
else:
|
||||
f_infinity = hF.mean_freq_of_spiketimes_after_time_x(spiketimes, 0.4)
|
||||
f_infinities.append(f_infinity)
|
||||
f_infinity = hF.mean_freq_of_spiketimes_after_time_x(spiketimes, self.get_sampling_interval(), 0.3)
|
||||
f_infinities.append(f_infinity)
|
||||
|
||||
popt, pcov = curve_fit(fu.line, contrasts, f_infinities, maxfev=10000)
|
||||
|
||||
@@ -193,9 +193,58 @@ class LifacNoiseModel(AbstractModel):
|
||||
|
||||
return f_infinities, f_infinities_slope
|
||||
|
||||
def find_v_offset(self, goal_baseline_frequency, base_stimulus, threshold=10):
|
||||
test_model = self.get_model_copy()
|
||||
simulation_length = 5
|
||||
|
||||
v_search_step_size = 1000
|
||||
|
||||
current_v_offset = 0
|
||||
|
||||
current_freq = test_v_offset(test_model, current_v_offset, base_stimulus, simulation_length)
|
||||
|
||||
while current_freq < goal_baseline_frequency:
|
||||
current_v_offset += v_search_step_size
|
||||
current_freq = test_v_offset(test_model, current_v_offset, base_stimulus, simulation_length)
|
||||
|
||||
lower_bound = current_v_offset - v_search_step_size
|
||||
upper_bound = current_v_offset
|
||||
|
||||
return binary_search_base_freq(test_model, base_stimulus, goal_baseline_frequency, simulation_length, lower_bound, upper_bound, threshold)
|
||||
|
||||
|
||||
def binary_search_base_freq(model: LifacNoiseModel, base_stimulus, goal_frequency, simulation_length, lower_bound, upper_bound, threshold):
|
||||
|
||||
if threshold <= 0:
|
||||
raise ValueError("binary_search_base_freq() - LifacNoiseModel: threshold is not allowed to be negative!")
|
||||
while True:
|
||||
middle = upper_bound - (upper_bound - lower_bound)/2
|
||||
frequency = test_v_offset(model, middle, base_stimulus, simulation_length)
|
||||
|
||||
# print('{:.1f}, {:.1f}, {:.1f}, {:.1f} vs {:.1f} '.format(lower_bound, middle, upper_bound, frequency, goal_frequency))
|
||||
if abs(frequency - goal_frequency) < threshold:
|
||||
return middle
|
||||
elif frequency < goal_frequency:
|
||||
lower_bound = middle
|
||||
elif frequency > goal_frequency:
|
||||
upper_bound = middle
|
||||
elif abs(upper_bound-lower_bound) < 0.01 * threshold:
|
||||
return middle
|
||||
else:
|
||||
print('lower bound: {:.1f}, middle: {:.1f}, upper_bound: {:.1f}, frequency: {:.1f} vs goal: {:.1f} '.format(lower_bound, middle, upper_bound, frequency, goal_frequency))
|
||||
raise ValueError("binary_search_base_freq() - LifacNoiseModel: Goal frequency might be nan?")
|
||||
|
||||
|
||||
def test_v_offset(model: LifacNoiseModel, v_offset, base_stimulus, simulation_length):
|
||||
model.set_variable("v_offset", v_offset)
|
||||
_, spiketimes = model.simulate_fast(base_stimulus, simulation_length)
|
||||
freq = hF.mean_freq_of_spiketimes_after_time_x(spiketimes, 0.005, simulation_length/3)
|
||||
|
||||
return freq
|
||||
|
||||
|
||||
@jit(nopython=True)
|
||||
def rectify_stimulus_array(stimulus_array:np.ndarray):
|
||||
def rectify_stimulus_array(stimulus_array: np.ndarray):
|
||||
return np.array([x if x > 0 else 0 for x in stimulus_array])
|
||||
|
||||
|
||||
@@ -212,8 +261,9 @@ def simulate_fast(rectified_stimulus_array, total_time_s, parameters: np.ndarray
|
||||
v_offset = parameters[7]
|
||||
mem_tau = parameters[8]
|
||||
noise_strength = parameters[9]
|
||||
time_start = parameters[10]
|
||||
|
||||
time = np.arange(0, total_time_s * 1000, step_size)
|
||||
time = np.arange(time_start, total_time_s, step_size)
|
||||
length = len(time)
|
||||
output_voltage = np.zeros(length)
|
||||
adaption = np.zeros(length)
|
||||
@@ -223,7 +273,8 @@ def simulate_fast(rectified_stimulus_array, total_time_s, parameters: np.ndarray
|
||||
output_voltage[0] = v_zero
|
||||
adaption[0] = a_zero
|
||||
|
||||
for i in range(len(time)-1):
|
||||
for i in range(1, len(time), 1):
|
||||
|
||||
noise_value = np.random.normal()
|
||||
noise = noise_strength * noise_value / np.sqrt(step_size)
|
||||
|
||||
@@ -233,7 +284,7 @@ def simulate_fast(rectified_stimulus_array, total_time_s, parameters: np.ndarray
|
||||
if output_voltage[i] > threshold:
|
||||
output_voltage[i] = v_base
|
||||
spiketimes.append(i*step_size)
|
||||
adaption[i] += delta_a / (tau_a / 1000)
|
||||
adaption[i] += delta_a / tau_a
|
||||
|
||||
return output_voltage, adaption, spiketimes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user