measures/
elec.rs

1use core::fmt;
2use core::ops::{Add, BitOr, Neg};
3
4use crate::units::*;
5
6#[derive(Debug, Copy, Clone)]
7pub enum Cct {
8    Thevenin(Volt, Ohm),
9    Norton(Amp, Siemen),
10}
11use self::Cct::*;
12
13impl Cct {
14    pub fn i_short(self) -> Amp {
15        match self {
16            Thevenin(v, r) => v / r,
17            Norton(i, _) => i,
18        }
19    }
20    pub fn v_open(self) -> Volt {
21        match self {
22            Thevenin(v, _) => v,
23            Norton(i, g) => i * (1.0 / g),
24        }
25    }
26    pub fn r_equiv(self) -> Ohm {
27        match self {
28            Thevenin(_, r) => r,
29            Norton(_, g) => 1.0 / g,
30        }
31    }
32    pub fn g_equiv(self) -> Siemen {
33        match self {
34            Thevenin(_, r) => 1.0 / r,
35            Norton(_, g) => g,
36        }
37    }
38}
39
40fn norton_wins(lhs: Cct, rhs: Cct) -> bool {
41    match (lhs, rhs) {
42        (Thevenin(_, _), Thevenin(_, _)) => false,
43        (Norton(_, _), Norton(_, _)) => true,
44        (Norton(_, g), _) if g.0 < n => true,
45        (_, Norton(_, g)) if g.0 < n => true,
46        _ => false,
47    }
48}
49
50impl BitOr<Cct> for Cct {
51    type Output = Cct;
52    fn bitor(self, rhs: Cct) -> Cct {
53        if norton_wins(self, rhs) {
54            let ge = self.g_equiv() + rhs.g_equiv();
55            let ie = self.i_short() + rhs.i_short();
56            Norton(ie, ge)
57        } else {
58            let re = self.r_equiv() | rhs.r_equiv();
59            let rs = self.r_equiv() + rhs.r_equiv();
60            let n1 = rhs.r_equiv() / rs;
61            let n2 = self.r_equiv() / rs;
62            let ve = self.v_open() * n1 + rhs.v_open() * n2;
63            Thevenin(ve, re)
64        }
65    }
66}
67
68impl Add<Cct> for Cct {
69    type Output = Cct;
70    fn add(self, rhs: Cct) -> Cct {
71        if norton_wins(self, rhs) {
72            let ge = self.g_equiv() | rhs.g_equiv();
73            let gp = self.g_equiv() + rhs.g_equiv();
74            let n1 = rhs.g_equiv() / gp;
75            let n2 = self.g_equiv() / gp;
76            let ie = self.i_short() * n1 + rhs.i_short() * n2;
77            Norton(ie, ge)
78        } else {
79            let re = self.r_equiv() + rhs.r_equiv();
80            let ve = self.v_open() + rhs.v_open();
81            Thevenin(ve, re)
82        }
83    }
84}
85
86impl Neg for Cct {
87    type Output = Cct;
88    fn neg(self) -> Cct {
89        match self {
90            Thevenin(v, r) => Thevenin(-v, r),
91            Norton(i, g) => Norton(-i, g),
92        }
93    }
94}
95
96impl fmt::Display for Cct {
97    fn fmt(&self, dst: &mut fmt::Formatter) -> fmt::Result {
98        match self {
99            Thevenin(v, r) => write!(dst, "{} + {}", v, r),
100            Norton(i, g) => write!(dst, "{} | {}", i, g),
101        }
102    }
103}
104
105// Conversions from elec units to Cct
106
107impl Add<Ohm> for Volt {
108    type Output = Cct;
109    fn add(self, rhs: Ohm) -> Cct {
110        Thevenin(self, rhs)
111    }
112}
113
114impl BitOr<Siemen> for Amp {
115    type Output = Cct;
116    fn bitor(self, rhs: Siemen) -> Cct {
117        Norton(self, rhs)
118    }
119}
120
121impl BitOr<Ohm> for Cct {
122    type Output = Cct;
123    fn bitor(self, rhs: Ohm) -> Cct {
124        self | Thevenin(Volt(0.0), rhs)
125    }
126}
127
128impl Add<Ohm> for Cct {
129    type Output = Cct;
130    fn add(self, rhs: Ohm) -> Cct {
131        self + Thevenin(Volt(0.0), rhs)
132    }
133}
134
135impl BitOr<Siemen> for Cct {
136    type Output = Cct;
137    fn bitor(self, rhs: Siemen) -> Cct {
138        self | Norton(Amp(0.0), rhs)
139    }
140}
141
142impl Add<Siemen> for Cct {
143    type Output = Cct;
144    fn add(self, rhs: Siemen) -> Cct {
145        self + Norton(Amp(0.0), rhs)
146    }
147}
148
149#[test]
150fn open_evse_cp_example() {
151    let r7 = 200.0 * Ohm(k);
152    let r6 = 100.0 * Ohm(k);
153    let r5 = 56.0 * Ohm(k);
154
155    let vcc = Volt(5.0);
156    let v_cp_hi = Volt(12.0);
157    let gnd = Volt(0.0);
158
159    let cct = v_cp_hi + r7 | gnd + r6 | vcc + r5;
160
161    fn divider3(v1: Volt, r1: Ohm, v2: Volt, r2: Ohm, v3: Volt, r3: Ohm) -> Volt {
162        (v1 / r1 + v2 / r2 + v3 / r3) * (r1 | r2 | r3)
163    }
164
165    let v1 = cct.v_open();
166    let v2 = divider3(v_cp_hi, r7, gnd, r6, vcc, r5);
167
168    assert_eq!(v1, v2)
169}
170
171#[test]
172fn doc_example() {
173    let vcc = Volt(5.0);
174    let r1 = Ohm(10.0 * k);
175    let r2 = Ohm(5.0 * k);
176
177    let circuit = vcc + r1    // A voltage source vcc in series with resistor r1 forms a Cct,
178        | r2; // which is extended by resistor r2 in parallel
179
180    let v1 = circuit.v_open(); // v1 is the voltage produced
181    assert_eq!(v1, r2 / (r1 + r2) * vcc)
182}