sc_neurocore_engine/neurons/trivial/
nonlinear_lif.rs1#[derive(Clone, Debug)]
11pub struct NonlinearLIFNeuron {
12 pub v: f64,
13 pub w: f64,
14 pub v_rest: f64,
15 pub v_crit: f64,
16 pub v_threshold: f64,
17 pub v_reset: f64,
18 pub a: f64,
19 pub b: f64,
20 pub tau_w: f64,
21 pub c_m: f64,
22 pub dt: f64,
23}
24
25impl NonlinearLIFNeuron {
26 pub fn new() -> Self {
27 Self {
28 v: -65.0,
29 w: 0.0,
30 v_rest: -65.0,
31 v_crit: -40.0,
32 v_threshold: -20.0,
33 v_reset: -65.0,
34 a: 0.04,
35 b: 0.5,
36 tau_w: 100.0,
37 c_m: 1.0,
38 dt: 0.1,
39 }
40 }
41
42 pub fn step(&mut self, current: f64) -> i32 {
43 let v_prev = self.v;
44 let cubic = self.a * (self.v - self.v_rest) * (self.v - self.v_crit);
45 self.v += (cubic - self.w + current) / self.c_m * self.dt;
46 self.w += (self.b * (self.v - self.v_rest) - self.w) / self.tau_w * self.dt;
47 if self.v >= self.v_threshold && v_prev < self.v_threshold {
48 self.v = self.v_reset;
49 1
50 } else {
51 0
52 }
53 }
54
55 pub fn reset(&mut self) {
56 self.v = self.v_rest;
57 self.w = 0.0;
58 }
59}
60
61impl Default for NonlinearLIFNeuron {
62 fn default() -> Self {
63 Self::new()
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn nlif_fires() {
73 let mut n = NonlinearLIFNeuron::new();
74 let total: i32 = (0..2000).map(|_| n.step(500.0)).sum();
75 assert!(total > 0);
76 }
77 #[test]
78 fn nlif_silent_without_input() {
79 let mut n = NonlinearLIFNeuron::new();
80 let t: i32 = (0..200).map(|_| n.step(0.0)).sum();
81 assert_eq!(t, 0);
82 }
83 #[test]
84 fn nlif_reset_clears_state() {
85 let mut n = NonlinearLIFNeuron::new();
86 for _ in 0..100 {
87 n.step(500.0);
88 }
89 n.reset();
90 assert!((n.v - n.v_rest).abs() < 1e-10);
91 }
92 #[test]
93 fn nlif_bounded() {
94 let mut n = NonlinearLIFNeuron::new();
95 for _ in 0..2000 {
96 n.step(1e4);
97 }
98 assert!(n.v.is_finite());
99 }
100 #[test]
101 fn nlif_nan_no_panic() {
102 NonlinearLIFNeuron::new().step(f64::NAN);
103 }
104 #[test]
105 fn nlif_recovery_evolves() {
106 let mut n = NonlinearLIFNeuron::new();
107 for _ in 0..2000 {
108 n.step(500.0);
109 }
110 assert!(
111 n.w > 0.0,
112 "recovery variable w should increase during spiking"
113 );
114 }
115}