sc_neurocore_engine/neurons/trivial/
sfa.rs1#[derive(Clone, Debug)]
11pub struct SFANeuron {
12 pub v: f64,
13 pub g_sfa: f64,
14 pub v_rest: f64,
15 pub v_reset: f64,
16 pub v_threshold: f64,
17 pub tau_m: f64,
18 pub tau_sfa: f64,
19 pub delta_g: f64,
20 pub e_k: f64,
21 pub resistance: f64,
22 pub dt: f64,
23}
24
25impl SFANeuron {
26 pub fn new() -> Self {
27 Self {
28 v: -70.0,
29 g_sfa: 0.0,
30 v_rest: -70.0,
31 v_reset: -70.0,
32 v_threshold: -50.0,
33 tau_m: 10.0,
34 tau_sfa: 200.0,
35 delta_g: 0.5,
36 e_k: -80.0,
37 resistance: 1.0,
38 dt: 1.0,
39 }
40 }
41
42 pub fn step(&mut self, current: f64) -> i32 {
43 self.v += (-(self.v - self.v_rest) - self.g_sfa * (self.v - self.e_k)
44 + self.resistance * current)
45 / self.tau_m
46 * self.dt;
47 self.g_sfa *= (-self.dt / self.tau_sfa).exp();
48 if self.v >= self.v_threshold {
49 self.v = self.v_reset;
50 self.g_sfa += self.delta_g;
51 1
52 } else {
53 0
54 }
55 }
56
57 pub fn reset(&mut self) {
58 self.v = self.v_rest;
59 self.g_sfa = 0.0;
60 }
61}
62
63impl Default for SFANeuron {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn sfa_fires_then_adapts() {
75 let mut n = SFANeuron::new();
76 let first: i32 = (0..100).map(|_| n.step(30.0)).sum();
77 let second: i32 = (0..100).map(|_| n.step(30.0)).sum();
78 assert!(first > 0);
79 assert!(second <= first + 2);
80 }
81 #[test]
82 fn sfa_silent_without_input() {
83 let mut n = SFANeuron::new();
84 let t: i32 = (0..200).map(|_| n.step(0.0)).sum();
85 assert_eq!(t, 0);
86 }
87 #[test]
88 fn sfa_reset_clears_state() {
89 let mut n = SFANeuron::new();
90 for _ in 0..100 {
91 n.step(30.0);
92 }
93 n.reset();
94 assert!((n.v - n.v_rest).abs() < 1e-10);
95 assert!((n.g_sfa - 0.0).abs() < 1e-10);
96 }
97 #[test]
98 fn sfa_bounded() {
99 let mut n = SFANeuron::new();
100 for _ in 0..1000 {
101 n.step(1e4);
102 }
103 assert!(n.v.is_finite());
104 }
105 #[test]
106 fn sfa_nan_no_panic() {
107 SFANeuron::new().step(f64::NAN);
108 }
109}