pub trait WdfComponent {
fn incident(&mut self, a: f32);
fn reflected(&self) -> f32;
fn port_resistance(&self) -> f32;
}
pub struct WdfResistor {
resistance: f32,
}
impl WdfResistor {
pub fn new(resistance: f32) -> Self {
assert!(resistance > 0.0, "Resistance must be positive");
Self { resistance }
}
pub fn resistance(&self) -> f32 {
self.resistance
}
pub fn set_resistance(&mut self, r: f32) {
assert!(r > 0.0, "Resistance must be positive");
self.resistance = r;
}
}
impl WdfComponent for WdfResistor {
#[inline]
fn incident(&mut self, _a: f32) {
}
#[inline]
fn reflected(&self) -> f32 {
0.0
}
#[inline]
fn port_resistance(&self) -> f32 {
self.resistance
}
}
pub struct WdfCapacitor {
capacitance: f32,
sample_rate: f32,
port_resistance: f32,
state: f32,
}
impl WdfCapacitor {
pub fn new(capacitance: f32) -> Self {
assert!(capacitance > 0.0, "Capacitance must be positive");
Self {
capacitance,
sample_rate: 44100.0,
port_resistance: 1.0 / (2.0 * capacitance * 44100.0),
state: 0.0,
}
}
pub fn set_sample_rate(&mut self, sample_rate: f32) {
self.sample_rate = sample_rate;
self.port_resistance = 1.0 / (2.0 * self.capacitance * sample_rate);
}
pub fn capacitance(&self) -> f32 {
self.capacitance
}
pub fn set_capacitance(&mut self, c: f32) {
assert!(c > 0.0, "Capacitance must be positive");
self.capacitance = c;
self.port_resistance = 1.0 / (2.0 * c * self.sample_rate);
}
pub fn reset(&mut self) {
self.state = 0.0;
}
}
impl WdfComponent for WdfCapacitor {
#[inline]
fn incident(&mut self, a: f32) {
self.state = a;
}
#[inline]
fn reflected(&self) -> f32 {
self.state
}
#[inline]
fn port_resistance(&self) -> f32 {
self.port_resistance
}
}
pub struct WdfInductor {
inductance: f32,
sample_rate: f32,
port_resistance: f32,
state: f32,
}
impl WdfInductor {
pub fn new(inductance: f32) -> Self {
assert!(inductance > 0.0, "Inductance must be positive");
Self {
inductance,
sample_rate: 44100.0,
port_resistance: 2.0 * inductance * 44100.0,
state: 0.0,
}
}
pub fn set_sample_rate(&mut self, sample_rate: f32) {
self.sample_rate = sample_rate;
self.port_resistance = 2.0 * self.inductance * sample_rate;
}
pub fn inductance(&self) -> f32 {
self.inductance
}
pub fn set_inductance(&mut self, l: f32) {
assert!(l > 0.0, "Inductance must be positive");
self.inductance = l;
self.port_resistance = 2.0 * l * self.sample_rate;
}
pub fn reset(&mut self) {
self.state = 0.0;
}
}
impl WdfComponent for WdfInductor {
#[inline]
fn incident(&mut self, a: f32) {
self.state = -a;
}
#[inline]
fn reflected(&self) -> f32 {
self.state
}
#[inline]
fn port_resistance(&self) -> f32 {
self.port_resistance
}
}
pub struct WdfIdealVoltageSource {
voltage: f32,
port_resistance: f32,
a: f32,
}
impl WdfIdealVoltageSource {
pub fn new(port_resistance: f32) -> Self {
Self {
voltage: 0.0,
port_resistance,
a: 0.0,
}
}
#[inline]
pub fn set_voltage(&mut self, v: f32) {
self.voltage = v;
}
pub fn voltage(&self) -> f32 {
self.voltage
}
pub fn set_port_resistance(&mut self, r: f32) {
self.port_resistance = r;
}
}
impl WdfComponent for WdfIdealVoltageSource {
#[inline]
fn incident(&mut self, a: f32) {
self.a = a;
}
#[inline]
fn reflected(&self) -> f32 {
self.voltage - self.a
}
#[inline]
fn port_resistance(&self) -> f32 {
self.port_resistance
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resistor_absorbs_energy() {
let mut r = WdfResistor::new(1000.0);
assert_eq!(r.reflected(), 0.0);
r.incident(1.0);
assert_eq!(r.reflected(), 0.0);
r.incident(-5.0);
assert_eq!(r.reflected(), 0.0);
assert_eq!(r.port_resistance(), 1000.0);
}
#[test]
fn test_capacitor_state_update() {
let mut c = WdfCapacitor::new(1e-6); c.set_sample_rate(48000.0);
let expected_r = 1.0 / (2.0 * 1e-6 * 48000.0);
assert!((c.port_resistance() - expected_r).abs() < 1e-3);
assert_eq!(c.reflected(), 0.0);
c.incident(1.0);
assert_eq!(c.reflected(), 1.0);
c.incident(0.5);
assert_eq!(c.reflected(), 0.5);
}
#[test]
fn test_inductor_sign_flip() {
let mut l = WdfInductor::new(0.01); l.set_sample_rate(44100.0);
let expected_r = 2.0 * 0.01 * 44100.0;
assert!((l.port_resistance() - expected_r).abs() < 1e-2);
assert_eq!(l.reflected(), 0.0);
l.incident(1.0);
assert_eq!(l.reflected(), -1.0);
l.incident(-3.0);
assert_eq!(l.reflected(), 3.0);
}
#[test]
fn test_capacitor_rc_step_response() {
let r_val = 1000.0; let c_val = 1e-6; let tau = r_val * c_val; let fs = 48000.0;
let mut cap = WdfCapacitor::new(c_val);
cap.set_sample_rate(fs);
let r_c = cap.port_resistance(); let r_r = r_val;
let r_total = r_r + r_c;
let gamma = r_r / r_total;
let vs = 1.0;
let samples_at_tau = (tau * fs) as usize;
let mut vc = 0.0f32;
for _ in 0..samples_at_tau {
let b_r = 0.0; let b_c = cap.reflected();
let b_root = b_r + b_c;
let a_root = vs - b_root;
let diff = a_root - b_root;
let a_r = b_r + gamma * diff; let a_c = b_c + (1.0 - gamma) * diff;
let _ = a_r; cap.incident(a_c);
vc = a_c + b_c;
}
let expected = 1.0 - (-1.0f32).exp(); let error = (vc - expected).abs();
assert!(
error < 0.02,
"RC step response error too large: vc={vc}, expected={expected}, error={error}"
);
}
#[test]
fn test_voltage_source() {
let mut vs = WdfIdealVoltageSource::new(100.0);
vs.set_voltage(5.0);
vs.incident(0.0);
assert_eq!(vs.reflected(), 5.0);
vs.incident(3.0);
assert_eq!(vs.reflected(), 2.0);
}
#[test]
fn test_capacitor_reset() {
let mut c = WdfCapacitor::new(1e-6);
c.set_sample_rate(44100.0);
c.incident(5.0);
assert_eq!(c.reflected(), 5.0);
c.reset();
assert_eq!(c.reflected(), 0.0);
}
#[test]
fn test_inductor_reset() {
let mut l = WdfInductor::new(0.01);
l.set_sample_rate(44100.0);
l.incident(5.0);
assert_eq!(l.reflected(), -5.0);
l.reset();
assert_eq!(l.reflected(), 0.0);
}
}