Skip to main content

rill_core_wdf/
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        let alpha: Vec<T> = self
147            .elements
148            .iter()
149            .map(|e| {
150                let g_i = T::ONE / e.read().port_resistance();
151                two * g_i / total_g
152            })
153            .collect();
154
155        let mut sum_alpha_b = T::ZERO;
156        for (i, element) in self.elements.iter().enumerate() {
157            let b_i = element.write().process_incident(a);
158            sum_alpha_b += alpha[i] * b_i;
159        }
160
161        sum_alpha_b - a
162    }
163
164    fn update_state(&mut self) {
165        for element in &self.elements {
166            element.write().update_state();
167        }
168    }
169
170    fn voltage(&self) -> T {
171        self.elements
172            .first()
173            .map(|e| e.read().voltage())
174            .unwrap_or(T::ZERO)
175    }
176
177    fn current(&self) -> T {
178        self.elements
179            .iter()
180            .map(|e| e.read().current())
181            .fold(T::ZERO, |a, b| a + b)
182    }
183
184    fn reset(&mut self) {
185        for element in &self.elements {
186            element.write().reset();
187        }
188    }
189}
190
191#[cfg(test)]
192mod tests {
193    use super::*;
194    use crate::elements::{Capacitor, Resistor};
195
196    #[test]
197    fn test_series_adapter() {
198        let sample_rate = 44100.0;
199
200        let resistor: Arc<RwLock<dyn WdfElement<f64>>> =
201            Arc::new(RwLock::new(Resistor::new(1000.0)));
202        let capacitor: Arc<RwLock<dyn WdfElement<f64>>> =
203            Arc::new(RwLock::new(Capacitor::new(1e-6, sample_rate)));
204
205        let elements = vec![resistor.clone(), capacitor.clone()];
206        let adapter: SeriesAdapter<f64> = SeriesAdapter::new(elements);
207
208        let total_r = adapter.port_resistance();
209        let r1 = resistor.read().port_resistance();
210        let r2 = capacitor.read().port_resistance();
211
212        assert!((total_r - (r1 + r2)).abs() < 1e-10);
213    }
214}