1use crate::prelude::*;
5
6#[derive(Debug, Clone, PartialEq)]
12#[cfg_attr(feature="pybindings", pyclass)]
13pub struct RBWaveform {
14 pub event_id : u32,
15 pub rb_id : u8,
16 pub rb_channel_a : u8,
18 pub rb_channel_b : u8,
19 pub stop_cell : u16,
21 pub adc_a : Vec<u16>,
22 pub adc_b : Vec<u16>,
23 pub paddle_id : u8,
27 pub voltages_a : Vec<f32>,
28 pub nanoseconds_a : Vec<f32>,
29 pub voltages_b : Vec<f32>,
30 pub nanoseconds_b : Vec<f32>
31}
32
33impl RBWaveform {
34
35 pub fn new() -> Self {
36 Self {
37 event_id : 0,
38 rb_id : 0,
39 rb_channel_a : 0,
40 rb_channel_b : 0,
41 stop_cell : 0,
42 paddle_id : 0,
43 adc_a : Vec::<u16>::new(),
44 voltages_a : Vec::<f32>::new(),
45 nanoseconds_a : Vec::<f32>::new(),
46 adc_b : Vec::<u16>::new(),
47 voltages_b : Vec::<f32>::new(),
48 nanoseconds_b : Vec::<f32>::new()
49 }
50 }
51
52 pub fn time_over_threshold_a(&self, threshold : f32) -> f32 {
55 let mut tot : f32 = 0.0;
56 for k in 1..self.voltages_a.len() {
57 if self.voltages_a[k] > threshold {
58 tot += self.nanoseconds_a[k] - self.nanoseconds_a[k-1];
59 }
60 }
61 return tot;
62 }
63
64 pub fn time_over_threshold_b(&self, threshold : f32) -> f32 {
67 let mut tot : f32 = 0.0;
68 for k in 1..self.voltages_b.len() {
69 if self.voltages_b[k] > threshold {
70 tot += self.nanoseconds_b[k] - self.nanoseconds_b[k-1];
71 }
72 }
73 return tot;
74 }
75
76 pub fn charge_a_below_500(&self) -> f32 {
77 if self.nanoseconds_b.len() == 0 || self.voltages_b.len() == 0 {
78 return 0.0;
79 }
80
81 let mut total_area = 0.0f32;
82 for i in 0..(self.nanoseconds_a.len() - 1) {
83 let h = self.nanoseconds_a[i + 1] - self.nanoseconds_a[i]; let mut v1 = self.voltages_a[i];
85 let mut v2 = self.voltages_a[i + 1];
86 if v1 > 500.0 {
87 v1 = 500.0;
88 }
89 if v2 > 500.0 {
90 v2 = 500.0;
91 }
92 let area = h * (v1 + v2) / 2.0;
93 total_area += area;
94 }
95 total_area
96 }
97
98 pub fn charge_b_below_500(&self) -> f32 {
99 if self.nanoseconds_b.len() == 0 || self.voltages_b.len() == 0 {
100 return 0.0;
101 }
102
103 let mut total_area = 0.0f32;
104 for i in 0..(self.nanoseconds_b.len() - 1) {
105 let h = self.nanoseconds_b[i + 1] - self.nanoseconds_b[i]; let mut v1 = self.voltages_b[i];
107 let mut v2 = self.voltages_b[i + 1];
108 if v1 > 500.0 {
109 v1 = 500.0;
110 }
111 if v2 > 500.0 {
112 v2 = 500.0;
113 }
114 let area = h * (v1 + v2) / 2.0;
115 total_area += area;
116 }
117 total_area
118 }
119
120 pub fn charge_a_trap(&self) -> f32 {
131 if self.nanoseconds_b.len() == 0 || self.voltages_b.len() == 0 {
132 return 0.0;
133 }
134 let mut total_area = 0.0f32;
135 for i in 0..(self.nanoseconds_a.len() - 1) {
136 let h = self.nanoseconds_a[i + 1] - self.nanoseconds_a[i]; let area = h * (self.voltages_a[i] + self.voltages_a[i + 1]) / 2.0;
138 total_area += area;
139 }
140 total_area
141 }
142
143 pub fn charge_b_trap(&self) -> f32 {
144 if self.nanoseconds_b.len() == 0 || self.voltages_b.len() == 0 {
145 return 0.0;
146 }
147 let mut total_area = 0.0f32;
148 for i in 0..(self.nanoseconds_b.len() - 1) {
149 let h = self.nanoseconds_b[i + 1] - self.nanoseconds_b[i]; let area = h * (self.voltages_b[i] + self.voltages_b[i + 1]) / 2.0;
151 total_area += area;
152 }
153 total_area
154 }
155
156 pub fn guess_max_peak_a(&self) -> f32 {
157 let mut current_max = -1000.0f32;
158 for k in 20..self.voltages_a.len() {
159 if self.voltages_a[k] > current_max {
160 current_max = self.voltages_a[k];
161 }
162 }
163 current_max
164 }
165
166 pub fn guess_max_peak_b(&self) -> f32 {
167 let mut current_max = -1000.0f32;
168 for k in 20..self.voltages_b.len() {
169 if self.voltages_b[k] > current_max {
170 current_max = self.voltages_b[k];
171 }
172 }
173 current_max
174 }
175
176 pub fn subtract_pedestals(&mut self) {
177 let (ped_a, _ped_a_err) = calculate_pedestal(&self.voltages_a,
178 10.0,
179 700,
180 200);
181 let (ped_b, _ped_b_err) = calculate_pedestal(&self.voltages_b,
182 10.0,
183 700,
184 200);
185 for k in 0..self.voltages_a.len() {
186 self.voltages_a[k] = self.voltages_a[k] - ped_a;
187 self.voltages_b[k] = self.voltages_b[k] - ped_b;
188 }
189 }
190
191 pub fn calibrate(&mut self, cali : &RBCalibrations) -> Result<(), CalibrationError> {
194 if cali.rb_id != self.rb_id {
195 error!("Calibration is for board {}, but wf is for {}", cali.rb_id, self.rb_id);
196 return Err(CalibrationError::WrongBoardId);
197 }
198 let mut voltages = vec![0.0f32;1024];
199 let mut nanosecs = vec![0.0f32;1024];
200 cali.voltages(self.rb_channel_a as usize + 1,
201 self.stop_cell as usize,
202 &self.adc_a,
203 &mut voltages);
204 self.voltages_a = voltages.clone();
205 cali.nanoseconds(self.rb_channel_a as usize + 1,
206 self.stop_cell as usize,
207 &mut nanosecs);
208 self.nanoseconds_a = nanosecs.clone();
209 cali.voltages(self.rb_channel_b as usize + 1,
210 self.stop_cell as usize,
211 &self.adc_b,
212 &mut voltages);
213 self.voltages_b = voltages;
214 cali.nanoseconds(self.rb_channel_b as usize + 1,
215 self.stop_cell as usize,
216 &mut nanosecs);
217 self.nanoseconds_b = nanosecs;
218 Ok(())
219 }
220
221 pub fn apply_spike_filter(&mut self) {
223 clean_spikes(&mut self.voltages_a, true);
224 clean_spikes(&mut self.voltages_b, true);
225 }
226}
227
228impl TofPackable for RBWaveform {
229 const TOF_PACKET_TYPE : TofPacketType = TofPacketType::RBWaveform;
230}
231
232impl Serialization for RBWaveform {
233 const HEAD : u16 = 43690; const TAIL : u16 = 21845; const SIZE : usize = 14 + (4*NWORDS);
236
237 fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
238 -> Result<Self, SerializationError> {
239 Self::verify_fixed(stream, pos)?;
240 let mut wf = RBWaveform::new();
241 wf.event_id = parse_u32(stream, pos);
242 wf.rb_id = parse_u8(stream, pos);
243 wf.rb_channel_a = parse_u8(stream, pos);
244 wf.rb_channel_b = parse_u8(stream, pos);
245 wf.stop_cell = parse_u16(stream, pos);
246 wf.paddle_id = parse_u8 (stream, pos);
247 if stream.len() < *pos+2*NWORDS {
248 return Err(SerializationError::StreamTooShort);
249 }
250 let data_a = &stream[*pos..*pos+2*NWORDS];
251 wf.adc_a = u8_to_u16(data_a);
254 *pos += 2*NWORDS;
255 if stream.len() < *pos+2*NWORDS {
256 return Err(SerializationError::StreamTooShort);
257 }
258 let data_b = &stream[*pos..*pos+2*NWORDS];
259 wf.adc_b = u8_to_u16(data_b);
260 *pos += 2*NWORDS;
261 *pos +=2;
266 Ok(wf)
267 }
268
269 fn to_bytestream(&self) -> Vec<u8> {
270 let mut stream = Vec::<u8>::new();
271 stream.extend_from_slice(&Self::HEAD.to_le_bytes());
272 stream.extend_from_slice(&self.event_id.to_le_bytes());
273 stream.extend_from_slice(&self.rb_id.to_le_bytes());
274 stream.extend_from_slice(&self.rb_channel_a.to_le_bytes());
275 stream.extend_from_slice(&self.rb_channel_b.to_le_bytes());
276 stream.extend_from_slice(&self.stop_cell.to_le_bytes());
277 stream.push(self.paddle_id);
278 if self.adc_a.len() != 0 {
279 for k in 0..NWORDS {
280 stream.extend_from_slice(&self.adc_a[k].to_le_bytes());
281 }
282 }
283 if self.adc_b.len() != 0 {
284 for k in 0..NWORDS {
285 stream.extend_from_slice(&self.adc_b[k].to_le_bytes());
286 }
287 }
288 stream.extend_from_slice(&Self::TAIL.to_le_bytes());
289 stream
290 }
291}
292
293impl fmt::Display for RBWaveform {
294 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
295 let mut repr = String::from("<RBWaveform:");
296 repr += &(format!("\n Event ID : {}", self.event_id));
297 repr += &(format!("\n RB : {}", self.rb_id));
298 repr += &(format!("\n ChannelA : {}", self.rb_channel_a));
299 repr += &(format!("\n ChannelB : {}", self.rb_channel_b));
300 repr += &(format!("\n Paddle ID : {}", self.paddle_id));
301 repr += &(format!("\n Stop cell : {}", self.stop_cell));
302 if self.adc_a.len() >= 273 {
303 repr += &(format!("\n adc [A] [{}] : .. {} {} {} ..",self.adc_a.len(), self.adc_a[270], self.adc_a[271], self.adc_a[272]));
304 } else {
305 repr += &(String::from("\n adc [A] [EMPTY]"));
306 }
307 if self.adc_b.len() >= 273 {
308 repr += &(format!("\n adc [B] [{}] : .. {} {} {} ..",self.adc_b.len(), self.adc_b[270], self.adc_b[271], self.adc_b[272]));
309 } else {
310 repr += &(String::from("\n adc [B] [EMPTY]"));
311 }
312 write!(f, "{}", repr)
313 }
314}
315
316#[cfg(feature="pybindings")]
319#[pymethods]
320impl RBWaveform {
321
322 #[getter]
324 fn get_paddle_id(&self) -> u8 {
325 self.paddle_id
326 }
327
328 #[getter]
329 fn max_peak_a_guess(&self) -> f32 {
330 self.guess_max_peak_a()
331 }
332
333 #[getter]
334 fn max_peak_b_guess(&self) -> f32 {
335 self.guess_max_peak_b()
336 }
337
338 #[getter]
339 fn get_rb_id(&self) -> u8 {
340 self.rb_id
341 }
342
343 #[getter]
344 fn get_event_id(&self) -> u32 {
345 self.event_id
346 }
347
348 #[getter]
349 fn get_rb_channel_a(&self) -> u8 {
350 self.rb_channel_a
351 }
352
353 #[getter]
354 fn get_rb_channel_b(&self) -> u8 {
355 self.rb_channel_b
356 }
357
358 #[getter]
359 fn get_stop_cell(&self) -> u16 {
360 self.stop_cell
361 }
362
363 #[getter]
365 fn get_adc_a<'_py>(&self, py: Python<'_py>) -> Bound<'_py, PyArray1<u16>> {
366 self.adc_a.to_pyarray(py)
368 }
370
371 #[getter]
372 fn get_adc_b<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<u16>>> {
373 let arr = PyArray1::<u16>::from_slice(py, self.adc_b.as_slice());
374 Ok(arr)
375 }
376
377 #[getter]
378 fn get_voltages_a<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<f32>>> {
379 let arr = PyArray1::<f32>::from_slice(py, self.voltages_a.as_slice());
380 Ok(arr)
381 }
382
383 #[getter]
384 fn get_times_a<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<f32>>> {
385 let arr = PyArray1::<f32>::from_slice(py, self.nanoseconds_a.as_slice());
386 Ok(arr)
387 }
388
389 #[getter]
390 fn get_voltages_b<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<f32>>> {
391 let arr = PyArray1::<f32>::from_slice(py, self.voltages_b.as_slice());
392 Ok(arr)
393 }
394
395 fn get_tot_a(&self, threshold : f32) -> f32 {
402 self.time_over_threshold_a(threshold)
403 }
404
405 fn get_tot_b(&self, threshold : f32) -> f32 {
412 self.time_over_threshold_b(threshold)
413 }
414
415 #[pyo3(name="subtract_pedestals")]
416 fn subtract_pedestals_py(&mut self) {
417 self.subtract_pedestals()
418 }
419
420 #[getter]
421 fn get_charge_a_trap(&self) -> f32 {
422 self.charge_a_trap()
423 }
424
425 #[getter]
426 fn get_charge_a_below_500_trap(&self) -> f32 {
427 self.charge_a_below_500()
428 }
429
430 #[getter]
431 fn get_charge_b_below_500_trap(&self) -> f32 {
432 self.charge_b_below_500()
433 }
434
435
436 #[getter]
437 fn get_charge_b_trap(&self) -> f32 {
438 self.charge_b_trap()
439 }
440
441 #[getter]
442 fn get_times_b<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<f32>>> {
443 let arr = PyArray1::<f32>::from_slice(py, self.nanoseconds_b.as_slice());
444 Ok(arr)
445 }
446
447 #[pyo3(name="calibrate")]
450 fn calibrate_py(&mut self, cali : &RBCalibrations) -> PyResult<()> {
451 match self.calibrate(&cali) {
452 Ok(_) => {
453 return Ok(());
454 }
455 Err(err) => {
456 return Err(PyValueError::new_err(err.to_string()));
457 }
458 }
459 }
460
461 #[pyo3(name="apply_spike_filter")]
462 fn apply_spike_filter_py(&mut self) {
463 self.apply_spike_filter();
464 }
465}
466
467#[cfg(feature="pybindings")]
468pythonize_packable!(RBWaveform);
469
470#[cfg(feature = "random")]
477impl FromRandom for RBWaveform {
478
479 fn from_random() -> Self {
480 let mut wf = Self::new();
481 let mut rng = rand::rng();
482 wf.event_id = rng.random::<u32>();
483 wf.rb_id = rng.random_range(1..50);
484 wf.rb_channel_a = rng.random_range(1..9);
485 wf.rb_channel_b = rng.random_range(1..9);
486 wf.stop_cell = rng.random_range(0..1024);
487 let random_numbers_a: Vec<u16> = (0..NWORDS).map(|_| rng.random()).collect();
489 wf.adc_a = random_numbers_a;
490 let random_numbers_b: Vec<u16> = (0..NWORDS).map(|_| rng.random()).collect();
491 wf.adc_b = random_numbers_b;
492 wf
493 }
494}
495
496#[test]
499#[cfg(feature = "random")]
500fn pack_rbwaveform() {
501 for _ in 0..100 {
502 let wf = RBWaveform::from_random();
503 let test : RBWaveform = wf.pack().unpack().unwrap();
504 assert_eq!(wf, test);
505 }
506}
507
508#[test]
509#[cfg(feature="random")]
510fn emit_rbwaveform() {
511 for _ in 0..100 {
512 let ev = RBEvent::from_random();
513 for wf in ev.get_rbwaveforms() {
514 assert_eq!(ev.header.rb_id, wf.rb_id);
515 }
516 }
517}
518
519