Microwave & RF 📡#

Overview#

Warning

RF simulations and functionality will require new license requirements in an upcoming release. All RF-specific classes are now available within the sub-package ‘tidy3d.rf’.

Warning

Breaking changes were introduced in v2.10.0, please see the migration guide for help migrating your code.

This page consolidates Tidy3D features related to microwave and RF simulation. While microwave/RF and optical simulations have many properties in common, there are some differences in the typical RF user workflow that deserve special consideration.

The following sections discuss:

See also

If you are completely new to Tidy3D, we recommend first checking out the following beginner resources:

TerminalComponentModeler#

tidy3d.rf.TerminalComponentModeler

Tool for modeling two-terminal multiport devices and computing port parameters with lumped and wave ports.

tidy3d.rf.TerminalComponentModelerData

Data associated with a TerminalComponentModeler simulation run.

tidy3d.rf.MicrowaveSMatrixData

Stores the computed S-matrix and reference impedances for the terminal ports.

tidy3d.rf.TerminalPortDataArray

Port parameter matrix elements for terminal-based ports.

tidy3d.rf.PortDataArray

Array of values over dimensions of frequency and port name.

The TerminalComponentModeler is the core simulation object for 3D RF/microwave simulations in Tidy3D. Its primary function is to simulate the system over N number of ports and M number of frequency points, with the end result being a MxNxN S-parameter matrix.

my_tcm = TerminalComponentModeler(
    simulation=base_sim,
    ports=[port1, port2],
    freqs=my_frequencies,
    ...
)

The key parts of a TerminalComponentModeler are:

  • The Simulation field defines the underlying Tidy3D Simulation object. This base Simulation object contains information about the simulation domain such as structures, boundary conditions, grid specifications, and monitors. Note that sources should not be included in the base simulation, but rather in the ports field instead.

  • The ports field defines the list of source excitations. These are commonly of type LumpedPort or WavePort. The number of ports determines the number of batch jobs in the TerminalComponentModeler and the dimensionality of the S-parameter matrix. Note: Port names cannot contain the ‘@’ symbol (reserved for internal indexing).

  • The freqs field defines the list of frequency points for the simulation.

More information and explanation for additional fields can be found in the documentation page for the TerminalComponentModeler.

Workflow#

In order to submit the simulation, use web.upload(), web.start(), web.monitor(), and web.load().

Alternatively, use the web.run() method to perform all of the above in one single step.

To get the S-matrix from the results, use the smatrix() method of the TerminalComponentModelerData object.

# Get S-matrix from results
my_s_matrix = my_tcm_data.smatrix()

The S-matrix is stored as a MicrowaveSMatrixData whose data property contains a TerminalPortDataArray instance. To obtain a specific S_ij value, use the port_in and port_out coordinates with the corresponding port name. To obtain a specific frequency, use the f coordinate.

# Get return loss
my_S11 = my_s_matrix.data.sel(port_in="my_port_1", port_out="my_port_1")

Note

At this moment, Tidy3D uses the physics phase convention \(e^{-i\omega t}\). Other RF simulation software and texts may use the electrical engineering convention \(e^{i\omega t}\). This affects the sign of the imaginary part of calculated S-parameters and impedance values. To convert between the two, simply use the complex conjugation operation, e.g. np.conjugate().

See also

To learn more about the web API workflow in Tidy3D, please refer to the following pages:

To learn more about data post-processing and visualization, please refer to the following pages:

Please refer to the following example models to see the TerminalComponentModeler in action:


RF Materials Models#

tidy3d.PECMedium

Perfect electrical conductor class.

tidy3d.PMCMedium

Perfect magnetic conductor class.

tidy3d.rf.LossyMetalMedium

Lossy metal that can be modeled with a surface impedance boundary condition (SIBC).

tidy3d.rf.SurfaceImpedanceFitterParam

Advanced parameters for fitting surface impedance of a LossyMetalMedium.

tidy3d.rf.HammerstadSurfaceRoughness

Modified Hammerstad surface roughness model.

tidy3d.rf.HuraySurfaceRoughness

Huray surface roughness model.

The PECMedium and LossyMetalMedium classes can be used to model metallic materials.

# lossless metal
my_pec = PECMedium()

# lossy metal (conductivity in S/um)
my_lossy_metal = LossyMetalMedium(conductivity=58, freq_range=(1e9, 10e9))

Note that the unit of conductivity is S/um and the unit of freq_range is Hz. The LossyMetalMedium class implements the surface impedance boundary condition (SIBC). It can accept surface roughness specifications using the Hammerstad or Huray models. Please refer to their respective documentation pages for details. Edge singularity correction is also available but turned off by default at this time.

