1use crate::prelude::*;
7
8pub fn get_max_value_idx<T : std::cmp::PartialOrd + std::fmt::Display + Copy>(values : &[T],
18 start_idx : usize,
19 n_idx : usize) -> Result<usize, WaveformError> {
20 if start_idx >= values.len() {
21 error!("Invalid value for start index {}", start_idx);
22 return Err(WaveformError::OutOfRangeLowerBound);
23 }
24 if start_idx + n_idx >= values.len() {
25 error!("Start index {} + n steps of {} is larger tan array size!", start_idx, n_idx);
26 return Err(WaveformError::OutOfRangeUpperBound);
27 }
28 let mut maxval = values[start_idx];
29 let mut maxbin = start_idx;
30 for n in start_idx..start_idx + n_idx {
31 if values[n] > maxval {
32 maxval = values[n];
33 maxbin = n;
34 }
35 } trace!("Got index {} for a max value of {}", maxbin, maxval);
37 Ok(maxbin)
38} pub fn time_over_threshold(voltages : &Vec<f32>, times : &Vec<f32>,threshold : f32) -> (f32, f32) {
48 let mut tot : f32 = 0.0;
49 let mut vlt_0 : f32 = -1.0;
50 let mut vlt_1 : f32 = -1.0;
51 let mut t_0 : f32 = -1.0;
52 let mut t_1 : f32 = -1.0;
53 for k in 1..voltages.len() {
54 if voltages[k] > threshold {
55 tot += times[k] - times[k-1];
56 if k > 1 && k < voltages.len() - 2 {
57 if vlt_0 < 0.0 {
58 vlt_0 = voltages[k - 2];
59 t_0 = times[k - 2];
60 }
61 if vlt_1 < 0.0 {
62 vlt_1 = voltages[k + 2];
63 t_1 = times[k + 2];
64 }
65 }
66 }
67 }
68 let slope = (vlt_1 - vlt_0)/(t_1 - t_0);
69 return (tot, slope);
70}
71
72#[cfg(feature="pybindings")]
75#[pyfunction]
76#[pyo3(name="get_max_value_idx")]
77pub fn get_max_value_idx_py<'_py>(value : Bound<'_py,PyArray1<f32>>,
78 start_idx :usize,
79 n_idx : usize) -> PyResult<usize> {
80 unsafe {
81 match get_max_value_idx::<f32>(value.as_slice().unwrap(), start_idx, n_idx) {
82 Err(err) => {
83 return Err(PyValueError::new_err(err.to_string()));
84 }
85 Ok(max_val) => {
86 return Ok(max_val);
87 }
88 }
89 }
90}
91
92pub fn interpolate_time<T : AsRef<[f32]>> (volts : &T,
106 times : &T,
107 mut threshold : f32,
108 mut idx : usize,
109 size : usize) -> Result<f32, WaveformError> {
110 let voltages = volts.as_ref();
111 let nanoseconds = times.as_ref();
112 if idx + 1 > nanoseconds.len() {
113 return Err(WaveformError::OutOfRangeUpperBound);
114 }
115 threshold = threshold.abs();
116 let mut lval = (voltages[idx]).abs();
117 let mut hval : f32 = 0.0;
118 if size == 1 {
119 hval = (voltages[idx+1]).abs();
120 } else {
121 for n in idx+1..idx+size {
122 hval = voltages[n].abs();
123 if (hval>=threshold) && (threshold<=lval) { idx = n-1; break;
126 }
127 lval = hval;
128 }
129 }
130 if ((lval > threshold) && (size != 1)) || lval == hval {
131 return Ok(nanoseconds[idx]);
132 } else {
133 return Ok(nanoseconds[idx]
134 + (threshold-lval)/(hval-lval) * (nanoseconds[idx+1]
135 - nanoseconds[idx]));
136 }
137}
138
139
140#[cfg(feature = "pybindings")]
141#[pyfunction]
142#[pyo3(name="interpolate_time")]
143pub fn interpolate_time_py(voltages : PyReadonlyArray1<f32>,
157 nanoseconds : PyReadonlyArray1<f32>,
158 threshold : f32,
159 idx : usize,
160 size : usize) -> PyResult<f32> {
161 let i = idx;
162 match interpolate_time(&voltages.readonly().as_slice().unwrap(),
163 &nanoseconds.readonly().as_slice().unwrap(),
164 threshold, i, size) {
165 Ok(time) => {
166 return Ok(time);
167 }
168 Err(err) => {
169 return Err(PyValueError::new_err(err.to_string()));
170 }
171 }
172}
173
174
175pub fn integrate(voltages : &Vec<f32>,
185 nanoseconds : &Vec<f32>,
186 lo_bin : usize,
187 upper_bin : usize,
188 impedance : f32) -> Result<f32, WaveformError> {
189 if upper_bin > voltages.len() {
190 return Err(WaveformError::OutOfRangeUpperBound);
191 }
192 if lo_bin < 1 {
193 return Err(WaveformError::OutOfRangeLowerBound);
194 }
195 let mut sum = 0f32;
196 for n in lo_bin..upper_bin {
197 sum += voltages[n] * (nanoseconds[n] - nanoseconds[n-1]) ;
198 }
199 sum /= impedance;
200 Ok(sum)
201}
202
203pub fn time2bin(nanoseconds : &Vec<f32>,
207 t_ns : f32) -> Result<usize, WaveformError> {
208 for n in 0..nanoseconds.len() {
209 if nanoseconds[n] > t_ns {
210 return Ok(n-1);
211 }
212 }
213 debug!("Did not find a bin corresponding to the given time {}!", t_ns);
214 return Err(WaveformError::TimesTooSmall);
215}
216
217pub fn calculate_pedestal(voltages : &Vec<f32>,
232 threshold : f32,
233 ped_begin_bin : usize,
234 ped_range_bin : usize) -> (f32,f32) {
235 let mut sum = 0f32;
236 let mut sum2 = 0f32;
237 for k in ped_begin_bin..ped_begin_bin + ped_range_bin {
238 if f32::abs(voltages[k]) < threshold {
239 sum += voltages[k];
240 sum2 += voltages[k]*voltages[k];
241 }
242 }
243 let average = sum/(ped_range_bin as f32);
244 let sigma = f32::sqrt(sum2/(ped_range_bin as f32 - (average*average)));
245 (average, sigma)
246}
247
248pub fn cfd_simple(voltages : &Vec<f32>,
254 nanoseconds : &Vec<f32>,
255 cfd_frac : f32,
256 start_peak : usize,
257 end_peak : usize) -> Result<f32, WaveformError> {
258
259 let idx = get_max_value_idx(&voltages, start_peak, end_peak-start_peak)?;
260 let mut sum : f32 = 0.0;
261 for n in idx-1..idx+1{
262 sum += voltages[n];
263 }
264 let tmp_thresh : f32 = f32::abs(cfd_frac * (sum / 3.0));
265 trace!("Calculated tmp threshold of {}", tmp_thresh);
266 let mut lo_bin : usize = voltages.len();
271 let mut n = idx;
272 if idx < start_peak {
273 error!("The index {} is smaller than the beginning of the peak {}!", idx, start_peak);
274 return Err(WaveformError::OutOfRangeLowerBound);
275 }
276 if start_peak >= 10 {
277 while n > start_peak - 10 {
278 if f32::abs(voltages[n]) < tmp_thresh {
279 lo_bin = n;
280 break;
281 }
282 n -= 1;
283 }
284 } else {
285 debug!("We require that the peak is at least 10 bins away from the start!");
286 return Err(WaveformError::OutOfRangeLowerBound);
287 }
288
289 trace!("Lo bin {} , start peak {}", lo_bin, start_peak);
290 let cfd_time : f32;
291 if lo_bin < nanoseconds.len() -1 {
292 cfd_time = interpolate_time(voltages, nanoseconds, tmp_thresh, lo_bin, 1)?;
293 } else {
294 cfd_time = nanoseconds[nanoseconds.len() - 1];
295 }
296 Ok(cfd_time)
297}
298
299pub fn find_peaks(voltages : &Vec<f32>,
319 nanoseconds : &Vec<f32>,
320 start_time : f32,
321 window_size : f32,
322 min_peak_width : usize,
323 threshold : f32,
324 max_peaks : usize)
325-> Result<Vec<(usize,usize)>, WaveformError> {
326 let mut peaks = Vec::<(usize,usize)>::new();
327 let mut start_bin = time2bin(nanoseconds, start_time)?;
328 if start_bin <= 10 {
329 debug!("We deliberatly do not search for peaks within the first 10 bins! Correcting..");
330 start_bin = 10;
331 }
332 let window_bin = time2bin(nanoseconds, start_time + window_size)? - start_bin;
333 if start_bin + window_bin > voltages.len () {
334 return Err(WaveformError::OutOfRangeUpperBound);
335 }
336
337 let mut pos = 0usize;
338 for k in start_bin..start_bin + window_bin {
341 if voltages[k] >= threshold {
342 pos = k;
343 break;
344 }
345 }
346 if pos == 0 && start_bin == 0 && voltages[pos] < threshold {
347 return Err(WaveformError::DidNotCrossThreshold)
349 }
350 let mut nbins_peak = 0usize;
352 let mut begin_peak = pos;
353 let mut end_peak : usize;
354 if (pos + window_bin) > voltages.len() {
355 return Err(WaveformError::OutOfRangeUpperBound);
356 }
357 for k in pos..(pos + window_bin) {
358 if voltages[k] >= threshold {
359 nbins_peak += 1;
360 let mut slope = 0i16; if nbins_peak == min_peak_width {
367 begin_peak = k - min_peak_width -1;
369 } else if nbins_peak > min_peak_width {
370 for j in 0..min_peak_width {
371 if voltages[k -j] > voltages[k-j-1] {
372 slope = 1; }
374 }
375 if slope == 1 {
376 continue;
378 }
379 if slope == 0 {
380 end_peak = k;
382 nbins_peak = 0; peaks.push((begin_peak, end_peak));
384 if peaks.len() == max_peaks {
385 break;
386 }
387 }
388 } } else {
392 if nbins_peak > min_peak_width {
393 end_peak = k;
394 peaks.push((begin_peak, end_peak));
395 if peaks.len() == max_peaks {
396 break;
397 }
398 }
399 nbins_peak = 0;
400 }
401 }
402 let len_pks_dirty = peaks.len();
404 peaks.retain(|&x| {(x.0 < NWORDS - 1) & (x.1 <= NWORDS - 1)});
405 let len_pks_clean = peaks.len();
406 if len_pks_clean != len_pks_dirty {
407 debug!("We removed {} pks because they had values outside of 0-{}!", len_pks_dirty - len_pks_clean, NWORDS);
408 }
409 Ok(peaks)
410}
411
412
413#[cfg(feature = "advanced-algorithms")]
414fn find_sequence_ranges(vec: Vec<usize>) -> Vec<(usize, usize)> {
415 let mut ranges = Vec::new();
416 let mut start = vec[0];
417 let mut end = vec[0];
418
419 for &value in vec.iter().skip(1) {
420 if value == end + 1 {
421 end = value;
423 } else {
424 ranges.push((start, end));
426 start = value;
427 end = value;
428 }
429 }
430
431 ranges.push((start, end));
433 ranges
434}
435
436#[cfg(feature = "advanced-algorithms")]
437pub fn find_peaks_zscore(nanoseconds : &Vec<f32>,
490 voltages : &Vec<f32>,
491 start_time : f32,
492 window_size : f32,
493 lag : usize,
494 threshold : f64,
495 influence : f64)
496-> Result<Vec<(usize,usize)>, WaveformError> {
497 let mut peaks = Vec::<(usize, usize)>::new();
498 let start_bin = time2bin(nanoseconds, start_time)?;
499 let end_bin = time2bin(nanoseconds, start_time + window_size)?;
500 let mut ranged_voltage = Vec::<f32>::with_capacity(end_bin - start_bin);
501 ranged_voltage.extend_from_slice(&voltages[start_bin..=end_bin]);
502 let output: Vec<_> = voltages
505 .into_iter()
506 .enumerate()
507 .peaks(PeaksDetector::new(lag, threshold, influence), |e| *e.1 as f64)
508 .map(|((i, _), p)| (i, p))
509 .collect();
510 if output.len() == 0 {
512 return Ok(peaks);
513 }
514 let mut peak_high = Vec::<usize>::new();
515 for k in output.iter() {
516 if matches!(k.1, Peak::High) {
517 peak_high.push(k.0);
518 }
519 }
520 if peaks.len() > 0 {
521 peaks = find_sequence_ranges(peak_high);
522 }
523 Ok(peaks)
524}
525
526pub fn fit_sine_simple<T>(volts: &[T], times: &[T]) -> (f32, f32, f32)
530 where T: Float + NumAssign + NumAssignOps + NumOps + Copy + NumCast + FloatConst {
531 let start_bin = 20;
532 let size_bin = 900;
533 let mut data_size = T::zero();
534
535 let mut xi_yi = T::zero();
536 let mut xi_zi = T::zero();
537 let mut yi_zi = T::zero();
538 let mut xi_xi = T::zero();
539 let mut yi_yi = T::zero();
540 let mut xi_sum = T::zero();
541 let mut yi_sum = T::zero();
542 let mut zi_sum = T::zero();
543
544 let c1 = T::from(2).unwrap();
545 let c2 = T::from(0.02f32).unwrap();
546 for i in start_bin..(start_bin + size_bin) {
547 let xi = (c1 * T::PI() * c2 * times[i]).cos();
548 let yi = (c1 * T::PI() * c2 * times[i]).sin();
549 let zi = volts[i];
550
551 xi_yi += xi * yi;
552 xi_zi += xi * zi;
553 yi_zi += yi * zi;
554 xi_xi += xi * xi;
555 yi_yi += yi * yi;
556 xi_sum += xi;
557 yi_sum += yi;
558 zi_sum += zi;
559
560 data_size += T::one();
561 }
562
563 let mut a_matrix = [[T::zero(); 3]; 3];
564 a_matrix[0][0] = xi_xi;
565 a_matrix[0][1] = xi_yi;
566 a_matrix[0][2] = xi_sum;
567 a_matrix[1][0] = xi_yi;
568 a_matrix[1][1] = yi_yi;
569 a_matrix[1][2] = yi_sum;
570 a_matrix[2][0] = xi_sum;
571 a_matrix[2][1] = yi_sum;
572 a_matrix[2][2] = data_size;
573
574 let determinant = a_matrix[0][0] * a_matrix[1][1] * a_matrix[2][2]
575 + a_matrix[0][1] * a_matrix[1][2] * a_matrix[2][0]
576 + a_matrix[0][2] * a_matrix[1][0] * a_matrix[2][1]
577 - a_matrix[0][0] * a_matrix[1][2] * a_matrix[2][1]
578 - a_matrix[0][1] * a_matrix[1][0] * a_matrix[2][2]
579 - a_matrix[0][2] * a_matrix[1][1] * a_matrix[2][0];
580
581 let inverse_factor = T::one() / determinant;
582
583 let mut cofactor_matrix = [[T::zero(); 3]; 3];
584 cofactor_matrix[0][0] = a_matrix[1][1] * a_matrix[2][2] - a_matrix[2][1] * a_matrix[1][2];
585 cofactor_matrix[0][1] = (a_matrix[1][0] * a_matrix[2][2] - a_matrix[2][0] * a_matrix[1][2]) * -T::one();
586 cofactor_matrix[0][2] = a_matrix[1][0] * a_matrix[2][1] - a_matrix[2][0] * a_matrix[1][1];
587 cofactor_matrix[1][0] = (a_matrix[0][1] * a_matrix[2][2] - a_matrix[2][1] * a_matrix[0][2]) * -T::one();
588 cofactor_matrix[1][1] = a_matrix[0][0] * a_matrix[2][2] - a_matrix[2][0] * a_matrix[0][2];
589 cofactor_matrix[1][2] = (a_matrix[0][0] * a_matrix[2][1] - a_matrix[2][0] * a_matrix[0][1]) * -T::one();
590 cofactor_matrix[2][0] = a_matrix[0][1] * a_matrix[1][2] - a_matrix[1][1] * a_matrix[0][2];
591 cofactor_matrix[2][1] = (a_matrix[0][0] * a_matrix[1][2] - a_matrix[1][0] * a_matrix[0][2]) * -T::one();
592 cofactor_matrix[2][2] = a_matrix[0][0] * a_matrix[1][1] - a_matrix[1][0] * a_matrix[0][1];
593
594 let mut inverse_matrix = [[T::zero(); 3]; 3];
595 for i in 0..3 {
596 for j in 0..3 {
597 inverse_matrix[i][j] = cofactor_matrix[j][i] * inverse_factor;
598 }
599 }
600
601 let p = [xi_zi, yi_zi, zi_sum];
602 let a = inverse_matrix[0][0] * p[0] + inverse_matrix[1][0] * p[1] + inverse_matrix[2][0] * p[2];
603 let b = inverse_matrix[0][1] * p[0] + inverse_matrix[1][1] * p[1] + inverse_matrix[2][1] * p[2];
604
605 let phi = <f32 as NumCast>::from(a.atan2(b)).unwrap();
606 let amp = <f32 as NumCast>::from((a*a + b*b).sqrt()).unwrap();
607 let freq = 0.02 as f32;
608
609 (amp, freq, phi)
610}
611
612#[cfg(feature="pybindings")]
613#[pyfunction]
614#[pyo3(name="fit_sine_simple")]
615pub fn fit_sine_simple_py<'_py>(xs : Bound<'_py,PyArray1<f32>>, ys: Bound<'_py, PyArray1<f32>>) -> (f32,f32,f32) {
616 unsafe {
617 fit_sine_simple::<f32>(ys.as_slice().unwrap(), xs.as_slice().unwrap())
618 }
619}
620