substrate/simulation/
waveform.rs

1//! Time-domain waveforms.
2
3use std::cmp::Ordering;
4use std::iter::FusedIterator;
5use std::ops::{Add, Div, Mul, Sub};
6
7use serde::{Deserialize, Serialize};
8
9/// A time-dependent waveform that owns its data.
10#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Hash, Eq, Serialize, Deserialize)]
11pub struct Waveform<T> {
12    /// List of [`TimePoint`]s.
13    values: Vec<TimePoint<T>>,
14}
15
16/// A time-dependent waveform that references data stored elsewhere.
17#[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/// A single point `(t, x)` on a waveform.
24#[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    /// Create a new [`TimePoint`].
34    #[inline]
35    pub fn new(t: T, x: T) -> Self {
36        Self { t, x }
37    }
38
39    /// Converts the TimePoint's datatype into another datatype.
40    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    /// The time associated with this point.
56    #[inline]
57    pub fn t(&self) -> T {
58        self.t
59    }
60
61    /// The value associated with this point.
62    #[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
78/// A time-domain waveform.
79pub trait TimeWaveform {
80    /// The datatype of time and signal values in the waveform.
81    ///
82    /// Typically, this should be [`f64`] or [`rust_decimal::Decimal`].
83    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    /// Get the value of the waveform at the given index.
91    fn get(&self, idx: usize) -> Option<TimePoint<Self::Data>>;
92
93    /// Returns the number of time points in the waveform.
94    fn len(&self) -> usize;
95
96    /// Returns `true` if the waveform is empty.
97    fn is_empty(&self) -> bool {
98        self.len() == 0
99    }
100
101    /// The time associated with the first point in the waveform.
102    fn first_t(&self) -> Option<Self::Data> {
103        Some(self.first()?.t())
104    }
105
106    /// The value associated with the first point in the waveform.
107    fn first_x(&self) -> Option<Self::Data> {
108        Some(self.first()?.x())
109    }
110
111    /// The time associated with the last point in the waveform.
112    fn last_t(&self) -> Option<Self::Data> {
113        Some(self.last()?.t())
114    }
115
116    /// The value associated with the last point in the waveform.
117    fn last_x(&self) -> Option<Self::Data> {
118        Some(self.last()?.x())
119    }
120
121    /// The first point in the waveform.
122    fn first(&self) -> Option<TimePoint<Self::Data>> {
123        self.get(0)
124    }
125
126    /// The last point in the waveform.
127    fn last(&self) -> Option<TimePoint<Self::Data>> {
128        self.get(self.len() - 1)
129    }
130
131    /// Returns an iterator over the edges in the waveform.
132    ///
133    /// See [`Edges`] for more information.
134    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    /// Returns an iterator over the transitions in the waveform.
143    ///
144    /// See [`Transitions`] for more information.
145    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    /// Returns an iterator over the values in the waveform.
163    ///
164    /// See [`Values`] for more information.
165    fn values(&self) -> Values<'_, Self> {
166        Values {
167            waveform: self,
168            idx: 0,
169        }
170    }
171
172    /// Returns the index of the last point in the waveform with a time before `t`.
173    fn time_index_before(&self, t: Self::Data) -> Option<usize> {
174        search_for_time(self, t)
175    }
176
177    /// Retrieves the value of the waveform at the given time.
178    ///
179    /// By default, linearly interpolates between two adjacent points on the waveform.
180    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    /// Returns the maximum value seen in this waveform.
194    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    /// Returns the minimum value seen in this waveform.
210    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    /// Returns the middle value seen in this waveform.
226    ///
227    /// This is typically the arithmetic average of the max and min values.
228    fn mid_x(&self) -> Option<Self::Data> {
229        Some((self.max_x()? + self.min_x()?) / Self::Data::from(2))
230    }
231
232    /// Returns the time integral of this waveform.
233    ///
234    /// By default, uses trapezoidal integration.
235    /// Returns 0.0 if the length of the waveform is less than 2.
236    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/// An iterator over the values in the waveform.
270#[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/// Possible edge directions.
337#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
338pub enum EdgeDir {
339    /// A falling edge.
340    Falling,
341    /// A rising edge.
342    Rising,
343}
344
345/// An edge.
346#[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/// An iterator over the edges in a waveform.
354#[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 at the given time.
366    High,
367    /// Unknown.
368    #[default]
369    Unknown,
370    /// Low at the given time.
371    Low,
372}
373
374/// An iterator over the transitions in a waveform.
375#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
376pub struct Transitions<'a, W: ?Sized, T> {
377    waveform: &'a W,
378    state: TransitionState,
379    /// Time at which the waveform was in either a high or low state.
380    t: T,
381    prev_idx: usize,
382    /// Index of the **next** element to process.
383    idx: usize,
384    low_thresh: T,
385    high_thresh: T,
386}
387
388/// A single observed transition in a waveform.
389#[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    /// Creates a new, empty waveform.
400    #[inline]
401    pub fn new() -> Self {
402        Self { values: Vec::new() }
403    }
404
405    /// Converts the waveform's datatype into another datatype.
406    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    /// Creates a new waveform with a single point `(0, x)`.
419    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    /// Adds the given point to the waveform.
429    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    /// Returns `true` if this is a rising edge.
640    #[inline]
641    pub fn is_rising(&self) -> bool {
642        matches!(self, EdgeDir::Rising)
643    }
644
645    /// Returns `true` if this is a falling edge.
646    #[inline]
647    pub fn is_falling(&self) -> bool {
648        matches!(self, EdgeDir::Falling)
649    }
650}
651
652impl<T> Edge<T> {
653    /// The direction (rising or falling) of the edge.
654    #[inline]
655    pub fn dir(&self) -> EdgeDir {
656        self.dir
657    }
658
659    /// The time at which the waveform crossed the threshold.
660    ///
661    /// The waveform is linearly interpolated to find the threshold crossing time.
662    #[inline]
663    pub fn t(&self) -> T
664    where
665        T: Copy,
666    {
667        self.t
668    }
669
670    /// The index in the waveform **before** the threshold was passed.
671    #[inline]
672    pub fn idx_before(&self) -> usize {
673        self.start_idx
674    }
675
676    /// The index in the waveform **after** the threshold was passed.
677    #[inline]
678    pub fn idx_after(&self) -> usize {
679        self.start_idx + 1
680    }
681}
682
683impl<T> Transition<T> {
684    /// The direction (rising or falling) of the transition.
685    #[inline]
686    pub fn dir(&self) -> EdgeDir {
687        self.dir
688    }
689
690    /// The time at which this transition starts.
691    #[inline]
692    pub fn start_time(&self) -> T
693    where
694        T: Copy,
695    {
696        self.start_t
697    }
698
699    /// The time at which this transition ends.
700    #[inline]
701    pub fn end_time(&self) -> T
702    where
703        T: Copy,
704    {
705        self.end_t
706    }
707
708    /// The index of the transition start point in the original waveform.
709    #[inline]
710    pub fn start_idx(&self) -> usize {
711        self.start_idx
712    }
713
714    /// The index of the transition end point in the original waveform.
715    #[inline]
716    pub fn end_idx(&self) -> usize {
717        self.end_idx
718    }
719
720    /// The duration of the transition.
721    ///
722    /// Equal to the difference between the end time and the start time.
723    #[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    /// The average of the start and end times.
732    #[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    /// Creates a new waveform referencing the given `t` and `x` data.
743    ///
744    /// # Panics
745    ///
746    /// Panics if the two slices have different lengths.
747    #[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
783/// Parameters for constructing a [`DigitalWaveformBuilder`].
784pub struct DigitalWaveformParams<T> {
785    /// The digital supply voltage (V).
786    pub vdd: T,
787    /// The digital clock period (sec).
788    pub period: T,
789    /// The offset of the digital waveform (sec).
790    pub offset: T,
791    /// The rise time (sec).
792    pub tr: T,
793    /// The fall time (sec).
794    pub tf: T,
795}
796
797/// A builder for creating clocked digital waveforms.
798pub 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    /// Creates a new builder with the given parameters.
817    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    /// Adds one cycle of logical high to the waveform.
827    ///
828    /// If the waveform was previously logical low, the waveform will
829    /// transition to logical high with a duration governed by the rise time parameter.
830    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    /// Adds one cycle of logical low to the waveform.
858    ///
859    /// If the waveform was previously logical high, the waveform will
860    /// transition to logical low with a duration governed by the fall time parameter.
861    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    /// Adds one cycle of the given bit value to the waveform.
888    ///
889    /// If `bit` is `true`, this is equivalent to calling [`DigitalWaveformBuilder::add_hi`].
890    /// If `bit` is `false`, this is equivalent to calling [`DigitalWaveformBuilder::add_lo`].
891    #[inline]
892    pub fn add(&mut self, bit: bool) -> &mut Self {
893        if bit { self.add_hi() } else { self.add_lo() }
894    }
895
896    /// Consumes the builder, producing a [`Waveform`].
897    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}