Note

When modeling lossy metals, always be sure to check the skin depth — if the skin depth is significant compared to the geometry size, then LossyMetalMedium may be not accurate. In that case, use a regular dispersive medium instead.

tidy3d.Medium

Dispersionless medium.

tidy3d.plugins.dispersion.FastDispersionFitter

Tool for fitting refractive index data to get a dispersive medium described by PoleResidue model.

To model lossless dielectrics, use the regular Medium.

# lossless dielectric
my_lossless_dielectric = Medium(permittivity=2.2)

To model a lossy dielectric with constant loss tangent, use the constant_loss_tangent_model() method of the tidy3d.plugins.dispersion.FastDispersionFitter utility class.

# lossy dielectric (constant loss tangent)
my_lossy_dielectric = FastDispersionFitter.constant_loss_tangent_model(
    eps_real=4.4,
    loss_tangent=0.002,
    frequency_range=(1e9, 5e9)
)

More advanced material models, including frequency dependence and anisotropy, are also available in Tidy3D.

See also

For a more comprehensive discussion of the different EM mediums available in Tidy3D, please refer to the EM Mediums page:


RF Materials Library#

The RF material library is a dictionary containing various dispersive models for real-world RF materials. To use the materials in the library, import it first by:

>>> from tidy3d.rf import rf_material_library

The key of the dictionary is the abbreviated material name.

Note: some materials have multiple variant models, in which case the second key is the “variant” name.

To import a material “mat” of variant “var”:

>>> medium = rf_material_library['mat']['var']

For example, Rogers3010 laminate can be loaded as:

>>> Rogers3010 = rf_material_library['RO3010']['design']

You can also import the default variant of a material by:

>>> medium = rf_material_library['mat'].medium

It is often useful to see the full list of variants for a given medium:

>>> print(rf_material_library['mat'].variants.keys())

To access the details of a variant, including material model and references, use the following command:

>>> rf_material_library['mat'].variants['var']

Variant

Valid for

Model Info

Reference

'design' (default)

1.0 - 30.0 GHz

5-pole, lossy

[1]

'process'

1.0 - 30.0 GHz

5-pole, lossy

[1]

Examples:

>>> medium = material_library['AD255C']['design']
>>> medium = material_library['AD255C']['process']

References:

  1. AD255C High Performance Polyimide Laminates [url]

Variant

Valid for

Model Info

Reference

'lowloss'

1.0 - 3.0 GHz

5-pole, lossy

[1]

'standard' (default)

1.0 - 3.0 GHz

5-pole, lossy

[2]

Examples:

>>> medium = material_library['FR4']['lowloss']
>>> medium = material_library['FR4']['standard']

References:

  1. Low loss FR-4 Epoxy Glass Cloth Laminate [url]

  2. Standard FR-4 Epoxy Glass Cloth Laminate [url]

Variant

Valid for

Model Info

Reference

'design' (default)

1.0 - 30.0 GHz

5-pole, lossy

[1]

'process'

1.0 - 30.0 GHz

5-pole, lossy

[1]

Examples:

>>> medium = material_library['RO3003']['design']
>>> medium = material_library['RO3003']['process']

References:

  1. RO3003™ Laminates [url]

Variant

Valid for

Model Info

Reference

'design' (default)

1.0 - 30.0 GHz

5-pole, lossy

[1]

'process'

1.0 - 30.0 GHz

5-pole, lossy

[1]

Examples:

>>> medium = material_library['RO3010']['design']
>>> medium = material_library['RO3010']['process']

References:

  1. RO3010™ Laminates [url]

Variant

Valid for

Model Info

Reference

'design' (default)

8.0 - 40.0 GHz

5-pole, lossy

[1]

'process'

8.0 - 40.0 GHz

5-pole, lossy

[1]

Examples:

>>> medium = material_library['RO4003C']['design']
>>> medium = material_library['RO4003C']['process']

References:

  1. RO4003C™ Laminates [url]

Variant

Valid for

Model Info

Reference

'design' (default)

8.0 - 40.0 GHz

5-pole, lossy

[1]

'process'

8.0 - 40.0 GHz

5-pole, lossy

[1]

Examples:

>>> medium = material_library['RO4350B']['design']
>>> medium = material_library['RO4350B']['process']

References:

  1. RO4350B™ Laminates [url]

Layer-based Grid Refinement#

tidy3d.LayerRefinementSpec

Specification for automatic mesh refinement and snapping in layered structures.

