reda_sp/model/control/
sim.rs1use derive_builder::Builder;
2use reda_unit::{Frequency, Time, Voltage};
3
4use crate::ToSpice;
5
6#[derive(Debug, Clone)]
7pub enum SimCommand {
8 Op,
9 Dc(DcCommand),
10 Ac(AcCommand),
11 Tran(TranCommand)
12}
13
14#[derive(Debug, Clone, Builder)]
15#[builder(setter(strip_option, into))]
16pub struct DcCommand {
17 pub src_name: String,
18 pub start: Voltage,
19 pub stop: Voltage,
20 pub step: Voltage,
21}
22
23#[derive(Debug, Clone, PartialEq, PartialOrd)]
24pub enum AcSweepType {
25 Lin, Dec, Oct, }
29
30#[derive(Debug, Clone)]
31pub struct AcCommand {
32 pub sweep_type: AcSweepType,
33 pub points: usize,
34 pub f_start: Frequency,
35 pub f_stop: Frequency,
36}
37
38impl AcCommand {
39 pub fn linear<F1: Into<Frequency>, F2: Into<Frequency>>(points: usize, f_start: F1, f_stop: F2) -> Self {
40 Self::new(AcSweepType::Lin, points, f_start, f_stop)
41
42 }
43
44 pub fn dec<F1: Into<Frequency>, F2: Into<Frequency>>(points: usize, f_start: F1, f_stop: F2) -> Self {
45 Self::new(AcSweepType::Dec, points, f_start, f_stop)
46
47 }
48
49 pub fn oct<F1: Into<Frequency>, F2: Into<Frequency>>(points: usize, f_start: F1, f_stop: F2) -> Self {
50 Self::new(AcSweepType::Oct, points, f_start, f_stop)
51
52 }
53
54 pub fn new<F1: Into<Frequency>, F2: Into<Frequency>>(ty: AcSweepType, points: usize, f_start: F1, f_stop: F2) -> Self {
55 Self {
56 sweep_type: ty,
57 points,
58 f_start: f_start.into(),
59 f_stop: f_stop.into(),
60 }
61 }
62}
63
64#[derive(Debug, Clone, Builder)]
65#[builder(setter(into, strip_option))]
66pub struct TranCommand {
67 pub t_step: Time,
68 pub t_stop: Time,
69 #[builder(default)]
70 pub t_start: Option<Time>,
71 #[builder(default)]
72 pub t_max: Option<Time>,
73 #[builder(default = "false")]
74 pub uic: bool, }
76
77impl ToSpice for SimCommand {
78 fn to_spice(&self) -> String {
79 match self {
80 SimCommand::Op => ".op".to_string(),
81 SimCommand::Dc(dc) => dc.to_spice(),
82 SimCommand::Ac(ac) => ac.to_spice(),
83 SimCommand::Tran(tran) => tran.to_spice(),
84 }
85 }
86}
87
88impl ToSpice for DcCommand {
89 fn to_spice(&self) -> String {
90 format!(
91 ".DC {} {} {} {}",
92 self.src_name, self.start, self.stop, self.step
93 )
94 }
95}
96
97impl ToSpice for AcCommand {
98 fn to_spice(&self) -> String {
99 format!(
100 ".AC {} {} {} {}",
101 self.sweep_type.to_spice_str(),
102 self.points,
103 self.f_start.to_spice(),
104 self.f_stop.to_spice(),
105 )
106 }
107}
108
109impl ToSpice for TranCommand {
110 fn to_spice(&self) -> String {
111 let mut line = format!(".TRAN {} {}", self.t_step, self.t_stop);
112
113 if let Some(t_start) = self.t_start {
114 line.push_str(&format!(" {}", t_start));
115 }
116
117 if let Some(t_max) = self.t_max {
118 if self.t_start.is_none() {
119 line.push_str(" 0");
120 }
121 line.push_str(&format!(" {}", t_max));
122 }
123
124 if self.uic {
125 line.push_str(" UIC");
126 }
127
128 line
129 }
130}
131
132impl AcSweepType {
133 pub fn to_spice_str(&self) -> &'static str {
134 match self {
135 AcSweepType::Lin => "LIN",
136 AcSweepType::Dec => "DEC",
137 AcSweepType::Oct => "OCT",
138 }
139 }
140}