1use crate::CalcError;
13use crate::impedance::{common, microstrip, types::ImpedanceResult};
14
15pub struct EmbeddedMicrostripInput {
17 pub width: f64,
19 pub height: f64,
21 pub thickness: f64,
23 pub er: f64,
25 pub cover_height: f64,
28 pub frequency: f64,
30}
31
32pub fn calculate(input: &EmbeddedMicrostripInput) -> Result<ImpedanceResult, CalcError> {
40 let EmbeddedMicrostripInput {
41 width, height, thickness, er, cover_height, frequency,
42 } = *input;
43
44 if cover_height < 0.0 {
45 return Err(CalcError::NegativeDimension {
46 name: "cover_height",
47 value: cover_height,
48 });
49 }
50
51 let surface = microstrip::calculate(µstrip::MicrostripInput {
53 width,
54 height,
55 thickness,
56 er,
57 frequency,
58 })?;
59
60 if cover_height == 0.0 {
62 return Ok(surface);
63 }
64
65 let exp_factor = (-2.0 * cover_height / height).exp();
67
68 let zo = surface.zo * (1.0 - exp_factor);
69 let er_eff = er - (er - surface.er_eff) * exp_factor;
70
71 let tpd = common::propagation_delay(er_eff);
72 let lo = common::inductance_per_length(zo, tpd);
73 let co = common::capacitance_per_length(zo, tpd);
74
75 Ok(ImpedanceResult {
76 zo,
77 er_eff,
78 tpd_ps_per_in: tpd,
79 lo_nh_per_in: lo,
80 co_pf_per_in: co,
81 })
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use approx::assert_relative_eq;
88
89 #[test]
90 fn zero_cover_equals_surface() {
91 let surface = microstrip::calculate(µstrip::MicrostripInput {
92 width: 10.0,
93 height: 5.0,
94 thickness: 1.4,
95 er: 4.6,
96 frequency: 0.0,
97 })
98 .unwrap();
99
100 let embedded = calculate(&EmbeddedMicrostripInput {
101 width: 10.0,
102 height: 5.0,
103 thickness: 1.4,
104 er: 4.6,
105 cover_height: 0.0,
106 frequency: 0.0,
107 })
108 .unwrap();
109
110 assert_relative_eq!(embedded.zo, surface.zo, max_relative = 1e-10);
111 assert_relative_eq!(embedded.er_eff, surface.er_eff, max_relative = 1e-10);
112 }
113
114 #[test]
115 fn burial_reduces_impedance() {
116 let surface = microstrip::calculate(µstrip::MicrostripInput {
117 width: 10.0,
118 height: 5.0,
119 thickness: 1.4,
120 er: 4.6,
121 frequency: 0.0,
122 })
123 .unwrap();
124
125 let embedded = calculate(&EmbeddedMicrostripInput {
126 width: 10.0,
127 height: 5.0,
128 thickness: 1.4,
129 er: 4.6,
130 cover_height: 5.0,
131 frequency: 0.0,
132 })
133 .unwrap();
134
135 assert!(
136 embedded.zo < surface.zo,
137 "embedded Zo {} should be < surface Zo {}",
138 embedded.zo,
139 surface.zo
140 );
141 }
142
143 #[test]
144 fn burial_increases_er_eff() {
145 let surface = microstrip::calculate(µstrip::MicrostripInput {
146 width: 10.0,
147 height: 5.0,
148 thickness: 1.4,
149 er: 4.6,
150 frequency: 0.0,
151 })
152 .unwrap();
153
154 let embedded = calculate(&EmbeddedMicrostripInput {
155 width: 10.0,
156 height: 5.0,
157 thickness: 1.4,
158 er: 4.6,
159 cover_height: 5.0,
160 frequency: 0.0,
161 })
162 .unwrap();
163
164 assert!(
165 embedded.er_eff > surface.er_eff,
166 "embedded er_eff {} should be > surface er_eff {}",
167 embedded.er_eff,
168 surface.er_eff
169 );
170 }
171
172 #[test]
173 fn deep_burial_approaches_er() {
174 let embedded = calculate(&EmbeddedMicrostripInput {
175 width: 10.0,
176 height: 5.0,
177 thickness: 1.4,
178 er: 4.6,
179 cover_height: 50.0, frequency: 0.0,
181 })
182 .unwrap();
183
184 assert_relative_eq!(embedded.er_eff, 4.6, max_relative = 0.01);
186 }
187
188 #[test]
189 fn rejects_negative_cover() {
190 let result = calculate(&EmbeddedMicrostripInput {
191 width: 10.0,
192 height: 5.0,
193 thickness: 1.4,
194 er: 4.6,
195 cover_height: -1.0,
196 frequency: 0.0,
197 });
198 assert!(result.is_err());
199 }
200}