1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/// Compose two WDF elements into Series or Parallel.
#[macro_export]
macro_rules! wdf_compose {
(
name: $name:ident<T>,
kind: Series,
elements: ($left:ty, $right:ty),
) => {
/// Series composite of two WDF elements.
///
/// Port resistance is the sum of element resistances. Incident waves
/// are distributed proportionally to each element's resistance share.
#[derive(Debug, Clone, Copy)]
pub struct $name<T: $crate::Transcendental> {
/// Left (first) WDF element in the series composite.
pub left: $left,
/// Right (second) WDF element in the series composite.
pub right: $right,
}
impl<T: $crate::Transcendental> $name<T> {
/// Create a new series composite from two WDF elements.
pub fn new(left: $left, right: $right) -> Self {
Self { left, right }
}
}
impl<T: $crate::Transcendental> $crate::WdfElement<T> for $name<T> {
fn port_resistance(&self) -> T {
self.left.port_resistance() + self.right.port_resistance()
}
fn process_incident(&mut self, a: T) -> T {
let r1 = self.left.port_resistance();
let r2 = self.right.port_resistance();
let total = r1 + r2;
let a1 = a * (r1 / total);
let a2 = a * (r2 / total);
let b1 = self.left.process_incident(a1);
let b2 = self.right.process_incident(a2);
b1 * (r1 / total) + b2 * (r2 / total)
}
fn update_state(&mut self) {
self.left.update_state();
self.right.update_state();
}
fn voltage(&self) -> T {
self.left.voltage() + self.right.voltage()
}
fn current(&self) -> T {
self.left.current()
}
fn reset(&mut self) {
self.left.reset();
self.right.reset();
}
}
};
(
name: $name:ident<T>,
kind: Parallel,
elements: ($left:ty, $right:ty),
) => {
/// Parallel composite of two WDF elements.
///
/// Port resistance is the parallel combination
/// `(r1 * r2) / (r1 + r2)`. Incident waves are scattered using
/// conductance weighting.
#[derive(Debug, Clone, Copy)]
pub struct $name<T: $crate::Transcendental> {
/// Left (first) WDF element in the parallel composite.
pub left: $left,
/// Right (second) WDF element in the parallel composite.
pub right: $right,
}
impl<T: $crate::Transcendental> $name<T> {
/// Create a new parallel composite from two WDF elements.
pub fn new(left: $left, right: $right) -> Self {
Self { left, right }
}
}
impl<T: $crate::Transcendental> $crate::WdfElement<T> for $name<T> {
fn port_resistance(&self) -> T {
let r1 = self.left.port_resistance();
let r2 = self.right.port_resistance();
(r1 * r2) / (r1 + r2)
}
fn process_incident(&mut self, a: T) -> T {
let r1 = self.left.port_resistance();
let r2 = self.right.port_resistance();
let g1 = T::ONE / r1;
let g2 = T::ONE / r2;
let total_g = g1 + g2;
let two = T::from_f32(2.0);
let a1 = two * g1 / total_g;
let a2 = two * g2 / total_g;
let b1 = self.left.process_incident(a);
let b2 = self.right.process_incident(a);
a1 * b1 + a2 * b2 - a
}
fn update_state(&mut self) {
self.left.update_state();
self.right.update_state();
}
fn voltage(&self) -> T {
self.left.voltage()
}
fn current(&self) -> T {
self.left.current() + self.right.current()
}
fn reset(&mut self) {
self.left.reset();
self.right.reset();
}
}
};
}