tidy3d.CornerFinderSpec

Specification for corner detection on a 2D plane.

tidy3d.GridRefinement

Specification for local mesh refinement that defines the grid step size and the number of grid cells in the refinement region.

The LayerRefinementSpec class allows the user to specify automated refinement within a layered region, for instance, the metallic trace plane of a printed circuit board. The grid will be automatically refined near any metallic corners and edges in that layer.

import tidy3d as td
# Define layer refinement spec
my_layer_refinement_spec = td.LayerRefinementSpec(
    axis=2,  # layer normal axis
    center=(0, 0, 0),  # layer center
    size=(3, 2, 0.1),  # layer size
    min_steps_along_axis=2,  # minimum number of grid points along normal axis
    corner_refinement=td.GridRefinement(dl=100, num_cells=2)  # metal corner refinement specification
)

# Add layer refinement spec to overall grid specification
my_grid_spec = td.GridSpec(
    ...,
    layer_refinement_specs = [my_layer_refinement_spec]
)

More than one LayerRefinementSpec is permitted. In addition to manually defining the center and size of the LayerRefinementSpec, one can alternatively use the from_bounds(), from_layer_bounds(), or from_structures() convenience methods.

my_layer_refinement_spec_2 = LayerRefinementSpec.from_structures(
    structures=[my_planar_structure],   # position, size, and axis automatically determined based on structure
    ...
)

Note that different LayerRefinementSpec instances are recommended for structures on different physical layers.

See also

For more explanation and examples, please refer to the following pages:

Example applications:


Path Integrals#

Path integrals compute voltage and current from electromagnetic field data by integrating electric and magnetic fields along specified paths. These are essential for characterizing transmission lines and computing characteristic impedance.

Note

For information on how path integrals are used to calculate characteristic impedance in transmission line mode analysis, see RF Mode Analysis. For the corresponding specification classes (*Spec) used in MicrowaveModeSpec, see the end of this page.

Voltage Path Integrals#

tidy3d.rf.AxisAlignedVoltageIntegral

Class for computing the voltage between two points defined by an axis-aligned line.

tidy3d.rf.Custom2DVoltageIntegral

Class for computing the voltage between two points defined by a custom path.

Voltage path integrals compute voltage by integrating the electric field \(\mathbf{E}\) along a line path:

\[V = -\int_{\text{path}} \mathbf{E} \cdot d\mathbf{l}\]

AxisAlignedVoltageIntegral

Integrates along an axis-aligned path, suitable for transmission lines with dominant electric field directions.

import tidy3d.web as web

# Create voltage path integral
voltage_integral = AxisAlignedVoltageIntegral(
    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
)

# Compute voltage from mode data
mode_data = web.run(mode_solver, task_name='mode_solver')
voltage = voltage_integral.compute_voltage(mode_data)

print(f"Voltage: {voltage.values} V")

The sign parameter determines integration direction: "+" integrates toward positive axis, "-" toward negative.

Custom2DVoltageIntegral

Integrates along an arbitrary 2D path for non-standard geometries.

import numpy as np

# Define custom path vertices in 2D plane
vertices = np.array([
    [0, 0],    # Start point
    [0, 1],    # Intermediate point
    [1, 1],    # End point
])

# Create custom voltage integral
custom_voltage = Custom2DVoltageIntegral(
    axis=2,         # Normal axis (z)
    position=0.0,   # Position along z-axis
    vertices=vertices
)

# Compute voltage
voltage = custom_voltage.compute_voltage(mode_data)

The path follows the vertices in order, integrating \(\mathbf{E} \cdot d\mathbf{l}\) along each segment.

Current Path Integrals#

tidy3d.rf.AxisAlignedCurrentIntegral

Class for computing conduction current via Ampère's circuital law on an axis-aligned loop.

tidy3d.rf.Custom2DCurrentIntegral

Class for computing conduction current via Ampère's circuital law on a custom path.

tidy3d.rf.CompositeCurrentIntegral

Current integral comprising one or more disjoint paths

Current path integrals compute current using Ampère’s circuital law by integrating the magnetic field \(\mathbf{H}\) around a closed contour:

\[I = \oint_{\text{contour}} \mathbf{H} \cdot d\mathbf{l}\]

AxisAlignedCurrentIntegral

Integrates around an axis-aligned rectangular loop, the most common approach for transmission lines.

# Create current path integral
current_integral = AxisAlignedCurrentIntegral(
    center=(0, 0, 0),
    size=(3, 2, 0),  # Loop dimensions in xy-plane
    sign="+",
    snap_contour_to_grid=True  # Snap contour to grid for accuracy
)

