sc_neurocore_engine/neuron/
izhikevich.rs1#[derive(Clone, Debug)]
16pub struct Izhikevich {
17 pub v: f64,
18 pub u: f64,
19 pub a: f64,
20 pub b: f64,
21 pub c: f64,
22 pub d: f64,
23 pub dt: f64,
24}
25
26impl Izhikevich {
27 pub fn new(a: f64, b: f64, c: f64, d: f64, dt: f64) -> Self {
29 Self {
30 v: c,
31 u: b * c,
32 a,
33 b,
34 c,
35 d,
36 dt,
37 }
38 }
39
40 pub fn regular_spiking() -> Self {
42 Self::new(0.02, 0.2, -65.0, 8.0, 1.0)
43 }
44
45 pub fn step(&mut self, current: f64) -> i32 {
47 let half = self.dt * 0.5;
48 for _ in 0..2 {
49 let dv = (0.04 * self.v * self.v + 5.0 * self.v + 140.0 - self.u + current) * half;
50 let du = (self.a * (self.b * self.v - self.u)) * half;
51 self.v += dv;
52 self.u += du;
53 }
54
55 if self.v >= 30.0 {
56 self.v = self.c;
57 self.u += self.d;
58 1
59 } else {
60 0
61 }
62 }
63
64 pub fn reset(&mut self) {
66 self.v = self.c;
67 self.u = self.b * self.c;
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::Izhikevich;
74
75 #[test]
76 fn regular_spiking_preset_fires_with_current() {
77 let mut neuron = Izhikevich::regular_spiking();
78 let spikes: i32 = (0..100).map(|_| neuron.step(10.0)).sum();
79 assert!(spikes > 0, "RS neuron must fire with I=10");
80 }
81
82 #[test]
83 fn regular_spiking_preset_is_silent_without_input() {
84 let mut neuron = Izhikevich::regular_spiking();
85 let spikes: i32 = (0..100).map(|_| neuron.step(0.0)).sum();
86 assert_eq!(spikes, 0, "no spikes without input");
87 }
88
89 #[test]
90 fn reset_restores_initial_state() {
91 let mut neuron = Izhikevich::regular_spiking();
92 for _ in 0..50 {
93 neuron.step(10.0);
94 }
95 neuron.reset();
96 assert_eq!(neuron.v, neuron.c);
97 assert!((neuron.u - neuron.b * neuron.c).abs() < 1e-12);
98 }
99
100 #[test]
101 fn chattering_preset_fires_more_than_regular_spiking() {
102 let mut chattering = Izhikevich::new(0.02, 0.2, -50.0, 2.0, 1.0);
103 let mut regular_spiking = Izhikevich::regular_spiking();
104 let mut chattering_spikes = 0;
105 let mut regular_spikes = 0;
106 for _ in 0..200 {
107 chattering_spikes += chattering.step(10.0);
108 regular_spikes += regular_spiking.step(10.0);
109 }
110 assert!(
111 chattering_spikes > regular_spikes,
112 "chattering ({chattering_spikes}) should fire more than RS ({regular_spikes})"
113 );
114 }
115}