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>,
320 nanoseconds : &Vec<f32>,
321 start_time : f32,
322 window_size : f32,
323 min_peak_width : usize,
324 threshold : f32,
325 max_peaks : usize)
326-> Result<Vec<(usize,usize)>, WaveformError> {
327 let mut peaks = Vec::<(usize,usize)>::new();
328 let mut start_bin = time2bin(nanoseconds, start_time)?;
329 if start_bin <= 10 {
330 debug!("We deliberatly do not search for peaks within the first 10 bins! Correcting..");
331 start_bin = 10;
332 }
333 let window_bin = time2bin(nanoseconds, start_time + window_size)? - start_bin;
334 if start_bin + window_bin > voltages.len () {
335 return Err(WaveformError::OutOfRangeUpperBound);
336 }
337
338 let mut pos = 0usize;
339 for k in start_bin..start_bin + window_bin {
342 if voltages[k] >= threshold {
343 pos = k;
344 break;
345 }
346 }
347 if pos == 0 && start_bin == 0 && voltages[pos] < threshold {
348 return Err(WaveformError::DidNotCrossThreshold)
350 }
351 let mut nbins_peak = 0usize;
353 let mut begin_peak = pos;
354 let mut end_peak : usize;
355 if (pos + window_bin) > voltages.len() {
356 return Err(WaveformError::OutOfRangeUpperBound);
357 }
358 for k in pos..(pos + window_bin) {
359 if voltages[k] >= threshold {
360 nbins_peak += 1;
361 let mut slope = 0i16; if nbins_peak == min_peak_width {
368 begin_peak = k - min_peak_width -1;
370 } else if nbins_peak > min_peak_width {
371 for j in 0..min_peak_width {
372 if voltages[k -j] > voltages[k-j-1] {
373 slope = 1; }
375 }
376 if slope == 1 {
377 continue;
379 }
380 if slope == 0 {
381 end_peak = k;
383 nbins_peak = 0; peaks.push((begin_peak, end_peak));
385 if peaks.len() == max_peaks {
386 break;
387 }
388 }
389 } } else {
393 if nbins_peak > min_peak_width {
394 end_peak = k;
395 peaks.push((begin_peak, end_peak));
396 if peaks.len() == max_peaks {
397 break;
398 }
399 }
400 nbins_peak = 0;
401 }
402 }
403 let len_pks_dirty = peaks.len();
405 peaks.retain(|&x| {(x.0 < NWORDS - 1) & (x.1 <= NWORDS - 1)});
406 let len_pks_clean = peaks.len();
407 if len_pks_clean != len_pks_dirty {
408 debug!("We removed {} pks because they had values outside of 0-{}!", len_pks_dirty - len_pks_clean, NWORDS);
409 }
410 Ok(peaks)
411}
412
413
414#[cfg(feature = "advanced-algorithms")]
415fn find_sequence_ranges(vec: Vec<usize>) -> Vec<(usize, usize)> {
416 let mut ranges = Vec::new();
417 let mut start = vec[0];
418 let mut end = vec[0];
419
420 for &value in vec.iter().skip(1) {
421 if value == end + 1 {
422 end = value;
424 } else {
425 ranges.push((start, end));
427 start = value;
428 end = value;
429 }
430 }
431
432 ranges.push((start, end));
434 ranges
435}
436
437#[cfg(feature = "advanced-algorithms")]
438pub fn find_peaks_zscore(nanoseconds : &Vec<f32>,
491 voltages : &Vec<f32>,
492 start_time : f32,
493 window_size : f32,
494 lag : usize,
495 threshold : f64,
496 influence : f64)
497-> Result<Vec<(usize,usize)>, WaveformError> {
498 let mut peaks = Vec::<(usize, usize)>::new();
499 let start_bin = time2bin(nanoseconds, start_time)?;
500 let end_bin = time2bin(nanoseconds, start_time + window_size)?;
501 let mut ranged_voltage = Vec::<f32>::with_capacity(end_bin - start_bin);
502 ranged_voltage.extend_from_slice(&voltages[start_bin..=end_bin]);
503 let output: Vec<_> = voltages
506 .into_iter()
507 .enumerate()
508 .peaks(PeaksDetector::new(lag, threshold, influence), |e| *e.1 as f64)
509 .map(|((i, _), p)| (i, p))
510 .collect();
511 if output.len() == 0 {
513 return Ok(peaks);
514 }
515 let mut peak_high = Vec::<usize>::new();
516 for k in output.iter() {
517 if matches!(k.1, Peak::High) {
518 peak_high.push(k.0);
519 }
520 }
521 if peaks.len() > 0 {
522 peaks = find_sequence_ranges(peak_high);
523 }
524 Ok(peaks)
525}
526
527pub fn fit_sine_simple<T>(volts: &[T], times: &[T]) -> (f32, f32, f32)
531 where T: Float + NumAssign + NumAssignOps + NumOps + Copy + NumCast + FloatConst {
532 let start_bin = 20;
533 let size_bin = 900;
534 let mut data_size = T::zero();
535
536 let mut xi_yi = T::zero();
537 let mut xi_zi = T::zero();
538 let mut yi_zi = T::zero();
539 let mut xi_xi = T::zero();
540 let mut yi_yi = T::zero();
541 let mut xi_sum = T::zero();
542 let mut yi_sum = T::zero();
543 let mut zi_sum = T::zero();
544
545 let c1 = T::from(2).unwrap();
546 let c2 = T::from(0.02f32).unwrap();
547 for i in start_bin..(start_bin + size_bin) {
548 let xi = (c1 * T::PI() * c2 * times[i]).cos();
549 let yi = (c1 * T::PI() * c2 * times[i]).sin();
550 let zi = volts[i];
551
552 xi_yi += xi * yi;
553 xi_zi += xi * zi;
554 yi_zi += yi * zi;
555 xi_xi += xi * xi;
556 yi_yi += yi * yi;
557 xi_sum += xi;
558 yi_sum += yi;
559 zi_sum += zi;
560
561 data_size += T::one();
562 }
563
564 let mut a_matrix = [[T::zero(); 3]; 3];
565 a_matrix[0][0] = xi_xi;
566 a_matrix[0][1] = xi_yi;
567 a_matrix[0][2] = xi_sum;
568 a_matrix[1][0] = xi_yi;
569 a_matrix[1][1] = yi_yi;
570 a_matrix[1][2] = yi_sum;
571 a_matrix[2][0] = xi_sum;
572 a_matrix[2][1] = yi_sum;
573 a_matrix[2][2] = data_size;
574
575 let determinant = a_matrix[0][0] * a_matrix[1][1] * a_matrix[2][2]
576 + a_matrix[0][1] * a_matrix[1][2] * a_matrix[2][0]
577 + a_matrix[0][2] * a_matrix[1][0] * a_matrix[2][1]
578 - a_matrix[0][0] * a_matrix[1][2] * a_matrix[2][1]
579 - a_matrix[0][1] * a_matrix[1][0] * a_matrix[2][2]
580 - a_matrix[0][2] * a_matrix[1][1] * a_matrix[2][0];
581
582 let inverse_factor = T::one() / determinant;
583
584 let mut cofactor_matrix = [[T::zero(); 3]; 3];
585 cofactor_matrix[0][0] = a_matrix[1][1] * a_matrix[2][2] - a_matrix[2][1] * a_matrix[1][2];
586 cofactor_matrix[0][1] = (a_matrix[1][0] * a_matrix[2][2] - a_matrix[2][0] * a_matrix[1][2]) * -T::one();
587 cofactor_matrix[0][2] = a_matrix[1][0] * a_matrix[2][1] - a_matrix[2][0] * a_matrix[1][1];
588 cofactor_matrix[1][0] = (a_matrix[0][1] * a_matrix[2][2] - a_matrix[2][1] * a_matrix[0][2]) * -T::one();
589 cofactor_matrix[1][1] = a_matrix[0][0] * a_matrix[2][2] - a_matrix[2][0] * a_matrix[0][2];
590 cofactor_matrix[1][2] = (a_matrix[0][0] * a_matrix[2][1] - a_matrix[2][0] * a_matrix[0][1]) * -T::one();
591 cofactor_matrix[2][0] = a_matrix[0][1] * a_matrix[1][2] - a_matrix[1][1] * a_matrix[0][2];
592 cofactor_matrix[2][1] = (a_matrix[0][0] * a_matrix[1][2] - a_matrix[1][0] * a_matrix[0][2]) * -T::one();
593 cofactor_matrix[2][2] = a_matrix[0][0] * a_matrix[1][1] - a_matrix[1][0] * a_matrix[0][1];
594
595 let mut inverse_matrix = [[T::zero(); 3]; 3];
596 for i in 0..3 {
597 for j in 0..3 {
598 inverse_matrix[i][j] = cofactor_matrix[j][i] * inverse_factor;
599 }
600 }
601
602 let p = [xi_zi, yi_zi, zi_sum];
603 let a = inverse_matrix[0][0] * p[0] + inverse_matrix[1][0] * p[1] + inverse_matrix[2][0] * p[2];
604 let b = inverse_matrix[0][1] * p[0] + inverse_matrix[1][1] * p[1] + inverse_matrix[2][1] * p[2];
605
606 let phi = <f32 as NumCast>::from(a.atan2(b)).unwrap();
607 let amp = <f32 as NumCast>::from((a*a + b*b).sqrt()).unwrap();
608 let freq = 0.02 as f32;
609
610 (amp, freq, phi)
611}
612
613#[cfg(feature="pybindings")]
614#[pyfunction]
615#[pyo3(name="fit_sine_simple")]
616pub fn fit_sine_simple_py<'_py>(xs : Bound<'_py,PyArray1<f32>>, ys: Bound<'_py, PyArray1<f32>>) -> (f32,f32,f32) {
617 unsafe {
618 fit_sine_simple::<f32>(ys.as_slice().unwrap(), xs.as_slice().unwrap())
619 }
620}
621