dune_netlist/ir.rs
1//! Intermediate representation of a parsed deck (PLAN.md §2.1).
2//!
3//! Faithful to the 3f5 contract: identifiers are lowercased (the C
4//! lowercases the whole deck), parameter names are the 3f5 keywords,
5//! nodes are strings and `0` is ground. Everything carries a [`Span`].
6
7use crate::span::Span;
8
9/// A lowercased identifier (device, node, model or subcircuit name).
10pub type Ident = String;
11
12#[derive(Clone, Debug, Default)]
13pub struct Netlist {
14 pub title: String,
15 /// Flat element list (subcircuits already expanded).
16 pub elements: Vec<Element>,
17 pub models: Vec<Model>,
18 pub analyses: Vec<Analysis>,
19 /// `.options`, as given; defaults live in `dune-core::consts`.
20 pub options: Vec<Param>,
21 /// `.print` / `.plot` / `.save` / `.four`.
22 pub outputs: Vec<Output>,
23 /// `.ic` and `.nodeset` entries.
24 pub node_inits: Vec<NodeInit>,
25 /// `.measure` / `.meas` cards (ngspice grammar; pure
26 /// post-processing, never part of the simulation).
27 pub measures: Vec<Measure>,
28 /// `.control` … `.endc` lines, verbatim and uninterpreted.
29 pub control: Vec<String>,
30 /// `.width out=N`: print column width (the `in=` half only ever
31 /// mattered to punched-card decks and is ignored).
32 pub width_out: Option<usize>,
33}
34
35/// One circuit element (an instance line).
36#[derive(Clone, Debug)]
37pub struct Element {
38 /// Full lowercased name; the first letter is the device type.
39 /// Subcircuit expansion produces dotted names (`x1.r1`).
40 pub name: Ident,
41 /// Connection nodes, in card order (empty for `K`).
42 pub nodes: Vec<Ident>,
43 pub device: Device,
44 pub span: Span,
45}
46
47/// Extra per-card data, one variant per 3f5 device letter.
48///
49/// `params` hold the keyword parameters exactly as the card gave
50/// them (3f5 keywords, lowercase); validation against each device's
51/// real parameter table is `dune-core`'s job when the device is
52/// implemented.
53#[derive(Clone, Debug)]
54pub enum Device {
55 /// `R`: `RXXXXXXX N1 N2 VALUE` / semiconductor form with MNAME.
56 Resistor {
57 value: Option<f64>,
58 model: Option<Ident>,
59 params: Vec<Param>,
60 },
61 /// `C`: `CXXXXXXX N+ N- VALUE <IC=INCOND>` / semiconductor form.
62 Capacitor {
63 value: Option<f64>,
64 model: Option<Ident>,
65 params: Vec<Param>,
66 },
67 /// `L`: `LYYYYYYY N+ N- VALUE <IC=INCOND>`.
68 Inductor {
69 value: Option<f64>,
70 params: Vec<Param>,
71 },
72 /// `K`: `KXXXXXXX LYYYYYYY LZZZZZZZ VALUE` (no nodes).
73 Mutual { l1: Ident, l2: Ident, k: f64 },
74 /// `V`/`I`: independent source.
75 Source {
76 kind: SourceKind,
77 dc: Option<f64>,
78 ac: Option<AcSpec>,
79 tran: Option<TranFn>,
80 /// `DISTOF1 <MAG <PHASE>>`.
81 distof1: Option<DistoSpec>,
82 distof2: Option<DistoSpec>,
83 /// `PORTNUM N <Z0 Z>` (ngspice RF port, V sources only):
84 /// present only when the card makes the source a port —
85 /// `N > 0` and a positive reference impedance — as
86 /// `VSRCtemp` decides it.
87 port: Option<RfPort>,
88 },
89 /// `E`: VCVS, 4 nodes + gain.
90 Vcvs { gain: Option<f64> },
91 /// `G`: VCCS, 4 nodes + transconductance.
92 Vccs { gain: Option<f64> },
93 /// `F`: CCCS, 2 nodes + controlling V-source + gain.
94 Cccs { vname: Ident, gain: Option<f64> },
95 /// `H`: CCVS, 2 nodes + controlling V-source + transresistance.
96 Ccvs { vname: Ident, gain: Option<f64> },
97 /// `D`: `DXXXXXXX N+ N- MNAME <AREA> <OFF> <IC=VD> <TEMP=T>`.
98 Diode {
99 model: Ident,
100 area: Option<f64>,
101 off: bool,
102 params: Vec<Param>,
103 },
104 /// `Q`: 3 or 4 nodes (optional substrate) + model.
105 Bjt {
106 model: Ident,
107 area: Option<f64>,
108 off: bool,
109 params: Vec<Param>,
110 },
111 /// `J`: `JXXXXXXX ND NG NS MNAME <AREA> <OFF> <IC=…>`.
112 Jfet {
113 model: Ident,
114 area: Option<f64>,
115 off: bool,
116 params: Vec<Param>,
117 },
118 /// `Z`: MESFET, same shape as `J`.
119 Mesfet {
120 model: Ident,
121 area: Option<f64>,
122 off: bool,
123 params: Vec<Param>,
124 },
125 /// `M`: 4 nodes + model + geometry parameters.
126 Mosfet { model: Ident, params: Vec<Param> },
127 /// `S`: voltage-controlled switch, 4 nodes + model.
128 SwitchV { model: Ident, state: Option<OnOff> },
129 /// `W`: current-controlled switch, 2 nodes + V-source + model.
130 SwitchI {
131 vname: Ident,
132 model: Ident,
133 state: Option<OnOff>,
134 },
135 /// `T`: lossless transmission line, 4 nodes, `Z0=` etc.
136 TlineIdeal { params: Vec<Param> },
137 /// `O`: lossy transmission line, 4 nodes + LTRA model.
138 TlineLossy { model: Ident },
139 /// `U`: uniform distributed RC, 3 nodes + URC model.
140 Urc { model: Ident, params: Vec<Param> },
141 /// `B`: non-linear dependent source (`ASRC`), `V=EXPR` or
142 /// `I=EXPR`; when the card gives both, the last one wins, as in
143 /// `INPdevParse` + `ASRCparam`.
144 Behavioral { kind: SourceKind, expr: Expr },
145 /// `X`: subcircuit call, only seen before expansion.
146 SubcktCall { subname: Ident },
147}
148
149#[derive(Clone, Copy, Debug, PartialEq, Eq)]
150pub enum SourceKind {
151 Voltage,
152 Current,
153}
154
155/// A B-source expression: the 3f5 parse tree (`INPparseNode`,
156/// `inpptree.h`) as `PTparse` builds it — no constant folding (only
157/// the derivative trees fold, in `dune-core`) and every name already
158/// resolved. Built by [`crate::parse_expr`].
159#[derive(Clone, Debug, PartialEq)]
160pub enum Expr {
161 /// `PT_CONSTANT`: a number or one of the constants `e`, `pi`.
162 Num(f64),
163 /// `v(node)` (`PT_VAR` of type `IF_NODE`). `v(a,b)` is parsed
164 /// into `v(a) - v(b)`, as `mkfnode` does.
165 V(Ident),
166 /// `i(vname)` (`PT_VAR` of type `IF_INSTANCE`): the branch current
167 /// of a device with a branch equation (V, E, H, L, a voltage-type
168 /// B).
169 I(Ident),
170 /// `PT_PLUS` … `PT_POWER`.
171 Bin(ExprOp, Box<Expr>, Box<Expr>),
172 /// `PT_FUNCTION` (unary minus included, as `ExprFunc::Neg`).
173 Call(ExprFunc, Box<Expr>),
174}
175
176/// The binary operators of the 3f5 expression grammar (`ops[]` in
177/// `inpptree.c`).
178#[derive(Clone, Copy, Debug, PartialEq, Eq)]
179pub enum ExprOp {
180 Plus,
181 Minus,
182 Times,
183 Divide,
184 Power,
185}
186
187/// The functions of `ptfuncs.c` (`funcs[]` in `inpptree.c`), with
188/// their 3f5 semantics: `log` is the base-10 logarithm, `ln`/`log`/
189/// `sqrt` act on `|x|`, `u` is the unit step (½ at 0), `uramp` the
190/// unit ramp.
191#[derive(Clone, Copy, Debug, PartialEq, Eq)]
192pub enum ExprFunc {
193 Abs,
194 Acos,
195 Acosh,
196 Asin,
197 Asinh,
198 Atan,
199 Atanh,
200 Cos,
201 Cosh,
202 Exp,
203 Ln,
204 Log,
205 Sgn,
206 Sin,
207 Sinh,
208 Sqrt,
209 Tan,
210 Tanh,
211 U,
212 Uramp,
213 /// Unary minus (`PTF_UMINUS`, the function named `-`).
214 Neg,
215}
216
217impl ExprFunc {
218 /// The 3f5 function table, by name (`funcs[]`; `-` is reached
219 /// only through the unary-minus token).
220 pub const TABLE: [(&'static str, ExprFunc); 20] = [
221 ("abs", ExprFunc::Abs),
222 ("acos", ExprFunc::Acos),
223 ("acosh", ExprFunc::Acosh),
224 ("asin", ExprFunc::Asin),
225 ("asinh", ExprFunc::Asinh),
226 ("atan", ExprFunc::Atan),
227 ("atanh", ExprFunc::Atanh),
228 ("cos", ExprFunc::Cos),
229 ("cosh", ExprFunc::Cosh),
230 ("exp", ExprFunc::Exp),
231 ("ln", ExprFunc::Ln),
232 ("log", ExprFunc::Log),
233 ("sgn", ExprFunc::Sgn),
234 ("sin", ExprFunc::Sin),
235 ("sinh", ExprFunc::Sinh),
236 ("sqrt", ExprFunc::Sqrt),
237 ("tan", ExprFunc::Tan),
238 ("tanh", ExprFunc::Tanh),
239 ("u", ExprFunc::U),
240 ("uramp", ExprFunc::Uramp),
241 ];
242
243 /// The name the function is written with (`-` for [`ExprFunc::Neg`]).
244 pub fn name(self) -> &'static str {
245 if self == ExprFunc::Neg {
246 return "-";
247 }
248 Self::TABLE
249 .iter()
250 .find(|(_, f)| *f == self)
251 .map_or("?", |(n, _)| n)
252 }
253}
254
255impl Expr {
256 /// Visit every `v()` node name and `i()` device name, mutably
257 /// (subcircuit expansion renames them). Depth is bounded by the
258 /// parser, so the recursion is too.
259 pub fn visit_refs_mut(
260 &mut self,
261 node: &mut dyn FnMut(&mut Ident),
262 device: &mut dyn FnMut(&mut Ident),
263 ) {
264 match self {
265 Expr::Num(_) => {}
266 Expr::V(n) => node(n),
267 Expr::I(d) => device(d),
268 Expr::Bin(_, l, r) => {
269 l.visit_refs_mut(node, device);
270 r.visit_refs_mut(node, device);
271 }
272 Expr::Call(_, a) => a.visit_refs_mut(node, device),
273 }
274 }
275}
276
277#[derive(Clone, Copy, Debug, PartialEq, Eq)]
278pub enum OnOff {
279 On,
280 Off,
281}
282
283/// `AC <ACMAG <ACPHASE>>` — defaults are the 3f5's (magnitude 1,
284/// phase 0 when omitted).
285#[derive(Clone, Copy, Debug, PartialEq)]
286pub struct AcSpec {
287 pub mag: f64,
288 pub phase: f64,
289}
290
291/// An ngspice RF port on a V source (`PORTNUM N <Z0 Z>`, `vsrc.c`
292/// under `RFSPICE`): the source sits behind a series reference
293/// impedance `z0` (default 50 Ω) and `.sp` excites it as port `num`.
294#[derive(Clone, Copy, Debug, PartialEq)]
295pub struct RfPort {
296 /// Port index, 1-based (`VSRCportNum`).
297 pub num: u32,
298 /// Reference impedance in ohms (`VSRCportZ0`), > 0.
299 pub z0: f64,
300}
301
302/// `DISTOF1/DISTOF2 <MAG <PHASE>>` (defaults 1 and 0).
303#[derive(Clone, Copy, Debug, PartialEq)]
304pub struct DistoSpec {
305 pub mag: f64,
306 pub phase: f64,
307}
308
309/// A time-dependent source function. Arguments are stored exactly as
310/// given; defaults (many depend on TSTEP/TSTOP) are applied by
311/// `dune-core` at analysis time, as the 3f5 does.
312#[derive(Clone, Debug, PartialEq)]
313pub struct TranFn {
314 pub kind: TranFnKind,
315 pub args: Vec<f64>,
316}
317
318#[derive(Clone, Copy, Debug, PartialEq, Eq)]
319pub enum TranFnKind {
320 Pulse,
321 Sin,
322 Exp,
323 Pwl,
324 Sffm,
325 /// ngspice-47 `TRNOISE(NA NT NALPHA NAMP RTSAM RTSCAPT RTSEMT)`:
326 /// transient noise (white, 1/f^alpha, random telegraph).
327 TrNoise,
328 /// ngspice-47 `TRRANDOM(TYPE TS TD PARAM1 PARAM2)`: a random
329 /// value held for `TS` seconds.
330 TrRandom,
331}
332
333/// A keyword parameter from a card: `IC=3`, `OFF`, `IC=2,0.5,0,0.2`,
334/// `METHOD=GEAR`.
335#[derive(Clone, Debug)]
336pub struct Param {
337 /// Lowercased 3f5 keyword.
338 pub name: Ident,
339 pub value: ParamValue,
340 pub span: Span,
341}
342
343#[derive(Clone, Debug, PartialEq)]
344pub enum ParamValue {
345 /// Bare keyword (`off`, `uic`, `acct`).
346 Flag,
347 Num(f64),
348 /// Consecutive numbers after the keyword (`ic=2,0.5,0,0.2`).
349 NumList(Vec<f64>),
350 /// Non-numeric value (`method=gear`).
351 Str(String),
352}
353
354/// `.model MNAME TYPE(PNAME1=PVAL1 …)`.
355#[derive(Clone, Debug)]
356pub struct Model {
357 pub name: Ident,
358 /// 3f5 type name: `r c sw csw urc ltra d npn pnp njf pjf nmos
359 /// pmos nmf pmf`.
360 pub mtype: Ident,
361 pub params: Vec<Param>,
362 pub span: Span,
363}
364
365/// An analysis request (one dot card).
366#[derive(Clone, Debug)]
367pub enum Analysis {
368 /// `.op`
369 Op { span: Span },
370 /// `.dc SRCNAM VSTART VSTOP VINCR [SRC2 START2 STOP2 INCR2]`
371 Dc { sweeps: Vec<DcSweep>, span: Span },
372 /// `.ac DEC|OCT|LIN N FSTART FSTOP`
373 Ac {
374 variation: Variation,
375 points: f64,
376 fstart: f64,
377 fstop: f64,
378 span: Span,
379 },
380 /// `.tran TSTEP TSTOP <TSTART <TMAX>> <UIC>`
381 Tran {
382 tstep: f64,
383 tstop: f64,
384 tstart: Option<f64>,
385 tmax: Option<f64>,
386 uic: bool,
387 span: Span,
388 },
389 /// `.pz NODE1 NODE2 NODE3 NODE4 CUR|VOL POL|ZER|PZ`
390 Pz {
391 nodes: [Ident; 4],
392 input: PzInput,
393 which: PzWhich,
394 span: Span,
395 },
396 /// `.noise V(OUT<,REF>) SRC DEC|LIN|OCT PTS FSTART FSTOP <PPS>`
397 Noise {
398 output: Ident,
399 output_ref: Option<Ident>,
400 src: Ident,
401 variation: Variation,
402 points: f64,
403 fstart: f64,
404 fstop: f64,
405 pts_per_summary: Option<f64>,
406 span: Span,
407 },
408 /// `.disto DEC|OCT|LIN NP FSTART FSTOP <F2OVERF1>`
409 Disto {
410 variation: Variation,
411 points: f64,
412 fstart: f64,
413 fstop: f64,
414 f2overf1: Option<f64>,
415 span: Span,
416 },
417 /// `.sens OUTVAR [FILTER…] [AC DEC|OCT|LIN N FSTART FSTOP | DC]`
418 /// (the filters — glob patterns over the sensitivity vector
419 /// names, `*` and `?` — are ngspice's extension of the 3f5 card).
420 Sens {
421 outvar: OutVar,
422 filters: Vec<Ident>,
423 ac: Option<(Variation, f64, f64, f64)>,
424 span: Span,
425 },
426 /// `.sp DEC|OCT|LIN N FSTART FSTOP <DONOISE>` — ngspice's
427 /// S-parameter analysis over the `PORTNUM` V sources
428 /// (`inp2dot.c` `dot_sp`; `DONOISE` is the integer 1 to add the
429 /// noise-correlation outputs).
430 Sp {
431 variation: Variation,
432 points: f64,
433 fstart: f64,
434 fstop: f64,
435 donoise: bool,
436 span: Span,
437 },
438 /// `.pss FREQ TSTAB OSCNODE <POINTS <HARMS <SCITER <STEADYCOEFF>>>>
439 /// <UIC>` — the periodic steady state, in ngspice-47's positional
440 /// grammar (`inp2dot.c` `dot_pss`; there every field up to
441 /// STEADYCOEFF is required). `FREQ = 0` asks Dune to take the
442 /// fundamental from the periodic sources.
443 Pss {
444 freq: f64,
445 tstab: f64,
446 osc_node: Ident,
447 points: Option<f64>,
448 harmonics: Option<f64>,
449 sc_iter: Option<f64>,
450 steady_coeff: Option<f64>,
451 uic: bool,
452 span: Span,
453 },
454 /// `.tf OUTVAR INSRC`
455 Tf {
456 outvar: OutVar,
457 insrc: Ident,
458 span: Span,
459 },
460}
461
462/// One `.dc` sweep source: name, start, stop, increment.
463#[derive(Clone, Debug)]
464pub struct DcSweep {
465 pub src: Ident,
466 pub start: f64,
467 pub stop: f64,
468 pub step: f64,
469}
470
471#[derive(Clone, Copy, Debug, PartialEq, Eq)]
472pub enum Variation {
473 Dec,
474 Oct,
475 Lin,
476}
477
478#[derive(Clone, Copy, Debug, PartialEq, Eq)]
479pub enum PzInput {
480 Current,
481 Voltage,
482}
483
484#[derive(Clone, Copy, Debug, PartialEq, Eq)]
485pub enum PzWhich {
486 Poles,
487 Zeros,
488 Both,
489}
490
491/// `.print` / `.plot` / `.save` / `.four`.
492#[derive(Clone, Debug)]
493pub struct Output {
494 pub kind: OutputKind,
495 /// `DC`, `AC`, `TRAN`, `NOISE` or `DISTO` for print/plot.
496 pub analysis: Option<Ident>,
497 pub vars: Vec<OutVar>,
498 pub span: Span,
499}
500
501#[derive(Clone, Debug, PartialEq)]
502pub enum OutputKind {
503 Print,
504 Plot,
505 Save,
506 /// `.four FREQ OV1 …`
507 Four {
508 freq: f64,
509 },
510}
511
512/// An output variable reference.
513#[derive(Clone, Debug, PartialEq)]
514pub enum OutVar {
515 /// `V(N1<,N2>)` with an optional AC suffix (`VM`, `VP`, `VR`,
516 /// `VI`, `VDB`).
517 Voltage {
518 node: Ident,
519 reference: Option<Ident>,
520 suffix: Option<AcSuffix>,
521 },
522 /// `I(VXXXXXXX)` with the same optional suffixes.
523 Current {
524 vsrc: Ident,
525 suffix: Option<AcSuffix>,
526 },
527 /// Anything else (a raw vector name for `.save`, e.g. `all`).
528 Raw(Ident),
529}
530
531#[derive(Clone, Copy, Debug, PartialEq, Eq)]
532pub enum AcSuffix {
533 Real,
534 Imag,
535 Mag,
536 Phase,
537 Db,
538}
539
540/// One `.ic`/`.nodeset` assignment.
541#[derive(Clone, Debug)]
542pub struct NodeInit {
543 pub kind: NodeInitKind,
544 pub node: Ident,
545 pub value: f64,
546 pub span: Span,
547}
548
549#[derive(Clone, Copy, Debug, PartialEq, Eq)]
550pub enum NodeInitKind {
551 /// `.ic`: enforced initial condition.
552 Ic,
553 /// `.nodeset`: initial guess only.
554 Nodeset,
555}
556
557/// One `.measure` card (ngspice-47 `com_measure2.c` grammar — the
558/// 3f5 has none, so ngspice is the contract here; see
559/// `docs/dune-measure.md`).
560#[derive(Clone, Debug, PartialEq)]
561pub struct Measure {
562 /// Which plot the card measures.
563 pub analysis: MeasAnalysis,
564 /// Result name (lowercased, like every deck identifier).
565 pub name: Ident,
566 /// The measurement itself.
567 pub func: MeasFunc,
568 /// The function keyword as written, lowercased (`trig`, `when`,
569 /// `avg`…), for ngspice-style messages.
570 pub keyword: String,
571 /// The card text as written (continuations joined).
572 pub text: String,
573 pub span: Span,
574}
575
576/// The analysis a `.measure` card applies to (`chkAnalysisType`).
577#[derive(Clone, Copy, Debug, PartialEq, Eq)]
578pub enum MeasAnalysis {
579 Tran,
580 Ac,
581 Dc,
582 /// ngspice's `.sp` (measured like `.ac`).
583 Sp,
584}
585
586impl MeasAnalysis {
587 /// The card keyword (`tran`, `ac`, `dc`, `sp`).
588 pub fn keyword(self) -> &'static str {
589 match self {
590 MeasAnalysis::Tran => "tran",
591 MeasAnalysis::Ac => "ac",
592 MeasAnalysis::Dc => "dc",
593 MeasAnalysis::Sp => "sp",
594 }
595 }
596}
597
598/// What a `.measure` computes.
599#[derive(Clone, Debug, PartialEq)]
600pub enum MeasFunc {
601 /// `TRIG … TARG …` (also spelled `DELAY`): `targ − trig`.
602 Delay { trig: MeasTrig, targ: MeasTrig },
603 /// `WHEN out=val|out2`: the scale value of a crossing.
604 When(MeasCross),
605 /// `FIND out AT=x` / `FIND out WHEN …`: the interpolated value.
606 Find { var: OutVar, at: MeasPoint },
607 /// `DERIV out AT=x` / `DERIV out WHEN …`: d(out)/d(scale) —
608 /// a Dune extension; ngspice-47 parses it but reports
609 /// "currently not supported".
610 Deriv { var: OutVar, at: MeasPoint },
611 /// `AVG|MIN|MAX|MIN_AT|MAX_AT|PP|RMS|INTEG out FROM= TO=`.
612 Stat {
613 stat: MeasStat,
614 var: OutVar,
615 window: MeasWindow,
616 },
617}
618
619/// One side of a `TRIG … TARG …` delay.
620#[derive(Clone, Debug, PartialEq)]
621pub enum MeasTrig {
622 /// `TRIG AT=x`: a fixed scale value.
623 At(f64),
624 /// `TRIG out VAL=v RISE|FALL|CROSS=n …`.
625 Cross(MeasCross),
626}
627
628/// Where `FIND`/`DERIV` evaluate.
629#[derive(Clone, Debug, PartialEq)]
630pub enum MeasPoint {
631 At(f64),
632 When(MeasCross),
633}
634
635/// A level crossing: `out` against a constant or a second vector.
636#[derive(Clone, Debug, PartialEq)]
637pub struct MeasCross {
638 pub var: OutVar,
639 pub level: MeasLevel,
640 pub edge: MeasEdge,
641 pub window: MeasWindow,
642}
643
644#[derive(Clone, Debug, PartialEq)]
645pub enum MeasLevel {
646 Value(f64),
647 /// `WHEN v(a)=v(b)`.
648 Var(OutVar),
649}
650
651/// Which crossing counts (`RISE=`, `FALL=`, `CROSS=`; the last one
652/// given wins, as in `measure_parse_stdParams`).
653#[derive(Clone, Copy, Debug, PartialEq, Eq)]
654pub enum MeasEdge {
655 /// None given: the first crossing either way.
656 Any,
657 Rise(MeasCount),
658 Fall(MeasCount),
659 Cross(MeasCount),
660}
661
662#[derive(Clone, Copy, Debug, PartialEq, Eq)]
663pub enum MeasCount {
664 /// The n-th (1-based).
665 Nth(u32),
666 /// `=LAST` (or a bare `LAST`, which means `CROSS=LAST`).
667 Last,
668}
669
670/// `TD=`, `FROM=`, `TO=` as given (`None` = not on the card; the
671/// per-analysis defaults are applied by the evaluator, like ngspice).
672#[derive(Clone, Copy, Debug, Default, PartialEq)]
673pub struct MeasWindow {
674 pub td: Option<f64>,
675 pub from: Option<f64>,
676 pub to: Option<f64>,
677}
678
679#[derive(Clone, Copy, Debug, PartialEq, Eq)]
680pub enum MeasStat {
681 Min,
682 Max,
683 /// The scale value of the minimum.
684 MinAt,
685 /// The scale value of the maximum.
686 MaxAt,
687 /// Peak to peak.
688 Pp,
689 Avg,
690 Rms,
691 Integ,
692}