# Compute current from mode data
current = current_integral.compute_current(mode_data)

print(f"Current: {current.values} A")

The rectangular loop is automatically constructed as four line segments. The sign parameter determines circulation direction and should match the power flow direction.

Custom2DCurrentIntegral

Integrates around an arbitrary closed 2D contour for non-standard geometries.

# Define closed contour (counterclockwise for positive current)
vertices = np.array([
    [0, 0],
    [2, 0],
    [2, 1],
    [0, 1],
    [0, 0],  # Close the loop
])

# Create custom current integral
custom_current = Custom2DCurrentIntegral(
    axis=2,         # Normal axis
    position=0.0,   # Position along normal axis
    vertices=vertices
)

# Compute current
current = custom_current.compute_current(mode_data)

For positive current in the positive axis direction, order vertices counterclockwise when viewed from the positive axis.

CompositeCurrentIntegral

Combines multiple current paths for complex geometries like differential lines.

# Define two separate current paths
path_1 = AxisAlignedCurrentIntegral(
    center=(-2, 0, 0),
    size=(1, 1, 0),
    sign="+"
)

path_2 = AxisAlignedCurrentIntegral(
    center=(2, 0, 0),
    size=(1, 1, 0),
    sign="+"
)

# Combine paths
composite_current = CompositeCurrentIntegral(
    path_specs=(path_1, path_2),
    sum_spec="sum"  # "sum" adds currents, "split" keeps them separate
)

# Compute combined current
current = composite_current.compute_current(mode_data)

The sum_spec parameter controls combination:

  • "sum": Adds all currents together

  • "split": Returns maximum of phase-separated contributions (useful for identifying dominant current directions)

Usage with ImpedanceCalculator#

Path integrals are commonly used with ImpedanceCalculator to compute characteristic impedance:

# Create impedance calculator from voltage and current integrals
Z_calculator = ImpedanceCalculator(
    voltage_integral=voltage_integral,
    current_integral=current_integral
)

# Compute impedance: Z = V / I
Z0 = Z_calculator.compute_impedance(mode_data)

# Or get voltage, current, and impedance together
Z, V, I = Z_calculator.compute_impedance(
    mode_data,
    return_voltage_and_current=True
)

See Impedance Calculator for more details.

Additional Information#

Best Practices

  • For voltage integrals, the path should follow 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

Path Integral Specification Classes

The classes documented above (*Integral) are execution classes that perform actual computations on field data. For use in MicrowaveModeSpec impedance specifications, corresponding specification classes (*Spec) exist:

tidy3d.rf.AxisAlignedVoltageIntegralSpec

Class for specifying the voltage calculation between two points defined by an axis-aligned line.

tidy3d.rf.Custom2DVoltageIntegralSpec

Class for specifying the computation of voltage between two points defined by a custom path.

tidy3d.rf.AxisAlignedCurrentIntegralSpec

Class for specifying the computation of conduction current via Ampère's circuital law on an axis-aligned loop.

tidy3d.rf.Custom2DCurrentIntegralSpec

Class for specifying the computation of conduction current via Ampère's circuital law on a custom path.

tidy3d.rf.CompositeCurrentIntegralSpec

Specification for a composite current integral.

These specification classes have the same parameters but are used for configuration (in CustomImpedanceSpec) rather than direct computation. See RF Mode Analysis for their usage in mode analysis.

See also

Related documentation:

Practical examples:


Impedance Calculator#

tidy3d.ImpedanceCalculator

Tool for computing the characteristic impedance of a transmission line.

The 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: \(Z_0 = V / I\) (when both voltage and current integrals are provided)

  • P and V method: \(Z_0 = |V|^2 / (2P^*)\) (when only voltage integral is provided)

  • P and I method: \(Z_0 = 2P / |I|^2\) (when only current integral is provided)

where \(P = \frac{V I^*}{2}\) is the complex power flow through the cross-section.

Basic Usage

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
# Note: The impedance calculator can also accept "None" for either the "voltage_integral" or the "current_integral",
# which determines the method for computing the impedance. This alternative method is detailed below.
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:

import tidy3d.web as web

# 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_sim_data = web.run(mode_sim, task_name='mode_solver')
# Calculate impedance for each mode
Z0 = Z_calculator.compute_impedance(mode_sim_data.modes)

Obtaining Voltage and Current

You can also retrieve the voltage and current values along with impedance:

# 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 complex power flow is automatically used:

# 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)

Note

