1use alloc::vec;
19use alloc::vec::Vec;
20
21pub struct DeltaEncoderFixed {
32 prev: Vec<i16>,
34 threshold: Vec<i16>,
36 initialized: bool,
38}
39
40impl DeltaEncoderFixed {
41 pub fn new(n_features: usize, threshold: i16) -> Self {
48 Self {
49 prev: vec![0; n_features],
50 threshold: vec![threshold; n_features],
51 initialized: false,
52 }
53 }
54
55 pub fn new_per_feature(thresholds: Vec<i16>) -> Self {
61 let n = thresholds.len();
62 Self {
63 prev: vec![0; n],
64 threshold: thresholds,
65 initialized: false,
66 }
67 }
68
69 #[inline]
71 pub fn n_features(&self) -> usize {
72 self.prev.len()
73 }
74
75 #[inline]
77 pub fn n_output_channels(&self) -> usize {
78 self.prev.len() * 2
79 }
80
81 pub fn encode(&mut self, input: &[i16], out_spikes: &mut [u8]) {
94 let n = self.prev.len();
95 assert_eq!(
96 input.len(),
97 n,
98 "input length {} does not match encoder n_features {}",
99 input.len(),
100 n
101 );
102 assert!(
103 out_spikes.len() >= 2 * n,
104 "out_spikes length {} too small for {} channels",
105 out_spikes.len(),
106 2 * n
107 );
108
109 if !self.initialized {
110 self.prev.copy_from_slice(input);
112 for spike in out_spikes[..2 * n].iter_mut() {
113 *spike = 0;
114 }
115 self.initialized = true;
116 return;
117 }
118
119 for i in 0..n {
120 let delta = input[i] as i32 - self.prev[i] as i32;
121 let thr = self.threshold[i] as i32;
122
123 out_spikes[2 * i] = if delta > thr { 1 } else { 0 };
125 out_spikes[2 * i + 1] = if delta < -thr { 1 } else { 0 };
127 }
128
129 self.prev.copy_from_slice(input);
131 }
132
133 pub fn reset(&mut self) {
137 for v in self.prev.iter_mut() {
138 *v = 0;
139 }
140 self.initialized = false;
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn first_call_produces_no_spikes() {
150 let mut enc = DeltaEncoderFixed::new(3, 100);
151 let input = [500_i16, -200, 1000];
152 let mut spikes = vec![0u8; 6];
153 enc.encode(&input, &mut spikes);
154 assert!(
155 spikes.iter().all(|&s| s == 0),
156 "first call should produce no spikes"
157 );
158 }
159
160 #[test]
161 fn positive_spike_on_increase() {
162 let mut enc = DeltaEncoderFixed::new(2, 100);
163 let mut spikes = vec![0u8; 4];
164
165 enc.encode(&[0, 0], &mut spikes);
167
168 enc.encode(&[200, 0], &mut spikes);
170 assert_eq!(spikes[0], 1, "feature 0 should have positive spike");
171 assert_eq!(spikes[1], 0, "feature 0 should not have negative spike");
172 assert_eq!(spikes[2], 0, "feature 1 should have no positive spike");
173 assert_eq!(spikes[3], 0, "feature 1 should have no negative spike");
174 }
175
176 #[test]
177 fn negative_spike_on_decrease() {
178 let mut enc = DeltaEncoderFixed::new(2, 100);
179 let mut spikes = vec![0u8; 4];
180
181 enc.encode(&[500, 500], &mut spikes);
182 enc.encode(&[500, 200], &mut spikes); assert_eq!(spikes[0], 0, "feature 0 pos should be 0");
185 assert_eq!(spikes[1], 0, "feature 0 neg should be 0");
186 assert_eq!(spikes[2], 0, "feature 1 pos should be 0");
187 assert_eq!(spikes[3], 1, "feature 1 should have negative spike");
188 }
189
190 #[test]
191 fn no_spike_within_threshold() {
192 let mut enc = DeltaEncoderFixed::new(1, 500);
193 let mut spikes = vec![0u8; 2];
194
195 enc.encode(&[1000], &mut spikes);
196 enc.encode(&[1100], &mut spikes);
198
199 assert_eq!(spikes[0], 0, "should not spike for small increase");
200 assert_eq!(spikes[1], 0, "should not spike for small change");
201 }
202
203 #[test]
204 fn both_spikes_in_same_step() {
205 let mut enc = DeltaEncoderFixed::new(2, 100);
206 let mut spikes = vec![0u8; 4];
207
208 enc.encode(&[0, 1000], &mut spikes);
209 enc.encode(&[500, 500], &mut spikes);
211
212 assert_eq!(spikes[0], 1, "feature 0 should have positive spike");
213 assert_eq!(spikes[1], 0, "feature 0 should not have negative spike");
214 assert_eq!(spikes[2], 0, "feature 1 should not have positive spike");
215 assert_eq!(spikes[3], 1, "feature 1 should have negative spike");
216 }
217
218 #[test]
219 fn per_feature_thresholds() {
220 let thresholds = vec![100_i16, 1000];
221 let mut enc = DeltaEncoderFixed::new_per_feature(thresholds);
222 let mut spikes = vec![0u8; 4];
223
224 enc.encode(&[0, 0], &mut spikes);
225 enc.encode(&[200, 200], &mut spikes);
228
229 assert_eq!(spikes[0], 1, "feature 0 should spike (200 > 100)");
230 assert_eq!(spikes[2], 0, "feature 1 should not spike (200 < 1000)");
231 }
232
233 #[test]
234 fn reset_clears_state() {
235 let mut enc = DeltaEncoderFixed::new(2, 100);
236 let mut spikes = vec![0u8; 4];
237
238 enc.encode(&[1000, 2000], &mut spikes);
239 enc.encode(&[2000, 3000], &mut spikes);
240 assert!(
241 spikes.iter().any(|&s| s == 1),
242 "should have spikes before reset"
243 );
244
245 enc.reset();
246 enc.encode(&[5000, 5000], &mut spikes);
248 assert!(
249 spikes.iter().all(|&s| s == 0),
250 "after reset, first call should produce no spikes"
251 );
252 }
253
254 #[test]
255 fn sequential_encoding_uses_updated_prev() {
256 let mut enc = DeltaEncoderFixed::new(1, 100);
257 let mut spikes = vec![0u8; 2];
258
259 enc.encode(&[0], &mut spikes);
260 enc.encode(&[500], &mut spikes); assert_eq!(spikes[0], 1, "first increase should spike");
262
263 enc.encode(&[600], &mut spikes); assert_eq!(spikes[0], 0, "small subsequent change should not spike");
265
266 enc.encode(&[1200], &mut spikes); assert_eq!(spikes[0], 1, "large subsequent change should spike");
268 }
269
270 #[test]
271 fn output_channel_count() {
272 let enc = DeltaEncoderFixed::new(5, 100);
273 assert_eq!(enc.n_features(), 5);
274 assert_eq!(enc.n_output_channels(), 10);
275 }
276}