sc_neurocore_engine/neuron/
adex.rs1mod simulation;
10
11#[derive(Clone, Debug)]
14pub struct AdExNeuron {
15 pub v: f64,
16 pub w: f64,
17 pub v_rest: f64,
18 pub v_reset: f64,
19 pub v_threshold: f64,
20 pub v_rh: f64,
21 pub delta_t: f64,
22 pub tau: f64,
23 pub tau_w: f64,
24 pub a: f64,
25 pub b: f64,
26 pub c_m: f64,
27 pub dt: f64,
28}
29
30impl Default for AdExNeuron {
31 fn default() -> Self {
32 Self::new()
33 }
34}
35
36impl AdExNeuron {
37 pub fn new() -> Self {
38 Self {
39 v: -65.0,
40 w: 0.0,
41 v_rest: -65.0,
42 v_reset: -68.0,
43 v_threshold: -50.0,
44 v_rh: -55.0,
45 delta_t: 2.0,
46 tau: 20.0,
47 tau_w: 100.0,
48 a: 0.5,
49 b: 7.0,
50 c_m: 200.0,
51 dt: 0.1,
52 }
53 }
54
55 pub fn step(&mut self, current: f64) -> i32 {
61 self.try_step(current).unwrap_or(0)
62 }
63
64 pub fn try_step(&mut self, current: f64) -> Result<i32, &'static str> {
66 if !self.v.is_finite()
67 || !self.w.is_finite()
68 || !self.v_rest.is_finite()
69 || !self.v_reset.is_finite()
70 || !self.v_threshold.is_finite()
71 || !self.v_rh.is_finite()
72 || !self.delta_t.is_finite()
73 || !self.tau.is_finite()
74 || !self.tau_w.is_finite()
75 || !self.a.is_finite()
76 || !self.b.is_finite()
77 || !self.c_m.is_finite()
78 || !self.dt.is_finite()
79 || !current.is_finite()
80 || self.delta_t <= 0.0
81 || self.tau <= 0.0
82 || self.tau_w <= 0.0
83 || self.c_m <= 0.0
84 || self.dt <= 0.0
85 {
86 return Err("invalid AdEx state, parameters, timestep, or input");
87 }
88
89 let exp_arg = ((self.v - self.v_rh) / self.delta_t).clamp(-20.0, 20.0);
90 let exp_term = self.delta_t * exp_arg.exp();
91 let dv = ((-(self.v - self.v_rest) + exp_term) / self.tau + (-self.w + current) / self.c_m)
92 * self.dt;
93 let dw = (self.a * (self.v - self.v_rest) - self.w) / self.tau_w * self.dt;
94 let next_v = self.v + dv;
95 let next_w = self.w + dw;
96 if !exp_term.is_finite()
97 || !dv.is_finite()
98 || !dw.is_finite()
99 || !next_v.is_finite()
100 || !next_w.is_finite()
101 {
102 return Err("non-finite AdEx integrator candidate");
103 }
104
105 if next_v >= self.v_threshold {
106 let spike_w = next_w + self.b;
107 if !spike_w.is_finite() {
108 return Err("non-finite AdEx spike-adaptation candidate");
109 }
110 self.v = self.v_reset;
111 self.w = spike_w;
112 Ok(1)
113 } else {
114 self.v = next_v;
115 self.w = next_w;
116 Ok(0)
117 }
118 }
119
120 pub fn reset(&mut self) {
121 self.v = self.v_rest;
122 self.w = 0.0;
123 }
124}
125
126#[cfg(test)]
127mod tests;