For detailed information on path integral classes (voltage integrals, current integrals, composite integrals, custom paths, etc.), see Path Integrals.

Field Data Compatibility

The impedance calculator and path integral classes work with various types of field data:

  • ModeSolverData: Mode field profiles from 2D mode solver

  • FieldData: Frequency-domain field data from monitors

  • FieldTimeData: Time-domain field data from monitors

  • MicrowaveModeSolverData: Microwave mode solver data (includes pre-computed integrals)

# 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 \(e^{-i\omega t}\). Some RF simulation software and textbooks use the electrical engineering convention \(e^{i\omega t}\). This affects calculated S-parameters and impedance values.

To convert between conventions, use complex conjugation:

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)

See also

Related documentation:

Tutorials and examples:


RF Mode Analysis#

tidy3d.rf.MicrowaveModeSpec

The MicrowaveModeSpec class specifies how quantities related to transmission line modes and microwave waveguides are computed.

tidy3d.rf.AutoImpedanceSpec

Specification for fully automatic transmission line impedance computation.

tidy3d.rf.CustomImpedanceSpec

Specification for custom transmission line voltages and currents in mode solvers.

tidy3d.rf.MicrowaveModeMonitor

Monitor that records amplitudes from modal decomposition of fields on plane.

tidy3d.rf.MicrowaveModeSolverMonitor

Monitor that stores the mode field profiles returned by the mode solver in the monitor plane.

tidy3d.ModeSimulation

Simulation class for solving electromagnetic eigenmodes in a 2D plane with translational invariance in the third dimension.

The MicrowaveModeSpec extends the standard ModeSpec to include automatic characteristic impedance calculation for transmission line modes. This is particularly useful for microwave and RF applications where the characteristic impedance \(Z_0\) is a critical parameter.

Unlike the standard ModeSpec, 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.

# Create a microwave mode specification with automatic impedance calculation
mode_spec = MicrowaveModeSpec(
    num_modes=2,
    target_neff=1.5,
    impedance_specs=AutoImpedanceSpec()  # Automatic path integral setup
)

# Use in a microwave mode monitor
monitor = MicrowaveModeMonitor(
    center=(0, 0, 0),
    size=(2, 2, 0),
    freqs=[1e9, 2e9, 3e9],
    mode_spec=mode_spec,
    name='mode_monitor'
)

Automatic Impedance Calculation

The 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.

# Using automatic impedance specification (recommended)
mode_spec_auto = MicrowaveModeSpec(
    num_modes=1,
    impedance_specs=AutoImpedanceSpec()
)

Custom Impedance Calculation

For more control over the impedance calculation, you can specify custom voltage and current integration paths using CustomImpedanceSpec. This allows you to define exactly where and how the voltage and current are computed.

# Define custom voltage path (line integral)
voltage_spec = AxisAlignedVoltageIntegralSpec(
    center=(0, 0, 0),
    size=(0, 0, 1),  # Vertical line
    sign="+"
)

# Define custom current path (contour integral)
current_spec = AxisAlignedCurrentIntegralSpec(
    center=(0, 0, 0),
    size=(2, 1, 0),  # Rectangular loop
    sign="+"
)

# Create custom impedance specification
custom_impedance = CustomImpedanceSpec(
    voltage_spec=voltage_spec,
    current_spec=current_spec
)

# Use in mode specification
mode_spec_custom = MicrowaveModeSpec(
    num_modes=1,
    impedance_specs=custom_impedance
)

Multiple Modes

When solving for multiple modes, you can provide different impedance specifications for each mode:

