reda_sp/model/sources/
sine.rs

1use 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    // F(t) = A sin(2pi f t)
21    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    // F(t) = A cos(2pi f t)
30    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}