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")]
84#[pyfunction]
85#[pyo3(name="get_max_value_idx")]
86pub fn get_max_value_idx_py<'_py>(value : Bound<'_py,PyArray1<f32>>,
87 start_idx :usize,
88 n_idx : usize) -> PyResult<usize> {
89 unsafe {
90 match get_max_value_idx::<f32>(value.as_slice().unwrap(), start_idx, n_idx) {
91 Err(err) => {
92 return Err(PyValueError::new_err(err.to_string()));
93 }
94 Ok(max_val) => {
95 return Ok(max_val);
96 }
97 }
98 }
99}
100
101pub fn interpolate_time<T : AsRef<[f32]>> (volts : &T,
115 times : &T,
116 mut threshold : f32,
117 mut idx : usize,
118 size : usize) -> Result<f32, WaveformError> {
119 let voltages = volts.as_ref();
120 let nanoseconds = times.as_ref();
121 if idx + 1 > nanoseconds.len() {
122 return Err(WaveformError::OutOfRangeUpperBound);
123 }
124 threshold = threshold.abs();
125 let mut lval = (voltages[idx]).abs();
126 let mut hval : f32 = 0.0;
127 if size == 1 {
128 hval = (voltages[idx+1]).abs();
129 } else {
130 for n in idx+1..idx+size {
131 hval = voltages[n].abs();
132 if (hval>=threshold) && (threshold<=lval) { idx = n-1; break;
135 }
136 lval = hval;
137 }
138 }
139 if ((lval > threshold) && (size != 1)) || lval == hval {
140 return Ok(nanoseconds[idx]);
141 } else {
142 return Ok(nanoseconds[idx]
143 + (threshold-lval)/(hval-lval) * (nanoseconds[idx+1]
144 - nanoseconds[idx]));
145 }
146}
147
148
149#[cfg(feature = "pybindings")]
150#[pyfunction]
151#[pyo3(name="interpolate_time")]
152pub fn interpolate_time_py(voltages : PyReadonlyArray1<f32>,
166 nanoseconds : PyReadonlyArray1<f32>,
167 threshold : f32,
168 idx : usize,
169 size : usize) -> PyResult<f32> {
170 let i = idx;
171 match interpolate_time(&voltages.readonly().as_slice().unwrap(),
172 &nanoseconds.readonly().as_slice().unwrap(),
173 threshold, i, size) {
174 Ok(time) => {
175 return Ok(time);
176 }
177 Err(err) => {
178 return Err(PyValueError::new_err(err.to_string()));
179 }
180 }
181}
182
183
184pub fn integrate(voltages : &Vec<f32>,
194 nanoseconds : &Vec<f32>,
195 lo_bin : usize,
196 upper_bin : usize,
197 impedance : f32) -> Result<f32, WaveformError> {
198 if upper_bin > voltages.len() {
199 return Err(WaveformError::OutOfRangeUpperBound);
200 }
201 if lo_bin < 1 {
202 return Err(WaveformError::OutOfRangeLowerBound);
203 }
204 let mut sum = 0f32;
205 for n in lo_bin..upper_bin {
206 sum += voltages[n] * (nanoseconds[n] - nanoseconds[n-1]) ;
207 }
208 sum /= impedance;
209 Ok(sum)
210}
211
212pub fn time2bin(nanoseconds : &Vec<f32>,
216 t_ns : f32) -> Result<usize, WaveformError> {
217 for n in 0..nanoseconds.len() {
218 if nanoseconds[n] > t_ns {
219 return Ok(n-1);
220 }
221 }
222 debug!("Did not find a bin corresponding to the given time {}!", t_ns);
223 return Err(WaveformError::TimesTooSmall);
224}
225
226pub fn calculate_pedestal(voltages : &Vec<f32>,
241 threshold : f32,
242 ped_begin_bin : usize,
243 ped_range_bin : usize) -> (f32,f32) {
244 let mut sum = 0f32;
245 let mut sum2 = 0f32;
246 for k in ped_begin_bin..ped_begin_bin + ped_range_bin {
247 if f32::abs(voltages[k]) < threshold {
248 sum += voltages[k];
249 sum2 += voltages[k]*voltages[k];
250 }
251 }
252 let average = sum/(ped_range_bin as f32);
253 let sigma = f32::sqrt(sum2/(ped_range_bin as f32 - (average*average)));
254 (average, sigma)
255}
256
257pub fn cfd_simple(voltages : &Vec<f32>,
263 nanoseconds : &Vec<f32>,
264 cfd_frac : f32,
265 start_peak : usize,
266 end_peak : usize) -> Result<f32, WaveformError> {
267
268 let idx = get_max_value_idx(&voltages, start_peak, end_peak-start_peak)?;
269 let mut sum : f32 = 0.0;
270 for n in idx-1..idx+1{
271 sum += voltages[n];
272 }
273 let tmp_thresh : f32 = f32::abs(cfd_frac * (sum / 3.0));
274 trace!("Calculated tmp threshold of {}", tmp_thresh);
275 let mut lo_bin : usize = voltages.len();
280 let mut n = idx;
281 if idx < start_peak {
282 error!("The index {} is smaller than the beginning of the peak {}!", idx, start_peak);
283 return Err(WaveformError::OutOfRangeLowerBound);
284 }
285 if start_peak >= 10 {
286 while n > start_peak - 10 {
287 if f32::abs(voltages[n]) < tmp_thresh {
288 lo_bin = n;
289 break;
290 }
291 n -= 1;
292 }
293 } else {
294 debug!("We require that the peak is at least 10 bins away from the start!");
295 return Err(WaveformError::OutOfRangeLowerBound);
296 }
297
298 trace!("Lo bin {} , start peak {}", lo_bin, start_peak);
299 let cfd_time : f32;
300 if lo_bin < nanoseconds.len() -1 {
301 cfd_time = interpolate_time(voltages, nanoseconds, tmp_thresh, lo_bin, 1)?;
302 } else {
303 cfd_time = nanoseconds[nanoseconds.len() - 1];
304 }
305 Ok(cfd_time)
306}
307
308pub fn find_peaks(voltages : &Vec<f32>,
328 nanoseconds : &Vec<f32>,
329 start_time : f32,
330 window_size : f32,
331 min_peak_width : usize,
332 threshold : f32,
333 max_peaks : usize)
334-> Result<Vec<(usize,usize)>, WaveformError> {
335 let mut peaks = Vec::<(usize,usize)>::new();
336 let mut start_bin = time2bin(nanoseconds, start_time)?;
337 if start_bin <= 10 {
338 debug!("We deliberatly do not search for peaks within the first 10 bins! Correcting..");
339 start_bin = 10;
340 }
341 let window_bin = time2bin(nanoseconds, start_time + window_size)? - start_bin;
342 if start_bin + window_bin > voltages.len () {
343 return Err(WaveformError::OutOfRangeUpperBound);
344 }
345
346 let mut pos = 0usize;
347 for k in start_bin..start_bin + window_bin {
350 if voltages[k] >= threshold {
351 pos = k;
352 break;
353 }
354 }
355 if pos == 0 && start_bin == 0 && voltages[pos] < threshold {
356 return Err(WaveformError::DidNotCrossThreshold)
358 }
359 let mut nbins_peak = 0usize;
361 let mut begin_peak = pos;
362 let mut end_peak : usize;
363 if (pos + window_bin) > voltages.len() {
364 return Err(WaveformError::OutOfRangeUpperBound);
365 }
366 for k in pos..(pos + window_bin) {
367 if voltages[k] >= threshold {
368 nbins_peak += 1;
369 let mut slope = 0i16; if nbins_peak == min_peak_width {
376 begin_peak = k - min_peak_width -1;
378 } else if nbins_peak > min_peak_width {
379 for j in 0..min_peak_width {
380 if voltages[k -j] > voltages[k-j-1] {
381 slope = 1; }
383 }
384 if slope == 1 {
385 continue;
387 }
388 if slope == 0 {
389 end_peak = k;
391 nbins_peak = 0; peaks.push((begin_peak, end_peak));
393 if peaks.len() == max_peaks {
394 break;
395 }
396 }
397 } } else {
401 if nbins_peak > min_peak_width {
402 end_peak = k;
403 peaks.push((begin_peak, end_peak));
404 if peaks.len() == max_peaks {
405 break;
406 }
407 }
408 nbins_peak = 0;
409 }
410 }
411 let len_pks_dirty = peaks.len();
413 peaks.retain(|&x| {(x.0 < NWORDS - 1) & (x.1 <= NWORDS - 1)});
414 let len_pks_clean = peaks.len();
415 if len_pks_clean != len_pks_dirty {
416 debug!("We removed {} pks because they had values outside of 0-{}!", len_pks_dirty - len_pks_clean, NWORDS);
417 }
418 Ok(peaks)
419}
420
421
422#[cfg(feature = "advanced-algorithms")]
423fn find_sequence_ranges(vec: Vec<usize>) -> Vec<(usize, usize)> {
424 let mut ranges = Vec::new();
425 let mut start = vec[0];
426 let mut end = vec[0];
427
428 for &value in vec.iter().skip(1) {
429 if value == end + 1 {
430 end = value;
432 } else {
433 ranges.push((start, end));
435 start = value;
436 end = value;
437 }
438 }
439
440 ranges.push((start, end));
442 ranges
443}
444
445#[cfg(feature = "advanced-algorithms")]
446pub fn find_peaks_zscore(nanoseconds : &Vec<f32>,
499 voltages : &Vec<f32>,
500 start_time : f32,
501 window_size : f32,
502 lag : usize,
503 threshold : f64,
504 influence : f64)
505-> Result<Vec<(usize,usize)>, WaveformError> {
506 let mut peaks = Vec::<(usize, usize)>::new();
507 let start_bin = time2bin(nanoseconds, start_time)?;
508 let end_bin = time2bin(nanoseconds, start_time + window_size)?;
509 let mut ranged_voltage = Vec::<f32>::with_capacity(end_bin - start_bin);
510 ranged_voltage.extend_from_slice(&voltages[start_bin..=end_bin]);
511 let output: Vec<_> = voltages
514 .into_iter()
515 .enumerate()
516 .peaks(PeaksDetector::new(lag, threshold, influence), |e| *e.1 as f64)
517 .map(|((i, _), p)| (i, p))
518 .collect();
519 if output.len() == 0 {
521 return Ok(peaks);
522 }
523 let mut peak_high = Vec::<usize>::new();
524 for k in output.iter() {
525 if matches!(k.1, Peak::High) {
526 peak_high.push(k.0);
527 }
528 }
529 if peaks.len() > 0 {
530 peaks = find_sequence_ranges(peak_high);
531 }
532 Ok(peaks)
533}
534
535pub fn fit_sine_simple<T>(volts: &[T], times: &[T]) -> (f32, f32, f32)
547 where T: Float + NumAssign + NumAssignOps + NumOps + Copy + NumCast + FloatConst {
548 let start_bin = 20;
549 let size_bin = 900;
550 let mut data_size = T::zero();
551
552 let mut xi_yi = T::zero();
553 let mut xi_zi = T::zero();
554 let mut yi_zi = T::zero();
555 let mut xi_xi = T::zero();
556 let mut yi_yi = T::zero();
557 let mut xi_sum = T::zero();
558 let mut yi_sum = T::zero();
559 let mut zi_sum = T::zero();
560
561 let c1 = T::from(2).unwrap();
562 let c2 = T::from(0.02f32).unwrap();
563 for i in start_bin..(start_bin + size_bin) {
564 let xi = (c1 * T::PI() * c2 * times[i]).cos();
565 let yi = (c1 * T::PI() * c2 * times[i]).sin();
566 let zi = volts[i];
567
568 xi_yi += xi * yi;
569 xi_zi += xi * zi;
570 yi_zi += yi * zi;
571 xi_xi += xi * xi;
572 yi_yi += yi * yi;
573 xi_sum += xi;
574 yi_sum += yi;
575 zi_sum += zi;
576
577 data_size += T::one();
578 }
579
580 let mut a_matrix = [[T::zero(); 3]; 3];
581 a_matrix[0][0] = xi_xi;
582 a_matrix[0][1] = xi_yi;
583 a_matrix[0][2] = xi_sum;
584 a_matrix[1][0] = xi_yi;
585 a_matrix[1][1] = yi_yi;
586 a_matrix[1][2] = yi_sum;
587 a_matrix[2][0] = xi_sum;
588 a_matrix[2][1] = yi_sum;
589 a_matrix[2][2] = data_size;
590
591 let determinant = a_matrix[0][0] * a_matrix[1][1] * a_matrix[2][2]
592 + a_matrix[0][1] * a_matrix[1][2] * a_matrix[2][0]
593 + a_matrix[0][2] * a_matrix[1][0] * a_matrix[2][1]
594 - a_matrix[0][0] * a_matrix[1][2] * a_matrix[2][1]
595 - a_matrix[0][1] * a_matrix[1][0] * a_matrix[2][2]
596 - a_matrix[0][2] * a_matrix[1][1] * a_matrix[2][0];
597
598 let inverse_factor = T::one() / determinant;
599
600 let mut cofactor_matrix = [[T::zero(); 3]; 3];
601 cofactor_matrix[0][0] = a_matrix[1][1] * a_matrix[2][2] - a_matrix[2][1] * a_matrix[1][2];
602 cofactor_matrix[0][1] = (a_matrix[1][0] * a_matrix[2][2] - a_matrix[2][0] * a_matrix[1][2]) * -T::one();
603 cofactor_matrix[0][2] = a_matrix[1][0] * a_matrix[2][1] - a_matrix[2][0] * a_matrix[1][1];
604 cofactor_matrix[1][0] = (a_matrix[0][1] * a_matrix[2][2] - a_matrix[2][1] * a_matrix[0][2]) * -T::one();
605 cofactor_matrix[1][1] = a_matrix[0][0] * a_matrix[2][2] - a_matrix[2][0] * a_matrix[0][2];
606 cofactor_matrix[1][2] = (a_matrix[0][0] * a_matrix[2][1] - a_matrix[2][0] * a_matrix[0][1]) * -T::one();
607 cofactor_matrix[2][0] = a_matrix[0][1] * a_matrix[1][2] - a_matrix[1][1] * a_matrix[0][2];
608 cofactor_matrix[2][1] = (a_matrix[0][0] * a_matrix[1][2] - a_matrix[1][0] * a_matrix[0][2]) * -T::one();
609 cofactor_matrix[2][2] = a_matrix[0][0] * a_matrix[1][1] - a_matrix[1][0] * a_matrix[0][1];
610
611 let mut inverse_matrix = [[T::zero(); 3]; 3];
612 for i in 0..3 {
613 for j in 0..3 {
614 inverse_matrix[i][j] = cofactor_matrix[j][i] * inverse_factor;
615 }
616 }
617
618 let p = [xi_zi, yi_zi, zi_sum];
619 let a = inverse_matrix[0][0] * p[0] + inverse_matrix[1][0] * p[1] + inverse_matrix[2][0] * p[2];
620 let b = inverse_matrix[0][1] * p[0] + inverse_matrix[1][1] * p[1] + inverse_matrix[2][1] * p[2];
621
622 let phi = <f32 as NumCast>::from(a.atan2(b)).unwrap();
623 let amp = <f32 as NumCast>::from((a*a + b*b).sqrt()).unwrap();
624 let freq = 0.02 as f32;
625
626 (amp, freq, phi)
627}
628
629#[cfg(feature="pybindings")]
639#[pyfunction]
640#[pyo3(name="fit_sine_simple")]
641pub fn fit_sine_simple_py<'_py>(xs : Bound<'_py,PyArray1<f32>>, ys: Bound<'_py, PyArray1<f32>>) -> (f32,f32,f32) {
642 unsafe {
643 fit_sine_simple::<f32>(ys.as_slice().unwrap(), xs.as_slice().unwrap())
644 }
645}
646