Skip to main content

rill_core_wdf/
lib.rs

1//! Wave Digital Filter (WDF) core — elements, adapters, and analysis
2//! for analog circuit modeling.
3//!
4//! All types are generic over [`rill_core::Transcendental`], supporting both `f32`
5//! and `f64`. The SIMD module (behind the `simd` feature) uses the
6//! [`rill_core_dsp`](https://docs.rs/rill-core-dsp) vector infrastructure.
7//!
8//! # Design
9//!
10//! WDF elements are built around the [`WdfElement`] trait, which defines a
11//! port resistance, wave processing, and state update cycle. Elements can be
12//! combined via [`SeriesAdapter`] and [`ParallelAdapter`] to form arbitrary
13//! linear circuits. Nonlinear elements like [`Diode`] use Newton-Raphson
14//! iteration for implicit solution.
15//!
16//! References:
17//! - A. Fettweis, "Wave Digital Filters: Theory and Practice" (1986)
18//! - K. J. Werner et al., "An Improved and Generalized Diode Clipper
19//!   Model for Wave Digital Filters" (2015)
20
21#![warn(missing_docs)]
22#![deny(unsafe_code)]
23
24pub use rill_core::Transcendental;
25
26/// WDF eDSL macros for defining elements and filters
27pub mod macros;
28
29mod adapters;
30/// Frequency response and distortion analysis
31pub mod analysis;
32/// Physical constants and tolerances
33pub mod constants;
34mod elements;
35
36#[cfg(feature = "simd")]
37pub mod simd;
38
39/// WDF-based filter models
40pub mod filters;
41
42pub use adapters::{ParallelAdapter, SeriesAdapter};
43pub use elements::{Capacitor, Diode, Inductor, Resistor};
44
45/// Wave port type for WDF adapters
46#[derive(Debug, Clone, Copy, PartialEq)]
47pub enum PortType {
48    /// Series connection
49    Series,
50    /// Parallel connection
51    Parallel,
52    /// Reflection port
53    Reflection,
54}
55
56/// Wave variables: a (incident), b (reflected)
57#[derive(Debug, Clone, Copy)]
58pub struct WaveVariables<T: Transcendental> {
59    /// Incident wave
60    pub a: T,
61    /// Reflected wave
62    pub b: T,
63}
64
65impl<T: Transcendental> WaveVariables<T> {
66    /// Create zero wave variables
67    pub fn new() -> Self {
68        Self {
69            a: T::ZERO,
70            b: T::ZERO,
71        }
72    }
73
74    /// Compute voltage and current from wave variables
75    pub fn to_voltage_current(&self, port_resistance: T) -> (T, T) {
76        let two = T::from_f32(2.0);
77        let v = (self.a + self.b) / two;
78        let i = (self.a - self.b) / (two * port_resistance);
79        (v, i)
80    }
81
82    /// Compute wave variables from voltage and current
83    pub fn from_voltage_current(v: T, i: T, port_resistance: T) -> Self {
84        let a = v + port_resistance * i;
85        let b = v - port_resistance * i;
86        Self { a, b }
87    }
88}
89
90impl<T: Transcendental> Default for WaveVariables<T> {
91    fn default() -> Self {
92        Self::new()
93    }
94}
95
96/// Base WDF element trait
97///
98/// Every WDF element has a port resistance and processes incident
99/// waves to produce reflected waves.
100pub trait WdfElement<T: Transcendental>: Send + Sync {
101    /// Port resistance
102    fn port_resistance(&self) -> T;
103
104    /// Process incident wave, return reflected wave
105    fn process_incident(&mut self, a: T) -> T;
106
107    /// Update internal state (called after wave computation)
108    fn update_state(&mut self);
109
110    /// Current voltage across the element
111    fn voltage(&self) -> T;
112
113    /// Current current through the element
114    fn current(&self) -> T;
115
116    /// Reset to initial state
117    fn reset(&mut self);
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_wave_variables() {
126        let wv: WaveVariables<f64> = WaveVariables::new();
127        assert_eq!(wv.a, 0.0);
128        assert_eq!(wv.b, 0.0);
129    }
130
131    #[test]
132    fn test_wave_to_voltage_current() {
133        let wv: WaveVariables<f64> = WaveVariables { a: 2.0, b: 0.5 };
134        let (v, i) = wv.to_voltage_current(100.0);
135        assert!((v - 1.25).abs() < 1e-10);
136        assert!((i - 0.0075).abs() < 1e-10);
137    }
138
139    #[test]
140    fn test_voltage_current_to_wave() {
141        let wv: WaveVariables<f64> = WaveVariables::from_voltage_current(1.0, 0.01, 100.0);
142        assert!((wv.a - 2.0).abs() < 1e-10);
143        assert!((wv.b - 0.0).abs() < 1e-10);
144    }
145}