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