Skip to main content

sc_neurocore_engine/neurons/hardware/
spinnaker2.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Commercial license available
3// © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
4// © Code 2020–2026 Miroslav Šotek. All rights reserved.
5// ORCID: 0009-0009-3560-0851
6// Contact: www.anulum.li | protoscience@anulum.li
7// SC-NeuroCore — SpiNNaker 2 Neuron Emulator
8
9/// SpiNNaker2 — TU Dresden ARM Cortex-M4F fixed-point LIF.
10#[derive(Clone, Debug)]
11pub struct SpiNNaker2Neuron {
12    pub v: i32,
13    pub v_rest: i32,
14    pub v_reset: i32,
15    pub v_threshold: i32,
16    pub decay_mult: i32,
17    pub decay_shift: i32,
18    pub refrac_steps: i32,
19    pub refrac_count: i32,
20}
21
22impl SpiNNaker2Neuron {
23    pub fn new() -> Self {
24        Self {
25            v: 0,
26            v_rest: 0,
27            v_reset: 0,
28            v_threshold: 1024,
29            decay_mult: 243,
30            decay_shift: 8,
31            refrac_steps: 2,
32            refrac_count: 0,
33        }
34    }
35    pub fn step(&mut self, current: i32) -> i32 {
36        if self.refrac_count > 0 {
37            self.refrac_count -= 1;
38            return 0;
39        }
40        self.v = ((self.v - self.v_rest).wrapping_mul(self.decay_mult) >> self.decay_shift)
41            + self.v_rest
42            + current;
43        if self.v >= self.v_threshold {
44            self.v = self.v_reset;
45            self.refrac_count = self.refrac_steps;
46            1
47        } else {
48            0
49        }
50    }
51    pub fn reset(&mut self) {
52        self.v = self.v_rest;
53        self.refrac_count = 0;
54    }
55}
56impl Default for SpiNNaker2Neuron {
57    fn default() -> Self {
58        Self::new()
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn spinnaker2_fires() {
68        let mut n = SpiNNaker2Neuron::new();
69        let t: i32 = (0..200).map(|_| n.step(100)).sum();
70        assert!(t > 0);
71    }
72    #[test]
73    fn spinnaker2_silent() {
74        let mut n = SpiNNaker2Neuron::new();
75        let t: i32 = (0..200).map(|_| n.step(0)).sum();
76        assert_eq!(t, 0);
77    }
78    #[test]
79    fn spinnaker2_reset() {
80        let mut n = SpiNNaker2Neuron::new();
81        for _ in 0..50 {
82            n.step(100);
83        }
84        n.reset();
85    }
86    #[test]
87    fn spinnaker2_bounded() {
88        let mut n = SpiNNaker2Neuron::new();
89        for _ in 0..1000 {
90            n.step(10000);
91        }
92    }
93}