# Different impedance specs for each mode
mode_spec_multi = MicrowaveModeSpec(
    num_modes=2,
    impedance_specs=(
        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 = MicrowaveModeSpec(
    num_modes=2,
    impedance_specs=AutoImpedanceSpec()  # Applied to both modes
)

Mode Solver Monitors

There are two types of monitors for microwave mode analysis:

  • MicrowaveModeMonitor: Records mode amplitudes and transmission line parameters (voltage, current, impedance) on a monitor plane during a full 3D FDTD simulation.

  • MicrowaveModeSolverMonitor: Stores the complete 2D mode field profiles along with transmission line parameters from a standalone mode solver calculation.

# Monitor for mode amplitudes in full simulation
mode_monitor = 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 = 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 ModeSimulation:

import tidy3d.web as web

# Create a mode simulation for transmission line analysis
mode_sim = ModeSimulation(
    size=(10, 10, 0),
    grid_spec=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_sim_data = web.run(mode_sim, task_name='mode_analysis')

# Access impedance results from the modes
Z0 = mode_sim_data.modes.transmission_line_data.Z0

Lumped Port & Elements#

tidy3d.rf.LumpedPort

Class representing a single rectangular lumped port.

tidy3d.rf.CoaxialLumpedPort

Class representing a single coaxial lumped port.

The LumpedPort feature represents a planar, uniform current excitation with a fixed impedance termination.

# Define a lumped port
my_port_1 = LumpedPort(
    name="My Port 1",
    center=(0,0,0),
    size=(0, port_width, port_height),
    voltage_axis=2,   # z-axis aligned excitation
    impedance=50,   # port impedance
)

The LumpedPort can be 1D (line) or 2D (plane). For 2D, only axis-aligned planes are supported at this time. Only real impedance values are supported at this time.

Note

Lumped ports and elements are fundamentally approximations and thus should only be used when the port/element size is much smaller than the wavelength of interest (typically lambda/10). For more accurate results, especially when the port is adjacent to an intentional waveguide or transmission line, consider using the WavePort excitation instead.

The CoaxialLumpedPort represents an analytical coaxial field source.

# Define coaxial lumped port
my_coaxial_port_1 = CoaxialLumpedPort(
    name="My Coaxial Port 1",
    center=(0,0,0),
    inner_diameter=1000,   # inner diameter in um
    outer_diameter=2000,   # outer diameter in um
    normal_axis=0,   # normal axis to port plane
    direction="+",   # direction of signal along normal axis
    impedance=50,   # port impedance
)

Note

Because the CoaxialLumpedPort injects an analytical field source, the structure connected to this port must match the physical port dimensions. Any deviation will result in signal reflection and potential inaccuracies. One common source of this issue is in imported geometries with faceted cylinders.

tidy3d.rf.LumpedResistor

Class representing a rectangular lumped resistor.

tidy3d.rf.CoaxialLumpedResistor

Class representing a coaxial lumped resistor.

tidy3d.rf.LinearLumpedElement

Lumped element representing a network consisting of resistors, capacitors, and inductors.

tidy3d.rf.RLCNetwork

Class for representing a simple network consisting of a resistor, capacitor, and inductor.

tidy3d.rf.AdmittanceNetwork

Class for representing a network consisting of an arbitrary number of resistors, capacitors, and inductors.

For a simple resistive lumped element, use LumpedResistor.

my_resistor = LumpedResistor(
    name="My resistor",
    center=(0,0,0),
    size=(0, element_width, element_height),
    voltage_axis=2,   # z-axis aligned
    resistance=50,   # real-valued impedance
)

For more complicated RLC networks, use the general LinearLumpedElement class.

my_lumped_element = LinearLumpedElement(
    name="My lumped element",
    center=(0,0,0),
    size=(0, element_width, element_height),
    voltage_axis=2,   # z-axis aligned
    network=RLCNetwork(resistance=50, inductance=1e-9)  # RLC network
)

All lumped elements should be added to the lumped_elements field of the base Simulation instance.

my_simulation = Simulation(
    lumped_elements=[my_resistor, my_lumped_element],
    ...,
)

See also

For more in-depth discussion and examples, please see the following learning center article:

Example applications:


Wave Port#

tidy3d.rf.WavePort

Class representing a single wave port

The WavePort represents a modal source port for RF and microwave simulations. The port mode is first calculated in the 2D mode solver with automatic characteristic impedance calculation, then injected into the 3D simulation. The WavePort is also automatically terminated with a modal absorbing boundary ModeABCBoundary that perfectly absorbs the outgoing mode. Any non-matching modes are subject to PEC reflection.

Basic Usage

my_wave_port_1 = WavePort(
    center=(0,0,0),
    size=(port_width, port_height, 0),
    name='My Wave Port 1',
    direction='+',  # direction of signal
    mode_spec=MicrowaveModeSpec(
        num_modes=1,
        target_neff=1.5,
        impedance_specs=AutoImpedanceSpec()  # automatic impedance calculation
    ),
)

Key parameters:

Multimode WavePort Support

WavePorts can support multiple modes simultaneously. This is useful for multimode waveguides and transmission lines.

# Create a WavePort that solves for 3 modes
multimode_port = WavePort(
    center=(0, 0, 0),
    size=(4, 4, 0),
    direction='+',
    mode_spec=MicrowaveModeSpec(
        num_modes=3,  # solve for 3 modes
        impedance_specs=AutoImpedanceSpec()  # applied to all modes
    ),
    name='multimode_port'
)

When creating sources from a multimode port, specify which mode to excite:

source_time = GaussianPulse(freq0=10e9, fwidth=1e9)

# Create sources for different modes
source_mode0 = multimode_port.to_source(source_time, mode_index=0)
source_mode1 = multimode_port.to_source(source_time, mode_index=1)
source_mode2 = multimode_port.to_source(source_time, mode_index=2)

You can also specify different impedance calculations for each mode:

mode_spec = MicrowaveModeSpec(
    num_modes=2,
    impedance_specs=(
        CustomImpedanceSpec(...),  # custom for mode 0
        AutoImpedanceSpec(),       # auto for mode 1
    )
)

Mode Solver

If you need to solve for the 2D port mode without running a full 3D simulation, use the to_mode_solver() convenience method:

import tidy3d.web as web

# Define a mode solver from the wave port
my_mode_solver = my_wave_port_1.to_mode_solver(
    simulation=base_sim,   # base Simulation object
    freqs=my_frequencies,   # frequencies for 2D mode solver
)

# Execute mode solver
my_mode_data = web.run(my_mode_solver, task_name='mode solver')

The resulting my_mode_data will be MicrowaveModeSolverData containing mode fields and transmission line parameters (characteristic impedance, voltage/current coefficients).

Accessing Transmission Line Data

After running a simulation with WavePort, you can access the transmission line characteristics from the mode data:

# Get mode data from TerminalComponentModeler results
mode_data = tcm_data.data['port1']['mode_monitor']

# Access characteristic impedance for each mode
Z0_mode0 = mode_data.transmission_line_data.Z0.sel(mode_index=0)

# Get voltage and current coefficients
voltage_coeff = mode_data.transmission_line_data.voltage_coeffs.sel(mode_index=0)
current_coeff = mode_data.transmission_line_data.current_coeffs.sel(mode_index=0)

Alternatively, use the port’s get_port_impedance() method:

# Get impedance directly from port
Z0 = my_wave_port_1.get_port_impedance(mode_data, mode_index=0)

See also

Related Documentation:

Tutorials and Examples:


Radiation & Scattering#

tidy3d.rf.DirectivityMonitor

Monitor that records the radiation characteristics of antennas in the frequency domain at specified observation angles.

tidy3d.rf.DirectivityMonitorSpec

Specification for automatically generating a DirectivityMonitor.

tidy3d.rf.RectangularAntennaArrayCalculator

This class provides methods to calculate the array factor and far-field radiation patterns for rectangular phased antenna arrays.

tidy3d.rf.LobeMeasurer

Tool for detecting and analyzing lobes in antenna radiation patterns, along with their characteristics such as direction and beamwidth.

When modeling antennas or scattering problems, it is vital to analyze the radiated far-field. For such applications, the DirectivityMonitor should be used.

# Define angular coordinates
# Theta is the elevation angle relative to global +z axis
# Phi is the azimuthal angle relative to global +x axis
my_theta = np.linspace(0, np.pi, 91)
my_phi = np.linspace(0, 2*np.pi, 181)

# Define directivity monitor
my_directivity_monitor = DirectivityMonitor(
    center=(0,0,0),
    size=(100, 100, 100),
    freqs=my_frequencies,
    phi=my_phi,
    theta=my_theta,
    name='My radiation monitor',
)

The DirectivityMonitor should completely surround the structure of interest.

Alternatively, a DirectivityMonitorSpec can be used to create a specification for automatic generation of a DirectivityMonitor in the TerminalComponentModeler.

# Define directivity monitor spec
my_directivity_monitor_spec = DirectivityMonitorSpec()

Once the monitor or monitor spec is defined, it should be added to the radiation_monitors option of the TerminalComponentModeler.

# Add directivity monitor to simulation
my_tcm = TerminalComponentModeler(
    ...,
    radiation_monitors=[my_directivity_monitor, my_directivity_monitor_spec],
)

Once the simulation is completed, the get_antenna_metrics_data() method of the TerminalComponentModelerData object is used to obtain the radiation metrics.

# Get radiation metrics
my_antenna_metrics = my_tcm_data.get_antenna_metrics_data()

# Get individual metrics
my_directivity = my_antenna_metrics.directivity
my_gain = my_antenna_metrics.gain
my_radiation_efficiency = my_antenna_metrics.radiation_efficiency
my_reflection_efficiency = my_antenna_metrics.reflection_efficiency
my_realized_gain = my_antenna_metrics.realized_gain
my_supplied_power = my_antenna_metrics.supplied_power
my_radiated_power = my_antenna_metrics.radiated_power
my_radiation_intensity = my_antenna_metrics.radiation_intensity
my_axial_ratio = my_antenna_metrics.axial_ratio
my_left_pol = my_antenna_metrics.left_polarization
my_right_pol = my_antenna_metrics.right_polarization

Each metric is in the form of an xarray.DataArray object that can be used for plotting, export, and further analysis. For examples of how these datasets can be manipulated, please refer to the notebooks in the “See also” section below.

The LobeMeasurer utility class can be used to analyze radiation pattern lobes.

# Define lobe measurer
my_lobes = LobeMeasurer(
    angle=phi,   # Angular axis of interest
    radiation_pattern=my_gain,   # Radiation pattern to measure
)

# Get lobe characteristics
my_lobe_measures = my_lobes.lobe_measures
my_main_lobe = my_lobes.main_lobe
my_side_lobes = my_lobes.side_lobe

Lobe characteristics such as direction, magnitude, and -3 dB beamwidth can be obtained for the main and side lobes. Additionally, the LobeMeasurer.plot() utility function adds main lobe beam direction and width markers to polar radiation plots.

See also

For more in-depth discussion and examples, please see the following learning center article:

Example applications:


RF Output Data#

Monitor Data#

tidy3d.rf.MicrowaveModeData

Data associated with a ModeMonitor for microwave and RF applications: modal amplitudes, propagation indices, mode profiles, and transmission line data.

tidy3d.rf.MicrowaveModeSolverData

Data associated with a ModeSolverMonitor for microwave and RF applications: scalar components of E and H fields plus characteristic impedance data.

tidy3d.rf.DirectivityData

Data associated with a DirectivityMonitor.

tidy3d.rf.AntennaMetricsData

Data representing the main parameters and figures of merit for antennas.

  • MicrowaveModeData: Mode amplitudes with transmission line parameters (Z0, voltage, current) and propagation characteristics (γ, α, β).

  • MicrowaveModeSolverData: Complete 2D mode field profiles with transmission line parameters and mode classification.

  • DirectivityData: Far-field radiation patterns including directivity and radiated power.

  • AntennaMetricsData: Antenna figures of merit including gain, radiation efficiency, reflection efficiency, and realized gain.

Base Classes

MicrowaveModeDataBase

Base class for microwave mode data that extends standard mode data with RF/microwave features.

Note

MicrowaveModeDataBase is a base class providing shared properties and methods for microwave mode data. The base class documentation is provided to help users discover inherited properties.

Datasets and Data Arrays#

Datasets

tidy3d.components.microwave.data.dataset.TransmissionLineDataset

Holds mode data that is specific to transmission lines in microwave and RF applications, like characteristic impedance.

Data Arrays

tidy3d.components.data.data_array.VoltageTimeDataArray

Voltage data array in time domain.

tidy3d.components.data.data_array.VoltageFreqDataArray

Voltage data array in frequency domain.

tidy3d.components.data.data_array.VoltageFreqModeDataArray

Voltage data array in frequency-mode domain.

tidy3d.components.data.data_array.CurrentTimeDataArray

Current data array in time domain.

tidy3d.components.data.data_array.CurrentFreqDataArray

Current data array in frequency domain.

tidy3d.components.data.data_array.CurrentFreqModeDataArray

Current data array in frequency-mode domain.

tidy3d.components.data.data_array.ImpedanceTimeDataArray

Impedance data array in time domain.

tidy3d.components.data.data_array.ImpedanceFreqDataArray

Impedance data array in frequency domain.

tidy3d.components.data.data_array.ImpedanceFreqModeDataArray

Impedance data array in frequency-mode domain.

tidy3d.components.microwave.data.data_array.PropagationConstantArray

Data array for the complex propagation constant \(\gamma = -\alpha + j\beta\) with units of 1/m.

tidy3d.components.microwave.data.data_array.PhaseConstantArray

Data array for the phase constant \(\beta = \text{Im}(\gamma)\) with units of rad/m.

tidy3d.components.microwave.data.data_array.AttenuationConstantArray

Data array for the attenuation constant \(\alpha = -\text{Re}(\gamma)\) with units of Nepers/m.

tidy3d.components.microwave.data.data_array.PhaseVelocityArray

Data array for the phase velocity \(v_p = c/n_{\mathrm{eff}}\) with units of m/s.

tidy3d.components.microwave.data.data_array.GroupVelocityArray

Data array for the group velocity \(v_g = c/n_{\mathrm{group}}\) with units of m/s.


See also

Related documentation:

  • Output Data - General information on working with output data in Tidy3D

For general information on working with monitor data: