Skip to main content

rill_core_model/
adapters.rs

1use crate::WdfElement;
2use parking_lot::RwLock;
3use rill_core::Transcendental;
4use std::sync::Arc;
5
6/// Series adapter — connects WDF elements in series
7///
8/// Total port resistance is the sum of all element port resistances.
9/// Current is equal through all elements, voltage sums.
10#[derive(Clone)]
11pub struct SeriesAdapter<T: Transcendental> {
12    elements: Vec<Arc<RwLock<dyn WdfElement<T>>>>,
13    port_resistance: T,
14}
15
16impl<T: Transcendental> std::fmt::Debug for SeriesAdapter<T> {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("SeriesAdapter")
19            .field("num_elements", &self.elements.len())
20            .field("port_resistance", &self.port_resistance)
21            .finish()
22    }
23}
24
25impl<T: Transcendental> SeriesAdapter<T> {
26    /// Create a new series adapter from WDF elements
27    pub fn new(elements: Vec<Arc<RwLock<dyn WdfElement<T>>>>) -> Self {
28        let port_resistance: T = elements
29            .iter()
30            .map(|e| e.read().port_resistance())
31            .fold(T::ZERO, |a, b| a + b);
32
33        Self {
34            elements,
35            port_resistance,
36        }
37    }
38
39    /// Get a reference to the inner elements
40    pub fn elements(&self) -> &[Arc<RwLock<dyn WdfElement<T>>>] {
41        &self.elements
42    }
43}
44
45impl<T: Transcendental> WdfElement<T> for SeriesAdapter<T> {
46    fn port_resistance(&self) -> T {
47        self.port_resistance
48    }
49
50    fn process_incident(&mut self, a: T) -> T {
51        let total_r = self.port_resistance;
52        let mut b_total = T::ZERO;
53
54        for element in &self.elements {
55            let r_i = element.read().port_resistance();
56            let a_i = a * (r_i / total_r);
57
58            let b_i = element.write().process_incident(a_i);
59            b_total += b_i * (r_i / total_r);
60        }
61
62        b_total
63    }
64
65    fn update_state(&mut self) {
66        for element in &self.elements {
67            element.write().update_state();
68        }
69    }
70
71    fn voltage(&self) -> T {
72        self.elements
73            .iter()
74            .map(|e| e.read().voltage())
75            .fold(T::ZERO, |a, b| a + b)
76    }
77
78    fn current(&self) -> T {
79        self.elements
80            .first()
81            .map(|e| e.read().current())
82            .unwrap_or(T::ZERO)
83    }
84
85    fn reset(&mut self) {
86        for element in &self.elements {
87            element.write().reset();
88        }
89    }
90}
91
92/// Parallel adapter — connects WDF elements in parallel
93///
94/// Total conductance is the sum of all element conductances.
95/// Voltage is equal across all elements, current sums.
96#[derive(Clone)]
97pub struct ParallelAdapter<T: Transcendental> {
98    elements: Vec<Arc<RwLock<dyn WdfElement<T>>>>,
99    port_resistance: T,
100}
101
102impl<T: Transcendental> std::fmt::Debug for ParallelAdapter<T> {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        f.debug_struct("ParallelAdapter")
105            .field("num_elements", &self.elements.len())
106            .field("port_resistance", &self.port_resistance)
107            .finish()
108    }
109}
110
111impl<T: Transcendental> ParallelAdapter<T> {
112    /// Create a new parallel adapter from WDF elements
113    pub fn new(elements: Vec<Arc<RwLock<dyn WdfElement<T>>>>) -> Self {
114        let inv_port_resistance: T = elements
115            .iter()
116            .map(|e| T::ONE / e.read().port_resistance())
117            .fold(T::ZERO, |a, b| a + b);
118
119        let port_resistance = T::ONE / inv_port_resistance;
120
121        Self {
122            elements,
123            port_resistance,
124        }
125    }
126
127    /// Get a reference to the inner elements
128    pub fn elements(&self) -> &[Arc<RwLock<dyn WdfElement<T>>>] {
129        &self.elements
130    }
131}
132
133impl<T: Transcendental> WdfElement<T> for ParallelAdapter<T> {
134    fn port_resistance(&self) -> T {
135        self.port_resistance
136    }
137
138    fn process_incident(&mut self, a: T) -> T {
139        let total_g: T = self
140            .elements
141            .iter()
142            .map(|e| T::ONE / e.read().port_resistance())
143            .fold(T::ZERO, |a, b| a + b);
144
145        let two = T::from_f32(2.0);
146        // Stack-allocated alpha array (max 8 elements for practical WDF circuits)
147        let mut alpha = [T::ZERO; 8];
148
149        for (i, e) in self.elements.iter().enumerate() {
150            let g_i = T::ONE / e.read().port_resistance();
151            alpha[i] = two * g_i / total_g;
152        }
153
154        let mut sum_alpha_b = T::ZERO;
155        for (i, element) in self.elements.iter().enumerate() {
156            let b_i = element.write().process_incident(a);
157            sum_alpha_b += alpha[i] * b_i;
158        }
159
160        sum_alpha_b - a
161    }
162
163    fn update_state(&mut self) {
164        for element in &self.elements {
165            element.write().update_state();
166        }
167    }
168
169    fn voltage(&self) -> T {
170        self.elements
171            .first()
172            .map(|e| e.read().voltage())
173            .unwrap_or(T::ZERO)
174    }
175
176    fn current(&self) -> T {
177        self.elements
178            .iter()
179            .map(|e| e.read().current())
180            .fold(T::ZERO, |a, b| a + b)
181    }
182
183    fn reset(&mut self) {
184        for element in &self.elements {
185            element.write().reset();
186        }
187    }
188}
189
190#[cfg(test)]
191mod tests {
192    use super::*;
193    use crate::elements::{Capacitor, Resistor};
194
195    #[test]
196    fn test_series_adapter() {
197        let sample_rate = 44100.0;
198
199        let resistor: Arc<RwLock<dyn WdfElement<f64>>> =
200            Arc::new(RwLock::new(Resistor::new(1000.0)));
201        let capacitor: Arc<RwLock<dyn WdfElement<f64>>> =
202            Arc::new(RwLock::new(Capacitor::new(1e-6, sample_rate)));
203
204        let elements = vec![resistor.clone(), capacitor.clone()];
205        let adapter: SeriesAdapter<f64> = SeriesAdapter::new(elements);
206
207        let total_r = adapter.port_resistance();
208        let r1 = resistor.read().port_resistance();
209        let r2 = capacitor.read().port_resistance();
210
211        assert!((total_r - (r1 + r2)).abs() < 1e-10);
212    }
213}