1
|
|
|
"""!
|
2
|
|
|
|
3
|
|
|
@brief Oscillatory Neural Network based on Hodgkin-Huxley Neuron Model
|
4
|
|
|
@details Based on article description:
|
5
|
|
|
- D.Chik, R.Borisyuk, Y.Kazanovich. Selective attention model with spiking elements. 2009.
|
6
|
|
|
|
7
|
|
|
@authors Andrei Novikov ([email protected])
|
8
|
|
|
@date 2014-2018
|
9
|
|
|
@copyright GNU Public License
|
10
|
|
|
|
11
|
|
|
@cond GNU_PUBLIC_LICENSE
|
12
|
|
|
PyClustering is free software: you can redistribute it and/or modify
|
13
|
|
|
it under the terms of the GNU General Public License as published by
|
14
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
15
|
|
|
(at your option) any later version.
|
16
|
|
|
|
17
|
|
|
PyClustering is distributed in the hope that it will be useful,
|
18
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20
|
|
|
GNU General Public License for more details.
|
21
|
|
|
|
22
|
|
|
You should have received a copy of the GNU General Public License
|
23
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
24
|
|
|
@endcond
|
25
|
|
|
|
26
|
|
|
"""
|
27
|
|
|
|
28
|
|
|
from scipy.integrate import odeint;
|
|
|
|
|
29
|
|
|
|
30
|
|
|
import pyclustering.core.hhn_wrapper as wrapper;
|
31
|
|
|
|
32
|
|
|
from pyclustering.nnet import *;
|
|
|
|
|
33
|
|
|
|
34
|
|
|
from pyclustering.utils import allocate_sync_ensembles;
|
35
|
|
|
|
36
|
|
|
import numpy;
|
|
|
|
|
37
|
|
|
import random;
|
38
|
|
|
|
39
|
|
|
class hhn_parameters:
|
40
|
|
|
"""!
|
41
|
|
|
@brief Describes parameters of Hodgkin-Huxley Oscillatory Network.
|
42
|
|
|
|
43
|
|
|
@see hhn_network
|
44
|
|
|
|
45
|
|
|
"""
|
46
|
|
|
|
47
|
|
|
def __init__(self):
|
48
|
|
|
"""!
|
49
|
|
|
@brief Default constructor of parameters for Hodgkin-Huxley Oscillatory Network.
|
50
|
|
|
@details Constructor initializes parameters by default non-zero values that can be
|
51
|
|
|
used for simple simulation.
|
52
|
|
|
"""
|
53
|
|
|
|
54
|
|
|
## Intrinsic noise.
|
55
|
|
|
self.nu = random.random() * 2.0 - 1.0;
|
56
|
|
|
|
57
|
|
|
## Maximal conductivity for sodium current.
|
58
|
|
|
self.gNa = 120.0 * (1 + 0.02 * self.nu);
|
59
|
|
|
|
60
|
|
|
## Maximal conductivity for potassium current.
|
61
|
|
|
self.gK = 36.0 * (1 + 0.02 * self.nu);
|
62
|
|
|
|
63
|
|
|
## Maximal conductivity for leakage current.
|
64
|
|
|
self.gL = 0.3 * (1 + 0.02 * self.nu);
|
65
|
|
|
|
66
|
|
|
|
67
|
|
|
## Reverse potential of sodium current [mV].
|
68
|
|
|
self.vNa = 50.0;
|
69
|
|
|
|
70
|
|
|
## Reverse potential of potassium current [mV].
|
71
|
|
|
self.vK = -77.0;
|
72
|
|
|
|
73
|
|
|
## Reverse potantial of leakage current [mV].
|
74
|
|
|
self.vL = -54.4;
|
75
|
|
|
|
76
|
|
|
## Rest potential [mV].
|
77
|
|
|
self.vRest = -65.0;
|
78
|
|
|
|
79
|
|
|
|
80
|
|
|
## External current [mV] for central element 1.
|
81
|
|
|
self.Icn1 = 5.0;
|
82
|
|
|
|
83
|
|
|
## External current [mV] for central element 2.
|
84
|
|
|
self.Icn2 = 30.0;
|
85
|
|
|
|
86
|
|
|
|
87
|
|
|
## Synaptic reversal potential [mV] for inhibitory effects.
|
88
|
|
|
self.Vsyninh = -80.0;
|
89
|
|
|
|
90
|
|
|
## Synaptic reversal potential [mV] for exciting effects.
|
91
|
|
|
self.Vsynexc = 0.0;
|
92
|
|
|
|
93
|
|
|
## Alfa-parameter for alfa-function for inhibitory effect.
|
94
|
|
|
self.alfa_inhibitory = 6.0;
|
95
|
|
|
|
96
|
|
|
## Betta-parameter for alfa-function for inhibitory effect.
|
97
|
|
|
self.betta_inhibitory = 0.3;
|
98
|
|
|
|
99
|
|
|
|
100
|
|
|
## Alfa-parameter for alfa-function for excitatory effect.
|
101
|
|
|
self.alfa_excitatory = 40.0;
|
102
|
|
|
|
103
|
|
|
## Betta-parameter for alfa-function for excitatory effect.
|
104
|
|
|
self.betta_excitatory = 2.0;
|
105
|
|
|
|
106
|
|
|
|
107
|
|
|
## Strength of the synaptic connection from PN to CN1.
|
108
|
|
|
self.w1 = 0.1;
|
109
|
|
|
|
110
|
|
|
## Strength of the synaptic connection from CN1 to PN.
|
111
|
|
|
self.w2 = 9.0;
|
112
|
|
|
|
113
|
|
|
## Strength of the synaptic connection from CN2 to PN.
|
114
|
|
|
self.w3 = 5.0;
|
115
|
|
|
|
116
|
|
|
|
117
|
|
|
## Period of time [ms] when high strength value of synaptic connection exists from CN2 to PN.
|
118
|
|
|
self.deltah = 650.0;
|
119
|
|
|
|
120
|
|
|
## Threshold of the membrane potential that should exceeded by oscillator to be considered as an active.
|
121
|
|
|
self.threshold = -10;
|
122
|
|
|
|
123
|
|
|
## Affects pulse counter.
|
124
|
|
|
self.eps = 0.16;
|
125
|
|
|
|
126
|
|
|
|
127
|
|
|
class central_element:
|
128
|
|
|
"""!
|
129
|
|
|
@brief Central element consist of two central neurons that are described by a little bit different dynamic than peripheral.
|
130
|
|
|
|
131
|
|
|
@see hhn_network
|
132
|
|
|
|
133
|
|
|
"""
|
134
|
|
|
|
135
|
|
|
def __init__(self):
|
136
|
|
|
"""!
|
137
|
|
|
@brief Constructor of central element.
|
138
|
|
|
|
139
|
|
|
"""
|
140
|
|
|
|
141
|
|
|
## Membrane potential of cenral neuron (V).
|
142
|
|
|
self.membrane_potential = 0.0;
|
143
|
|
|
|
144
|
|
|
## Activation conductance of the sodium channel (m).
|
145
|
|
|
self.active_cond_sodium = 0.0;
|
146
|
|
|
|
147
|
|
|
## Inactivaton conductance of the sodium channel (h).
|
148
|
|
|
self.inactive_cond_sodium = 0.0;
|
149
|
|
|
|
150
|
|
|
## Activaton conductance of the sodium channel (h).
|
151
|
|
|
self.active_cond_potassium = 0.0;
|
152
|
|
|
|
153
|
|
|
## Spike generation of central neuron.
|
154
|
|
|
self.pulse_generation = False;
|
155
|
|
|
|
156
|
|
|
## Timestamps of generated pulses.
|
157
|
|
|
self.pulse_generation_time = [];
|
158
|
|
|
|
159
|
|
|
def __repr__(self):
|
160
|
|
|
"""!
|
161
|
|
|
@brief Returns string that represents central element.
|
162
|
|
|
|
163
|
|
|
"""
|
164
|
|
|
return "%s, %s" % (self.membrane_potential, self.pulse_generation_time);
|
165
|
|
|
|
166
|
|
|
|
167
|
|
|
class hhn_network(network):
|
168
|
|
|
"""!
|
169
|
|
|
@brief Oscillatory Neural Network with central element based on Hodgkin-Huxley neuron model. Interaction between oscillators is performed via
|
170
|
|
|
central element (no connection between oscillators that are called as peripheral). Peripheral oscillators receive external stimulus.
|
171
|
|
|
Central element consist of two oscillators: the first is used for synchronization some ensemble of oscillators and the second controls
|
172
|
|
|
synchronization of the first cental oscillator with various ensembles.
|
173
|
|
|
|
174
|
|
|
Usage example where oscillatory network with 6 oscillators is used for simulation. The first two oscillators
|
175
|
|
|
has the same stimulus, as well as the third and fourth oscillators and the the last two. Thus three synchronous
|
176
|
|
|
ensembles are expected after simulation.
|
177
|
|
|
@code
|
178
|
|
|
# change period of time when high strength value of synaptic connection exists from CN2 to PN.
|
179
|
|
|
params = hhn_parameters();
|
180
|
|
|
params.deltah = 400;
|
181
|
|
|
|
182
|
|
|
# create oscillatory network with stimulus
|
183
|
|
|
net = hhn_network(6, [0, 0, 25, 25, 47, 47], params);
|
184
|
|
|
|
185
|
|
|
# simulate network
|
186
|
|
|
(t, dyn) = net.simulate(1200, 600);
|
187
|
|
|
|
188
|
|
|
# draw network output during simulation (membrane potential of peripheral and central neurons).
|
189
|
|
|
amount_canvases = 6 + 2; # 6 peripheral oscillator + 2 central elements
|
190
|
|
|
visualizer = dynamic_visualizer(amount_canvases, x_title="Time", y_title="V", y_labels=False);
|
191
|
|
|
visualizer.append_dynamics(t, dyn_peripheral, 0, separate);
|
192
|
|
|
visualizer.append_dynamics(t, dyn_central, amount_canvases - 2, True);
|
193
|
|
|
visualizer.show();
|
194
|
|
|
@endcode
|
195
|
|
|
|
196
|
|
|
To increase performance CCORE can be used, for that purpose special flag should be specified when network is
|
197
|
|
|
constructed:
|
198
|
|
|
@code
|
199
|
|
|
# create oscillatory network with stimulus using CCORE
|
200
|
|
|
net = hhn_network(6, [0, 0, 25, 25, 47, 47], params, ccore=True);
|
201
|
|
|
@endcode
|
202
|
|
|
|
203
|
|
|
There is visualized results of simulation where three synchronous ensembles of oscillators can be observed. The
|
204
|
|
|
first and the second forms the first ensemble, the third and the fourth forms the second ensemble and the last
|
205
|
|
|
two oscillators forms the third ensemble.
|
206
|
|
|
@image html hhn_three_ensembles.png
|
207
|
|
|
|
208
|
|
|
"""
|
209
|
|
|
|
210
|
|
|
def __init__(self, num_osc, stimulus = None, parameters = None, type_conn = None, type_conn_represent = conn_represent.MATRIX, ccore = False):
|
211
|
|
|
"""!
|
212
|
|
|
@brief Constructor of oscillatory network based on Hodgkin-Huxley neuron model.
|
213
|
|
|
|
214
|
|
|
@param[in] num_osc (uint): Number of peripheral oscillators in the network.
|
215
|
|
|
@param[in] stimulus (list): List of stimulus for oscillators, number of stimulus should be equal to number of peripheral oscillators.
|
216
|
|
|
@param[in] parameters (hhn_parameters): Parameters of the network.
|
217
|
|
|
@param[in] type_conn (conn_type): Type of connections between oscillators in the network (ignored for this type of network).
|
218
|
|
|
@param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list.
|
219
|
|
|
@param[in] ccore (bool): If 'True' then CCORE is used (C/C++ implementation of the model).
|
220
|
|
|
|
221
|
|
|
"""
|
222
|
|
|
|
223
|
|
|
super().__init__(num_osc, conn_type.NONE, type_conn_represent);
|
224
|
|
|
|
225
|
|
|
if (stimulus is None):
|
226
|
|
|
self._stimulus = [0.0] * num_osc;
|
227
|
|
|
else:
|
228
|
|
|
self._stimulus = stimulus;
|
229
|
|
|
|
230
|
|
|
if (parameters is not None):
|
231
|
|
|
self._params = parameters;
|
232
|
|
|
else:
|
233
|
|
|
self._params = hhn_parameters();
|
234
|
|
|
|
235
|
|
|
self.__ccore_hhn_pointer = None;
|
236
|
|
|
self.__ccore_hhn_dynamic_pointer = None;
|
237
|
|
|
|
238
|
|
|
if (ccore is not False):
|
239
|
|
|
self.__ccore_hhn_pointer = wrapper.hhn_create(num_osc, self._params);
|
240
|
|
|
else:
|
241
|
|
|
self._membrane_dynamic_pointer = None; # final result is stored here.
|
242
|
|
|
|
243
|
|
|
self._membrane_potential = [0.0] * self._num_osc;
|
244
|
|
|
self._active_cond_sodium = [0.0] * self._num_osc;
|
245
|
|
|
self._inactive_cond_sodium = [0.0] * self._num_osc;
|
246
|
|
|
self._active_cond_potassium = [0.0] * self._num_osc;
|
247
|
|
|
self._link_activation_time = [0.0] * self._num_osc;
|
248
|
|
|
self._link_pulse_counter = [0.0] * self._num_osc;
|
249
|
|
|
self._link_deactivation_time = [0.0] * self._num_osc;
|
250
|
|
|
self._link_weight3 = [0.0] * self._num_osc;
|
251
|
|
|
self._pulse_generation_time = [ [] for i in range(self._num_osc) ];
|
252
|
|
|
self._pulse_generation = [False] * self._num_osc;
|
253
|
|
|
|
254
|
|
|
self._noise = [random.random() * 2.0 - 1.0 for i in range(self._num_osc)];
|
255
|
|
|
|
256
|
|
|
self._central_element = [central_element(), central_element()];
|
257
|
|
|
|
258
|
|
|
|
259
|
|
|
def __del__(self):
|
260
|
|
|
"""!
|
261
|
|
|
@brief Destroy dynamically allocated oscillatory network instance in case of CCORE usage.
|
262
|
|
|
|
263
|
|
|
"""
|
264
|
|
|
if self.__ccore_hhn_pointer:
|
265
|
|
|
wrapper.hhn_destroy(self.__ccore_hhn_pointer)
|
266
|
|
|
|
267
|
|
|
|
268
|
|
|
def simulate(self, steps, time, solution = solve_type.RK4):
|
269
|
|
|
"""!
|
270
|
|
|
@brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model.
|
271
|
|
|
@details Output dynamic is sensible to amount of steps of simulation and solver of differential equation.
|
272
|
|
|
Python implementation uses 'odeint' from 'scipy', CCORE uses classical RK4 and RFK45 methods,
|
273
|
|
|
therefore in case of CCORE HHN (Hodgkin-Huxley network) amount of steps should be greater than in
|
274
|
|
|
case of Python HHN.
|
275
|
|
|
|
276
|
|
|
@param[in] steps (uint): Number steps of simulations during simulation.
|
277
|
|
|
@param[in] time (double): Time of simulation.
|
278
|
|
|
@param[in] solution (solve_type): Type of solver for differential equations.
|
279
|
|
|
|
280
|
|
|
@return (tuple) Dynamic of oscillatory network represented by (time, peripheral neurons dynamic, central elements
|
281
|
|
|
dynamic), where types are (list, list, list).
|
282
|
|
|
|
283
|
|
|
"""
|
284
|
|
|
|
285
|
|
|
return self.simulate_static(steps, time, solution);
|
286
|
|
|
|
287
|
|
|
|
288
|
|
|
def simulate_static(self, steps, time, solution = solve_type.RK4):
|
289
|
|
|
"""!
|
290
|
|
|
@brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model.
|
291
|
|
|
@details Output dynamic is sensible to amount of steps of simulation and solver of differential equation.
|
292
|
|
|
Python implementation uses 'odeint' from 'scipy', CCORE uses classical RK4 and RFK45 methods,
|
293
|
|
|
therefore in case of CCORE HHN (Hodgkin-Huxley network) amount of steps should be greater than in
|
294
|
|
|
case of Python HHN.
|
295
|
|
|
|
296
|
|
|
@param[in] steps (uint): Number steps of simulations during simulation.
|
297
|
|
|
@param[in] time (double): Time of simulation.
|
298
|
|
|
@param[in] solution (solve_type): Type of solver for differential equations.
|
299
|
|
|
|
300
|
|
|
@return (tuple) Dynamic of oscillatory network represented by (time, peripheral neurons dynamic, central elements
|
301
|
|
|
dynamic), where types are (list, list, list).
|
302
|
|
|
|
303
|
|
|
"""
|
304
|
|
|
|
305
|
|
|
# Check solver before simulation
|
306
|
|
|
if (solution == solve_type.FAST):
|
307
|
|
|
raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.");
|
308
|
|
|
|
309
|
|
|
self._membrane_dynamic_pointer = None;
|
310
|
|
|
|
311
|
|
|
if (self.__ccore_hhn_pointer is not None):
|
312
|
|
|
self.__ccore_hhn_dynamic_pointer = wrapper.hhn_dynamic_create(True, False, False, False);
|
313
|
|
|
wrapper.hhn_simulate(self.__ccore_hhn_pointer, steps, time, solution, self._stimulus, self.__ccore_hhn_dynamic_pointer);
|
314
|
|
|
|
315
|
|
|
peripheral_membrane_potential = wrapper.hhn_dynamic_get_peripheral_evolution(self.__ccore_hhn_dynamic_pointer, 0);
|
316
|
|
|
central_membrane_potential = wrapper.hhn_dynamic_get_central_evolution(self.__ccore_hhn_dynamic_pointer, 0);
|
317
|
|
|
dynamic_time = wrapper.hhn_dynamic_get_time(self.__ccore_hhn_dynamic_pointer);
|
318
|
|
|
|
319
|
|
|
self._membrane_dynamic_pointer = peripheral_membrane_potential;
|
320
|
|
|
|
321
|
|
|
wrapper.hhn_dynamic_destroy(self.__ccore_hhn_dynamic_pointer);
|
322
|
|
|
|
323
|
|
|
return (dynamic_time, peripheral_membrane_potential, central_membrane_potential);
|
324
|
|
|
|
325
|
|
|
if (solution == solve_type.RKF45):
|
326
|
|
|
raise NameError("Solver RKF45 is not support in python version.");
|
327
|
|
|
|
328
|
|
|
dyn_peripheral = [ self._membrane_potential[:] ];
|
329
|
|
|
dyn_central = [ [0.0, 0.0] ];
|
330
|
|
|
dyn_time = [ 0.0 ];
|
331
|
|
|
|
332
|
|
|
step = time / steps;
|
333
|
|
|
int_step = step / 10.0;
|
334
|
|
|
|
335
|
|
|
for t in numpy.arange(step, time + step, step):
|
336
|
|
|
# update states of oscillators
|
337
|
|
|
(memb_peripheral, memb_central) = self._calculate_states(solution, t, step, int_step);
|
338
|
|
|
|
339
|
|
|
# update states of oscillators
|
340
|
|
|
dyn_peripheral.append(memb_peripheral);
|
341
|
|
|
dyn_central.append(memb_central);
|
342
|
|
|
dyn_time.append(t);
|
343
|
|
|
|
344
|
|
|
self._membrane_dynamic_pointer = dyn_peripheral;
|
345
|
|
|
return (dyn_time, dyn_peripheral, dyn_central);
|
346
|
|
|
|
347
|
|
|
|
348
|
|
|
def _calculate_states(self, solution, t, step, int_step):
|
|
|
|
|
349
|
|
|
"""!
|
350
|
|
|
@brief Caclculates new state of each oscillator in the network. Returns only excitatory state of oscillators.
|
351
|
|
|
|
352
|
|
|
@param[in] solution (solve_type): Type solver of the differential equations.
|
353
|
|
|
@param[in] t (double): Current time of simulation.
|
354
|
|
|
@param[in] step (uint): Step of solution at the end of which states of oscillators should be calculated.
|
355
|
|
|
@param[in] int_step (double): Differentiation step that is used for solving differential equation.
|
356
|
|
|
|
357
|
|
|
@return (list) New states of membrance potentials for peripheral oscillators and for cental elements as a list where
|
358
|
|
|
the last two values correspond to central element 1 and 2.
|
359
|
|
|
|
360
|
|
|
"""
|
361
|
|
|
|
362
|
|
|
next_membrane = [0.0] * self._num_osc;
|
363
|
|
|
next_active_sodium = [0.0] * self._num_osc;
|
364
|
|
|
next_inactive_sodium = [0.0] * self._num_osc;
|
365
|
|
|
next_active_potassium = [0.0] * self._num_osc;
|
366
|
|
|
|
367
|
|
|
# Update states of oscillators
|
368
|
|
|
for index in range (0, self._num_osc, 1):
|
369
|
|
|
result = odeint(self.hnn_state,
|
370
|
|
|
[ self._membrane_potential[index], self._active_cond_sodium[index], self._inactive_cond_sodium[index], self._active_cond_potassium[index] ],
|
371
|
|
|
numpy.arange(t - step, t, int_step),
|
372
|
|
|
(index , ));
|
373
|
|
|
|
374
|
|
|
[ next_membrane[index], next_active_sodium[index], next_inactive_sodium[index], next_active_potassium[index] ] = result[len(result) - 1][0:4];
|
375
|
|
|
|
376
|
|
|
next_cn_membrane = [0.0, 0.0];
|
377
|
|
|
next_cn_active_sodium = [0.0, 0.0];
|
378
|
|
|
next_cn_inactive_sodium = [0.0, 0.0];
|
379
|
|
|
next_cn_active_potassium = [0.0, 0.0];
|
380
|
|
|
|
381
|
|
|
# Update states of central elements
|
382
|
|
|
for index in range(0, len(self._central_element)):
|
383
|
|
|
result = odeint(self.hnn_state,
|
384
|
|
|
[ self._central_element[index].membrane_potential, self._central_element[index].active_cond_sodium, self._central_element[index].inactive_cond_sodium, self._central_element[index].active_cond_potassium ],
|
385
|
|
|
numpy.arange(t - step, t, int_step),
|
386
|
|
|
(self._num_osc + index , ));
|
387
|
|
|
|
388
|
|
|
[ next_cn_membrane[index], next_cn_active_sodium[index], next_cn_inactive_sodium[index], next_cn_active_potassium[index] ] = result[len(result) - 1][0:4];
|
389
|
|
|
|
390
|
|
|
# Noise generation
|
391
|
|
|
self._noise = [ 1.0 + 0.01 * (random.random() * 2.0 - 1.0) for i in range(self._num_osc)];
|
392
|
|
|
|
393
|
|
|
# Updating states of PNs
|
394
|
|
|
self.__update_peripheral_neurons(t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium);
|
395
|
|
|
|
396
|
|
|
# Updation states of CN
|
397
|
|
|
self.__update_central_neurons(t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium);
|
398
|
|
|
|
399
|
|
|
return (next_membrane, next_cn_membrane);
|
400
|
|
|
|
401
|
|
|
|
402
|
|
|
def __update_peripheral_neurons(self, t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium):
|
403
|
|
|
"""!
|
404
|
|
|
@brief Update peripheral neurons in line with new values of current in channels.
|
405
|
|
|
|
406
|
|
|
@param[in] t (doubles): Current time of simulation.
|
407
|
|
|
@param[in] step (uint): Step (time duration) during simulation when states of oscillators should be calculated.
|
408
|
|
|
@param[in] next_membrane (list): New values of membrane potentials for peripheral neurons.
|
409
|
|
|
@Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for peripheral neurons.
|
410
|
|
|
@param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for peripheral neurons.
|
411
|
|
|
@param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for peripheral neurons.
|
412
|
|
|
|
413
|
|
|
"""
|
414
|
|
|
|
415
|
|
|
self._membrane_potential = next_membrane[:];
|
416
|
|
|
self._active_cond_sodium = next_active_sodium[:];
|
417
|
|
|
self._inactive_cond_sodium = next_inactive_sodium[:];
|
418
|
|
|
self._active_cond_potassium = next_active_potassium[:];
|
419
|
|
|
|
420
|
|
|
for index in range(0, self._num_osc):
|
421
|
|
|
if (self._pulse_generation[index] is False):
|
422
|
|
|
if (self._membrane_potential[index] >= 0.0):
|
423
|
|
|
self._pulse_generation[index] = True;
|
424
|
|
|
self._pulse_generation_time[index].append(t);
|
425
|
|
|
elif (self._membrane_potential[index] < 0.0):
|
426
|
|
|
self._pulse_generation[index] = False;
|
427
|
|
|
|
428
|
|
|
# Update connection from CN2 to PN
|
429
|
|
|
if (self._link_weight3[index] == 0.0):
|
430
|
|
|
if (self._membrane_potential[index] > self._params.threshold):
|
431
|
|
|
self._link_pulse_counter[index] += step;
|
432
|
|
|
|
433
|
|
|
if (self._link_pulse_counter[index] >= 1 / self._params.eps):
|
434
|
|
|
self._link_weight3[index] = self._params.w3;
|
435
|
|
|
self._link_activation_time[index] = t;
|
436
|
|
|
elif ( not ((self._link_activation_time[index] < t) and (t < self._link_activation_time[index] + self._params.deltah)) ):
|
437
|
|
|
self._link_weight3[index] = 0.0;
|
438
|
|
|
self._link_pulse_counter[index] = 0.0;
|
439
|
|
|
|
440
|
|
|
|
441
|
|
|
def __update_central_neurons(self, t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium):
|
442
|
|
|
"""!
|
443
|
|
|
@brief Update of central neurons in line with new values of current in channels.
|
444
|
|
|
|
445
|
|
|
@param[in] t (doubles): Current time of simulation.
|
446
|
|
|
@param[in] next_membrane (list): New values of membrane potentials for central neurons.
|
447
|
|
|
@Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for central neurons.
|
448
|
|
|
@param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for central neurons.
|
449
|
|
|
@param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for central neurons.
|
450
|
|
|
|
451
|
|
|
"""
|
452
|
|
|
|
453
|
|
|
for index in range(0, len(self._central_element)):
|
454
|
|
|
self._central_element[index].membrane_potential = next_cn_membrane[index];
|
455
|
|
|
self._central_element[index].active_cond_sodium = next_cn_active_sodium[index];
|
456
|
|
|
self._central_element[index].inactive_cond_sodium = next_cn_inactive_sodium[index];
|
457
|
|
|
self._central_element[index].active_cond_potassium = next_cn_active_potassium[index];
|
458
|
|
|
|
459
|
|
|
if (self._central_element[index].pulse_generation is False):
|
460
|
|
|
if (self._central_element[index].membrane_potential >= 0.0):
|
461
|
|
|
self._central_element[index].pulse_generation = True;
|
462
|
|
|
self._central_element[index].pulse_generation_time.append(t);
|
463
|
|
|
elif (self._central_element[index].membrane_potential < 0.0):
|
464
|
|
|
self._central_element[index].pulse_generation = False;
|
465
|
|
|
|
466
|
|
|
|
467
|
|
|
def hnn_state(self, inputs, t, argv):
|
468
|
|
|
"""!
|
469
|
|
|
@brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator.
|
470
|
|
|
|
471
|
|
|
@param[in] inputs (list): States of oscillator for integration [v, m, h, n] (see description below).
|
472
|
|
|
@param[in] t (double): Current time of simulation.
|
473
|
|
|
@param[in] argv (tuple): Extra arguments that are not used for integration - index of oscillator.
|
474
|
|
|
|
475
|
|
|
@return (list) new values of oscillator [v, m, h, n], where:
|
476
|
|
|
v - membrane potantial of oscillator,
|
477
|
|
|
m - activation conductance of the sodium channel,
|
478
|
|
|
h - inactication conductance of the sodium channel,
|
479
|
|
|
n - activation conductance of the potassium channel.
|
480
|
|
|
|
481
|
|
|
"""
|
482
|
|
|
|
483
|
|
|
index = argv;
|
484
|
|
|
|
485
|
|
|
v = inputs[0]; # membrane potential (v).
|
486
|
|
|
m = inputs[1]; # activation conductance of the sodium channel (m).
|
487
|
|
|
h = inputs[2]; # inactivaton conductance of the sodium channel (h).
|
488
|
|
|
n = inputs[3]; # activation conductance of the potassium channel (n).
|
489
|
|
|
|
490
|
|
|
# Calculate ion current
|
491
|
|
|
# gNa * m[i]^3 * h * (v[i] - vNa) + gK * n[i]^4 * (v[i] - vK) + gL (v[i] - vL)
|
492
|
|
|
active_sodium_part = self._params.gNa * (m ** 3) * h * (v - self._params.vNa);
|
493
|
|
|
inactive_sodium_part = self._params.gK * (n ** 4) * (v - self._params.vK);
|
494
|
|
|
active_potassium_part = self._params.gL * (v - self._params.vL);
|
495
|
|
|
|
496
|
|
|
Iion = active_sodium_part + inactive_sodium_part + active_potassium_part;
|
497
|
|
|
|
498
|
|
|
Iext = 0.0;
|
499
|
|
|
Isyn = 0.0;
|
500
|
|
|
if (index < self._num_osc):
|
501
|
|
|
# PN - peripheral neuron - calculation of external current and synaptic current.
|
502
|
|
|
Iext = self._stimulus[index] * self._noise[index]; # probably noise can be pre-defined for reducting compexity
|
503
|
|
|
|
504
|
|
|
memory_impact1 = 0.0;
|
505
|
|
|
for i in range(0, len(self._central_element[0].pulse_generation_time)):
|
506
|
|
|
memory_impact1 += self.__alfa_function(t - self._central_element[0].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);
|
507
|
|
|
|
508
|
|
|
memory_impact2 = 0.0;
|
509
|
|
|
for i in range(0, len(self._central_element[1].pulse_generation_time)):
|
510
|
|
|
memory_impact2 += self.__alfa_function(t - self._central_element[1].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory);
|
511
|
|
|
|
512
|
|
|
Isyn = self._params.w2 * (v - self._params.Vsyninh) * memory_impact1 + self._link_weight3[index] * (v - self._params.Vsyninh) * memory_impact2;
|
513
|
|
|
else:
|
514
|
|
|
# CN - central element.
|
515
|
|
|
central_index = index - self._num_osc;
|
516
|
|
|
if (central_index == 0):
|
517
|
|
|
Iext = self._params.Icn1; # CN1
|
518
|
|
|
|
519
|
|
|
memory_impact = 0.0;
|
520
|
|
|
for index_oscillator in range(0, self._num_osc):
|
521
|
|
|
for index_generation in range(0, len(self._pulse_generation_time[index_oscillator])):
|
522
|
|
|
memory_impact += self.__alfa_function(t - self._pulse_generation_time[index_oscillator][index_generation], self._params.alfa_excitatory, self._params.betta_excitatory);
|
523
|
|
|
|
524
|
|
|
Isyn = self._params.w1 * (v - self._params.Vsynexc) * memory_impact;
|
525
|
|
|
|
526
|
|
|
elif (central_index == 1):
|
527
|
|
|
Iext = self._params.Icn2; # CN2
|
528
|
|
|
Isyn = 0.0;
|
529
|
|
|
|
530
|
|
|
else:
|
531
|
|
|
assert 0;
|
532
|
|
|
|
533
|
|
|
|
534
|
|
|
# Membrane potential
|
535
|
|
|
dv = -Iion + Iext - Isyn;
|
536
|
|
|
|
537
|
|
|
# Calculate variables
|
538
|
|
|
potential = v - self._params.vRest;
|
539
|
|
|
am = (2.5 - 0.1 * potential) / (math.exp(2.5 - 0.1 * potential) - 1.0);
|
540
|
|
|
ah = 0.07 * math.exp(-potential / 20.0);
|
541
|
|
|
an = (0.1 - 0.01 * potential) / (math.exp(1.0 - 0.1 * potential) - 1.0);
|
542
|
|
|
|
543
|
|
|
bm = 4.0 * math.exp(-potential / 18.0);
|
544
|
|
|
bh = 1.0 / (math.exp(3.0 - 0.1 * potential) + 1.0);
|
545
|
|
|
bn = 0.125 * math.exp(-potential / 80.0);
|
546
|
|
|
|
547
|
|
|
dm = am * (1.0 - m) - bm * m;
|
548
|
|
|
dh = ah * (1.0 - h) - bh * h;
|
549
|
|
|
dn = an * (1.0 - n) - bn * n;
|
550
|
|
|
|
551
|
|
|
return [dv, dm, dh, dn];
|
552
|
|
|
|
553
|
|
|
|
554
|
|
|
def allocate_sync_ensembles(self, tolerance = 0.1):
|
555
|
|
|
"""!
|
556
|
|
|
@brief Allocates clusters in line with ensembles of synchronous oscillators where each. Synchronous ensemble corresponds to only one cluster.
|
557
|
|
|
|
558
|
|
|
@param[in] tolerance (double): maximum error for allocation of synchronous ensemble oscillators.
|
559
|
|
|
|
560
|
|
|
@return (list) Grours (lists) of indexes of synchronous oscillators. For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
|
561
|
|
|
|
562
|
|
|
"""
|
563
|
|
|
|
564
|
|
|
return allocate_sync_ensembles(self._membrane_dynamic_pointer, tolerance, 20.0, None);
|
565
|
|
|
|
566
|
|
|
|
567
|
|
|
def __alfa_function(self, time, alfa, betta):
|
568
|
|
|
"""!
|
569
|
|
|
@brief Calculates value of alfa-function for difference between spike generation time and current simulation time.
|
570
|
|
|
|
571
|
|
|
@param[in] time (double): Difference between last spike generation time and current time.
|
572
|
|
|
@param[in] alfa (double): Alfa parameter for alfa-function.
|
573
|
|
|
@param[in] betta (double): Betta parameter for alfa-function.
|
574
|
|
|
|
575
|
|
|
@return (double) Value of alfa-function.
|
576
|
|
|
|
577
|
|
|
"""
|
578
|
|
|
|
579
|
|
|
return alfa * time * math.exp(-betta * time);
|
580
|
|
|
|
581
|
|
|
|
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.py
files in your module folders. Make sure that you place one file in each sub-folder.