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
78 let mut total_area = 0.0f32;
79 for i in 0..(self.nanoseconds_a.len() - 1) {
80 let h = self.nanoseconds_a[i + 1] - self.nanoseconds_a[i]; let mut v1 = self.voltages_a[i];
82 let mut v2 = self.voltages_a[i + 1];
83 if v1 > 500.0 {
84 v1 = 500.0;
85 }
86 if v2 > 500.0 {
87 v2 = 500.0;
88 }
89 let area = h * (v1 + v2) / 2.0;
90 total_area += area;
91 }
92 total_area
93 }
94
95 pub fn charge_b_below_500(&self) -> f32 {
96
97 let mut total_area = 0.0f32;
98 for i in 0..(self.nanoseconds_b.len() - 1) {
99 let h = self.nanoseconds_b[i + 1] - self.nanoseconds_b[i]; let mut v1 = self.voltages_b[i];
101 let mut v2 = self.voltages_b[i + 1];
102 if v1 > 500.0 {
103 v1 = 500.0;
104 }
105 if v2 > 500.0 {
106 v2 = 500.0;
107 }
108 let area = h * (v1 + v2) / 2.0;
109 total_area += area;
110 }
111 total_area
112 }
113
114 pub fn charge_a_trap(&self) -> f32 {
125 let mut total_area = 0.0f32;
126 for i in 0..(self.nanoseconds_a.len() - 1) {
127 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;
129 total_area += area;
130 }
131 total_area
132 }
133
134 pub fn charge_b_trap(&self) -> f32 {
135 let mut total_area = 0.0f32;
136 for i in 0..(self.nanoseconds_b.len() - 1) {
137 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;
139 total_area += area;
140 }
141 total_area
142 }
143
144 pub fn guess_max_peak_a(&self) -> f32 {
145 let mut current_max = -1000.0f32;
146 for k in 20..self.voltages_a.len() {
147 if self.voltages_a[k] > current_max {
148 current_max = self.voltages_a[k];
149 }
150 }
151 current_max
152 }
153
154 pub fn guess_max_peak_b(&self) -> f32 {
155 let mut current_max = -1000.0f32;
156 for k in 20..self.voltages_b.len() {
157 if self.voltages_b[k] > current_max {
158 current_max = self.voltages_b[k];
159 }
160 }
161 current_max
162 }
163
164 pub fn subtract_pedestals(&mut self) {
165 let (ped_a, _ped_a_err) = calculate_pedestal(&self.voltages_a,
166 10.0,
167 700,
168 200);
169 let (ped_b, _ped_b_err) = calculate_pedestal(&self.voltages_b,
170 10.0,
171 700,
172 200);
173 for k in 0..self.voltages_a.len() {
174 self.voltages_a[k] = self.voltages_a[k] - ped_a;
175 self.voltages_b[k] = self.voltages_b[k] - ped_b;
176 }
177 }
178
179 pub fn calibrate(&mut self, cali : &RBCalibrations) -> Result<(), CalibrationError> {
182 if cali.rb_id != self.rb_id {
183 error!("Calibration is for board {}, but wf is for {}", cali.rb_id, self.rb_id);
184 return Err(CalibrationError::WrongBoardId);
185 }
186 let mut voltages = vec![0.0f32;1024];
187 let mut nanosecs = vec![0.0f32;1024];
188 cali.voltages(self.rb_channel_a as usize + 1,
189 self.stop_cell as usize,
190 &self.adc_a,
191 &mut voltages);
192 self.voltages_a = voltages.clone();
193 cali.nanoseconds(self.rb_channel_a as usize + 1,
194 self.stop_cell as usize,
195 &mut nanosecs);
196 self.nanoseconds_a = nanosecs.clone();
197 cali.voltages(self.rb_channel_b as usize + 1,
198 self.stop_cell as usize,
199 &self.adc_b,
200 &mut voltages);
201 self.voltages_b = voltages;
202 cali.nanoseconds(self.rb_channel_b as usize + 1,
203 self.stop_cell as usize,
204 &mut nanosecs);
205 self.nanoseconds_b = nanosecs;
206 Ok(())
207 }
208
209 pub fn apply_spike_filter(&mut self) {
211 clean_spikes(&mut self.voltages_a, true);
212 clean_spikes(&mut self.voltages_b, true);
213 }
214}
215
216impl TofPackable for RBWaveform {
217 const TOF_PACKET_TYPE : TofPacketType = TofPacketType::RBWaveform;
218}
219
220impl Serialization for RBWaveform {
221 const HEAD : u16 = 43690; const TAIL : u16 = 21845; const SIZE : usize = 13 + (4*NWORDS);
224
225 fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
226 -> Result<Self, SerializationError> {
227 Self::verify_fixed(stream, pos)?;
228 let mut wf = RBWaveform::new();
229 wf.event_id = parse_u32(stream, pos);
230 wf.rb_id = parse_u8(stream, pos);
231 wf.rb_channel_a = parse_u8(stream, pos);
232 wf.rb_channel_b = parse_u8(stream, pos);
233 wf.stop_cell = parse_u16(stream, pos);
234 wf.paddle_id = parse_u8 (stream, pos);
235 if stream.len() < *pos+2*NWORDS {
236 return Err(SerializationError::StreamTooShort);
237 }
238 let data_a = &stream[*pos..*pos+2*NWORDS];
239 wf.adc_a = u8_to_u16(data_a);
242 *pos += 2*NWORDS;
243 if stream.len() < *pos+2*NWORDS {
244 return Err(SerializationError::StreamTooShort);
245 }
246 let data_b = &stream[*pos..*pos+2*NWORDS];
247 wf.adc_b = u8_to_u16(data_b);
248 *pos += 2*NWORDS;
249 *pos +=2;
254 Ok(wf)
255 }
256
257 fn to_bytestream(&self) -> Vec<u8> {
258 let mut stream = Vec::<u8>::new();
259 stream.extend_from_slice(&Self::HEAD.to_le_bytes());
260 stream.extend_from_slice(&self.event_id.to_le_bytes());
261 stream.extend_from_slice(&self.rb_id.to_le_bytes());
262 stream.extend_from_slice(&self.rb_channel_a.to_le_bytes());
263 stream.extend_from_slice(&self.rb_channel_b.to_le_bytes());
264 stream.extend_from_slice(&self.stop_cell.to_le_bytes());
265 stream.push(self.paddle_id);
266 if self.adc_a.len() != 0 {
267 for k in 0..NWORDS {
268 stream.extend_from_slice(&self.adc_a[k].to_le_bytes());
269 }
270 }
271 if self.adc_b.len() != 0 {
272 for k in 0..NWORDS {
273 stream.extend_from_slice(&self.adc_b[k].to_le_bytes());
274 }
275 }
276 stream.extend_from_slice(&Self::TAIL.to_le_bytes());
277 stream
278 }
279}
280
281impl fmt::Display for RBWaveform {
282 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
283 let mut repr = String::from("<RBWaveform:");
284 repr += &(format!("\n Event ID : {}", self.event_id));
285 repr += &(format!("\n RB : {}", self.rb_id));
286 repr += &(format!("\n ChannelA : {}", self.rb_channel_a));
287 repr += &(format!("\n ChannelB : {}", self.rb_channel_b));
288 repr += &(format!("\n Paddle ID : {}", self.paddle_id));
289 repr += &(format!("\n Stop cell : {}", self.stop_cell));
290 if self.adc_a.len() >= 273 {
291 repr += &(format!("\n adc [A] [{}] : .. {} {} {} ..",self.adc_a.len(), self.adc_a[270], self.adc_a[271], self.adc_a[272]));
292 } else {
293 repr += &(String::from("\n adc [A] [EMPTY]"));
294 }
295 if self.adc_b.len() >= 273 {
296 repr += &(format!("\n adc [B] [{}] : .. {} {} {} ..",self.adc_b.len(), self.adc_b[270], self.adc_b[271], self.adc_b[272]));
297 } else {
298 repr += &(String::from("\n adc [B] [EMPTY]"));
299 }
300 write!(f, "{}", repr)
301 }
302}
303
304#[cfg(feature="pybindings")]
307#[pymethods]
308impl RBWaveform {
309
310 #[getter]
312 fn get_paddle_id(&self) -> u8 {
313 self.paddle_id
314 }
315
316 #[getter]
317 fn max_peak_a_guess(&self) -> f32 {
318 self.guess_max_peak_a()
319 }
320
321 #[getter]
322 fn max_peak_b_guess(&self) -> f32 {
323 self.guess_max_peak_b()
324 }
325
326 #[getter]
327 fn get_rb_id(&self) -> u8 {
328 self.rb_id
329 }
330
331 #[getter]
332 fn get_event_id(&self) -> u32 {
333 self.event_id
334 }
335
336 #[getter]
337 fn get_rb_channel_a(&self) -> u8 {
338 self.rb_channel_a
339 }
340
341 #[getter]
342 fn get_rb_channel_b(&self) -> u8 {
343 self.rb_channel_b
344 }
345
346 #[getter]
347 fn get_stop_cell(&self) -> u16 {
348 self.stop_cell
349 }
350
351 #[getter]
353 fn get_adc_a<'_py>(&self, py: Python<'_py>) -> Bound<'_py, PyArray1<u16>> {
354 self.adc_a.to_pyarray(py)
356 }
358
359 #[getter]
360 fn get_adc_b<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<u16>>> {
361 let arr = PyArray1::<u16>::from_slice(py, self.adc_b.as_slice());
362 Ok(arr)
363 }
364
365 #[getter]
366 fn get_voltages_a<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<f32>>> {
367 let arr = PyArray1::<f32>::from_slice(py, self.voltages_a.as_slice());
368 Ok(arr)
369 }
370
371 #[getter]
372 fn get_times_a<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<f32>>> {
373 let arr = PyArray1::<f32>::from_slice(py, self.nanoseconds_a.as_slice());
374 Ok(arr)
375 }
376
377 #[getter]
378 fn get_voltages_b<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<f32>>> {
379 let arr = PyArray1::<f32>::from_slice(py, self.voltages_b.as_slice());
380 Ok(arr)
381 }
382
383 fn get_tot_a(&self, threshold : f32) -> f32 {
390 self.time_over_threshold_a(threshold)
391 }
392
393 fn get_tot_b(&self, threshold : f32) -> f32 {
400 self.time_over_threshold_b(threshold)
401 }
402
403 #[pyo3(name="subtract_pedestals")]
404 fn subtract_pedestals_py(&mut self) {
405 self.subtract_pedestals()
406 }
407
408 #[getter]
409 fn get_charge_a_trap(&self) -> f32 {
410 self.charge_a_trap()
411 }
412
413 #[getter]
414 fn get_charge_a_below_500_trap(&self) -> f32 {
415 self.charge_a_below_500()
416 }
417
418 #[getter]
419 fn get_charge_b_below_500_trap(&self) -> f32 {
420 self.charge_b_below_500()
421 }
422
423
424 #[getter]
425 fn get_charge_b_trap(&self) -> f32 {
426 self.charge_b_trap()
427 }
428
429 #[getter]
430 fn get_times_b<'_py>(&self, py: Python<'_py>) -> PyResult<Bound<'_py, PyArray1<f32>>> {
431 let arr = PyArray1::<f32>::from_slice(py, self.nanoseconds_b.as_slice());
432 Ok(arr)
433 }
434
435 #[pyo3(name="calibrate")]
438 fn calibrate_py(&mut self, cali : &RBCalibrations) -> PyResult<()> {
439 match self.calibrate(&cali) {
440 Ok(_) => {
441 return Ok(());
442 }
443 Err(err) => {
444 return Err(PyValueError::new_err(err.to_string()));
445 }
446 }
447 }
448
449 #[pyo3(name="apply_spike_filter")]
450 fn apply_spike_filter_py(&mut self) {
451 self.apply_spike_filter();
452 }
453}
454
455#[cfg(feature="pybindings")]
456pythonize_packable!(RBWaveform);
457
458#[cfg(feature = "random")]
465impl FromRandom for RBWaveform {
466
467 fn from_random() -> Self {
468 let mut wf = Self::new();
469 let mut rng = rand::rng();
470 wf.event_id = rng.random::<u32>();
471 wf.rb_id = rng.random_range(1..50);
472 wf.rb_channel_a = rng.random_range(1..9);
473 wf.rb_channel_b = rng.random_range(1..9);
474 wf.stop_cell = rng.random_range(0..1024);
475 let random_numbers_a: Vec<u16> = (0..NWORDS).map(|_| rng.random()).collect();
477 wf.adc_a = random_numbers_a;
478 let random_numbers_b: Vec<u16> = (0..NWORDS).map(|_| rng.random()).collect();
479 wf.adc_b = random_numbers_b;
480 wf
481 }
482}
483
484#[test]
487#[cfg(feature = "random")]
488fn pack_rbwaveform() {
489 for _ in 0..100 {
490 let wf = RBWaveform::from_random();
491 let test : RBWaveform = wf.pack().unpack().unwrap();
492 assert_eq!(wf, test);
493 }
494}
495
496#[test]
497#[cfg(feature="random")]
498fn emit_rbwaveform() {
499 for _ in 0..100 {
500 let ev = RBEvent::from_random();
501 for wf in ev.get_rbwaveforms() {
502 assert_eq!(ev.header.rb_id, wf.rb_id);
503 }
504 }
505}
506
507