1use crate::constants::{BOLTZMANN, ELECTRON_CHARGE, NEWTON_TOLERANCE};
2use crate::WdfElement;
3use rill_core::math::vector::scalar::ScalarVector4;
4use rill_core::math::vector::traits::{Vector, VectorMask, VectorTranscendental};
5use rill_core::Transcendental;
6
7#[derive(Debug, Clone, Copy)]
9pub struct Resistor<T: Transcendental> {
10 resistance: T,
11 port_resistance: T,
12 voltage: T,
13 current: T,
14}
15
16impl<T: Transcendental> Resistor<T> {
17 pub fn new(resistance: T) -> Self {
19 Self {
20 port_resistance: resistance,
21 resistance,
22 voltage: T::ZERO,
23 current: T::ZERO,
24 }
25 }
26
27 pub fn resistance(&self) -> T {
29 self.resistance
30 }
31
32 pub fn process_incident_vector(&mut self, _a: ScalarVector4<T>) -> ScalarVector4<T> {
34 ScalarVector4::splat(T::ZERO)
35 }
36}
37
38impl<T: Transcendental> WdfElement<T> for Resistor<T> {
39 fn port_resistance(&self) -> T {
40 self.port_resistance
41 }
42
43 fn process_incident(&mut self, _a: T) -> T {
44 T::ZERO
45 }
46
47 fn update_state(&mut self) {
48 self.voltage = self.current * self.resistance;
49 }
50
51 fn voltage(&self) -> T {
52 self.voltage
53 }
54
55 fn current(&self) -> T {
56 self.current
57 }
58
59 fn reset(&mut self) {
60 self.voltage = T::ZERO;
61 self.current = T::ZERO;
62 }
63}
64
65#[derive(Debug, Clone, Copy)]
67pub struct Capacitor<T: Transcendental> {
68 capacitance: T,
69 sample_rate: T,
70 port_resistance: T,
71 voltage: T,
72 current: T,
73 state: T,
74}
75
76impl<T: Transcendental> Capacitor<T> {
77 pub fn new(capacitance: T, sample_rate: T) -> Self {
79 let two = T::from_f32(2.0);
80 let t = T::ONE / sample_rate;
81 let port_resistance = t / (two * capacitance);
82
83 Self {
84 capacitance,
85 sample_rate,
86 port_resistance,
87 voltage: T::ZERO,
88 current: T::ZERO,
89 state: T::ZERO,
90 }
91 }
92
93 pub fn capacitance(&self) -> T {
95 self.capacitance
96 }
97
98 pub fn set_capacitance(&mut self, capacitance: T) {
100 self.capacitance = capacitance;
101 let two = T::from_f32(2.0);
102 let t = T::ONE / self.sample_rate;
103 self.port_resistance = t / (two * capacitance);
104 }
105
106 pub fn set_sample_rate(&mut self, sample_rate: T) {
108 self.sample_rate = sample_rate;
109 let two = T::from_f32(2.0);
110 let t = T::ONE / sample_rate;
111 self.port_resistance = t / (two * self.capacitance);
112 }
113
114 pub fn process_incident_vector(&mut self, a: ScalarVector4<T>) -> ScalarVector4<T> {
116 let two = ScalarVector4::splat(T::from_f32(2.0));
117 let r = ScalarVector4::splat(self.port_resistance);
118 let b = ScalarVector4::splat(self.state).sub(&a);
119 let v = a.add(&b).div(&two);
120 let i = a.sub(&b).div(&two.mul(&r));
121 self.voltage = v.extract(0);
122 self.current = i.extract(0);
123 let next = v.add(&r.mul(&i));
124 self.state = next.extract(0);
125 b
126 }
127}
128
129impl<T: Transcendental> WdfElement<T> for Capacitor<T> {
130 fn port_resistance(&self) -> T {
131 self.port_resistance
132 }
133
134 fn process_incident(&mut self, a: T) -> T {
135 let two = T::from_f32(2.0);
136 let b = self.state - a;
137 self.voltage = (a + b) / two;
138 self.current = (a - b) / (two * self.port_resistance);
139 let next_state = self.voltage + self.port_resistance * self.current;
140 self.state = next_state;
141 b
142 }
143
144 fn update_state(&mut self) {
145 }
147
148 fn voltage(&self) -> T {
149 self.voltage
150 }
151
152 fn current(&self) -> T {
153 self.current
154 }
155
156 fn reset(&mut self) {
157 self.voltage = T::ZERO;
158 self.current = T::ZERO;
159 self.state = T::ZERO;
160 }
161}
162
163#[derive(Debug, Clone, Copy)]
165pub struct Inductor<T: Transcendental> {
166 inductance: T,
167 sample_rate: T,
168 port_resistance: T,
169 voltage: T,
170 current: T,
171 state: T,
172}
173
174impl<T: Transcendental> Inductor<T> {
175 pub fn new(inductance: T, sample_rate: T) -> Self {
177 let two = T::from_f32(2.0);
178 let t = T::ONE / sample_rate;
179 let port_resistance = two * inductance / t;
180
181 Self {
182 inductance,
183 sample_rate,
184 port_resistance,
185 voltage: T::ZERO,
186 current: T::ZERO,
187 state: T::ZERO,
188 }
189 }
190
191 pub fn process_incident_vector(&mut self, _a: ScalarVector4<T>) -> ScalarVector4<T> {
193 ScalarVector4::splat(-self.state)
194 }
195}
196
197impl<T: Transcendental> WdfElement<T> for Inductor<T> {
198 fn port_resistance(&self) -> T {
199 self.port_resistance
200 }
201
202 fn process_incident(&mut self, _a: T) -> T {
203 -self.state
204 }
205
206 fn update_state(&mut self) {
207 self.state = self.current * self.port_resistance;
208
209 let t = T::ONE / self.sample_rate;
210 self.current += self.voltage * t / self.inductance;
211 }
212
213 fn voltage(&self) -> T {
214 self.voltage
215 }
216
217 fn current(&self) -> T {
218 self.current
219 }
220
221 fn reset(&mut self) {
222 self.voltage = T::ZERO;
223 self.current = T::ZERO;
224 self.state = T::ZERO;
225 }
226}
227
228#[derive(Debug, Clone, Copy)]
230pub struct Diode<T: Transcendental> {
231 pub(crate) saturation_current: T,
232 pub(crate) thermal_voltage: T,
233 pub(crate) ideality_factor: T,
234 pub(crate) port_resistance: T,
235 pub(crate) voltage: T,
236 pub(crate) current: T,
237 last_b: T,
238}
239
240impl<T: Transcendental> Diode<T> {
241 pub fn new(saturation_current: T, ideality_factor: T, temperature_k: T) -> Self {
247 let k = T::from_f64(BOLTZMANN);
248 let q = T::from_f64(ELECTRON_CHARGE);
249 let thermal_voltage = (k * temperature_k) / q;
250 let port_resistance = thermal_voltage / saturation_current;
251
252 Self {
253 saturation_current,
254 thermal_voltage,
255 ideality_factor,
256 port_resistance,
257 voltage: T::ZERO,
258 current: T::ZERO,
259 last_b: T::ZERO,
260 }
261 }
262
263 pub fn saturation_current(&self) -> T {
265 self.saturation_current
266 }
267
268 pub fn thermal_voltage(&self) -> T {
270 self.thermal_voltage
271 }
272
273 pub(crate) fn diode_equation(&self, v: T) -> T {
274 let vt = self.thermal_voltage * self.ideality_factor;
275 self.saturation_current * ((v / vt).exp() - T::ONE)
276 }
277
278 pub(crate) fn diode_derivative(&self, v: T) -> T {
279 let vt = self.thermal_voltage * self.ideality_factor;
280 self.saturation_current * (v / vt).exp() / vt
281 }
282
283 pub(crate) fn solve_newton(&self, a: T, r: T) -> T {
284 let vt = self.thermal_voltage * self.ideality_factor;
285 let guess = vt * (T::ONE + a / (r * self.saturation_current)).ln();
290 let mut v = guess.max(T::ZERO);
291 let tolerance = T::from_f64(NEWTON_TOLERANCE);
292
293 for _ in 0..10 {
294 let i = self.diode_equation(v);
295 let g = self.diode_derivative(v);
296
297 let f = v + r * i - a;
298
299 if f.abs() < tolerance {
300 break;
301 }
302
303 let df = T::ONE + r * g;
304 v -= f / df;
305 }
306
307 v
308 }
309
310 pub fn process_incident_vector(&mut self, a: ScalarVector4<T>) -> ScalarVector4<T> {
312 let vt = T::from_f64(self.thermal_voltage.to_f64() * self.ideality_factor.to_f64());
313 let is_val = T::from_f64(self.saturation_current.to_f64());
314 let r_val = self.port_resistance;
315 let vt_s = ScalarVector4::splat(vt);
316 let is_s = ScalarVector4::splat(is_val);
317 let r_s = ScalarVector4::splat(r_val);
318 let tol = ScalarVector4::splat(T::from_f64(NEWTON_TOLERANCE));
319
320 let guess = vt_s.mul(&(ScalarVector4::splat(T::ONE).add(&a.div(&r_s.mul(&is_s)))).ln());
321 let mut v = guess.max(&ScalarVector4::splat(T::ZERO));
322
323 for _ in 0..10 {
324 let i = is_s.mul(&v.div(&vt_s).exp().sub(&ScalarVector4::splat(T::ONE)));
325 let g = is_s.mul(&v.div(&vt_s).exp()).div(&vt_s);
326 let f = v.add(&r_s.mul(&i)).sub(&a);
327 if <ScalarVector4<T> as VectorMask<T, 4>>::all(&f.abs().lt(&tol)) {
328 break;
329 }
330 let df = ScalarVector4::splat(T::ONE).add(&r_s.mul(&g));
331 v = v.sub(&f.div(&df));
332 }
333
334 ScalarVector4::splat(T::from_f32(2.0)).mul(&v).sub(&a)
335 }
336}
337
338impl<T: Transcendental> WdfElement<T> for Diode<T> {
339 fn port_resistance(&self) -> T {
340 self.port_resistance
341 }
342
343 fn process_incident(&mut self, a: T) -> T {
344 let v = self.solve_newton(a, self.port_resistance);
345 let i = self.diode_equation(v);
346
347 self.voltage = v;
348 self.current = i;
349
350 T::from_f32(2.0) * v - a
351 }
352
353 fn update_state(&mut self) {
354 let g = self.diode_derivative(self.voltage);
355 if g > T::ZERO {
356 self.port_resistance = T::ONE / g;
357 }
358 }
359
360 fn voltage(&self) -> T {
361 self.voltage
362 }
363
364 fn current(&self) -> T {
365 self.current
366 }
367
368 fn reset(&mut self) {
369 self.voltage = T::ZERO;
370 self.current = T::ZERO;
371 self.last_b = T::ZERO;
372 }
373}
374
375#[derive(Debug, Clone)]
378pub struct OpAmp<T: Transcendental> {
379 gain: T,
380 slew_rate: T,
381 bandwidth: T,
382 pos_rail: T,
383 neg_rail: T,
384 state: T,
385 output: T,
386}
387
388impl<T: Transcendental> OpAmp<T> {
389 pub fn new(gain: f64, slew_rate: f64, bandwidth: f64) -> Self {
395 Self {
396 gain: T::from_f64(gain),
397 slew_rate: T::from_f64(slew_rate * 1e6),
398 bandwidth: T::from_f64(bandwidth),
399 pos_rail: T::from_f64(15.0),
400 neg_rail: T::from_f64(-15.0),
401 state: T::ZERO,
402 output: T::ZERO,
403 }
404 }
405
406 pub fn set_rails(&mut self, neg: T, pos: T) {
408 self.neg_rail = neg;
409 self.pos_rail = pos;
410 }
411
412 pub fn process(&mut self, input: T, dt: T) -> T {
417 let ideal = input * self.gain;
418
419 let max_change = self.slew_rate * dt;
420 let diff = ideal - self.state;
421 let limited = diff.clamp(-max_change, max_change);
422 self.state += limited;
423
424 let pole_freq = self.bandwidth / self.gain;
425 let two_pi = T::from_f32(2.0) * T::PI;
426 let alpha = T::ONE / (T::ONE + two_pi * pole_freq * dt);
427 self.output = alpha * self.state + (T::ONE - alpha) * ideal;
428
429 self.output = self.output.clamp(self.neg_rail, self.pos_rail);
430 self.output
431 }
432
433 pub fn reset(&mut self) {
435 self.state = T::ZERO;
436 self.output = T::ZERO;
437 }
438
439 pub fn output_voltage(&self) -> T {
441 self.output
442 }
443}
444
445impl<T: Transcendental> WdfElement<T> for OpAmp<T> {
446 fn port_resistance(&self) -> T {
447 T::from_f32(100.0)
448 }
449
450 fn process_incident(&mut self, a: T) -> T {
451 self.process(a, T::ONE / T::from_f32(44100.0))
452 }
453
454 fn update_state(&mut self) {}
455
456 fn voltage(&self) -> T {
457 self.output
458 }
459
460 fn current(&self) -> T {
461 T::ZERO
462 }
463
464 fn reset(&mut self) {
465 self.reset();
466 }
467}
468
469#[allow(dead_code)]
472pub fn process_batch_simd<T: Transcendental>(
473 process_fn: &mut dyn FnMut(ScalarVector4<T>) -> ScalarVector4<T>,
474 inputs: &[T],
475 outputs: &mut [T],
476) {
477 let len = inputs.len().min(outputs.len());
478 let chunks = len / 4;
479 let remainder = len % 4;
480
481 for i in 0..chunks {
482 let offset = i * 4;
483 let a = ScalarVector4::load(&inputs[offset..offset + 4]);
484 let b = process_fn(a);
485 b.store(&mut outputs[offset..offset + 4]);
486 }
487
488 if remainder > 0 {
489 let offset = chunks * 4;
490 let mut tail = [T::ZERO; 4];
491 tail[..remainder].copy_from_slice(&inputs[offset..offset + remainder]);
492 let a = ScalarVector4::load(&tail);
493 let b = process_fn(a);
494 let mut b_arr = [T::ZERO; 4];
495 b.store(&mut b_arr);
496 outputs[offset..offset + remainder].copy_from_slice(&b_arr[..remainder]);
497 }
498}
499
500#[cfg(test)]
501mod tests {
502 use super::*;
503
504 #[test]
505 fn test_resistor_wdf() {
506 let mut resistor: Resistor<f64> = Resistor::new(1000.0);
507 assert_eq!(resistor.port_resistance(), 1000.0);
508
509 let b = resistor.process_incident(1.0);
510 assert!((b - 0.0).abs() < 1e-10);
511 }
512
513 #[test]
514 fn test_capacitor_wdf() {
515 let sample_rate = 44100.0;
516 let capacitance = 1e-6;
517 let capacitor: Capacitor<f64> = Capacitor::new(capacitance, sample_rate);
518
519 let expected_r = 1.0 / (sample_rate * 2.0 * capacitance);
520 assert!((capacitor.port_resistance() - expected_r).abs() < 1e-10);
521 }
522
523 #[test]
524 fn test_inductor_wdf() {
525 let sample_rate = 44100.0;
526 let inductance = 100e-6;
527 let inductor: Inductor<f64> = Inductor::new(inductance, sample_rate);
528
529 let t = 1.0 / sample_rate;
530 let expected_r = 2.0 * inductance / t;
531 assert!((inductor.port_resistance() - expected_r).abs() < 1e-10);
532 }
533
534 #[test]
535 fn test_diode_thermal_voltage() {
536 let diode: Diode<f64> = Diode::new(1e-9, 1.0, 300.0);
537 let expected_vt = 1.380649e-23 * 300.0 / 1.60217662e-19;
538 assert!((diode.thermal_voltage() - expected_vt).abs() < 1e-15);
539 }
540}