rill_core_wdf/
elements.rs1use crate::constants::{BOLTZMANN, ELECTRON_CHARGE, NEWTON_TOLERANCE};
2use crate::WdfElement;
3use rill_core::Transcendental;
4
5#[derive(Debug, Clone, Copy)]
7pub struct Resistor<T: Transcendental> {
8 resistance: T,
9 port_resistance: T,
10 voltage: T,
11 current: T,
12}
13
14impl<T: Transcendental> Resistor<T> {
15 pub fn new(resistance: T) -> Self {
17 Self {
18 port_resistance: resistance,
19 resistance,
20 voltage: T::ZERO,
21 current: T::ZERO,
22 }
23 }
24
25 pub fn resistance(&self) -> T {
27 self.resistance
28 }
29}
30
31impl<T: Transcendental> WdfElement<T> for Resistor<T> {
32 fn port_resistance(&self) -> T {
33 self.port_resistance
34 }
35
36 fn process_incident(&mut self, _a: T) -> T {
37 T::ZERO
38 }
39
40 fn update_state(&mut self) {
41 self.voltage = self.current * self.resistance;
42 }
43
44 fn voltage(&self) -> T {
45 self.voltage
46 }
47
48 fn current(&self) -> T {
49 self.current
50 }
51
52 fn reset(&mut self) {
53 self.voltage = T::ZERO;
54 self.current = T::ZERO;
55 }
56}
57
58#[derive(Debug, Clone, Copy)]
60pub struct Capacitor<T: Transcendental> {
61 capacitance: T,
62 sample_rate: T,
63 port_resistance: T,
64 voltage: T,
65 current: T,
66 state: T,
67}
68
69impl<T: Transcendental> Capacitor<T> {
70 pub fn new(capacitance: T, sample_rate: T) -> Self {
72 let two = T::from_f32(2.0);
73 let t = T::ONE / sample_rate;
74 let port_resistance = t / (two * capacitance);
75
76 Self {
77 capacitance,
78 sample_rate,
79 port_resistance,
80 voltage: T::ZERO,
81 current: T::ZERO,
82 state: T::ZERO,
83 }
84 }
85
86 pub fn capacitance(&self) -> T {
88 self.capacitance
89 }
90
91 pub fn set_capacitance(&mut self, capacitance: T) {
93 self.capacitance = capacitance;
94 let two = T::from_f32(2.0);
95 let t = T::ONE / self.sample_rate;
96 self.port_resistance = t / (two * capacitance);
97 }
98
99 pub fn set_sample_rate(&mut self, sample_rate: T) {
101 self.sample_rate = sample_rate;
102 let two = T::from_f32(2.0);
103 let t = T::ONE / sample_rate;
104 self.port_resistance = t / (two * self.capacitance);
105 }
106}
107
108impl<T: Transcendental> WdfElement<T> for Capacitor<T> {
109 fn port_resistance(&self) -> T {
110 self.port_resistance
111 }
112
113 fn process_incident(&mut self, a: T) -> T {
114 let two = T::from_f32(2.0);
115 let b = self.state - a;
116 self.voltage = (a + b) / two;
117 self.current = (a - b) / (two * self.port_resistance);
118 let next_state = self.voltage + self.port_resistance * self.current;
119 self.state = next_state;
120 b
121 }
122
123 fn update_state(&mut self) {
124 }
126
127 fn voltage(&self) -> T {
128 self.voltage
129 }
130
131 fn current(&self) -> T {
132 self.current
133 }
134
135 fn reset(&mut self) {
136 self.voltage = T::ZERO;
137 self.current = T::ZERO;
138 self.state = T::ZERO;
139 }
140}
141
142#[derive(Debug, Clone, Copy)]
144pub struct Inductor<T: Transcendental> {
145 inductance: T,
146 sample_rate: T,
147 port_resistance: T,
148 voltage: T,
149 current: T,
150 state: T,
151}
152
153impl<T: Transcendental> Inductor<T> {
154 pub fn new(inductance: T, sample_rate: T) -> Self {
156 let two = T::from_f32(2.0);
157 let t = T::ONE / sample_rate;
158 let port_resistance = two * inductance / t;
159
160 Self {
161 inductance,
162 sample_rate,
163 port_resistance,
164 voltage: T::ZERO,
165 current: T::ZERO,
166 state: T::ZERO,
167 }
168 }
169}
170
171impl<T: Transcendental> WdfElement<T> for Inductor<T> {
172 fn port_resistance(&self) -> T {
173 self.port_resistance
174 }
175
176 fn process_incident(&mut self, _a: T) -> T {
177 -self.state
178 }
179
180 fn update_state(&mut self) {
181 self.state = self.current * self.port_resistance;
182
183 let t = T::ONE / self.sample_rate;
184 self.current += self.voltage * t / self.inductance;
185 }
186
187 fn voltage(&self) -> T {
188 self.voltage
189 }
190
191 fn current(&self) -> T {
192 self.current
193 }
194
195 fn reset(&mut self) {
196 self.voltage = T::ZERO;
197 self.current = T::ZERO;
198 self.state = T::ZERO;
199 }
200}
201
202#[derive(Debug, Clone, Copy)]
204pub struct Diode<T: Transcendental> {
205 pub(crate) saturation_current: T,
206 pub(crate) thermal_voltage: T,
207 pub(crate) ideality_factor: T,
208 pub(crate) port_resistance: T,
209 pub(crate) voltage: T,
210 pub(crate) current: T,
211 last_b: T,
212}
213
214impl<T: Transcendental> Diode<T> {
215 pub fn new(saturation_current: T, ideality_factor: T, temperature_k: T) -> Self {
221 let k = T::from_f64(BOLTZMANN);
222 let q = T::from_f64(ELECTRON_CHARGE);
223 let thermal_voltage = (k * temperature_k) / q;
224 let port_resistance = thermal_voltage / saturation_current;
225
226 Self {
227 saturation_current,
228 thermal_voltage,
229 ideality_factor,
230 port_resistance,
231 voltage: T::ZERO,
232 current: T::ZERO,
233 last_b: T::ZERO,
234 }
235 }
236
237 pub fn saturation_current(&self) -> T {
239 self.saturation_current
240 }
241
242 pub fn thermal_voltage(&self) -> T {
244 self.thermal_voltage
245 }
246
247 pub(crate) fn diode_equation(&self, v: T) -> T {
248 let vt = self.thermal_voltage * self.ideality_factor;
249 self.saturation_current * ((v / vt).exp() - T::ONE)
250 }
251
252 pub(crate) fn diode_derivative(&self, v: T) -> T {
253 let vt = self.thermal_voltage * self.ideality_factor;
254 self.saturation_current * (v / vt).exp() / vt
255 }
256
257 pub(crate) fn solve_newton(&self, a: T, r: T) -> T {
258 let vt = self.thermal_voltage * self.ideality_factor;
259 let guess = vt * (T::ONE + a / (r * self.saturation_current)).ln();
264 let mut v = guess.max(T::ZERO);
265 let tolerance = T::from_f64(NEWTON_TOLERANCE);
266
267 for _ in 0..10 {
268 let i = self.diode_equation(v);
269 let g = self.diode_derivative(v);
270
271 let f = v + r * i - a;
272
273 if f.abs() < tolerance {
274 break;
275 }
276
277 let df = T::ONE + r * g;
278 v -= f / df;
279 }
280
281 v
282 }
283}
284
285impl<T: Transcendental> WdfElement<T> for Diode<T> {
286 fn port_resistance(&self) -> T {
287 self.port_resistance
288 }
289
290 fn process_incident(&mut self, a: T) -> T {
291 let v = self.solve_newton(a, self.port_resistance);
292 let i = self.diode_equation(v);
293
294 self.voltage = v;
295 self.current = i;
296
297 T::from_f32(2.0) * v - a
298 }
299
300 fn update_state(&mut self) {
301 let g = self.diode_derivative(self.voltage);
302 if g > T::ZERO {
303 self.port_resistance = T::ONE / g;
304 }
305 }
306
307 fn voltage(&self) -> T {
308 self.voltage
309 }
310
311 fn current(&self) -> T {
312 self.current
313 }
314
315 fn reset(&mut self) {
316 self.voltage = T::ZERO;
317 self.current = T::ZERO;
318 self.last_b = T::ZERO;
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325
326 #[test]
327 fn test_resistor_wdf() {
328 let mut resistor: Resistor<f64> = Resistor::new(1000.0);
329 assert_eq!(resistor.port_resistance(), 1000.0);
330
331 let b = resistor.process_incident(1.0);
332 assert!((b - 0.0).abs() < 1e-10);
333 }
334
335 #[test]
336 fn test_capacitor_wdf() {
337 let sample_rate = 44100.0;
338 let capacitance = 1e-6;
339 let capacitor: Capacitor<f64> = Capacitor::new(capacitance, sample_rate);
340
341 let expected_r = 1.0 / (sample_rate * 2.0 * capacitance);
342 assert!((capacitor.port_resistance() - expected_r).abs() < 1e-10);
343 }
344
345 #[test]
346 fn test_inductor_wdf() {
347 let sample_rate = 44100.0;
348 let inductance = 100e-6;
349 let inductor: Inductor<f64> = Inductor::new(inductance, sample_rate);
350
351 let t = 1.0 / sample_rate;
352 let expected_r = 2.0 * inductance / t;
353 assert!((inductor.port_resistance() - expected_r).abs() < 1e-10);
354 }
355
356 #[test]
357 fn test_diode_thermal_voltage() {
358 let diode: Diode<f64> = Diode::new(1e-9, 1.0, 300.0);
359 let expected_vt = 1.380649e-23 * 300.0 / 1.60217662e-19;
360 assert!((diode.thermal_voltage() - expected_vt).abs() < 1e-15);
361 }
362}