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
105impl 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 | r2; let v1 = circuit.v_open(); assert_eq!(v1, r2 / (r1 + r2) * vcc)
182}