1
+ """Test the microwave plugin."""
2
+
1
3
import pytest
2
4
import numpy as np
5
+ import pydantic .v1 as pydantic
6
+
7
+ from skrf import Frequency
8
+ from skrf .media import MLine
3
9
4
10
import tidy3d as td
5
11
from tidy3d import FieldData
9
15
CurrentIntegralAxisAligned ,
10
16
ImpedanceCalculator ,
11
17
)
12
- import pydantic .v1 as pydantic
18
+
19
+ from tidy3d .plugins .microwave .models import microstrip , coupled_microstrip
20
+
13
21
from tidy3d .exceptions import DataError
14
22
from ..utils import run_emulated
15
23
16
-
17
24
# Using similar code as "test_data/test_data_arrays.py"
18
25
MON_SIZE = (2 , 1 , 0 )
19
26
FIELDS = ("Ex" , "Ey" , "Hx" , "Hy" )
@@ -112,6 +119,7 @@ def make_field_data():
112
119
113
120
@pytest .mark .parametrize ("axis" , [0 , 1 , 2 ])
114
121
def test_voltage_integral_axes (axis ):
122
+ """Check VoltageIntegralAxisAligned runs."""
115
123
length = 0.5
116
124
size = [0 , 0 , 0 ]
117
125
size [axis ] = length
@@ -127,6 +135,7 @@ def test_voltage_integral_axes(axis):
127
135
128
136
@pytest .mark .parametrize ("axis" , [0 , 1 , 2 ])
129
137
def test_current_integral_axes (axis ):
138
+ """Check CurrentIntegralAxisAligned runs."""
130
139
length = 0.5
131
140
size = [length , length , length ]
132
141
size [axis ] = 0.0
@@ -140,6 +149,7 @@ def test_current_integral_axes(axis):
140
149
141
150
142
151
def test_voltage_integral_toggles ():
152
+ """Check VoltageIntegralAxisAligned runs with toggles."""
143
153
length = 0.5
144
154
size = [0 , 0 , 0 ]
145
155
size [0 ] = length
@@ -155,6 +165,7 @@ def test_voltage_integral_toggles():
155
165
156
166
157
167
def test_current_integral_toggles ():
168
+ """Check CurrentIntegralAxisAligned runs with toggles."""
158
169
length = 0.5
159
170
size = [length , length , length ]
160
171
size [0 ] = 0.0
@@ -170,6 +181,7 @@ def test_current_integral_toggles():
170
181
171
182
172
183
def test_voltage_missing_fields ():
184
+ """Check validation of VoltageIntegralAxisAligned with missing fields."""
173
185
length = 0.5
174
186
size = [0 , 0 , 0 ]
175
187
size [1 ] = length
@@ -185,6 +197,7 @@ def test_voltage_missing_fields():
185
197
186
198
187
199
def test_current_missing_fields ():
200
+ """Check validation of CurrentIntegralAxisAligned with missing fields."""
188
201
length = 0.5
189
202
size = [length , length , length ]
190
203
size [0 ] = 0.0
@@ -200,6 +213,7 @@ def test_current_missing_fields():
200
213
201
214
202
215
def test_time_monitor_voltage_integral ():
216
+ """Check VoltageIntegralAxisAligned runs on time domain data."""
203
217
length = 0.5
204
218
size = [0 , 0 , 0 ]
205
219
size [1 ] = length
@@ -214,6 +228,7 @@ def test_time_monitor_voltage_integral():
214
228
215
229
216
230
def test_mode_solver_monitor_voltage_integral ():
231
+ """Check VoltageIntegralAxisAligned runs on mode solver data."""
217
232
length = 0.5
218
233
size = [0 , 0 , 0 ]
219
234
size [1 ] = length
@@ -228,6 +243,7 @@ def test_mode_solver_monitor_voltage_integral():
228
243
229
244
230
245
def test_tiny_voltage_path ():
246
+ """Check VoltageIntegralAxisAligned runs when given a very short path."""
231
247
length = 0.02
232
248
size = [0 , 0 , 0 ]
233
249
size [1 ] = length
@@ -240,11 +256,13 @@ def test_tiny_voltage_path():
240
256
241
257
242
258
def test_impedance_calculator ():
259
+ """Check validation of ImpedanceCalculator when integrals are missing."""
243
260
with pytest .raises (pydantic .ValidationError ):
244
261
_ = ImpedanceCalculator (voltage_integral = None , current_integral = None )
245
262
246
263
247
264
def test_impedance_calculator_on_time_data ():
265
+ """Check ImpedanceCalculator runs on time domain data."""
248
266
# Setup path integrals
249
267
length = 0.5
250
268
size = [0 , length , 0 ]
@@ -269,6 +287,7 @@ def test_impedance_calculator_on_time_data():
269
287
270
288
271
289
def test_impedance_accuracy ():
290
+ """Test the accuracy of the ImpedanceCalculator."""
272
291
field_data = make_field_data ()
273
292
# Setup path integrals
274
293
size = [0 , STRIP_HEIGHT / 2 , 0 ]
@@ -303,3 +322,60 @@ def impedance_of_stripline(width, height):
303
322
assert np .all (np .isclose (Z1 , analytic_impedance , rtol = 0.02 ))
304
323
assert np .all (np .isclose (Z2 , analytic_impedance , atol = 3.5 ))
305
324
assert np .all (np .isclose (Z3 , analytic_impedance , atol = 3.5 ))
325
+
326
+
327
+ def test_microstrip_models ():
328
+ """Test that the microstrip model computes transmission line parameters accurately."""
329
+ width = 3.0
330
+ height = 1.0
331
+ thickness = 0.0
332
+ eps_r = 4.4
333
+
334
+ # Check zero thickness parameters
335
+ Z0 , eps_eff = microstrip .compute_line_params (eps_r , width , height , thickness )
336
+ freqs = Frequency (start = 1 , stop = 1 , npoints = 1 , unit = "ghz" )
337
+ mline = MLine (frequency = freqs , w = width , h = height , t = thickness , ep_r = eps_r , disp = "none" )
338
+
339
+ assert np .isclose (Z0 , mline .Z0 [0 ])
340
+ assert np .isclose (eps_eff , mline .ep_reff [0 ])
341
+
342
+ # Check end effect length computation
343
+ dL = microstrip .compute_end_effect_length (eps_r , eps_eff , width , height )
344
+ assert np .isclose (dL , 0.54 , rtol = 0.01 )
345
+
346
+ # Check finite thickness parameters
347
+ thickness = 0.1
348
+ Z0 , eps_eff = microstrip .compute_line_params (eps_r , width , height , thickness )
349
+ mline = MLine (frequency = freqs , w = width , h = height , t = thickness , ep_r = eps_r , disp = "none" )
350
+
351
+ assert np .isclose (Z0 , mline .Z0 [0 ])
352
+ assert np .isclose (eps_eff , mline .ep_reff [0 ])
353
+
354
+
355
+ def test_coupled_microstrip_model ():
356
+ """Test that the coupled microstrip model computes transmission line parameters accurately."""
357
+ w1 = 1.416
358
+ w2 = 2.396
359
+ height = 1.56
360
+ g1 = 0.134
361
+ g2 = 0.386
362
+ eps_r = 4.3
363
+ # Compare to: Taoufik, Ragani, N. Amar Touhami, and M. Agoutane. "Designing a Microstrip coupled line bandpass filter."
364
+ # International Journal of Engineering & Technology 2, no. 4 (2013): 266.
365
+ # and notebook "CoupledLineBandpassFilter"
366
+
367
+ (Z_even , Z_odd , eps_even , eps_odd ) = coupled_microstrip .compute_line_params (
368
+ eps_r , w1 , height , g1
369
+ )
370
+ assert np .isclose (Z_even , 101.5 , rtol = 0.01 )
371
+ assert np .isclose (Z_odd , 38.5 , rtol = 0.01 )
372
+ assert np .isclose (eps_even , 3.26 , rtol = 0.01 )
373
+ assert np .isclose (eps_odd , 2.71 , rtol = 0.01 )
374
+
375
+ (Z_even , Z_odd , eps_even , eps_odd ) = coupled_microstrip .compute_line_params (
376
+ eps_r , w2 , height , g2
377
+ )
378
+ assert np .isclose (Z_even , 71 , rtol = 0.01 )
379
+ assert np .isclose (Z_odd , 39 , rtol = 0.01 )
380
+ assert np .isclose (eps_even , 3.42 , rtol = 0.01 )
381
+ assert np .isclose (eps_odd , 2.80 , rtol = 0.01 )
0 commit comments