reda_sp/model/sources/
sine.rs1use core::f64;
2use derive_builder::Builder;
3use reda_unit::{num, Frequency, Number, Time, Voltage, u};
4
5#[derive(Debug, Clone, Builder)]
6#[builder(setter(into))]
7pub struct SineVoltage {
8 pub vo: Voltage,
9 pub va: Voltage,
10 pub freq_hz: Frequency,
11 #[builder(default = "u!(0 s)")]
12 pub delay: Time,
13 #[builder(default = "u!(0 hz)")]
14 pub damping: Frequency,
15 #[builder(default = "num!(0)")]
16 pub phase_deg: Number,
17}
18
19impl SineVoltage {
20 pub fn sin(amplitude: Voltage, frequency: Frequency) -> Self {
22 SineVoltageBuilder::default()
23 .vo(u!(0 V))
24 .va(amplitude)
25 .freq_hz(frequency)
26 .build().unwrap()
27 }
28
29 pub fn cos(amplitude: Voltage, frequency: Frequency) -> Self {
31 let period = frequency.to_period();
32 SineVoltageBuilder::default()
33 .vo(u!(0 V))
34 .va(amplitude)
35 .freq_hz(frequency)
36 .delay(-0.25 * period)
37 .build().unwrap()
38 }
39
40 pub fn period(&self) -> Time {
41 self.freq_hz.to_period()
42 }
43
44 pub fn voltage_at(&self, time: Time) -> Voltage {
45 if time < self.delay {
46 return self.vo;
47 }
48
49 let td = time - self.delay;
50 let envelope = (-self.damping * td).exp();
51 let omega = (2.0 * f64::consts::PI) * self.freq_hz;
52 let sine = (omega * td + self.phase_deg / 360.).sin();
53
54 self.vo + self.va * envelope * sine
55 }
56
57 pub fn to_spice(&self) -> String {
58 format!(
59 "SIN({} {} {} {} {} {})",
60 self.vo,
61 self.va,
62 self.freq_hz,
63 self.delay,
64 self.damping,
65 self.phase_deg
66 )
67 }
68}