sc_neurocore_engine/neurons/biophysical/
huber_braun.rs1#[derive(Clone, Debug)]
13pub struct HuberBraunNeuron {
14 pub v: f64,
15 pub a_sd: f64,
16 pub a_sr: f64,
17 pub g_sd: f64,
18 pub g_sr: f64,
19 pub g_l: f64,
20 pub e_sd: f64,
21 pub e_sr: f64,
22 pub e_l: f64,
23 pub tau_sd: f64,
24 pub tau_sr: f64,
25 pub eta: f64,
26 pub dt: f64,
27 pub v_threshold: f64,
28}
29
30impl HuberBraunNeuron {
31 pub fn new() -> Self {
32 Self {
33 v: -50.0,
34 a_sd: 0.0,
35 a_sr: 0.0,
36 g_sd: 1.5,
37 g_sr: 0.4,
38 g_l: 0.1,
39 e_sd: 50.0,
40 e_sr: -90.0,
41 e_l: -60.0,
42 tau_sd: 10.0,
43 tau_sr: 20.0,
44 eta: 0.012,
45 dt: 0.1,
46 v_threshold: -20.0,
47 }
48 }
49 pub fn step(&mut self, current: f64) -> i32 {
50 let v_prev = self.v;
51 let sd_inf = 1.0 / (1.0 + (-(self.v + 40.0) / 6.0).exp());
53 let sr_inf = 1.0 / (1.0 + ((self.v + 40.0) / 6.0).exp());
54 self.a_sd += (sd_inf - self.a_sd) / self.tau_sd * self.dt;
55 self.a_sr += (sr_inf - self.a_sr) / self.tau_sr * self.dt;
56 let i_sd = self.g_sd * self.a_sd * (self.v - self.e_sd);
57 let i_sr = self.g_sr * self.a_sr * (self.v - self.e_sr);
58 let i_l = self.g_l * (self.v - self.e_l);
59 self.v += (-i_sd - i_sr - i_l + current) * self.dt;
60 if self.v >= self.v_threshold && v_prev < self.v_threshold {
61 1
62 } else {
63 0
64 }
65 }
66 pub fn reset(&mut self) {
67 self.v = -50.0;
68 self.a_sd = 0.0;
69 self.a_sr = 0.0;
70 }
71}
72impl Default for HuberBraunNeuron {
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn default_matches_constructor_state() {
84 let default = HuberBraunNeuron::default();
85 let constructed = HuberBraunNeuron::new();
86 assert_eq!(default.v, constructed.v);
87 }
88
89 #[test]
90 fn hb_fires() {
91 let mut n = HuberBraunNeuron::new();
92 let t: i32 = (0..5000).map(|_| n.step(10.0)).sum();
93 assert!(t > 0);
94 }
95
96 #[test]
98 fn hb_silent_without_input() {
99 let mut n = HuberBraunNeuron::new();
100 let _t: i32 = (0..500).map(|_| n.step(0.0)).sum();
101 assert!(n.v.is_finite());
103 }
104 #[test]
105 fn hb_reset_clears_state() {
106 let mut n = HuberBraunNeuron::new();
107 for _ in 0..200 {
108 n.step(10.0);
109 }
110 n.reset();
111 assert!((n.v - (-50.0)).abs() < 1e-10);
112 }
113 #[test]
114 fn hb_extreme_bounded() {
115 let mut n = HuberBraunNeuron::new();
116 for _ in 0..200 {
117 n.step(1e4);
118 }
119 assert!(n.v.is_finite());
120 }
121 #[test]
122 fn hb_negative_no_crash() {
123 let mut n = HuberBraunNeuron::new();
124 for _ in 0..500 {
125 n.step(-10.0);
126 }
127 assert!(n.v.is_finite());
128 }
129 #[test]
130 fn hb_nan_no_panic() {
131 let mut n = HuberBraunNeuron::new();
132 n.step(f64::NAN);
133 }
134}