1use std::cmp::Ordering;
4use std::iter::FusedIterator;
5use std::ops::{Add, Div, Mul, Sub};
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Hash, Eq, Serialize, Deserialize)]
11pub struct Waveform<T> {
12 values: Vec<TimePoint<T>>,
14}
15
16#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Hash, Eq)]
18pub struct WaveformRef<'a, T> {
19 t: &'a [T],
20 x: &'a [T],
21}
22
23#[derive(
25 Debug, Default, Copy, Clone, PartialEq, Hash, Ord, Eq, PartialOrd, Serialize, Deserialize,
26)]
27pub struct TimePoint<T> {
28 t: T,
29 x: T,
30}
31
32impl<T> TimePoint<T> {
33 #[inline]
35 pub fn new(t: T, x: T) -> Self {
36 Self { t, x }
37 }
38
39 pub fn convert_into<U>(self) -> TimePoint<U>
41 where
42 T: Into<U>,
43 {
44 TimePoint {
45 t: self.t.into(),
46 x: self.x.into(),
47 }
48 }
49}
50
51impl<T> TimePoint<T>
52where
53 T: Copy,
54{
55 #[inline]
57 pub fn t(&self) -> T {
58 self.t
59 }
60
61 #[inline]
63 pub fn x(&self) -> T {
64 self.x
65 }
66}
67
68impl<T> From<(T, T)> for TimePoint<T> {
69 #[inline]
70 fn from(value: (T, T)) -> Self {
71 Self {
72 t: value.0,
73 x: value.1,
74 }
75 }
76}
77
78pub trait TimeWaveform {
80 type Data: Copy
84 + From<i32>
85 + Add<Self::Data, Output = Self::Data>
86 + Div<Self::Data, Output = Self::Data>
87 + PartialOrd
88 + Sub<Self::Data, Output = Self::Data>
89 + Mul<Self::Data, Output = Self::Data>;
90 fn get(&self, idx: usize) -> Option<TimePoint<Self::Data>>;
92
93 fn len(&self) -> usize;
95
96 fn is_empty(&self) -> bool {
98 self.len() == 0
99 }
100
101 fn first_t(&self) -> Option<Self::Data> {
103 Some(self.first()?.t())
104 }
105
106 fn first_x(&self) -> Option<Self::Data> {
108 Some(self.first()?.x())
109 }
110
111 fn last_t(&self) -> Option<Self::Data> {
113 Some(self.last()?.t())
114 }
115
116 fn last_x(&self) -> Option<Self::Data> {
118 Some(self.last()?.x())
119 }
120
121 fn first(&self) -> Option<TimePoint<Self::Data>> {
123 self.get(0)
124 }
125
126 fn last(&self) -> Option<TimePoint<Self::Data>> {
128 self.get(self.len() - 1)
129 }
130
131 fn edges(&self, threshold: Self::Data) -> Edges<'_, Self, Self::Data> {
135 Edges {
136 waveform: self,
137 idx: 0,
138 thresh: threshold,
139 }
140 }
141
142 fn transitions(
146 &self,
147 low_threshold: Self::Data,
148 high_threshold: Self::Data,
149 ) -> Transitions<'_, Self, Self::Data> {
150 assert!(high_threshold > low_threshold);
151 Transitions {
152 waveform: self,
153 state: TransitionState::Unknown,
154 t: Self::Data::from(0),
155 prev_idx: 0,
156 idx: 0,
157 low_thresh: low_threshold,
158 high_thresh: high_threshold,
159 }
160 }
161
162 fn values(&self) -> Values<'_, Self> {
166 Values {
167 waveform: self,
168 idx: 0,
169 }
170 }
171
172 fn time_index_before(&self, t: Self::Data) -> Option<usize> {
174 search_for_time(self, t)
175 }
176
177 fn sample_at(&self, t: Self::Data) -> Self::Data {
181 let idx = self
182 .time_index_before(t)
183 .expect("cannot extrapolate to the requested time");
184 debug_assert!(
185 idx < self.len() - 1,
186 "cannot extrapolate beyond end of signal"
187 );
188 let p0 = self.get(idx).unwrap();
189 let p1 = self.get(idx + 1).unwrap();
190 linear_interp(p0.t(), p0.x(), p1.t(), p1.x(), t)
191 }
192
193 fn max_x(&self) -> Option<Self::Data> {
195 let mut max = None;
196 for i in 0..self.len() {
197 let point = self.get(i)?;
198 if let Some(max_val) = max.as_mut() {
199 if *max_val < point.x {
200 *max_val = point.x;
201 }
202 } else {
203 max = Some(point.x);
204 }
205 }
206 max
207 }
208
209 fn min_x(&self) -> Option<Self::Data> {
211 let mut min = None;
212 for i in 0..self.len() {
213 let point = self.get(i)?;
214 if let Some(min_val) = min.as_mut() {
215 if *min_val > point.x {
216 *min_val = point.x;
217 }
218 } else {
219 min = Some(point.x);
220 }
221 }
222 min
223 }
224
225 fn mid_x(&self) -> Option<Self::Data> {
229 Some((self.max_x()? + self.min_x()?) / Self::Data::from(2))
230 }
231
232 fn integral(&self) -> Self::Data {
237 let n = self.len();
238 if n < 2 {
239 return Self::Data::from(0);
240 }
241
242 let mut integral = Self::Data::from(0);
243
244 for i in 0..self.len() - 1 {
245 let p0 = self.get(i).unwrap();
246 let p1 = self.get(i + 1).unwrap();
247 let dt = p1.t - p0.t;
248 let avg = (p0.x + p1.x) / Self::Data::from(2);
249 integral = integral + avg * dt;
250 }
251
252 integral
253 }
254}
255
256fn linear_interp<T>(t0: T, y0: T, t1: T, y1: T, t: T) -> T
257where
258 T: Copy
259 + Add<T, Output = T>
260 + Div<T, Output = T>
261 + PartialOrd
262 + Sub<T, Output = T>
263 + Mul<T, Output = T>,
264{
265 let c = (t - t0) / (t1 - t0);
266 y0 + c * (y1 - y0)
267}
268
269#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
271pub struct Values<'a, T: ?Sized> {
272 waveform: &'a T,
273 idx: usize,
274}
275
276impl<W> Iterator for Values<'_, W>
277where
278 W: TimeWaveform,
279{
280 type Item = TimePoint<W::Data>;
281 fn next(&mut self) -> Option<Self::Item> {
282 let val = self.waveform.get(self.idx);
283 if val.is_some() {
284 self.idx += 1;
285 }
286 val
287 }
288}
289
290impl<W> FusedIterator for Values<'_, W> where W: TimeWaveform {}
291
292impl<T> TimeWaveform for Waveform<T>
293where
294 T: Copy
295 + Add<T, Output = T>
296 + Div<T, Output = T>
297 + PartialOrd
298 + Sub<T, Output = T>
299 + Mul<T, Output = T>
300 + From<i32>,
301{
302 type Data = T;
303
304 fn get(&self, idx: usize) -> Option<TimePoint<T>> {
305 self.values.get(idx).copied()
306 }
307
308 fn len(&self) -> usize {
309 self.values.len()
310 }
311}
312
313impl<T> TimeWaveform for WaveformRef<'_, T>
314where
315 T: Copy
316 + Add<T, Output = T>
317 + Div<T, Output = T>
318 + PartialOrd
319 + Sub<T, Output = T>
320 + Mul<T, Output = T>
321 + From<i32>,
322{
323 type Data = T;
324 fn get(&self, idx: usize) -> Option<TimePoint<T>> {
325 if idx >= self.len() {
326 return None;
327 }
328 Some(TimePoint::new(self.t[idx], self.x[idx]))
329 }
330
331 fn len(&self) -> usize {
332 self.t.len()
333 }
334}
335
336#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
338pub enum EdgeDir {
339 Falling,
341 Rising,
343}
344
345#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
347pub struct Edge<T> {
348 pub(crate) t: T,
349 pub(crate) start_idx: usize,
350 pub(crate) dir: EdgeDir,
351}
352
353#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
355pub struct Edges<'a, W: ?Sized, T> {
356 waveform: &'a W,
357 idx: usize,
358 thresh: T,
359}
360
361#[derive(
362 Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
363)]
364enum TransitionState {
365 High,
367 #[default]
369 Unknown,
370 Low,
372}
373
374#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
376pub struct Transitions<'a, W: ?Sized, T> {
377 waveform: &'a W,
378 state: TransitionState,
379 t: T,
381 prev_idx: usize,
382 idx: usize,
384 low_thresh: T,
385 high_thresh: T,
386}
387
388#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
390pub struct Transition<T> {
391 pub(crate) start_t: T,
392 pub(crate) end_t: T,
393 pub(crate) start_idx: usize,
394 pub(crate) end_idx: usize,
395 pub(crate) dir: EdgeDir,
396}
397
398impl<T> Waveform<T> {
399 #[inline]
401 pub fn new() -> Self {
402 Self { values: Vec::new() }
403 }
404
405 pub fn convert_into<U>(self) -> Waveform<U>
407 where
408 T: Into<U>,
409 {
410 let values = self
411 .values
412 .into_iter()
413 .map(|tp| tp.convert_into())
414 .collect();
415 Waveform { values }
416 }
417
418 pub fn with_initial_value(x: T) -> Self
420 where
421 T: From<i32>,
422 {
423 Self {
424 values: vec![TimePoint::new(T::from(0), x)],
425 }
426 }
427
428 pub fn push(&mut self, t: T, x: T)
430 where
431 Self: TimeWaveform<Data = T>,
432 T: PartialOrd,
433 {
434 if let Some(tp) = self.last_t() {
435 assert!(t > tp);
436 }
437 self.values.push(TimePoint::new(t, x));
438 }
439}
440
441impl<T> FromIterator<(T, T)> for Waveform<T> {
442 fn from_iter<I: IntoIterator<Item = (T, T)>>(iter: I) -> Self {
443 Self {
444 values: iter
445 .into_iter()
446 .map(|(t, x)| TimePoint::new(t, x))
447 .collect(),
448 }
449 }
450}
451
452pub(crate) fn edge_crossing_time<T>(t0: T, y0: T, t1: T, y1: T, thresh: T) -> T
453where
454 T: Copy
455 + Add<T, Output = T>
456 + Div<T, Output = T>
457 + PartialOrd
458 + Sub<T, Output = T>
459 + Mul<T, Output = T>
460 + From<i32>,
461{
462 let c = (thresh - y0) / (y1 - y0);
463 debug_assert!(c >= T::from(0));
464 debug_assert!(c <= T::from(1));
465 t0 + c * (t1 - t0)
466}
467
468impl<W> Edges<'_, W, W::Data>
469where
470 W: TimeWaveform,
471 <W as TimeWaveform>::Data: Copy,
472{
473 fn check(&mut self) -> Option<Edge<W::Data>> {
474 let p0 = self.waveform.get(self.idx)?;
475 let p1 = self.waveform.get(self.idx + 1)?;
476 let first = p0.x - self.thresh;
477 let second = p1.x - self.thresh;
478 if (first >= <W as TimeWaveform>::Data::from(0))
479 != (second >= <W as TimeWaveform>::Data::from(0))
480 {
481 let dir = if second >= <W as TimeWaveform>::Data::from(0) {
482 EdgeDir::Rising
483 } else {
484 EdgeDir::Falling
485 };
486 Some(Edge {
487 dir,
488 t: edge_crossing_time(p0.t, p0.x, p1.t, p1.x, self.thresh),
489 start_idx: self.idx,
490 })
491 } else {
492 None
493 }
494 }
495}
496
497impl<W> Iterator for Edges<'_, W, W::Data>
498where
499 W: TimeWaveform,
500{
501 type Item = Edge<W::Data>;
502 fn next(&mut self) -> Option<Self::Item> {
503 if self.idx >= self.waveform.len() - 1 {
504 return None;
505 }
506 loop {
507 let val = self.check();
508 self.idx += 1;
509 if val.is_some() {
510 break val;
511 }
512 if self.idx >= self.waveform.len() - 1 {
513 break None;
514 }
515 }
516 }
517}
518
519impl<W> FusedIterator for Edges<'_, W, W::Data> where W: TimeWaveform {}
520
521impl<W> Transitions<'_, W, <W as TimeWaveform>::Data>
522where
523 W: TimeWaveform,
524 W::Data: PartialOrd,
525{
526 fn check(&mut self) -> Option<(TransitionState, W::Data)> {
527 let pt = self.waveform.get(self.idx)?;
528 Some((
529 if pt.x >= self.high_thresh {
530 TransitionState::High
531 } else if pt.x <= self.low_thresh {
532 TransitionState::Low
533 } else {
534 TransitionState::Unknown
535 },
536 pt.t,
537 ))
538 }
539}
540
541impl<W> Iterator for Transitions<'_, W, <W as TimeWaveform>::Data>
542where
543 W: TimeWaveform,
544 W::Data: PartialOrd,
545{
546 type Item = Transition<W::Data>;
547 fn next(&mut self) -> Option<Self::Item> {
548 if self.idx >= self.waveform.len() - 1 {
549 return None;
550 }
551 loop {
552 use TransitionState::*;
553
554 let (val, t) = self.check()?;
555 let end_idx = self.idx;
556 self.idx += 1;
557
558 match (self.state, val) {
559 (High, Low) => {
560 self.state = Low;
561 let (old_t, old_idx) = (self.t, self.prev_idx);
562 self.prev_idx = end_idx;
563 self.t = t;
564 return Some(Transition {
565 start_t: old_t,
566 end_t: t,
567 start_idx: old_idx,
568 end_idx,
569 dir: EdgeDir::Falling,
570 });
571 }
572 (Low, High) => {
573 self.state = High;
574 let (old_t, old_idx) = (self.t, self.prev_idx);
575 self.prev_idx = end_idx;
576 self.t = t;
577 return Some(Transition {
578 start_t: old_t,
579 end_t: t,
580 start_idx: old_idx,
581 end_idx,
582 dir: EdgeDir::Rising,
583 });
584 }
585 (Unknown, High) => {
586 self.state = High;
587 self.t = t;
588 self.prev_idx = end_idx;
589 }
590 (Unknown, Low) => {
591 self.state = Low;
592 self.t = t;
593 self.prev_idx = end_idx;
594 }
595 (High, High) | (Low, Low) => {
596 self.t = t;
597 self.prev_idx = end_idx;
598 }
599 _ => (),
600 }
601 }
602 }
603}
604
605impl<W> FusedIterator for Transitions<'_, W, <W as TimeWaveform>::Data>
606where
607 W: TimeWaveform,
608 <W as TimeWaveform>::Data: Copy
609 + Add<<W as TimeWaveform>::Data, Output = <W as TimeWaveform>::Data>
610 + Div<<W as TimeWaveform>::Data, Output = <W as TimeWaveform>::Data>
611 + PartialOrd
612 + Sub<<W as TimeWaveform>::Data, Output = <W as TimeWaveform>::Data>
613 + Mul<<W as TimeWaveform>::Data, Output = <W as TimeWaveform>::Data>
614 + From<i32>,
615{
616}
617
618impl<T> Default for Waveform<T> {
619 #[inline]
620 fn default() -> Self {
621 Self::new()
622 }
623}
624
625impl<T> std::ops::Index<usize> for Waveform<T> {
626 type Output = TimePoint<T>;
627 fn index(&self, index: usize) -> &Self::Output {
628 self.values.index(index)
629 }
630}
631
632impl<T> std::ops::IndexMut<usize> for Waveform<T> {
633 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
634 self.values.index_mut(index)
635 }
636}
637
638impl EdgeDir {
639 #[inline]
641 pub fn is_rising(&self) -> bool {
642 matches!(self, EdgeDir::Rising)
643 }
644
645 #[inline]
647 pub fn is_falling(&self) -> bool {
648 matches!(self, EdgeDir::Falling)
649 }
650}
651
652impl<T> Edge<T> {
653 #[inline]
655 pub fn dir(&self) -> EdgeDir {
656 self.dir
657 }
658
659 #[inline]
663 pub fn t(&self) -> T
664 where
665 T: Copy,
666 {
667 self.t
668 }
669
670 #[inline]
672 pub fn idx_before(&self) -> usize {
673 self.start_idx
674 }
675
676 #[inline]
678 pub fn idx_after(&self) -> usize {
679 self.start_idx + 1
680 }
681}
682
683impl<T> Transition<T> {
684 #[inline]
686 pub fn dir(&self) -> EdgeDir {
687 self.dir
688 }
689
690 #[inline]
692 pub fn start_time(&self) -> T
693 where
694 T: Copy,
695 {
696 self.start_t
697 }
698
699 #[inline]
701 pub fn end_time(&self) -> T
702 where
703 T: Copy,
704 {
705 self.end_t
706 }
707
708 #[inline]
710 pub fn start_idx(&self) -> usize {
711 self.start_idx
712 }
713
714 #[inline]
716 pub fn end_idx(&self) -> usize {
717 self.end_idx
718 }
719
720 #[inline]
724 pub fn duration(&self) -> T
725 where
726 T: Copy + Sub<T, Output = T>,
727 {
728 self.end_time() - self.start_time()
729 }
730
731 #[inline]
733 pub fn center_time(&self) -> T
734 where
735 T: Copy + Add<T, Output = T> + Div<T, Output = T> + From<i32>,
736 {
737 (self.start_time() + self.end_time()) / T::from(2)
738 }
739}
740
741impl<'a, T> WaveformRef<'a, T> {
742 #[inline]
748 pub fn new(t: &'a [T], x: &'a [T]) -> Self {
749 assert_eq!(t.len(), x.len());
750 Self { t, x }
751 }
752}
753
754fn search_for_time<W>(data: &W, target: <W as TimeWaveform>::Data) -> Option<usize>
755where
756 W: TimeWaveform + ?Sized,
757 <W as TimeWaveform>::Data: PartialOrd,
758{
759 if data.is_empty() {
760 return None;
761 }
762
763 let mut ans = None;
764 let mut lo = 0usize;
765 let mut hi = data.len() - 1;
766 let mut x;
767 while lo <= hi {
768 let mid = (lo + hi) / 2;
769 x = data.get(mid).unwrap().t();
770 match target.partial_cmp(&x)? {
771 Ordering::Less => hi = mid - 1,
772 Ordering::Greater => {
773 lo = mid + 1;
774 ans = Some(mid)
775 }
776 Ordering::Equal => return Some(mid),
777 }
778 }
779
780 ans
781}
782
783pub struct DigitalWaveformParams<T> {
785 pub vdd: T,
787 pub period: T,
789 pub offset: T,
791 pub tr: T,
793 pub tf: T,
795}
796
797pub struct DigitalWaveformBuilder<T> {
799 params: DigitalWaveformParams<T>,
800
801 ctr: usize,
802 values: Vec<TimePoint<T>>,
803 state: TransitionState,
804}
805
806impl<T> DigitalWaveformBuilder<T>
807where
808 T: Copy
809 + Add<T, Output = T>
810 + Div<T, Output = T>
811 + PartialOrd
812 + Sub<T, Output = T>
813 + Mul<T, Output = T>
814 + From<i32>,
815{
816 pub fn new(params: impl Into<DigitalWaveformParams<T>>) -> Self {
818 Self {
819 params: params.into(),
820 values: Vec::new(),
821 ctr: 0,
822 state: TransitionState::Unknown,
823 }
824 }
825
826 pub fn add_hi(&mut self) -> &mut Self {
831 let cycle = T::from(self.ctr as i32);
832 let cycle_next = T::from((self.ctr + 1) as i32);
833 match self.state {
834 TransitionState::High => {}
835 TransitionState::Low => {
836 self.values.push(TimePoint::new(
837 cycle * self.params.period + self.params.tr + self.params.offset,
838 self.params.vdd,
839 ));
840 }
841 TransitionState::Unknown => {
842 assert_eq!(self.ctr, 0);
843 self.values
844 .push(TimePoint::new(T::from(0), self.params.vdd));
845 }
846 }
847 self.values.push(TimePoint::new(
848 cycle_next * self.params.period + self.params.offset,
849 self.params.vdd,
850 ));
851
852 self.ctr += 1;
853 self.state = TransitionState::High;
854 self
855 }
856
857 pub fn add_lo(&mut self) -> &mut Self {
862 let cycle = T::from(self.ctr as i32);
863 let cycle_next = T::from((self.ctr + 1) as i32);
864 match self.state {
865 TransitionState::High => {
866 self.values.push(TimePoint::new(
867 cycle * self.params.period + self.params.tf + self.params.offset,
868 T::from(0),
869 ));
870 }
871 TransitionState::Low => {}
872 TransitionState::Unknown => {
873 assert_eq!(self.ctr, 0);
874 self.values.push(TimePoint::new(T::from(0), T::from(0)));
875 }
876 }
877 self.values.push(TimePoint::new(
878 cycle_next * self.params.period + self.params.offset,
879 T::from(0),
880 ));
881
882 self.ctr += 1;
883 self.state = TransitionState::Low;
884 self
885 }
886
887 #[inline]
892 pub fn add(&mut self, bit: bool) -> &mut Self {
893 if bit { self.add_hi() } else { self.add_lo() }
894 }
895
896 pub fn build(self) -> Waveform<T> {
898 Waveform {
899 values: self.values,
900 }
901 }
902}
903
904#[cfg(test)]
905mod tests {
906 use approx::{assert_relative_eq, assert_relative_ne};
907
908 use super::*;
909
910 #[test]
911 fn waveform_edges() {
912 let wav =
913 Waveform::from_iter([(0., 0.), (1., 1.), (2., 0.9), (3., 0.1), (4., 0.), (5., 1.)]);
914 let edges = wav.edges(0.5).collect::<Vec<_>>();
915 assert_eq!(
916 edges,
917 vec![
918 Edge {
919 t: 0.5,
920 start_idx: 0,
921 dir: EdgeDir::Rising,
922 },
923 Edge {
924 t: 2.5,
925 start_idx: 2,
926 dir: EdgeDir::Falling,
927 },
928 Edge {
929 t: 4.5,
930 start_idx: 4,
931 dir: EdgeDir::Rising,
932 },
933 ]
934 );
935 }
936
937 #[test]
938 fn waveform_sample_at() {
939 let wav =
940 Waveform::from_iter([(0., 0.), (1., 1.), (2., 0.9), (3., 0.1), (4., 0.), (5., 1.)]);
941 assert_relative_eq!(wav.sample_at(0.0), 0.0, epsilon = 1e-15);
942 assert_relative_eq!(wav.sample_at(0.5), 0.5, epsilon = 1e-15);
943 assert_relative_eq!(wav.sample_at(1.2), 0.98, epsilon = 1e-15);
944 assert_relative_eq!(wav.sample_at(1.8), 0.92, epsilon = 1e-15);
945 assert_relative_eq!(wav.sample_at(2.0), 0.9, epsilon = 1e-15);
946 assert_relative_eq!(wav.sample_at(4.0), 0.0, epsilon = 1e-15);
947 assert_relative_eq!(wav.sample_at(4.3), 0.3, epsilon = 1e-15);
948 assert_relative_eq!(wav.sample_at(4.5), 0.5, epsilon = 1e-15);
949 assert_relative_eq!(wav.sample_at(4.9), 0.9, epsilon = 1e-15);
950 assert_relative_ne!(wav.sample_at(4.9) + 1e-12, 0.9, epsilon = 1e-15);
951 assert_relative_eq!(wav.sample_at(4.99), 0.99, epsilon = 1e-15);
952 assert_relative_ne!(wav.sample_at(4.99) + 1e-12, 0.99, epsilon = 1e-15);
953 assert_relative_ne!(wav.sample_at(4.99) - 1e-12, 0.99, epsilon = 1e-15);
954 }
955
956 #[test]
957 fn waveform_transitions() {
958 let wav =
959 Waveform::from_iter([(0., 0.), (1., 1.), (2., 0.9), (3., 0.1), (4., 0.), (5., 1.)]);
960 let transitions = wav.transitions(0.1, 0.9).collect::<Vec<_>>();
961 assert_eq!(
962 transitions,
963 vec![
964 Transition {
965 start_t: 0.,
966 start_idx: 0,
967 end_t: 1.,
968 end_idx: 1,
969 dir: EdgeDir::Rising,
970 },
971 Transition {
972 start_t: 2.,
973 start_idx: 2,
974 end_t: 3.,
975 end_idx: 3,
976 dir: EdgeDir::Falling,
977 },
978 Transition {
979 start_t: 4.,
980 start_idx: 4,
981 end_t: 5.,
982 end_idx: 5,
983 dir: EdgeDir::Rising,
984 },
985 ]
986 );
987 }
988
989 #[test]
990 fn waveform_integral() {
991 let wav = Waveform::from_iter([
992 (0., 0.),
993 (1., 1.),
994 (2., 0.9),
995 (3., 0.1),
996 (4., 0.),
997 (5., 1.),
998 (8., 1.1),
999 ]);
1000 let expected = 0.5 + 0.95 + 0.5 + 0.05 + 0.5 + 3.0 * 1.05;
1001 let integral = wav.integral();
1002 assert_relative_eq!(integral, expected);
1003 assert_relative_ne!(integral, expected + 1e-12);
1004 assert_relative_ne!(integral, expected - 1e-12);
1005 }
1006}