|
| 1 | +.. _impedance_calculator: |
| 2 | + |
| 3 | +Impedance Calculator & Path Integrals |
| 4 | +-------------------------------------- |
| 5 | + |
| 6 | +The impedance calculator and path integral classes provide tools for computing characteristic impedance, voltage, and current from electromagnetic field data. These tools can be applied to mode solver results, field monitor data, or any electromagnetic field distribution. |
| 7 | + |
| 8 | +This section documents the **runtime execution** classes. For information on how to specify path integrals in :class:`.MicrowaveModeSpec`, see the :ref:`path_integrals` section. |
| 9 | + |
| 10 | +Impedance Calculator |
| 11 | +^^^^^^^^^^^^^^^^^^^^ |
| 12 | + |
| 13 | +.. autosummary:: |
| 14 | + :toctree: ../_autosummary/ |
| 15 | + :template: module.rst |
| 16 | + |
| 17 | + tidy3d.ImpedanceCalculator |
| 18 | + |
| 19 | +The :class:`~tidy3d.ImpedanceCalculator` computes characteristic impedance from electromagnetic field data using voltage and current path integrals. It supports three calculation methods depending on which integrals are provided: |
| 20 | + |
| 21 | +* **V and I method**: :math:`Z_0 = V / I` (when both voltage and current integrals are provided) |
| 22 | +* **P and V method**: :math:`Z_0 = V^2 / (2P)` (when only voltage integral is provided) |
| 23 | +* **P and I method**: :math:`Z_0 = 2P / I^2` (when only current integral is provided) |
| 24 | + |
| 25 | +where :math:`P` is the time-averaged power flux through the cross-section. |
| 26 | + |
| 27 | +**Basic Usage** |
| 28 | + |
| 29 | +.. code-block:: python |
| 30 | +
|
| 31 | + import tidy3d as td |
| 32 | +
|
| 33 | + # Define voltage integration path |
| 34 | + voltage_integral = td.AxisAlignedVoltageIntegral( |
| 35 | + center=(0, 0, 0), |
| 36 | + size=(0, 0, 2), # Vertical line |
| 37 | + sign="+", |
| 38 | + extrapolate_to_endpoints=True, |
| 39 | + snap_path_to_grid=True |
| 40 | + ) |
| 41 | +
|
| 42 | + # Define current integration contour |
| 43 | + current_integral = td.AxisAlignedCurrentIntegral( |
| 44 | + center=(0, 0, 0), |
| 45 | + size=(4, 2, 0), # Rectangular loop |
| 46 | + sign="+", |
| 47 | + snap_contour_to_grid=True |
| 48 | + ) |
| 49 | +
|
| 50 | + # Create impedance calculator |
| 51 | + Z_calculator = td.ImpedanceCalculator( |
| 52 | + voltage_integral=voltage_integral, |
| 53 | + current_integral=current_integral |
| 54 | + ) |
| 55 | +
|
| 56 | + # Compute impedance from mode data |
| 57 | + mode_data = # ... obtain from ModeSimulation or ModeSolver |
| 58 | + impedance = Z_calculator.compute_impedance(mode_data) |
| 59 | +
|
| 60 | +**Using with Mode Solver Data** |
| 61 | + |
| 62 | +The impedance calculator is commonly used with mode solver results to determine the characteristic impedance of transmission line modes: |
| 63 | + |
| 64 | +.. code-block:: python |
| 65 | +
|
| 66 | + # Run mode simulation |
| 67 | + mode_sim = td.ModeSimulation( |
| 68 | + size=(10, 10, 0), |
| 69 | + grid_spec=td.GridSpec.auto(wavelength=0.3), |
| 70 | + structures=[...], |
| 71 | + monitors=[mode_monitor], |
| 72 | + freqs=[1e9, 2e9, 3e9] |
| 73 | + ) |
| 74 | +
|
| 75 | + mode_data = td.web.run(mode_sim, task_name='mode_solver') |
| 76 | +
|
| 77 | + # Calculate impedance for each mode |
| 78 | + for mode_index in range(num_modes): |
| 79 | + mode_field = mode_data.sel(mode_index=mode_index) |
| 80 | + Z0 = Z_calculator.compute_impedance(mode_field) |
| 81 | + print(f"Mode {mode_index}: Z0 = {Z0} Ω") |
| 82 | +
|
| 83 | +**Obtaining Voltage and Current** |
| 84 | + |
| 85 | +You can also retrieve the voltage and current values along with impedance: |
| 86 | + |
| 87 | +.. code-block:: python |
| 88 | +
|
| 89 | + # Get impedance, voltage, and current |
| 90 | + Z, V, I = Z_calculator.compute_impedance( |
| 91 | + mode_data, |
| 92 | + return_voltage_and_current=True |
| 93 | + ) |
| 94 | +
|
| 95 | + print(f"Impedance: {Z} Ω") |
| 96 | + print(f"Voltage: {V} V") |
| 97 | + print(f"Current: {I} A") |
| 98 | +
|
| 99 | +**Single Integral Calculation** |
| 100 | + |
| 101 | +When only voltage or current integral is specified, the power flux is automatically used: |
| 102 | + |
| 103 | +.. code-block:: python |
| 104 | +
|
| 105 | + # Calculator with only voltage integral |
| 106 | + Z_calc_V = td.ImpedanceCalculator( |
| 107 | + voltage_integral=voltage_integral, |
| 108 | + current_integral=None |
| 109 | + ) |
| 110 | +
|
| 111 | + # Computes: Z = V^2 / (2*P) |
| 112 | + Z_from_V = Z_calc_V.compute_impedance(mode_data) |
| 113 | +
|
| 114 | + # Calculator with only current integral |
| 115 | + Z_calc_I = td.ImpedanceCalculator( |
| 116 | + voltage_integral=None, |
| 117 | + current_integral=current_integral |
| 118 | + ) |
| 119 | +
|
| 120 | + # Computes: Z = 2*P / I^2 |
| 121 | + Z_from_I = Z_calc_I.compute_impedance(mode_data) |
| 122 | +
|
| 123 | +Path Integral Execution Classes |
| 124 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 125 | + |
| 126 | +.. autosummary:: |
| 127 | + :toctree: ../_autosummary/ |
| 128 | + :template: module.rst |
| 129 | + |
| 130 | + tidy3d.AxisAlignedVoltageIntegral |
| 131 | + tidy3d.Custom2DVoltageIntegral |
| 132 | + tidy3d.AxisAlignedCurrentIntegral |
| 133 | + tidy3d.Custom2DCurrentIntegral |
| 134 | + tidy3d.CompositeCurrentIntegral |
| 135 | + tidy3d.AxisAlignedPathIntegral |
| 136 | + tidy3d.Custom2DPathIntegral |
| 137 | + |
| 138 | +These classes perform the actual runtime computation of path integrals on electromagnetic field data. They are created internally by :class:`~tidy3d.ImpedanceCalculator` and :class:`~tidy3d.MicrowaveModeSpec`, but can also be used directly for custom analysis. |
| 139 | + |
| 140 | +**Note on Specification vs Execution Classes** |
| 141 | + |
| 142 | +The path integral framework uses two parallel class hierarchies: |
| 143 | + |
| 144 | +* **Specification classes** (``*Spec``): Define the configuration for path integrals, used in :class:`.MicrowaveModeSpec` and :class:`.CustomImpedanceSpec`. See :ref:`path_integrals`. |
| 145 | +* **Execution classes** (``*Integral``): Perform the actual computation on field data, created from specifications or used directly. |
| 146 | + |
| 147 | +**Direct Usage of Integral Classes** |
| 148 | + |
| 149 | +While typically used through :class:`~tidy3d.ImpedanceCalculator`, you can also use the integral classes directly for custom analysis: |
| 150 | + |
| 151 | +.. code-block:: python |
| 152 | +
|
| 153 | + # Create voltage integral directly |
| 154 | + voltage_integral = td.AxisAlignedVoltageIntegral( |
| 155 | + center=(0, 0, 0), |
| 156 | + size=(0, 0, 2), |
| 157 | + sign="+", |
| 158 | + extrapolate_to_endpoints=True, |
| 159 | + snap_path_to_grid=True |
| 160 | + ) |
| 161 | +
|
| 162 | + # Compute voltage from field data |
| 163 | + voltage = voltage_integral.compute_voltage(field_data) |
| 164 | +
|
| 165 | + # Create current integral directly |
| 166 | + current_integral = td.AxisAlignedCurrentIntegral( |
| 167 | + center=(0, 0, 0), |
| 168 | + size=(4, 2, 0), |
| 169 | + sign="+", |
| 170 | + snap_contour_to_grid=True |
| 171 | + ) |
| 172 | +
|
| 173 | + # Compute current from field data |
| 174 | + current = current_integral.compute_current(field_data) |
| 175 | +
|
| 176 | + # Calculate impedance manually |
| 177 | + impedance = voltage / current |
| 178 | +
|
| 179 | +**Composite Current Integrals** |
| 180 | + |
| 181 | +For differential transmission lines or complex geometries with multiple current paths: |
| 182 | + |
| 183 | +.. code-block:: python |
| 184 | +
|
| 185 | + # Define multiple current paths |
| 186 | + path1 = td.AxisAlignedCurrentIntegral( |
| 187 | + center=(-2, 0, 0), |
| 188 | + size=(1, 1, 0), |
| 189 | + sign="+" |
| 190 | + ) |
| 191 | +
|
| 192 | + path2 = td.AxisAlignedCurrentIntegral( |
| 193 | + center=(2, 0, 0), |
| 194 | + size=(1, 1, 0), |
| 195 | + sign="+" |
| 196 | + ) |
| 197 | +
|
| 198 | + # Combine into composite integral |
| 199 | + composite_integral = td.CompositeCurrentIntegral( |
| 200 | + path_specs=(path1, path2), |
| 201 | + sum_spec="sum" # or "split" for phase-separated contributions |
| 202 | + ) |
| 203 | +
|
| 204 | + # Compute total or split current |
| 205 | + current = composite_integral.compute_current(field_data) |
| 206 | +
|
| 207 | +**Custom 2D Path Integrals** |
| 208 | + |
| 209 | +For arbitrary integration paths: |
| 210 | + |
| 211 | +.. code-block:: python |
| 212 | +
|
| 213 | + import numpy as np |
| 214 | +
|
| 215 | + # Define custom voltage path |
| 216 | + vertices_V = np.array([[0, 0], [0.5, 0.5], [1, 1]]) |
| 217 | +
|
| 218 | + custom_voltage_integral = td.Custom2DVoltageIntegral( |
| 219 | + axis=2, |
| 220 | + position=0.0, |
| 221 | + vertices=vertices_V |
| 222 | + ) |
| 223 | +
|
| 224 | + voltage = custom_voltage_integral.compute_voltage(field_data) |
| 225 | +
|
| 226 | + # Define custom current contour (must be closed) |
| 227 | + vertices_I = np.array([ |
| 228 | + [0, 0], [2, 0], [2, 1], [0, 1], [0, 0] |
| 229 | + ]) |
| 230 | +
|
| 231 | + custom_current_integral = td.Custom2DCurrentIntegral( |
| 232 | + axis=2, |
| 233 | + position=0.0, |
| 234 | + vertices=vertices_I |
| 235 | + ) |
| 236 | +
|
| 237 | + current = custom_current_integral.compute_current(field_data) |
| 238 | +
|
| 239 | +Field Data Compatibility |
| 240 | +^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 241 | + |
| 242 | +The impedance calculator and path integral classes work with various types of field data: |
| 243 | + |
| 244 | +* :class:`~tidy3d.ModeSolverData`: Mode field profiles from 2D mode solver |
| 245 | +* :class:`~tidy3d.FieldData`: Frequency-domain field data from monitors |
| 246 | +* :class:`~tidy3d.FieldTimeData`: Time-domain field data from monitors |
| 247 | +* :class:`~tidy3d.MicrowaveModeSolverData`: Microwave mode solver data (includes pre-computed integrals) |
| 248 | + |
| 249 | +.. code-block:: python |
| 250 | +
|
| 251 | + # Works with different data types |
| 252 | + Z_from_mode = Z_calculator.compute_impedance(mode_solver_data) |
| 253 | + Z_from_monitor = Z_calculator.compute_impedance(field_monitor_data) |
| 254 | + Z_from_time = Z_calculator.compute_impedance(field_time_data) |
| 255 | +
|
| 256 | +Phase Convention |
| 257 | +^^^^^^^^^^^^^^^^ |
| 258 | + |
| 259 | +.. note:: |
| 260 | + |
| 261 | + Tidy3D uses the physics phase convention :math:`e^{-i\omega t}`. Some RF simulation software and textbooks use the electrical engineering convention :math:`e^{i\omega t}`. This affects calculated S-parameters and impedance values. |
| 262 | + |
| 263 | + To convert between conventions, use complex conjugation: |
| 264 | + |
| 265 | + .. code-block:: python |
| 266 | +
|
| 267 | + import numpy as np |
| 268 | +
|
| 269 | + # Convert from physics to engineering convention |
| 270 | + Z_engineering = np.conjugate(Z_physics) |
| 271 | +
|
| 272 | + # Convert from engineering to physics convention |
| 273 | + Z_physics = np.conjugate(Z_engineering) |
| 274 | +
|
| 275 | +Practical Examples |
| 276 | +^^^^^^^^^^^^^^^^^^ |
| 277 | + |
| 278 | +**Example 1: Microstrip Line** |
| 279 | + |
| 280 | +.. code-block:: python |
| 281 | +
|
| 282 | + # Define microstrip geometry structures |
| 283 | + substrate = td.Structure(...) |
| 284 | + trace = td.Structure(...) |
| 285 | + ground = td.Structure(...) |
| 286 | +
|
| 287 | + # Create voltage integral (substrate to trace) |
| 288 | + V_int = td.AxisAlignedVoltageIntegral( |
| 289 | + center=(0, 0, substrate_height/2), |
| 290 | + size=(0, 0, substrate_height), |
| 291 | + sign="+", |
| 292 | + snap_path_to_grid=True |
| 293 | + ) |
| 294 | +
|
| 295 | + # Create current integral (loop around trace) |
| 296 | + I_int = td.AxisAlignedCurrentIntegral( |
| 297 | + center=(0, 0, substrate_height + trace_height/2), |
| 298 | + size=(trace_width*3, trace_width*3, 0), |
| 299 | + sign="+", |
| 300 | + snap_contour_to_grid=True |
| 301 | + ) |
| 302 | +
|
| 303 | + # Calculate impedance |
| 304 | + calc = td.ImpedanceCalculator(voltage_integral=V_int, current_integral=I_int) |
| 305 | + Z0 = calc.compute_impedance(mode_data) |
| 306 | +
|
| 307 | +**Example 2: Differential Stripline** |
| 308 | + |
| 309 | +.. code-block:: python |
| 310 | +
|
| 311 | + # Voltage between the two signal traces |
| 312 | + V_int = td.AxisAlignedVoltageIntegral( |
| 313 | + center=(0, 0, 0), |
| 314 | + size=(trace_spacing, 0, 0), # Horizontal line between traces |
| 315 | + sign="+", |
| 316 | + snap_path_to_grid=True |
| 317 | + ) |
| 318 | +
|
| 319 | + # Current around one of the traces |
| 320 | + I_int = td.AxisAlignedCurrentIntegral( |
| 321 | + center=(-trace_spacing/2, 0, 0), |
| 322 | + size=(trace_width*2, trace_width*2, 0), |
| 323 | + sign="+", |
| 324 | + snap_contour_to_grid=True |
| 325 | + ) |
| 326 | +
|
| 327 | + # Differential impedance |
| 328 | + calc = td.ImpedanceCalculator(voltage_integral=V_int, current_integral=I_int) |
| 329 | + Z_diff = calc.compute_impedance(mode_data) |
| 330 | +
|
| 331 | +.. seealso:: |
| 332 | + |
| 333 | + Related documentation: |
| 334 | + |
| 335 | + + :ref:`path_integrals` |
| 336 | + + :ref:`microwave_mode_solver` |
| 337 | + |
| 338 | + Tutorials and examples: |
| 339 | + |
| 340 | + + `Computing the characteristic impedance of transmission lines <../../notebooks/CharacteristicImpedanceCalculator.html>`_ |
| 341 | + + `Differential stripline benchmark <../../notebooks/DifferentialStripline.html>`_ |
| 342 | + |
| 343 | +~~~~ |
0 commit comments