From 2e3de93e0fe5b9f9ba8163330c872f1e3dc28871 Mon Sep 17 00:00:00 2001 From: dmarek Date: Wed, 15 Oct 2025 09:39:08 -0400 Subject: [PATCH] docs(rf): add documentation for the new and moved microwave components from the auto mode impedance feature --- docs/api/microwave/impedance_calculator.rst | 343 ++++++++++++++++++++ docs/api/microwave/index.rst | 8 + docs/api/microwave/mode_solver.rst | 169 ++++++++++ docs/api/microwave/output_data.rst | 279 ++++++++++++++++ docs/api/microwave/path_integrals.rst | 271 ++++++++++++++++ 5 files changed, 1070 insertions(+) create mode 100644 docs/api/microwave/impedance_calculator.rst create mode 100644 docs/api/microwave/mode_solver.rst create mode 100644 docs/api/microwave/output_data.rst create mode 100644 docs/api/microwave/path_integrals.rst diff --git a/docs/api/microwave/impedance_calculator.rst b/docs/api/microwave/impedance_calculator.rst new file mode 100644 index 0000000000..afefb45868 --- /dev/null +++ b/docs/api/microwave/impedance_calculator.rst @@ -0,0 +1,343 @@ +.. _impedance_calculator: + +Impedance Calculator & Path Integrals +-------------------------------------- + +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. + +This section documents the **runtime execution** classes. For information on how to specify path integrals in :class:`.MicrowaveModeSpec`, see the :ref:`path_integrals` section. + +Impedance Calculator +^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.ImpedanceCalculator + +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: + +* **V and I method**: :math:`Z_0 = V / I` (when both voltage and current integrals are provided) +* **P and V method**: :math:`Z_0 = V^2 / (2P)` (when only voltage integral is provided) +* **P and I method**: :math:`Z_0 = 2P / I^2` (when only current integral is provided) + +where :math:`P` is the time-averaged power flux through the cross-section. + +**Basic Usage** + +.. code-block:: python + + import tidy3d as td + + # Define voltage integration path + voltage_integral = td.AxisAlignedVoltageIntegral( + center=(0, 0, 0), + size=(0, 0, 2), # Vertical line + sign="+", + extrapolate_to_endpoints=True, + snap_path_to_grid=True + ) + + # Define current integration contour + current_integral = td.AxisAlignedCurrentIntegral( + center=(0, 0, 0), + size=(4, 2, 0), # Rectangular loop + sign="+", + snap_contour_to_grid=True + ) + + # Create impedance calculator + Z_calculator = td.ImpedanceCalculator( + voltage_integral=voltage_integral, + current_integral=current_integral + ) + + # Compute impedance from mode data + mode_data = # ... obtain from ModeSimulation or ModeSolver + impedance = Z_calculator.compute_impedance(mode_data) + +**Using with Mode Solver Data** + +The impedance calculator is commonly used with mode solver results to determine the characteristic impedance of transmission line modes: + +.. code-block:: python + + # Run mode simulation + mode_sim = td.ModeSimulation( + size=(10, 10, 0), + grid_spec=td.GridSpec.auto(wavelength=0.3), + structures=[...], + monitors=[mode_monitor], + freqs=[1e9, 2e9, 3e9] + ) + + mode_data = td.web.run(mode_sim, task_name='mode_solver') + + # Calculate impedance for each mode + for mode_index in range(num_modes): + mode_field = mode_data.sel(mode_index=mode_index) + Z0 = Z_calculator.compute_impedance(mode_field) + print(f"Mode {mode_index}: Z0 = {Z0} Ω") + +**Obtaining Voltage and Current** + +You can also retrieve the voltage and current values along with impedance: + +.. code-block:: python + + # Get impedance, voltage, and current + Z, V, I = Z_calculator.compute_impedance( + mode_data, + return_voltage_and_current=True + ) + + print(f"Impedance: {Z} Ω") + print(f"Voltage: {V} V") + print(f"Current: {I} A") + +**Single Integral Calculation** + +When only voltage or current integral is specified, the power flux is automatically used: + +.. code-block:: python + + # Calculator with only voltage integral + Z_calc_V = td.ImpedanceCalculator( + voltage_integral=voltage_integral, + current_integral=None + ) + + # Computes: Z = V^2 / (2*P) + Z_from_V = Z_calc_V.compute_impedance(mode_data) + + # Calculator with only current integral + Z_calc_I = td.ImpedanceCalculator( + voltage_integral=None, + current_integral=current_integral + ) + + # Computes: Z = 2*P / I^2 + Z_from_I = Z_calc_I.compute_impedance(mode_data) + +Path Integral Execution Classes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.AxisAlignedVoltageIntegral + tidy3d.Custom2DVoltageIntegral + tidy3d.AxisAlignedCurrentIntegral + tidy3d.Custom2DCurrentIntegral + tidy3d.CompositeCurrentIntegral + tidy3d.AxisAlignedPathIntegral + tidy3d.Custom2DPathIntegral + +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. + +**Note on Specification vs Execution Classes** + +The path integral framework uses two parallel class hierarchies: + +* **Specification classes** (``*Spec``): Define the configuration for path integrals, used in :class:`.MicrowaveModeSpec` and :class:`.CustomImpedanceSpec`. See :ref:`path_integrals`. +* **Execution classes** (``*Integral``): Perform the actual computation on field data, created from specifications or used directly. + +**Direct Usage of Integral Classes** + +While typically used through :class:`~tidy3d.ImpedanceCalculator`, you can also use the integral classes directly for custom analysis: + +.. code-block:: python + + # Create voltage integral directly + voltage_integral = td.AxisAlignedVoltageIntegral( + center=(0, 0, 0), + size=(0, 0, 2), + sign="+", + extrapolate_to_endpoints=True, + snap_path_to_grid=True + ) + + # Compute voltage from field data + voltage = voltage_integral.compute_voltage(field_data) + + # Create current integral directly + current_integral = td.AxisAlignedCurrentIntegral( + center=(0, 0, 0), + size=(4, 2, 0), + sign="+", + snap_contour_to_grid=True + ) + + # Compute current from field data + current = current_integral.compute_current(field_data) + + # Calculate impedance manually + impedance = voltage / current + +**Composite Current Integrals** + +For differential transmission lines or complex geometries with multiple current paths: + +.. code-block:: python + + # Define multiple current paths + path1 = td.AxisAlignedCurrentIntegral( + center=(-2, 0, 0), + size=(1, 1, 0), + sign="+" + ) + + path2 = td.AxisAlignedCurrentIntegral( + center=(2, 0, 0), + size=(1, 1, 0), + sign="+" + ) + + # Combine into composite integral + composite_integral = td.CompositeCurrentIntegral( + path_specs=(path1, path2), + sum_spec="sum" # or "split" for phase-separated contributions + ) + + # Compute total or split current + current = composite_integral.compute_current(field_data) + +**Custom 2D Path Integrals** + +For arbitrary integration paths: + +.. code-block:: python + + import numpy as np + + # Define custom voltage path + vertices_V = np.array([[0, 0], [0.5, 0.5], [1, 1]]) + + custom_voltage_integral = td.Custom2DVoltageIntegral( + axis=2, + position=0.0, + vertices=vertices_V + ) + + voltage = custom_voltage_integral.compute_voltage(field_data) + + # Define custom current contour (must be closed) + vertices_I = np.array([ + [0, 0], [2, 0], [2, 1], [0, 1], [0, 0] + ]) + + custom_current_integral = td.Custom2DCurrentIntegral( + axis=2, + position=0.0, + vertices=vertices_I + ) + + current = custom_current_integral.compute_current(field_data) + +Field Data Compatibility +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The impedance calculator and path integral classes work with various types of field data: + +* :class:`~tidy3d.ModeSolverData`: Mode field profiles from 2D mode solver +* :class:`~tidy3d.FieldData`: Frequency-domain field data from monitors +* :class:`~tidy3d.FieldTimeData`: Time-domain field data from monitors +* :class:`~tidy3d.MicrowaveModeSolverData`: Microwave mode solver data (includes pre-computed integrals) + +.. code-block:: python + + # Works with different data types + Z_from_mode = Z_calculator.compute_impedance(mode_solver_data) + Z_from_monitor = Z_calculator.compute_impedance(field_monitor_data) + Z_from_time = Z_calculator.compute_impedance(field_time_data) + +Phase Convention +^^^^^^^^^^^^^^^^ + +.. note:: + + 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. + + To convert between conventions, use complex conjugation: + + .. code-block:: python + + import numpy as np + + # Convert from physics to engineering convention + Z_engineering = np.conjugate(Z_physics) + + # Convert from engineering to physics convention + Z_physics = np.conjugate(Z_engineering) + +Practical Examples +^^^^^^^^^^^^^^^^^^ + +**Example 1: Microstrip Line** + +.. code-block:: python + + # Define microstrip geometry structures + substrate = td.Structure(...) + trace = td.Structure(...) + ground = td.Structure(...) + + # Create voltage integral (substrate to trace) + V_int = td.AxisAlignedVoltageIntegral( + center=(0, 0, substrate_height/2), + size=(0, 0, substrate_height), + sign="+", + snap_path_to_grid=True + ) + + # Create current integral (loop around trace) + I_int = td.AxisAlignedCurrentIntegral( + center=(0, 0, substrate_height + trace_height/2), + size=(trace_width*3, trace_width*3, 0), + sign="+", + snap_contour_to_grid=True + ) + + # Calculate impedance + calc = td.ImpedanceCalculator(voltage_integral=V_int, current_integral=I_int) + Z0 = calc.compute_impedance(mode_data) + +**Example 2: Differential Stripline** + +.. code-block:: python + + # Voltage between the two signal traces + V_int = td.AxisAlignedVoltageIntegral( + center=(0, 0, 0), + size=(trace_spacing, 0, 0), # Horizontal line between traces + sign="+", + snap_path_to_grid=True + ) + + # Current around one of the traces + I_int = td.AxisAlignedCurrentIntegral( + center=(-trace_spacing/2, 0, 0), + size=(trace_width*2, trace_width*2, 0), + sign="+", + snap_contour_to_grid=True + ) + + # Differential impedance + calc = td.ImpedanceCalculator(voltage_integral=V_int, current_integral=I_int) + Z_diff = calc.compute_impedance(mode_data) + +.. seealso:: + + Related documentation: + + + :ref:`path_integrals` + + :ref:`microwave_mode_solver` + + Tutorials and examples: + + + `Computing the characteristic impedance of transmission lines <../../notebooks/CharacteristicImpedanceCalculator.html>`_ + + `Differential stripline benchmark <../../notebooks/DifferentialStripline.html>`_ + +~~~~ diff --git a/docs/api/microwave/index.rst b/docs/api/microwave/index.rst index 19f7240191..3953f44ef0 100644 --- a/docs/api/microwave/index.rst +++ b/docs/api/microwave/index.rst @@ -24,6 +24,10 @@ The following sections discuss: * `Layer-based Grid Refinement`_: Automated grid refinement strategy for planar structures (e.g. printed circuit boards) * `Lumped Port & Elements`_: Lumped excitations and circuit elements * `Wave Port`_: Port excitation based on modal fields +* `Transmission Line Mode Analysis`_: Mode solving with automatic impedance calculation for transmission lines +* `Path Integral Specifications`_: Specifications for voltage, current, and impedance calculations +* `Impedance Calculator`_: Post-processing tool for impedance calculation from electromagnetic fields +* `Microwave Output Data`_: Data containers for microwave simulation results * `Radiation & Scattering`_: Useful features for antenna and scattering problems .. seealso:: @@ -40,4 +44,8 @@ The following sections discuss: .. include:: /api/discretization/layer.rst .. include:: /api/microwave/ports/lumped.rst .. include:: /api/microwave/ports/wave.rst +.. include:: /api/microwave/mode_solver.rst +.. include:: /api/microwave/path_integrals.rst +.. include:: /api/microwave/impedance_calculator.rst +.. include:: /api/microwave/output_data.rst .. include:: /api/microwave/radiation_scattering.rst diff --git a/docs/api/microwave/mode_solver.rst b/docs/api/microwave/mode_solver.rst new file mode 100644 index 0000000000..8d5d9d7447 --- /dev/null +++ b/docs/api/microwave/mode_solver.rst @@ -0,0 +1,169 @@ +.. _microwave_mode_solver: + +Transmission Line Mode Analysis +-------------------------------- + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.MicrowaveModeSpec + tidy3d.MicrowaveModeMonitor + tidy3d.MicrowaveModeSolverMonitor + tidy3d.ModeSimulation + +The :class:`.MicrowaveModeSpec` extends the standard :class:`.ModeSpec` to include automatic characteristic impedance calculation for transmission line modes. This is particularly useful for microwave and RF applications where the characteristic impedance :math:`Z_0` is a critical parameter. + +Unlike the standard :class:`.ModeSpec`, :class:`.MicrowaveModeSpec` includes an ``impedance_specs`` field that defines how voltage and current path integrals are computed for each mode. These integrals are then used to calculate the characteristic impedance of the transmission line. + +.. code-block:: python + + import tidy3d as td + + # Create a microwave mode specification with automatic impedance calculation + mode_spec = td.MicrowaveModeSpec( + num_modes=2, + target_neff=1.5, + impedance_specs=td.AutoImpedanceSpec() # Automatic path integral setup + ) + + # Use in a microwave mode monitor + monitor = td.MicrowaveModeMonitor( + center=(0, 0, 0), + size=(2, 2, 0), + freqs=[1e9, 2e9, 3e9], + mode_spec=mode_spec, + name='mode_monitor' + ) + +Automatic Impedance Calculation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :class:`.AutoImpedanceSpec` automatically determines appropriate voltage and current integration paths based on the mode field distribution. This is the recommended approach for most use cases, as it eliminates the need to manually define integration paths. + +.. code-block:: python + + # Using automatic impedance specification (recommended) + mode_spec_auto = td.MicrowaveModeSpec( + num_modes=1, + impedance_specs=td.AutoImpedanceSpec() + ) + +Custom Impedance Calculation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For more control over the impedance calculation, you can specify custom voltage and current integration paths using :class:`.CustomImpedanceSpec`. This allows you to define exactly where and how the voltage and current are computed. + +.. code-block:: python + + # Define custom voltage path (line integral) + voltage_spec = td.AxisAlignedVoltageIntegralSpec( + center=(0, 0, 0), + size=(0, 0, 1), # Vertical line + sign="+" + ) + + # Define custom current path (contour integral) + current_spec = td.AxisAlignedCurrentIntegralSpec( + center=(0, 0, 0), + size=(2, 1, 0), # Rectangular loop + sign="+" + ) + + # Create custom impedance specification + custom_impedance = td.CustomImpedanceSpec( + voltage_spec=voltage_spec, + current_spec=current_spec + ) + + # Use in mode specification + mode_spec_custom = td.MicrowaveModeSpec( + num_modes=1, + impedance_specs=custom_impedance + ) + +Multiple Modes +^^^^^^^^^^^^^^ + +When solving for multiple modes, you can provide different impedance specifications for each mode: + +.. code-block:: python + + # Different impedance specs for each mode + mode_spec_multi = td.MicrowaveModeSpec( + num_modes=2, + impedance_specs=( + td.AutoImpedanceSpec(), # Auto for first mode + custom_impedance, # Custom for second mode + ) + ) + + # Or use a single spec for all modes (will be duplicated) + mode_spec_shared = td.MicrowaveModeSpec( + num_modes=2, + impedance_specs=td.AutoImpedanceSpec() # Applied to both modes + ) + +Mode Solver Monitors +^^^^^^^^^^^^^^^^^^^^ + +There are two types of monitors for microwave mode analysis: + +* :class:`.MicrowaveModeMonitor`: Records mode amplitudes and transmission line parameters (voltage, current, impedance) on a monitor plane during a full 3D FDTD simulation. +* :class:`.MicrowaveModeSolverMonitor`: Stores the complete 2D mode field profiles along with transmission line parameters from a standalone mode solver calculation. + +.. code-block:: python + + # Monitor for mode amplitudes in full simulation + mode_monitor = td.MicrowaveModeMonitor( + center=(0, 0, 0), + size=(2, 2, 0), + freqs=[1e9, 2e9], + mode_spec=mode_spec, + name='mode_monitor' + ) + + # Monitor for mode field profiles (mode solver only) + mode_solver_monitor = td.MicrowaveModeSolverMonitor( + center=(0, 0, 0), + size=(2, 2, 0), + freqs=[1e9, 2e9], + mode_spec=mode_spec, + name='mode_solver_monitor' + ) + +Mode Simulation +^^^^^^^^^^^^^^^ + +For standalone mode solving (without a full 3D FDTD simulation), use :class:`.ModeSimulation`: + +.. code-block:: python + + # Create a mode simulation for transmission line analysis + mode_sim = td.ModeSimulation( + size=(10, 10, 0), + grid_spec=td.GridSpec.auto(wavelength=0.3), + structures=[...], # Your transmission line structures + mode_spec=mode_spec, # MicrowaveModeSpec defining impedance calculation + freqs=[1e9, 2e9, 3e9], + ) + + # Run the mode simulation + mode_data = td.web.run(mode_sim, task_name='mode_analysis') + + # Access impedance results + Z0 = mode_data.transmission_line_data.Z0 + +.. seealso:: + + For more information on path integral specifications, see: + + + :ref:`path_integrals` + + :ref:`impedance_calculator` + + For practical examples: + + + `Computing the characteristic impedance of transmission lines <../../notebooks/CharacteristicImpedanceCalculator.html>`_ + + `Differential stripline benchmark <../../notebooks/DifferentialStripline.html>`_ + +~~~~ diff --git a/docs/api/microwave/output_data.rst b/docs/api/microwave/output_data.rst new file mode 100644 index 0000000000..8c4afc74bb --- /dev/null +++ b/docs/api/microwave/output_data.rst @@ -0,0 +1,279 @@ +.. currentmodule:: tidy3d + +Microwave Output Data +--------------------- + +This page documents the data containers specific to microwave and RF simulations. These containers store electromagnetic field data along with computed transmission line parameters such as voltage, current, and characteristic impedance. + +Monitor Data +^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.MicrowaveModeData + tidy3d.MicrowaveModeSolverData + tidy3d.AntennaMetricsData + +**MicrowaveModeData** + +The :class:`.MicrowaveModeData` class stores mode amplitude data along with transmission line parameters from a :class:`.MicrowaveModeMonitor` in a full 3D FDTD simulation. It extends the standard :class:`.ModeData` to include the ``transmission_line_data`` attribute. + +.. code-block:: python + + # Access mode data from simulation results + sim_data = td.web.run(simulation, task_name='my_sim') + mode_data = sim_data['my_microwave_mode_monitor'] + + # Access mode amplitudes (standard ModeData attributes) + amps = mode_data.amps # Mode amplitudes + n_eff = mode_data.n_eff # Effective index + n_group = mode_data.n_group_raw # Group index + + # Access transmission line parameters (new in MicrowaveModeData) + tline_data = mode_data.transmission_line_data + Z0 = tline_data.Z0 # Characteristic impedance + V = tline_data.voltage_coeffs # Voltage coefficients + I = tline_data.current_coeffs # Current coefficients + +The transmission line data is available as a :class:`.TransmissionLineDataset` with coordinates for frequency and mode index. + +**MicrowaveModeSolverData** + +The :class:`.MicrowaveModeSolverData` class stores complete 2D mode field profiles along with transmission line parameters from a :class:`.MicrowaveModeSolverMonitor` or :class:`.ModeSimulation`. It extends :class:`.ModeSolverData` to include transmission line parameters. + +.. code-block:: python + + # Run mode simulation + mode_sim = td.ModeSimulation( + size=(10, 10, 0), + structures=[...], + monitors=[mode_solver_monitor], + freqs=[1e9, 2e9, 3e9] + ) + + mode_data = td.web.run(mode_sim, task_name='mode_solver') + + # Access 2D mode field profiles (standard ModeSolverData) + Ex = mode_data.Ex # Electric field x-component + Ey = mode_data.Ey # Electric field y-component + Ez = mode_data.Ez # Electric field z-component + Hx = mode_data.Hx # Magnetic field x-component + + # Access transmission line parameters + Z0 = mode_data.transmission_line_data.Z0 + voltage = mode_data.transmission_line_data.voltage_coeffs + current = mode_data.transmission_line_data.current_coeffs + + # Select specific mode and frequency + mode_0_at_2GHz = mode_data.sel(mode_index=0, f=2e9) + Z0_mode_0 = mode_0_at_2GHz.transmission_line_data.Z0 + +**AntennaMetricsData** + +The :class:`.AntennaMetricsData` class stores antenna performance metrics computed from far-field radiation patterns. See the `Radiation & Scattering `_ section for more details. + +Simulation Data +^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.ModeSimulationData + +**ModeSimulationData** + +The :class:`.ModeSimulationData` class is the top-level container for :class:`.ModeSimulation` results. It stores all monitor data from the mode simulation. + +.. code-block:: python + + # Run mode simulation + mode_data = td.web.run(mode_sim, task_name='mode_solver') + + # Access monitor data by name + monitor_data = mode_data['my_monitor_name'] + + # Iterate over all monitors + for monitor_name, monitor_data in mode_data.items(): + print(f"Monitor: {monitor_name}") + print(f"Type: {type(monitor_data)}") + +Dataset Types +^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.components.microwave.data.dataset.TransmissionLineDataset + tidy3d.components.data.data_array.ImpedanceFreqModeDataArray + tidy3d.components.data.data_array.VoltageFreqModeDataArray + tidy3d.components.data.data_array.CurrentFreqModeDataArray + +**TransmissionLineDataset** + +The :class:`.TransmissionLineDataset` groups transmission line parameters (impedance, voltage, current) for a set of modes and frequencies. It is stored in the ``transmission_line_data`` attribute of :class:`.MicrowaveModeData` and :class:`.MicrowaveModeSolverData`. + +.. code-block:: python + + # Access transmission line dataset + tline_data = mode_data.transmission_line_data + + # Access individual parameters + Z0 = tline_data.Z0 # ImpedanceFreqModeDataArray + V = tline_data.voltage_coeffs # VoltageFreqModeDataArray + I = tline_data.current_coeffs # CurrentFreqModeDataArray + + # Select by frequency and mode + Z0_at_2GHz = Z0.sel(f=2e9) # All modes at 2 GHz + Z0_mode_0 = Z0.sel(mode_index=0) # Mode 0 at all frequencies + Z0_specific = Z0.sel(f=2e9, mode_index=0) # Mode 0 at 2 GHz + + # Get values as numpy arrays + Z0_values = Z0.values + V_values = V.values + I_values = I.values + +**Data Array Types** + +The individual transmission line parameters are stored as specialized xarray DataArray types: + +* :class:`.ImpedanceFreqModeDataArray`: Characteristic impedance :math:`Z_0` [Ω] +* :class:`.VoltageFreqModeDataArray`: Voltage coefficients :math:`V` [V] +* :class:`.CurrentFreqModeDataArray`: Current coefficients :math:`I` [A] + +These arrays have coordinates: + +* ``f``: Frequency [Hz] +* ``mode_index``: Mode index (0-indexed integer) + +.. code-block:: python + + # Examine coordinates + print(Z0.coords) + # Coordinates: + # * f (f) float64 1e9 2e9 3e9 + # * mode_index (mode_index) int64 0 1 + + # Plot impedance vs frequency for all modes + import matplotlib.pyplot as plt + + for mode_idx in range(num_modes): + Z_vs_f = Z0.sel(mode_index=mode_idx) + plt.plot(Z_vs_f.f, Z_vs_f.values, label=f'Mode {mode_idx}') + + plt.xlabel('Frequency [Hz]') + plt.ylabel('Impedance [Ω]') + plt.legend() + plt.show() + +Working with Transmission Line Data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Accessing Data** + +The transmission line data is structured as an xarray Dataset, allowing for powerful slicing and selection: + +.. code-block:: python + + # Get transmission line dataset + tline = mode_data.transmission_line_data + + # Select specific frequency + tline_2GHz = tline.sel(f=2e9) + Z0_2GHz = tline_2GHz.Z0 + V_2GHz = tline_2GHz.voltage_coeffs + I_2GHz = tline_2GHz.current_coeffs + + # Select specific mode + tline_mode0 = tline.sel(mode_index=0) + + # Select frequency range + tline_range = tline.sel(f=slice(1e9, 3e9)) + + # Nearest neighbor selection + tline_nearest = tline.sel(f=2.1e9, method='nearest') + +**Computing Derived Quantities** + +You can compute additional quantities from the transmission line data: + +.. code-block:: python + + import numpy as np + + # Get impedance and mode amplitude + Z0 = mode_data.transmission_line_data.Z0 + mode_amp = mode_data.amps + + # Compute power from voltage and current + V = mode_data.transmission_line_data.voltage_coeffs + I = mode_data.transmission_line_data.current_coeffs + P = 0.5 * np.real(V * np.conj(I)) + + # Compute reflection coefficient (assuming Z_ref = 50Ω) + Z_ref = 50.0 + Gamma = (Z0 - Z_ref) / (Z0 + Z_ref) + + # Compute return loss in dB + return_loss_dB = -20 * np.log10(np.abs(Gamma)) + +**Saving and Loading** + +Microwave mode data can be saved and loaded like other Tidy3D data: + +.. code-block:: python + + # Save to HDF5 file + mode_data.to_file('mode_data.hdf5') + + # Load from file + loaded_data = td.MicrowaveModeSolverData.from_file('mode_data.hdf5') + + # The transmission line data is preserved + Z0_loaded = loaded_data.transmission_line_data.Z0 + +Coordinate Systems and Units +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Coordinates** + +Transmission line datasets use the following coordinate names: + +* ``f``: Frequency in Hertz [Hz] +* ``mode_index``: Integer mode index (0-indexed) + +Field data (in :class:`.MicrowaveModeSolverData`) additionally includes spatial coordinates: + +* ``x``, ``y``, ``z``: Spatial coordinates in micrometers [μm] + +**Units** + +* Impedance: Ohms [Ω] +* Voltage: Volts [V] +* Current: Amperes [A] +* Electric field: V/μm +* Magnetic field: A/μm +* Power flux: W/μm² + +.. seealso:: + + Related documentation: + + + :ref:`microwave_mode_solver` + + :ref:`path_integrals` + + :ref:`impedance_calculator` + + For general information on working with monitor data: + + + `Performing visualization of simulation data <../../notebooks/VizData.html>`_ + + `Advanced monitor data manipulation and visualization <../../notebooks/XarrayTutorial.html>`_ + + Example applications: + + + `Computing the characteristic impedance of transmission lines <../../notebooks/CharacteristicImpedanceCalculator.html>`_ + + `Differential stripline benchmark <../../notebooks/DifferentialStripline.html>`_ + +~~~~ diff --git a/docs/api/microwave/path_integrals.rst b/docs/api/microwave/path_integrals.rst new file mode 100644 index 0000000000..c98b75db9a --- /dev/null +++ b/docs/api/microwave/path_integrals.rst @@ -0,0 +1,271 @@ +.. _path_integrals: + +Path Integral Specifications +----------------------------- + +Path integral specifications define how voltage, current, and characteristic impedance are calculated for transmission line modes and electromagnetic field data. These specifications are used by :class:`~tidy3d.MicrowaveModeSpec` and :class:`~tidy3d.ImpedanceCalculator` to determine the integration paths for electromagnetic quantities. + +The path integral framework separates **specification** (configuration of what to compute) from **execution** (the actual computation). This section documents the specification classes (``*Spec``). For information on the runtime execution classes, see the :ref:`impedance_calculator` section. + +Impedance Specifications +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.AutoImpedanceSpec + tidy3d.CustomImpedanceSpec + +Impedance specifications define how the characteristic impedance :math:`Z_0` is calculated from voltage :math:`V` and current :math:`I` quantities. The characteristic impedance is a fundamental parameter for transmission lines and waveguides. + +**AutoImpedanceSpec (Recommended)** + +The :class:`.AutoImpedanceSpec` automatically determines appropriate voltage and current integration paths based on the electromagnetic field distribution. This is the recommended approach for most applications. + +.. code-block:: python + + import tidy3d as td + + # Automatic impedance calculation (recommended) + auto_spec = td.AutoImpedanceSpec() + + # Use in MicrowaveModeSpec + mode_spec = td.MicrowaveModeSpec( + num_modes=2, + impedance_specs=auto_spec + ) + +When using :class:`.AutoImpedanceSpec`, the voltage and current paths are automatically determined by analyzing the mode field profile. This works well for common transmission line geometries such as microstrip, stripline, coplanar waveguide, and coaxial lines. + +**CustomImpedanceSpec** + +For cases requiring manual control over the integration paths, :class:`.CustomImpedanceSpec` allows you to specify custom voltage and current path specifications. + +.. code-block:: python + + # Define custom voltage path + voltage_spec = td.AxisAlignedVoltageIntegralSpec( + center=(0, 0, 0), + size=(0, 0, 2), # Vertical line integral + sign="+", + extrapolate_to_endpoints=True, + snap_path_to_grid=True + ) + + # Define custom current path + current_spec = td.AxisAlignedCurrentIntegralSpec( + center=(0, 0, 0), + size=(4, 2, 0), # Rectangular contour + sign="+", + snap_contour_to_grid=True + ) + + # Create custom impedance specification + custom_spec = td.CustomImpedanceSpec( + voltage_spec=voltage_spec, + current_spec=current_spec + ) + + # Use in MicrowaveModeSpec + mode_spec = td.MicrowaveModeSpec( + num_modes=1, + impedance_specs=custom_spec + ) + +You can also specify only one of ``voltage_spec`` or ``current_spec``. When only one is provided, the impedance is calculated using the total power flux on the mode plane in combination with the specified quantity (:math:`Z = P/I^2` or :math:`Z = V^2/P`). + +.. code-block:: python + + # Specify only voltage path (power will be used for current) + voltage_only_spec = td.CustomImpedanceSpec( + voltage_spec=voltage_spec, + current_spec=None + ) + + # Specify only current path (power will be used for voltage) + current_only_spec = td.CustomImpedanceSpec( + voltage_spec=None, + current_spec=current_spec + ) + +Voltage Path Specifications +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.AxisAlignedVoltageIntegralSpec + tidy3d.Custom2DVoltageIntegralSpec + +Voltage path specifications define line integrals of the electric field :math:`E` to compute voltage: + +.. math:: + + V = \int_{\text{path}} \mathbf{E} \cdot d\mathbf{l} + +**AxisAlignedVoltageIntegralSpec** + +Specifies a voltage line integral along an axis-aligned path. This is suitable for transmission lines where the electric field has a dominant direction. + +.. code-block:: python + + # Voltage integral along the z-axis + voltage_spec = td.AxisAlignedVoltageIntegralSpec( + center=(0, 0, 0), + size=(0, 0, 2.0), # Line from (0,0,-1) to (0,0,1) + sign="+", + extrapolate_to_endpoints=True, # Extrapolate field to path endpoints + snap_path_to_grid=True # Snap path to simulation grid + ) + +The ``sign`` parameter determines the direction of integration. A positive sign integrates in the direction of the positive normal axis, while a negative sign integrates in the opposite direction. + +**Custom2DVoltageIntegralSpec** + +Specifies a voltage line integral along an arbitrary 2D path defined by vertices. This is useful for non-standard geometries or when the electric field pattern requires a custom integration path. + +.. code-block:: python + + import numpy as np + + # Define path vertices (2D coordinates in the plane perpendicular to axis) + vertices = np.array([ + [0, 0], # Start point + [0, 1], # Intermediate point + [1, 1], # End point + ]) + + # Voltage integral along custom path in the xy-plane at z=0 + custom_voltage_spec = td.Custom2DVoltageIntegralSpec( + axis=2, # Normal axis (z) + position=0.0, # Position along normal axis + vertices=vertices + ) + +Current Path Specifications +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.AxisAlignedCurrentIntegralSpec + tidy3d.Custom2DCurrentIntegralSpec + tidy3d.CompositeCurrentIntegralSpec + +Current path specifications define contour integrals using Ampère's circuital law to compute conduction current: + +.. math:: + + I = \oint_{\text{contour}} \mathbf{H} \cdot d\mathbf{l} + +**AxisAlignedCurrentIntegralSpec** + +Specifies a current contour integral around an axis-aligned rectangular loop. This is the most common approach for transmission lines. + +.. code-block:: python + + # Current integral around a rectangular loop + current_spec = td.AxisAlignedCurrentIntegralSpec( + center=(0, 0, 0), + size=(3, 2, 0), # Loop dimensions in xy-plane + sign="+", + extrapolate_to_endpoints=False, + snap_contour_to_grid=True # Snap contour to grid for accuracy + ) + +The rectangular loop is automatically constructed as four line segments around the specified rectangular area. The ``sign`` parameter determines the direction of circulation and should typically match the direction of power flow in the waveguide. + +**Custom2DCurrentIntegralSpec** + +Specifies a current contour integral along an arbitrary closed 2D path defined by vertices. The path should form a closed loop with the first and last vertices being identical. + +.. code-block:: python + + # Define closed contour vertices (counterclockwise for positive current) + vertices = np.array([ + [0, 0], + [2, 0], + [2, 1], + [0, 1], + [0, 0], # Close the loop + ]) + + # Current integral along custom contour + custom_current_spec = td.Custom2DCurrentIntegralSpec( + axis=2, # Normal axis + position=0.0, # Position along normal axis + vertices=vertices + ) + +For a positive current in the positive ``axis`` direction, vertices should be ordered counterclockwise when viewed from the positive axis direction. + +**CompositeCurrentIntegralSpec** + +Combines multiple current integral specifications for complex geometries. This is useful for differential lines or structures with multiple current-carrying paths. + +.. code-block:: python + + # Define two separate current paths + current_path_1 = td.AxisAlignedCurrentIntegralSpec( + center=(-2, 0, 0), + size=(1, 1, 0), + sign="+" + ) + + current_path_2 = td.AxisAlignedCurrentIntegralSpec( + center=(2, 0, 0), + size=(1, 1, 0), + sign="+" + ) + + # Combine into composite specification + composite_spec = td.CompositeCurrentIntegralSpec( + path_specs=(current_path_1, current_path_2), + sum_spec="sum" # "sum" adds currents, "split" keeps them separate + ) + +The ``sum_spec`` parameter controls how the individual currents are combined: + +* ``"sum"``: Simply adds all currents together +* ``"split"``: Keeps contributions with opposite phase separate, returning the maximum. This is useful for identifying dominant current directions in complex structures. + +Practical Guidelines +^^^^^^^^^^^^^^^^^^^^ + +**Choosing Between Auto and Custom** + +* Use :class:`.AutoImpedanceSpec` when: + - Working with standard transmission line geometries + - You want a quick setup without manual path definition + - The mode field distribution is well-behaved + +* Use :class:`.CustomImpedanceSpec` when: + - You need precise control over integration paths + - Working with non-standard or complex geometries + - Validating or debugging impedance calculations + - The automatic paths don't align with physical voltage/current definitions + +**Path Integral Guidelines** + +* For voltage integrals, the path should follow the electric field lines between conductors +* For current integrals, the contour should enclose the current-carrying region +* Use ``snap_path_to_grid=True`` and ``snap_contour_to_grid=True`` for improved accuracy +* Use ``extrapolate_to_endpoints=True`` for voltage paths to better capture fields at conductor boundaries +* Ensure the ``sign`` parameter matches the desired power flow direction + +.. seealso:: + + For information on using these specifications: + + + :ref:`microwave_mode_solver` + + :ref:`impedance_calculator` + + For practical examples and tutorials: + + + `Computing the characteristic impedance of transmission lines <../../notebooks/CharacteristicImpedanceCalculator.html>`_ + + `Differential stripline benchmark <../../notebooks/DifferentialStripline.html>`_ + +~~~~