1use std::fs::File;
14use std::io::{self, BufRead, BufReader};
15use std::path::Path;
16use std::fmt;
17use half::f16;
18use chrono::{
19 Utc,
21 TimeZone,
22 LocalResult
23};
24
25use crate::constants::{NWORDS, NCHN};
26use crate::errors::{WaveformError,
27 CalibrationError};
28use crate::serialization::{
29 Serialization,
30 Packable,
31 parse_bool,
32 parse_u8,
33 parse_u16,
34 parse_u32,
35 parse_f16,
36 parse_f32,
37 SerializationError
38};
39
40use crate::events::RBEvent;
41use crate::events::rb_event::unpack_traces_f32;
42
43use crate::packets::{
44 PacketType,
45 TofPacket
46};
47
48use crate::io::{
49 read_file,
50 TofPacketReader,
51};
52
53cfg_if::cfg_if! {
54 if #[cfg(feature = "random")] {
55 use crate::FromRandom;
56 extern crate rand;
57 use rand::Rng;
58 }
59}
60
61extern crate statistical;
62
63#[derive(Debug, Copy, Clone, serde::Deserialize, serde::Serialize)]
66#[repr(u8)]
67pub enum Edge {
68 Unknown = 0u8,
69 Rising = 10u8,
70 Falling = 20u8,
71 Average = 30u8,
72 None = 40u8
73}
74
75impl fmt::Display for Edge {
76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77 let r = serde_json::to_string(self).unwrap_or(
78 String::from("Error: cannot unwrap this Edge"));
79 write!(f, "<Edge: {}>", r)
80 }
81}
82
83impl From<u8> for Edge {
84 fn from(value: u8) -> Self {
85 match value {
86 0u8 => Edge::Unknown,
87 10u8 => Edge::Rising,
88 20u8 => Edge::Falling,
89 30u8 => Edge::Average,
90 40u8 => Edge::None,
91 _ => Edge::Unknown
92 }
93 }
94}
95
96#[cfg(feature = "random")]
97impl FromRandom for Edge {
98
99 fn from_random() -> Self {
100 let choices = [
101 Edge::Rising,
102 Edge::Falling,
103 Edge::Average,
104 Edge::None,
105 ];
106 let mut rng = rand::thread_rng();
107 let idx = rng.gen_range(0..choices.len());
108 choices[idx]
109 }
110}
111
112fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
116where P: AsRef<Path>, {
117 let file = File::open(filename)?;
118 Ok(io::BufReader::new(file).lines())
119}
120
121fn trace_check(event : &RBEvent) -> bool {
124 let mut check = true;
125 let mut nchan = 0usize;
126 let mut failed = true;
127 for ch in event.header.get_channels() {
128 if event.adc[ch as usize].len() != 1024 {
129 check = false;
130 }
131 for k in &event.adc[ch as usize] {
132 if *k != u16::MAX {
133 failed = false;
140 }
141 }
142
143 nchan += 1;
144 }
145 check && nchan == NCHN && !failed
148}
149
150pub fn clean_spikes(trace : &mut Vec<f32>, vcaldone : bool) {
157 let mut thresh : f32 = 360.0;
159 if vcaldone {
160 thresh = 16.0;
161 }
162
163 let mut spf_allch = vec![0usize;1023];
171 let tracelen = trace.len();
172 let spikefilter0 = (&trace[0..tracelen-3]).to_vec();
173 let spikefilter1 = (&trace[1..tracelen-2]).to_vec();
174 let spikefilter2 = (&trace[2..tracelen-1]).to_vec();
175 let spikefilter3 = (&trace[3..tracelen]).to_vec();
176 let spf_len = spikefilter0.len();
177 let mut spf_sum = vec![0f32;1024];
178 for k in 0..spf_len {
179 spf_sum[k] += spikefilter1[k] - spikefilter0[k] + spikefilter2[k] - spikefilter3[k];
180 }
181 for k in 0..spf_len {
182 if spf_sum[k] > thresh {
183 spf_allch[k] += 1;
184 }
185 }
186 let mut spikes = Vec::<usize>::new();
187 for k in 0..spf_allch.len() {
188 if spf_allch[k] >= 2 {
189 spikes.push(k);
190 }
191 }
192 for spike in spikes.iter() {
193 let d_v : f32 = (trace[spike+3] - trace[*spike])/3.0;
194 trace[spike+1] = trace[*spike] + d_v;
195 trace[spike+2] = trace[*spike] + 2.0*d_v;
196 }
197}
198
199pub fn find_zero_crossings(trace: &Vec<f32>) -> Vec<usize> {
204 let mut zero_crossings = Vec::new();
205 for i in 1..trace.len() {
206 if (trace[i - 1] > 0.0 && trace[i] < 0.0) || (trace[i - 1] < 0.0 && trace[i] > 0.0) {
208 zero_crossings.push(i - 1);
209 }
210 if i < trace.len() - 1 {
211 if trace[i - 1] > 0.0 && trace[i] == 0.0 && trace[i+1] < 0.0 {
212 zero_crossings.push(1);
213 }
214 if trace[i - 1] < 0.0 && trace[i] == 0.0 && trace[i+1] > 0.0 {
215 zero_crossings.push(i);
216 }
217 }
218 }
219 zero_crossings
220}
221
222pub fn get_periods(trace : &Vec<f32>,
231 dts : &Vec<f32>,
232 nperiod : f32,
233 nskip : f32,
234 edge : &Edge) -> (Vec<usize>, Vec<f32>) {
235 let mut trace_c = trace.clone();
236 let mut periods = Vec::<f32>::new();
237 if trace_c.len() == 0 {
238 let foo = Vec::<usize>::new();
239 return (foo, periods);
240 }
241 let firstbin : usize = 20;
242 let lastbin = firstbin + (nperiod * (900.0/nperiod).floor()).floor() as usize;
243 let mut vec_for_median = Vec::<f32>::new();
245 for bin in firstbin..lastbin {
246 if trace[bin].is_nan() {
247 continue;
248 }
249 vec_for_median.push(trace[bin]);
250 }
251 let median_val = median(&vec_for_median);
252 debug!("median val {median_val}");
253 for k in 0..trace_c.len() {
254 trace_c[k] -= median_val;
255 }
256 let mut zcs = find_zero_crossings(&trace_c);
257 let mut zcs_nskip = Vec::<usize>::with_capacity(zcs.len());
259 for k in 0..zcs.len() {
260 if zcs[k] > nskip as usize {
261 zcs_nskip.push(zcs[k]);
262 }
263 }
264 zcs = zcs_nskip;
265 let mut zcs_filter = Vec::<usize>::with_capacity(zcs.len());
266 for k in 0..zcs.len() {
267 match edge {
268 Edge::Rising => {
269 if trace_c[zcs[k]] < 0.0 {
270 zcs_filter.push(zcs[k]);
271 }
272 }
273 Edge::Falling => {
274 if trace_c[zcs[k]] > 0.0 {
276 zcs_filter.push(zcs[k]);
277 }
278 },
279 Edge::None => {
280 warn!("Unsure what to do for Edge::None");
281 },
282 Edge::Average => {
283 warn!("Unsure what to do for Edge::Average");
284 },
285 Edge::Unknown => {
286 warn!("Unsure what to do for Edge::Unknown");
287 }
288 }
289 }
290 debug!("Found {} zero crossings!", zcs_filter.len());
291 zcs = zcs_filter;
292 if zcs.len() < 3 {
293 return (zcs, periods);
294 }
295
296 for k in 0..zcs.len() -1 {
297 let zcs_a = &zcs[k];
298 let zcs_b = &zcs[k+1];
299 if zcs_a + 2 > trace_c.len() || zcs_b + 2 > trace_c.len() {
302 continue;
303 }
304 let tr_a = &trace_c[*zcs_a..*zcs_a+2];
305 let tr_b = &trace_c[*zcs_b..*zcs_b+2];
306 let mut period : f32 = 0.0;
307 for n in zcs_a+1..*zcs_b {
308 period += dts[n];
309 }
310 period += dts[*zcs_a]*f32::abs(tr_a[1]/(tr_a[1] - tr_a[0])); period += dts[*zcs_b]*f32::abs(tr_b[0]/(tr_b[1] - tr_b[0])); if period.is_nan() {
313 error!("NAN in period found!");
314 continue;
315 }
316
317 if f32::abs(*zcs_b as f32 - *zcs_a as f32 - nperiod) > 5.0 {
318 let mut zcs_tmp = Vec::<usize>::new();
319 zcs_tmp.extend_from_slice(&zcs[0..k+1]);
320 zcs = zcs_tmp;
321 break;
322 }
323 trace!("zcs_a, zcs_b, period, nperiod {} {} {} {}", zcs_a, zcs_b, period, nperiod);
324 periods.push(period);
325 }
326 debug!("Calculated {} zero-crossings and {} periods!", zcs.len(), periods.len());
327 (zcs, periods)
328}
329
330fn mean(input: &Vec<f32>) -> f32 {
333 if input.len() == 0 {
334 error!("Vector is empty, can not calculate mean!");
335 return f32::NAN;
336 }
337 let mut n_entries : f32 = 0.0;
338 let mut sum : f32 = 0.0;
339 for k in input.iter() {
340 if k.is_nan() {
341 continue;
342
343 }
344 sum += k;
345 n_entries += 1.0;
346 }
347 sum / n_entries
348}
349
350fn median(input: &Vec<f32>) -> f32 {
353 statistical::median(input)
354 }
374
375fn calculate_column_medians(data: &Vec<Vec<f32>>) -> Vec<f32> {
382 let num_columns = data[0].len();
384 let num_rows = data.len();
385 let mut column_medians: Vec<f32> = vec![0.0; num_columns];
387 debug!("Calculating medians for {} columns!", num_columns);
388 debug!("Calculating medians for {} rows!", num_rows);
389 for col in 0..num_columns {
391 let mut col_vals = vec![0.0; num_rows];
392 for k in 0..num_rows {
394 col_vals[k] = data[k][col];
395 }
396 col_vals.retain(|x| !x.is_nan());
397 if col_vals.len() == 0 {
398 column_medians[col] = f32::NAN;
399 } else {
400 column_medians[col] = statistical::median(col_vals.as_slice());}
402 }
403 column_medians
404}
405
406fn calculate_column_means(data: &Vec<Vec<f32>>) -> Vec<f32> {
410 let num_columns = data[0].len();
412 let num_rows = data.len();
413 debug!("Calculating means for {} columns and {} rows", num_columns, num_rows);
414 let mut column_means: Vec<f32> = vec![0.0; num_columns];
416 for col in 0..num_columns {
418 let mut col_vals = vec![0.0; num_rows];
419 for k in 0..num_rows {
420 col_vals[k] = data[k][col];
421 }
422 col_vals.retain(|x| !x.is_nan());
423 let thismean = mean(&col_vals);
424 if !thismean.is_nan() {
425 column_means[col] = thismean;
426 }
427 }
429 column_means
430}
431
432fn roll<T: Clone>(vec: &mut Vec<T>, offset: isize) {
435 let len = vec.len() as isize;
436
437 if len <= 1 {
438 return;
439 }
440
441 let offset = offset % len;
442
443 if offset == 0 {
444 return;
445 }
446
447 let split_point = if offset > 0 {
448 len - offset
449 } else {
450 -offset
451 } as usize;
452
453 let mut temp = Vec::with_capacity(len as usize);
454 temp.extend_from_slice(&vec[split_point..]);
455 temp.extend_from_slice(&vec[..split_point]);
456
457 vec.clear();
458 vec.extend_from_slice(&temp);
459
460 }
513
514#[derive(Debug, Clone, PartialEq)]
518pub struct RBCalibrationsFlightT {
519 pub rb_id : u8,
520 pub timestamp : u32, pub tbin : [[f16;NWORDS];NCHN], }
523
524impl RBCalibrationsFlightT {
525 pub fn new() -> Self {
526 Self {
527 rb_id : 0,
528 timestamp : 0,
529 tbin : [[f16::from_f32(0.0);NWORDS];NCHN],
530 }
531 }
532}
533
534impl Serialization for RBCalibrationsFlightT {
535 const SIZE : usize = NCHN*NWORDS*2 + 4 + 1;
536 const HEAD : u16 = 0xAAAA; const TAIL : u16 = 0x5555; fn from_bytestream(bytestream : &Vec<u8>,
540 pos : &mut usize)
541 -> Result<Self, SerializationError> {
542 let mut rb_cal = Self::new();
543 if parse_u16(bytestream, pos) != Self::HEAD {
544 return Err(SerializationError::HeadInvalid {});
545 }
546 rb_cal.rb_id = parse_u8(bytestream, pos);
547 rb_cal.timestamp = parse_u32(bytestream, pos);
548 for ch in 0..NCHN {
549 for k in 0..NWORDS {
550 let value = parse_f16(bytestream, pos);
551 rb_cal.tbin[ch][k] = value;
552 }
553 }
554 *pos += 2;
555 Ok(rb_cal)
556 }
557
558 fn to_bytestream(&self) -> Vec<u8> {
559
560 let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
561 bs.extend_from_slice(&Self::HEAD.to_le_bytes());
562 bs.extend_from_slice(&self.rb_id.to_le_bytes());
563 bs.extend_from_slice(&self.timestamp.to_le_bytes());
564 for ch in 0..NCHN {
565 for k in 0..NWORDS {
566 bs.extend_from_slice(&self.tbin[ch][k] .to_le_bytes());
567 }
568 }
569 bs.extend_from_slice(&Self::TAIL.to_le_bytes());
570 bs
571 }
572}
573
574impl Packable for RBCalibrationsFlightT {
575 const PACKET_TYPE : PacketType = PacketType::RBCalibrationFlightT;
576}
577
578impl fmt::Display for RBCalibrationsFlightT {
579 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
580 let mut timestamp_str = String::from("?");
581 match Utc.timestamp_opt(self.timestamp.into(), 0) {
582 LocalResult::Single(datetime_utc) => {
583 timestamp_str = datetime_utc.format("%Y/%m/%d %H:%M:%S").to_string();
584 },
585 LocalResult::Ambiguous(_, _) => {
586 error!("The given timestamp is ambiguous.");
587 },
588 LocalResult::None => {
589 error!("The given timestamp is not valid.");
590 },
591 }
592
593 write!(f,
595 "<ReadoutboardCalibrationsFlightT [{} UTC]:
596 RB : {}
597 T Bins [ch0]: .. {:?} {:?} ..>",
598 timestamp_str,
599 self.rb_id,
600 self.tbin[0][98],
601 self.tbin[0][99]
602 )
603 }
604}
605
606#[cfg(feature = "random")]
607impl FromRandom for RBCalibrationsFlightT {
608
609 fn from_random() -> Self {
610 let mut cali = Self::new();
611 let mut rng = rand::thread_rng();
612 cali.rb_id = rng.gen::<u8>();
613 cali.timestamp = rng.gen::<u32>();
614 for ch in 0..NCHN {
615 for n in 0..NWORDS {
616 cali.tbin [ch][n] = f16::from_f32(rng.gen::<f32>());
617 }
618 }
619 cali
620 }
621}
622
623#[derive(Debug, Clone, PartialEq)]
624pub struct RBCalibrationsFlightV {
625 pub rb_id : u8,
626 pub d_v : f32, pub timestamp : u32, pub v_offsets : [[f16;NWORDS];NCHN], pub v_dips : [[f16;NWORDS];NCHN], pub v_inc : [[f16;NWORDS];NCHN], }
633
634impl RBCalibrationsFlightV {
635 pub fn new() -> Self {
636 Self {
637 rb_id : 0,
638 d_v : 0.9,
639 timestamp : 0,
640 v_offsets : [[f16::from_f32(0.0);NWORDS];NCHN],
641 v_dips : [[f16::from_f32(0.0);NWORDS];NCHN],
642 v_inc : [[f16::from_f32(0.0);NWORDS];NCHN],
643 }
644 }
645}
646
647impl Serialization for RBCalibrationsFlightV {
648 const SIZE : usize = NCHN*NWORDS*2*3 + 4 + 4 + 1;
649 const HEAD : u16 = 0xAAAA; const TAIL : u16 = 0x5555; fn from_bytestream(bytestream : &Vec<u8>,
653 pos : &mut usize)
654 -> Result<Self, SerializationError> {
655 let mut rb_cal = Self::new();
656 if parse_u16(bytestream, pos) != Self::HEAD {
657 return Err(SerializationError::HeadInvalid {});
658 }
659 rb_cal.rb_id = parse_u8(bytestream, pos);
660 rb_cal.d_v = parse_f32(bytestream, pos);
661 rb_cal.timestamp = parse_u32(bytestream, pos);
662 for ch in 0..NCHN {
663 for k in 0..NWORDS {
664 let mut value = parse_f16(bytestream, pos);
665 rb_cal.v_offsets[ch][k] = value;
666 value = parse_f16(bytestream, pos);
667 rb_cal.v_dips[ch][k] = value;
668 value = parse_f16(bytestream, pos);
669 rb_cal.v_inc[ch][k] = value;
670 }
671 }
672 *pos += 2;
673 Ok(rb_cal)
674 }
675
676 fn to_bytestream(&self) -> Vec<u8> {
677 let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
678 bs.extend_from_slice(&Self::HEAD.to_le_bytes());
679 bs.extend_from_slice(&self.rb_id.to_le_bytes());
680 bs.extend_from_slice(&self.d_v.to_le_bytes());
681 bs.extend_from_slice(&self.timestamp.to_le_bytes());
682 for ch in 0..NCHN {
683 for k in 0..NWORDS {
684 bs.extend_from_slice(&self.v_offsets[ch][k].to_le_bytes());
685 bs.extend_from_slice(&self.v_dips[ch][k] .to_le_bytes());
686 bs.extend_from_slice(&self.v_inc[ch][k] .to_le_bytes());
687 }
688 }
689 bs.extend_from_slice(&Self::TAIL.to_le_bytes());
690 bs
691 }
692}
693
694impl Packable for RBCalibrationsFlightV {
695 const PACKET_TYPE : PacketType = PacketType::RBCalibrationFlightV;
696}
697
698impl fmt::Display for RBCalibrationsFlightV {
699 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
700 let mut timestamp_str = String::from("?");
701 match Utc.timestamp_opt(self.timestamp.into(), 0) {
702 LocalResult::Single(datetime_utc) => {
703 timestamp_str = datetime_utc.format("%Y/%m/%d %H:%M:%S").to_string();
704 },
705 LocalResult::Ambiguous(_, _) => {
706 error!("The given timestamp is ambiguous.");
707 },
708 LocalResult::None => {
709 error!("The given timestamp is not valid.");
710 },
711 }
712 write!(f,
713 "<ReadoutboardCalibration [{} UTC]:
714 RB : {}
715 V Offsets [ch0]: .. {:?} {:?} ..
716 V Incrmts [ch0]: .. {:?} {:?} ..
717 V Dips [ch0]: .. {:?} {:?} ..>",
718 timestamp_str,
719 self.rb_id,
720 self.v_offsets[0][98],
721 self.v_offsets[0][99],
722 self.v_inc[0][98],
723 self.v_inc[0][99],
724 self.v_dips[0][98],
725 self.v_dips[0][99]
726 )
727 }
728}
729
730#[cfg(feature = "random")]
731impl FromRandom for RBCalibrationsFlightV {
732
733 fn from_random() -> Self {
734 let mut cali = Self::new();
735 let mut rng = rand::thread_rng();
736 cali.rb_id = rng.gen::<u8>();
737 cali.d_v = rng.gen::<f32>();
738 cali.timestamp = rng.gen::<u32>();
739 for ch in 0..NCHN {
740 for n in 0..NWORDS {
741 cali.v_offsets [ch][n] = f16::from_f32(rng.gen::<f32>());
742 cali.v_dips [ch][n] = f16::from_f32(rng.gen::<f32>());
743 cali.v_inc [ch][n] = f16::from_f32(rng.gen::<f32>());
744 }
745 }
746 cali
747 }
748}
749
750#[derive(Debug, Clone, PartialEq)]
753pub struct RBCalibrations {
754 pub rb_id : u8,
755 pub d_v : f32, pub timestamp : u32, pub serialize_event_data : bool,
759 pub v_offsets : [[f32;NWORDS];NCHN], pub v_dips : [[f32;NWORDS];NCHN], pub v_inc : [[f32;NWORDS];NCHN], pub tbin : [[f32;NWORDS];NCHN], pub vcal_data : Vec::<RBEvent>,
767 pub tcal_data : Vec::<RBEvent>,
768 pub noi_data : Vec::<RBEvent>,
769}
770
771impl RBCalibrations {
772 pub const NSKIP : usize = 2;
776 pub const SINMAX : usize = 60; pub const DVCUT : f32 = 15.0; pub const NOMINALFREQ : f32 = 2.0; pub const CALFREQ : f32 = 0.025; pub fn assemble_from_flightcal(fcal_t : RBCalibrationsFlightT,
784 fcal_v : RBCalibrationsFlightV)
785 -> Result<Self, CalibrationError> {
786 if (fcal_t.timestamp != fcal_v.timestamp) || (fcal_t.rb_id != fcal_v.rb_id) {
787 error!("These calibrations do not match! {} , {}", fcal_t, fcal_v);
788 return Err(CalibrationError::IncompatibleFlightCalibrations);
789 }
790 let mut cal = Self::new(fcal_t.rb_id);
791 cal.rb_id = fcal_t.rb_id;
792 cal.timestamp = fcal_t.timestamp;
793 cal.d_v = fcal_v.d_v;
794 cal.serialize_event_data = false;
795 for ch in 0..NCHN {
796 for k in 0..NWORDS {
797 cal.tbin [ch][k] = f16::to_f32(fcal_t.tbin[ch][k]);
798 cal.v_offsets[ch][k] = f16::to_f32(fcal_v.v_offsets[ch][k]);
799 cal.v_dips [ch][k] = f16::to_f32(fcal_v.v_dips[ch][k]);
800 cal.v_inc [ch][k] = f16::to_f32(fcal_v.v_inc[ch][k]);
801 }
802 }
803 Ok(cal)
804 }
805
806 pub fn emit_flighttcal(&self) -> RBCalibrationsFlightT {
811 let mut cal = RBCalibrationsFlightT::new();
812 cal.rb_id = self.rb_id;
813 cal.timestamp = self.timestamp;
814 for ch in 0..NCHN {
815 for n in 0..NWORDS {
816 cal.tbin [ch][n] = f16::from_f32(self.tbin[ch][n]);
817 }
818 }
819 cal
820 }
821
822 pub fn emit_flightvcal(&self) -> RBCalibrationsFlightV {
827 let mut cal = RBCalibrationsFlightV::new();
828 cal.rb_id = self.rb_id;
829 cal.timestamp = self.timestamp;
830 cal.d_v = self.d_v;
831 for ch in 0..NCHN {
832 for n in 0..NWORDS {
833 cal.v_offsets [ch][n] = f16::from_f32(self.v_offsets[ch][n]);
834 cal.v_dips [ch][n] = f16::from_f32(self.v_dips[ch][n]);
835 cal.v_inc [ch][n] = f16::from_f32(self.v_inc[ch][n]);
836 }
837 }
838 cal
839 }
840
841 pub fn clean_input_data(&mut self) {
843 self.vcal_data.retain(|x| !x.header.drs_lost_trigger()
844 && !x.header.is_event_fragment()
845 && trace_check(x));
846 self.tcal_data.retain(|x| !x.header.drs_lost_trigger()
847 && !x.header.is_event_fragment()
848 && trace_check(x));
849 self.noi_data.retain(|x| !x.header.drs_lost_trigger()
850 && !x.header.is_event_fragment()
851 && trace_check(x));
852 self.noi_data.sort_by(|a, b| a.header.event_id.cmp(&b.header.event_id));
853 self.vcal_data.sort_by(|a, b| a.header.event_id.cmp(&b.header.event_id));
854 self.tcal_data.sort_by(|a, b| a.header.event_id.cmp(&b.header.event_id));
855 }
856
857 fn apply_vcal(&self,
860 data : &Vec<RBEvent>)
861 -> (Vec<Vec<Vec<f32>>>,Vec<isize>) {
862 let nevents = data.len();
863 let mut traces = Vec::<Vec::<Vec::<f32>>>::new();
864 let mut trace = Vec::<f32>::with_capacity(NWORDS);
865 let mut stop_cells = Vec::<isize>::new();
866 let mut empty_events = Vec::<Vec::<f32>>::new();
867 for _ in 0..nevents {
868 empty_events.push(trace.clone());
869 }
870 for ch in 0..NCHN {
871 traces.push(empty_events.clone());
872 for (k,ev) in data.iter().enumerate() {
873 trace.clear();
874 stop_cells.push(ev.header.stop_cell as isize);
875 for k in 0..NWORDS {
876 trace.push(ev.adc[ch][k] as f32);
877 }
878 self.voltages(ch + 1, ev.header.stop_cell as usize,
879 &ev.adc[ch], &mut trace);
880 traces[ch][k] = trace.clone();
881 }
882 }
883 (traces, stop_cells)
884 }
885
886 pub fn apply_vcal_constants(&self,
888 adc : &Vec<f32>,
889 channel : usize,
890 stop_cell : usize) -> Vec<f32> {
891 let mut waveform = Vec::<f32>::with_capacity(adc.len());
892 let mut value : f32;
893 for k in 0..adc.len() {
894 value = adc[k] as f32;
895 value -= self.v_offsets[channel][(k + (stop_cell)) %NWORDS];
896 value -= self.v_dips [channel][k];
897 value *= self.v_inc [channel][(k + (stop_cell)) %NWORDS];
898 waveform.push(value);
899 }
900 waveform
901 }
902
903 fn voltage_offset_and_dips(input_vcal_data : &Vec<RBEvent>)
910 -> Result<(Vec<Vec<f32>>, Vec<Vec<f32>>), CalibrationError> {
911 if input_vcal_data.len() == 0 {
912 return Err(CalibrationError::EmptyInputData);
913 }
914 let mut all_v_offsets = Vec::<Vec::<f32>>::new();
915 let mut all_v_dips = Vec::<Vec::<f32>>::new();
916 let nchn = input_vcal_data[0].header.get_nchan();
917
918 debug!("Found {nchn} channels!");
919 for _ in 0..nchn {
920 let empty_vec_off : Vec<f32> = vec![0.0;NWORDS];
921 all_v_offsets.push(empty_vec_off);
922 let empty_vec_dip : Vec<f32> = vec![0.0;NWORDS];
923 all_v_dips.push(empty_vec_dip);
924 }
925
926 let mut traces = unpack_traces_f32(&input_vcal_data);
929 let mut rolled_traces = traces.clone();
930 for ch in 0..nchn {
931 for n in 0..input_vcal_data.len() {
932 for k in 0..Self::NSKIP {
933 traces[ch][n][k] = f32::NAN;
934 rolled_traces[ch][n][k] = f32::NAN;
935 }
936 roll(&mut rolled_traces[ch][n],
940 input_vcal_data[n].header.stop_cell as isize);
941 }all_v_offsets[ch] = calculate_column_means(&rolled_traces[ch]);
943 debug!("We calculated {} voltage offset values for ch {}", all_v_offsets[ch].len(), ch);
945 for (n, ev) in input_vcal_data.iter().enumerate() {
950 let mut v_offsets_rolled = all_v_offsets[ch].clone();
952 roll(&mut v_offsets_rolled, -1*ev.header.stop_cell as isize);
953 for k in 0..traces[ch][n].len() {
954 traces[ch][n][k] -= v_offsets_rolled[k];
955 }
956 }
957 let v_dips = calculate_column_medians(&traces[ch]);
958 for k in 0..v_dips.len() {
959 if k < Self::NSKIP {
960 all_v_dips[ch][k] = 0.0;
961 } else {
962 all_v_dips[ch][k] = v_dips[k];
963 }
964 }
965 }
966 Ok((all_v_offsets, all_v_dips))
967 }
968
969
970 pub fn timing_calibration(&self,
977 edge : &Edge,
978 apply_vcal : bool)
979 -> Result<Vec<Vec<f32>>, CalibrationError> {
980 if self.tcal_data.len() == 0 {
981 error!("Input data for timing calibration is empty!");
982 return Err(CalibrationError::EmptyInputData);
983 }
984 let mut all_tcal = Vec::<Vec::<f32>>::new();
986 for _ in 0..NCHN {
987 all_tcal.push(Vec::<f32>::new());
988 }
989 let mut traces : Vec<Vec<Vec<f32>>>;
991 let mut stop_cells = Vec::<isize>::new();
992 if apply_vcal {
993 let result = self.apply_vcal(&self.tcal_data);
994 traces = result.0;
995 stop_cells = result.1;
996 } else {
997 warn!("Not applying voltage calibration to tcal data. This most likely makes no sense!");
998 traces = unpack_traces_f32(&self.tcal_data);
999 for ev in self.tcal_data.iter() {
1000 stop_cells.push(ev.header.event_id as isize);
1001 }
1002 }
1003 let do_spike_cleaning = true;
1004 if do_spike_cleaning {
1005 for k_ch in 0..traces.len() {
1006 for k_ev in 0..traces[k_ch].len() {
1007 clean_spikes(&mut traces[k_ch][k_ev], true);
1008 }
1009 }
1010 }
1011 let nwords = traces[0][0].len();
1012 for ch in 0..NCHN {
1013 for ev in 0..traces[ch].len() {
1014 for k in 0..nwords {
1015 if k < Self::NSKIP {
1016 traces[ch][ev][k] = f32::NAN;
1017 }
1018 if f32::abs(traces[ch][ev][k]) > Self::SINMAX as f32 {
1019 traces[ch][ev][k] = f32::NAN;
1020 }}
1022 }
1023 }
1024
1025 let mut rolled_traces = traces.clone();
1026 let mut drolled_traces = traces.clone();
1027 for ch in 0..NCHN {
1028 for ev in 0..traces[ch].len() {
1029 roll(&mut rolled_traces[ch][ev],
1030 stop_cells[ev]);
1031 }
1032 }
1033 for ch in 0..NCHN {
1034 for ev in 0..traces[ch].len() {
1035 for n in 0..traces[ch][ev].len() {
1036 let mut dval : f32;
1037 if n == traces[ch][ev].len() - 1 {
1038 dval = rolled_traces[ch][ev][0] - rolled_traces[ch][ev][traces[ch][ev].len() -1];
1039 } else {
1040 dval = rolled_traces[ch][ev][n + 1] - rolled_traces[ch][ev][n];
1041 }
1042 match edge {
1043 Edge::Rising | Edge::Average => {
1044 if dval < 0.0 {
1045 dval = f32::NAN;
1046 }
1047 },
1048 Edge::Falling => {
1049 if dval > 0.0 {
1050 dval = f32::NAN;
1051 }
1052 },
1053 _ => {
1054 error!("Only average, rising or falling edge supported!");
1056 }
1057 } dval = f32::abs(dval);
1059 if f32::abs(dval - 15.0) > Self::DVCUT {
1060 dval = f32::NAN;
1061 }
1062 drolled_traces[ch][ev][n] = dval;
1063 } } let col_means = calculate_column_means(&drolled_traces[ch]);
1066 let nfreq_vec : Vec<f32> = vec![1.0/Self::NOMINALFREQ;NWORDS];
1067 all_tcal[ch] = nfreq_vec;
1068 let ch_mean = mean(&col_means);
1069 for n in 0..all_tcal[ch].len() {
1070 all_tcal[ch][n] *= col_means[n]/ch_mean;
1071 }
1072 } Ok(all_tcal)
1074 }
1075
1076 pub fn calibrate(&mut self) -> Result<(), CalibrationError>{
1079 if self.vcal_data.len() == 0
1080 || self.tcal_data.len() == 0
1081 || self.noi_data.len() == 0 {
1082 return Err(CalibrationError::EmptyInputData);
1083 }
1084 info!("Starting calculating voltage calibration constants!");
1085 let (v_offsets_high, _v_dips_high)
1086 = Self::voltage_offset_and_dips(&self.vcal_data)?;
1087 let (v_offsets_low, v_dips_low)
1088 = Self::voltage_offset_and_dips(&self.noi_data)?;
1089 for ch in 0..NCHN {
1091 for k in 0..NWORDS {
1092 self.v_offsets[ch][k] = v_offsets_low[ch][k];
1093 self.v_dips[ch][k] = v_dips_low[ch][k];
1094 self.v_inc[ch][k] = self.d_v/(v_offsets_high[ch][k] - v_offsets_low[ch][k]);
1095 }
1096 }
1097 info!("Filnished calculating voltage calibration constants!");
1099 info!("Starting calculating timing calibration constants!");
1100 warn!("Calibration only supported for Edge::Average!");
1101 let mut edge = Edge::None;
1105 if matches!(edge, Edge::None) {
1106 edge = Edge::Average;
1107 }
1108
1109 let mut tcal_av = self.timing_calibration( &edge, true)?;
1110 if matches!(edge, Edge::Average) {
1111 edge = Edge::Falling;
1112 let tcal_falling = self.timing_calibration(&edge, true)?;
1113 for ch in 0..NCHN {
1114 for k in 0..tcal_av.len() {
1115 tcal_av[ch][k] += tcal_falling[ch][k];
1116 tcal_av[ch][k] /= 2.0;
1117 }
1118 }
1119 edge = Edge::Rising;
1121 } else {
1122 error!("This is not implemented for any other case yet!");
1123 todo!();
1124 }
1125
1126 let mut damping : f32 = 0.1;
1129 let corr_limit : f32 = 0.05;
1130 let nperiod = Self::NOMINALFREQ/Self::CALFREQ;
1133 let global = true;
1134 if global {
1135
1136 let result = self.apply_vcal(&self.tcal_data);
1140 let tcal_traces = result.0;
1141 let stop_cells = result.1;
1142
1143 for ch in 0..NCHN {
1145 for ev in 0..tcal_traces[ch].len() {
1146 let tracelen = tcal_traces[ch][ev].len();
1147 let stop_cell = stop_cells[ev];
1148 let mut tcal_av_cp = tcal_av.clone();
1149 roll(&mut tcal_av_cp[ch], -1* (stop_cell as isize));
1150
1151 let (zcs, periods) = get_periods(&tcal_traces[ch][ev],
1152 &tcal_av_cp[ch],
1153 nperiod,
1154 Self::NSKIP as f32,
1155 &edge);
1156 debug!("Will iterate over {} periods!", periods.len());
1157 for (n_p,period) in periods.iter().enumerate() {
1158 if *period == 0.0 {
1159 warn!("period is 0 {:?}", periods);
1160 }
1161 if period.is_nan() {
1162 warn!("period is nan! {:?}", periods);
1163 }
1164 let zcs_a = zcs[n_p] + stop_cell as usize;
1165 let zcs_b = zcs[n_p + 1] + stop_cell as usize;
1166 let mut corr = (1.0/Self::CALFREQ)/period;
1167 if matches!(edge, Edge::None) {
1168 corr *= 0.5;
1169 }
1170 if f32::abs(corr - 1.0) > corr_limit {
1171 continue;
1172 }
1173 corr = (corr-1.0)*damping + 1.0;
1174 let zcs_a_tl = zcs_a%tracelen;
1175 let zcs_b_tl = zcs_b%tracelen;
1176 if zcs_a < tracelen && zcs_b > tracelen {
1177 for m in zcs_a..tcal_av[ch].len() {
1178 tcal_av[ch][m] *= corr;
1179 }
1180 for m in 0..zcs_b_tl {
1181 tcal_av[ch][m] *= corr;
1182 }
1183 } else {
1184 for m in zcs_a_tl..zcs_b_tl {
1185 tcal_av[ch][m] *= corr;
1186 }
1187 }
1188 }
1189 } damping *= 0.99;
1192 } } for ch in 0..NCHN {
1196 for k in 0..NWORDS {
1197 self.tbin[ch][k] = tcal_av[ch][k];
1198 }
1199 }
1200 Ok(())
1201 }
1202
1203 pub fn spike_cleaning(voltages : &mut Vec<Vec<f32>>,
1205 stop_cell : u16)
1206 -> Result<(), WaveformError> {
1207
1208 let mut spikes : [i32;10] = [0;10];
1209 let mut filter : f32;
1210 let mut dfilter : f32;
1211 let mut n_neighbor : usize;
1212 let mut n_rsp = 0usize;
1213 let mut rsp : [i32;10] = [-1;10];
1214 let mut sp : [[usize;10];NCHN] = [[0;10];NCHN];
1217 let mut n_sp : [usize;10] = [0;10];
1218
1219 for j in 0..NWORDS as usize {
1220 for i in 0..NCHN as usize {
1221 filter = -voltages[i][j] + voltages[i][(j + 1) % NWORDS] + voltages[i][(j + 2) % NWORDS] - voltages[i][(j + 3) % NWORDS];
1222 dfilter = filter + 2.0 * voltages[i][(j + 3) % NWORDS] + voltages[i][(j + 4) % NWORDS] - voltages[i][(j + 5) % NWORDS];
1223 if filter > 20.0 && filter < 100.0 {
1224 if n_sp[i] < 10 { sp[i][n_sp[i] as usize] = (j + 1) % NWORDS ;
1226 n_sp[i] += 1;
1227 } else {
1228 return Err(WaveformError::TooSpiky);
1229 } }else if dfilter > 40.0 && dfilter < 100.0 && filter > 10.0 {
1232 if n_sp[i] < 9 { sp[i][n_sp[i] as usize] = (j + 1) % NWORDS ;
1234 sp[i][(n_sp[i] + 1) as usize] = (j + 3) % NWORDS ;
1235 n_sp[i] += 2;
1236 } else {
1237 return Err(WaveformError::TooSpiky);
1238 } } }} for i in 0..NCHN {
1246 for j in 0..n_sp[i] as usize {
1247 n_neighbor = 0;
1249 for k in 0..NCHN {
1250 for l in 0..n_sp[k] as usize {
1251 if (sp[i][j] as i32 + sp[k][l] as i32 - 2 * stop_cell as i32) as i32 % NWORDS as i32 == 1022 {
1253 break;
1255 }
1256 }
1257 } for k in 0..NCHN {
1261 if i != k {
1262 for l in 0..n_sp[k] {
1263 if sp[i][j] == sp[k][l] {
1264 n_neighbor += 1;
1265 break;
1266 }
1267 } } } if n_neighbor >= 2 {
1272 for k in 0..n_rsp {
1273 if rsp[k] == sp[i][j] as i32 {break;} if n_rsp < 10 && k == n_rsp {
1275 rsp[n_rsp] = sp[i][j] as i32;
1276 n_rsp += 1;
1277 }
1278 }
1279 }
1280
1281 } } let magic_value : f32 = 14.8;
1287 let mut x : f32;
1288 let mut y : f32;
1289
1290 let mut skip_next : bool = false;
1291 for k in 0..n_rsp {
1292 if skip_next {
1293 skip_next = false;
1294 continue;
1295 }
1296 spikes[k] = rsp[k];
1297 for i in 0..NCHN {
1299 if k < n_rsp && i32::abs(rsp[k] as i32 - rsp[k + 1] as i32 % NWORDS as i32) == 2
1300 {
1301 let j = if rsp[k] > rsp[k + 1] {rsp[k + 1] as usize} else {rsp[k] as usize};
1303 x = voltages[i][(j - 1) % NWORDS];
1304 y = voltages[i][(j + 4) % NWORDS];
1305 if f32::abs(x - y) < 15.0 {
1306 voltages[i][j % NWORDS] = x + 1.0 * (y - x) / 5.0;
1307 voltages[i][(j + 1) % NWORDS] = x + 2.0 * (y - x) / 5.0;
1308 voltages[i][(j + 2) % NWORDS] = x + 3.0 * (y - x) / 5.0;
1309 voltages[i][(j + 3) % NWORDS] = x + 4.0 * (y - x) / 5.0;
1310 } else {
1311 voltages[i][j % NWORDS] -= magic_value;
1312 voltages[i][(j + 1) % NWORDS] -= magic_value;
1313 voltages[i][(j + 2) % NWORDS] -= magic_value;
1314 voltages[i][(j + 3) % NWORDS] -= magic_value;
1315 }
1316 } else {
1317 x = voltages[i][((rsp[k] - 1) % NWORDS as i32) as usize];
1319 y = voltages[i][(rsp[k] + 2) as usize % NWORDS];
1320 if f32::abs(x - y) < 15.0 {
1321 voltages[i][rsp[k] as usize] = x + 1.0 * (y - x) / 3.0;
1322 voltages[i][(rsp[k] + 1) as usize % NWORDS] = x + 2.0 * (y - x) / 3.0;
1323 } else {
1324 voltages[i][rsp[k] as usize] -= magic_value;
1325 voltages[i][(rsp[k] + 1) as usize % NWORDS] -= magic_value;
1326 }
1327 } } if k < n_rsp && i32::abs(rsp[k] - rsp[k + 1] % NWORDS as i32) == 2
1330 {skip_next = true;} } Ok(())
1333 }
1334
1335 pub fn voltages(&self,
1348 channel : usize,
1349 stop_cell : usize,
1350 adc : &Vec<u16>,
1351 waveform : &mut Vec<f32>) {
1352 if channel > 9 || channel == 0 {
1354 error!("There is no channel larger than 9 and no channel 0! Channel {channel} was requested. Can not perform voltage calibration!");
1355 return;
1356 }
1357 if adc.len() != waveform.len() {
1358 error!("Ch{} has {} adc values, however we are expecting {}!", channel, adc.len(), waveform.len());
1359 return;
1360 }
1361
1362 let mut value : f32;
1363 for k in 0..NWORDS {
1364 value = adc[k] as f32;
1365 value -= self.v_offsets[channel -1][(k + (stop_cell)) %NWORDS];
1366 value -= self.v_dips [channel -1][k];
1367 value *= self.v_inc [channel -1][(k + (stop_cell)) %NWORDS];
1368 waveform[k] = value;
1369 }
1370 }
1371
1372 pub fn nanoseconds(&self,
1382 channel : usize,
1383 stop_cell : usize,
1384 times : &mut Vec<f32>) {
1385 if channel > 9 || channel == 0 {
1386 error!("There is no channel larger than 9 and no channel 0! Channel {channel} was requested. Can not perform timing calibration!");
1387 }
1388 for k in 1..NWORDS {
1389 times[k] = times[k-1] + self.tbin[channel -1][(k-1+(stop_cell))%NWORDS];
1390 }
1391 }
1392
1393 pub fn new(rb_id : u8) -> Self {
1394 let timestamp = Utc::now().timestamp() as u32;
1395 Self {
1396 rb_id : rb_id,
1397 d_v : 182.0, timestamp : timestamp,
1399 serialize_event_data : false, v_offsets : [[0.0;NWORDS];NCHN],
1401 v_dips : [[0.0;NWORDS];NCHN],
1402 v_inc : [[0.0;NWORDS];NCHN],
1403 tbin : [[0.0;NWORDS];NCHN],
1404 vcal_data : Vec::<RBEvent>::new(),
1405 tcal_data : Vec::<RBEvent>::new(),
1406 noi_data : Vec::<RBEvent>::new()
1407 }
1408 }
1409
1410 pub fn discard_data(&mut self) {
1412 self.vcal_data = Vec::<RBEvent>::new();
1413 self.tcal_data = Vec::<RBEvent>::new();
1414 self.noi_data = Vec::<RBEvent>::new();
1415 }
1416
1417 pub fn from_file(filename : String, discard_data : bool) -> Result<Self, SerializationError> {
1423 let mut reader = TofPacketReader::new(filename);
1424 loop {
1425 match reader.next() {
1426 None => {
1427 error!("Can't load calibration!");
1428 break;
1429 },
1430 Some(pack) => {
1431 if pack.packet_type == PacketType::RBCalibration {
1432 let mut cali = RBCalibrations::from_bytestream(&pack.payload, &mut 0)?;
1433 if discard_data {
1434 cali.discard_data();
1435 }
1436 return Ok(cali);
1437 } else {
1438 continue;
1439 }
1440 }
1441 }
1442 }
1443 Err(SerializationError::StreamTooShort)
1444 }
1445
1446
1447 pub fn from_txtfile(filename : &Path) -> Self {
1458 let mut rb_cal = Self::new(0);
1459 rb_cal.get_id_from_filename(&filename);
1460 info!("Attempting to open file {}", filename.display());
1461 let file = BufReader::new(File::open(filename).expect("Unable to open file {}"));
1462 let mut cnt = 0;
1464 for _ in file.lines() {
1465 cnt += 1;
1466 }
1467 if cnt != NCHN*4 {
1468 panic! ("The calibration file {} does not have the proper format! It has {} lines", filename.display(), cnt);
1469 }
1470 cnt = 0;
1471 let mut vals = 0usize;
1472
1473 if let Ok(lines) = read_lines(filename) {
1474 for data in lines.flatten() {
1476 let values: Vec<&str> = data.split(' ').collect();
1477 if values.len() == NWORDS {
1478 if vals == 0 {
1479 for n in 0..NWORDS {
1480 let data : f32 = values[n].parse::<f32>().unwrap();
1484 rb_cal.v_offsets[cnt][n] = data;
1485 }
1487 vals += 1;
1488 continue;
1489 }
1490 if vals == 1 {
1491 for n in 0..NWORDS {
1492 let data : f32 = values[n].parse::<f32>().unwrap();
1496 rb_cal.v_dips[cnt][n] = data;
1497 }
1499 vals += 1;
1500 continue;
1501 }
1502 if vals == 2 {
1503 for n in 0..NWORDS {
1504 let data : f32 = values[n].parse::<f32>().unwrap();
1508 rb_cal.v_inc[cnt][n] = data;
1509 }
1511 vals += 1;
1512 continue;
1513 }
1514 if vals == 3 {
1515 for n in 0..NWORDS {
1516 let data : f32 = values[n].parse::<f32>().unwrap();
1520 rb_cal.tbin[cnt][n] = data;
1521 }
1524 vals = 0;
1525 cnt += 1;
1526 continue;
1527 }
1528 } else {
1529 panic!("Invalid input line {}", data)
1530 }
1531 vals += 1;
1532 }
1533 }
1534 rb_cal
1535 }
1536
1537 pub fn get_id_from_filename(&mut self, filename : &Path) -> u8 {
1542 let rb_id : u8;
1543 match filename.file_name() {
1544 None => {
1545 error!("Path {} seems non-sensical!", filename.display());
1546 self.rb_id = 0;
1547 return 0;
1548 }
1549 Some(name) => {
1550 let fname = name.to_os_string().into_string().unwrap();
1552 let id = &fname[2..4];
1553 rb_id = id.parse::<u8>().unwrap();
1555 debug!("Extracted RB ID {} from filename {}", rb_id, fname);
1556 }
1557 }
1558 self.rb_id = rb_id;
1559 rb_id
1560 }
1561}
1562
1563impl Packable for RBCalibrations {
1564 const PACKET_TYPE : PacketType = PacketType::RBCalibration;
1565}
1566
1567impl Serialization for RBCalibrations {
1568 const SIZE : usize = NCHN*NWORDS*4*8 + 4 + 1 + 1;
1569 const HEAD : u16 = 0xAAAA; const TAIL : u16 = 0x5555; fn from_bytestream(bytestream : &Vec<u8>,
1573 pos : &mut usize)
1574 -> Result<Self, SerializationError> {
1575 let mut rb_cal = Self::new(0);
1576 if parse_u16(bytestream, pos) != Self::HEAD {
1577 return Err(SerializationError::HeadInvalid {});
1578 }
1579 rb_cal.rb_id = parse_u8(bytestream, pos);
1580 rb_cal.d_v = parse_f32(bytestream, pos);
1581 rb_cal.timestamp = parse_u32(bytestream, pos);
1582 rb_cal.serialize_event_data = parse_bool(bytestream, pos);
1583 for ch in 0..NCHN {
1584 for k in 0..NWORDS {
1585 let mut value = parse_f32(bytestream, pos);
1586 rb_cal.v_offsets[ch][k] = value;
1587 value = parse_f32(bytestream, pos);
1588 rb_cal.v_dips[ch][k] = value;
1589 value = parse_f32(bytestream, pos);
1590 rb_cal.v_inc[ch][k] = value;
1591 value = parse_f32(bytestream, pos);
1592 rb_cal.tbin[ch][k] = value;
1593 }
1594 }
1595 if rb_cal.serialize_event_data {
1596 let broken_event = RBEvent::new();
1597 let n_noi = parse_u16(bytestream, pos);
1598 debug!("Found {n_noi} no input data events!");
1599 for _ in 0..n_noi {
1600 match RBEvent::from_bytestream(bytestream, pos) {
1601 Ok(ev) => {
1602 rb_cal.noi_data.push(ev);
1603 }
1604 Err(err) => {
1605 error!("Unable to read RBEvent! {err}");
1606 }
1607 }
1608 }
1610 let n_vcal = parse_u16(bytestream, pos);
1611 debug!("Found {n_vcal} VCal data events!");
1612 for _ in 0..n_vcal {
1613 match RBEvent::from_bytestream(bytestream, pos) {
1614 Err(err) => {
1615 error!("Found broken event {err}");
1616 },
1617 Ok(good_ev) => {
1618 rb_cal.vcal_data.push(good_ev);
1619 }
1620 }
1621 }
1622 let n_tcal = parse_u16(bytestream, pos);
1623 debug!("Found {n_tcal} TCal data events!");
1624 for _ in 0..n_tcal {
1625 rb_cal.tcal_data.push(RBEvent::from_bytestream(bytestream, pos).unwrap_or(broken_event.clone()));
1626 }
1627 } else {
1628 *pos += 6;
1631 }
1632 if parse_u16(bytestream, pos) != Self::TAIL {
1633 return Err(SerializationError::TailInvalid {});
1634 }
1635 Ok(rb_cal)
1636 }
1637
1638 fn to_bytestream(&self) -> Vec<u8> {
1639 let mut bs = Vec::<u8>::with_capacity(Self::SIZE);
1640 bs.extend_from_slice(&Self::HEAD.to_le_bytes());
1641 bs.extend_from_slice(&self.rb_id.to_le_bytes());
1642 bs.extend_from_slice(&self.d_v.to_le_bytes());
1643 bs.extend_from_slice(&self.timestamp.to_le_bytes());
1644 let serialize_event_data = self.serialize_event_data as u8;
1645 bs.push(serialize_event_data);
1646 for ch in 0..NCHN {
1647 for k in 0..NWORDS {
1648 bs.extend_from_slice(&self.v_offsets[ch][k].to_le_bytes());
1649 bs.extend_from_slice(&self.v_dips[ch][k] .to_le_bytes());
1650 bs.extend_from_slice(&self.v_inc[ch][k] .to_le_bytes());
1651 bs.extend_from_slice(&self.tbin[ch][k] .to_le_bytes());
1652 }
1653 }
1654 if self.serialize_event_data {
1655 info!("Serializing calibration event data!");
1656 let n_noi = self.noi_data.len() as u16;
1657 let n_vcal = self.vcal_data.len() as u16;
1658 let n_tcal = self.tcal_data.len() as u16;
1659 bs.extend_from_slice(&n_noi.to_le_bytes());
1660 for ev in &self.noi_data {
1661 bs.extend_from_slice(&ev.to_bytestream());
1662 }
1663 bs.extend_from_slice(&n_vcal.to_le_bytes());
1664 for ev in &self.vcal_data {
1665 bs.extend_from_slice(&ev.to_bytestream());
1666 }
1667 bs.extend_from_slice(&n_tcal.to_le_bytes());
1668 for ev in &self.tcal_data {
1669 bs.extend_from_slice(&ev.to_bytestream());
1670 }
1671 } else { for _ in 0..6 {
1675 bs.push(0);
1676 }
1677 }
1681 bs.extend_from_slice(&Self::TAIL.to_le_bytes());
1682 bs
1683 }
1684}
1685
1686impl Default for RBCalibrations {
1687 fn default() -> Self {
1688 Self::new(0)
1689 }
1690}
1691
1692impl fmt::Display for RBCalibrations {
1693 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1694 let mut timestamp_str = String::from("?");
1695 match Utc.timestamp_opt(self.timestamp.into(), 0) {
1696 LocalResult::Single(datetime_utc) => {
1697 timestamp_str = datetime_utc.format("%Y/%m/%d %H:%M:%S").to_string();
1698 },
1699 LocalResult::Ambiguous(_, _) => {
1700 println!("The given timestamp is ambiguous.");
1701 },
1702 LocalResult::None => {
1703 println!("The given timestamp is not valid.");
1704 },
1705 }
1706
1707 write!(f,
1709 "<ReadoutboardCalibration [{} UTC]:
1710 RB : {}
1711 VCalData : {} (events)
1712 TCalData : {} (events)
1713 NoInputData : {} (events)
1714 V Offsets [ch0]: .. {:?} {:?} ..
1715 V Incrmts [ch0]: .. {:?} {:?} ..
1716 V Dips [ch0]: .. {:?} {:?} ..
1717 T Bins [ch0]: .. {:?} {:?} ..>",
1718 timestamp_str,
1719 self.rb_id,
1720 self.vcal_data.len(),
1721 self.tcal_data.len(),
1722 self.noi_data.len(),
1723 self.v_offsets[0][98],
1724 self.v_offsets[0][99],
1725 self.v_inc[0][98],
1726 self.v_inc[0][99],
1727 self.v_dips[0][98],
1728 self.v_dips[0][99],
1729 self.tbin[0][98],
1730 self.tbin[0][99])
1731 }
1732}
1733
1734
1735impl From<&Path> for RBCalibrations {
1736
1737 fn from(path : &Path) -> Self {
1739 let mut cali = RBCalibrations::new(0);
1740 if path.ends_with(".txt") {
1741 return RBCalibrations::from_txtfile(path);
1742 } else {
1743 match read_file(path) {
1744 Err(err) => {
1745 error!("Can not open {}! Err {err}", path.display());
1746 },
1747 Ok(stream) => {
1748 match TofPacket::from_bytestream(&stream, &mut 0) {
1750 Err(err) => {
1751 error!("Can not read TofPacket, error {err}");
1752 }
1753 Ok(pk) => {
1754 if pk.packet_type != PacketType::RBCalibration {
1755 error!("TofPacket does not contain calibration data! Packet: {}", pk);
1756 return cali;
1757 }
1758 match RBCalibrations::from_bytestream(&pk.payload, &mut 0) {
1759 Err(err) => {
1760 error!("Can not read calibration from binary file {}, Error {err}!", path.display());
1761 },
1762 Ok(c) => {
1763 cali = c;
1764 }
1765 }
1766 }
1767 }
1768 }
1769 }
1770 return cali;
1771 }
1772 }
1773}
1774
1775#[cfg(feature = "random")]
1776impl FromRandom for RBCalibrations {
1777
1778 fn from_random() -> Self {
1779 let mut cali = Self::new(0);
1780 let mut rng = rand::thread_rng();
1781 cali.rb_id = rng.gen::<u8>();
1782 cali.d_v = rng.gen::<f32>();
1783 cali.serialize_event_data = rng.gen::<bool>();
1784 for ch in 0..NCHN {
1785 for n in 0..NWORDS {
1786 cali.v_offsets[ch][n] = rng.gen::<f32>();
1787 cali.v_dips [ch][n] = rng.gen::<f32>();
1788 cali.v_inc [ch][n] = rng.gen::<f32>();
1789 cali.tbin [ch][n] = rng.gen::<f32>();
1790 }
1791 }
1792 if cali.serialize_event_data {
1793 for _ in 0..1000 {
1794 let mut ev = RBEvent::from_random();
1795 cali.vcal_data.push(ev);
1796 ev = RBEvent::from_random();
1797 cali.noi_data.push(ev);
1798 ev = RBEvent::from_random();
1799 cali.tcal_data.push(ev);
1800 }
1801 }
1802 cali
1803 }
1804}
1805
1806#[cfg(feature = "random")]
1807#[test]
1808fn serialization_rbcalibration_noeventpayload() {
1809 let mut calis = Vec::<RBCalibrations>::new();
1810 for _ in 0..100 {
1811 let cali = RBCalibrations::from_random();
1812 if cali.serialize_event_data {
1813 continue;
1814 }
1815 calis.push(cali);
1816 break;
1817 }
1818 let test = RBCalibrations::from_bytestream(&calis[0].to_bytestream(), &mut 0).unwrap();
1819 assert_eq!(calis[0], test);
1820}
1821
1822#[cfg(feature = "random")]
1823#[test]
1824fn serialization_rbcalibration_witheventpayload() {
1825 let mut calis = Vec::<RBCalibrations>::new();
1826 for _ in 0..100 {
1827 let cali = RBCalibrations::from_random();
1828 if !cali.serialize_event_data {
1829 continue;
1830 }
1831 calis.push(cali);
1832 break;
1833 }
1834 let test = RBCalibrations::from_bytestream(&calis[0].to_bytestream(), &mut 0).unwrap();
1835 assert_eq!(calis[0], test);
1836}
1837
1838#[cfg(feature = "random")]
1868#[test]
1869fn pack_rbcalibfilghtt() {
1870 for _ in 0..100 {
1871 let cfg = RBCalibrationsFlightT::from_random();
1872 let test : RBCalibrationsFlightT = cfg.pack().unpack().unwrap();
1873 assert_eq!(cfg, test);
1874 }
1875}
1876
1877#[cfg(feature = "random")]
1878#[test]
1879fn pack_rbcalibfilghtv() {
1880 for _ in 0..100 {
1881 let cfg = RBCalibrationsFlightV::from_random();
1882 let test : RBCalibrationsFlightV = cfg.pack().unpack().unwrap();
1883 assert_eq!(cfg, test);
1884 }
1885}
1886
1887#[cfg(feature = "random")]
1888#[test]
1889fn assemble_flightcal() {
1890 for _ in 0..10 {
1891 let cal = RBCalibrations::from_random();
1892 let fct = cal.emit_flighttcal();
1893 let fcv = cal.emit_flightvcal();
1894 let test = RBCalibrations::assemble_from_flightcal(fct, fcv).unwrap();
1895 assert_eq!(cal.rb_id, test.rb_id);
1896 assert_eq!(cal.d_v , test.d_v);
1897 assert_eq!(cal.timestamp, test.timestamp);
1898 assert_eq!(test.serialize_event_data, false);
1899 for ch in 0..NCHN {
1900 for k in 0..NWORDS {
1901 assert_eq!(f16::from_f32(cal.tbin[ch][k]), f16::from_f32(test.tbin[ch][k]));
1902 assert_eq!(f16::from_f32(cal.v_offsets[ch][k]),f16::from_f32(test.v_offsets[ch][k]));
1903 assert_eq!(f16::from_f32(cal.v_dips[ch][k]), f16::from_f32(test.v_dips[ch][k]));
1904 assert_eq!(f16::from_f32(cal.v_inc[ch][k]), f16::from_f32(test.v_inc[ch][k]));
1905 }
1906 }
1907 }
1908}
1909