@@ -34,15 +34,13 @@ class MicrowaveSMatrixData(Tidy3dBaseModel):
34
34
port_reference_impedances : Optional [PortDataArray ] = pd .Field (
35
35
None ,
36
36
title = "Port Reference Impedances" ,
37
- description = "Reference impedance for each port used in the S-parameter calculation. "
38
- "This is optional and may not be present if not specified or computed." ,
37
+ description = "Reference impedance for each port used in the S-parameter calculation. This is optional and may not be present if not specified or computed." ,
39
38
)
40
39
41
40
data : TerminalPortDataArray = pd .Field (
42
41
...,
43
42
title = "S-Matrix Data" ,
44
- description = "An array containing the computed S-matrix of the device. The data is organized "
45
- "by terminal ports, representing the scattering parameters between them." ,
43
+ description = "An array containing the computed S-matrix of the device. The data is organized by terminal ports, representing the scattering parameters between them." ,
46
44
)
47
45
48
46
@@ -51,8 +49,17 @@ class TerminalComponentModelerData(Tidy3dBaseModel):
51
49
Data associated with a :class:`TerminalComponentModeler` simulation run.
52
50
53
51
This class serves as a data container for the results of a component modeler simulation,
54
- holding the original simulation definition, the resulting S-matrix or raw port data,
55
- and the solver log.
52
+ with the original simulation definition, and port simulation data, and the solver log.
53
+
54
+ See Also
55
+ --------
56
+ :func:`tidy3d.plugins.smatrix.utils.ab_to_s`
57
+ :func:`tidy3d.plugins.smatrix.utils.check_port_impedance_sign`
58
+ :func:`tidy3d.plugins.smatrix.utils.compute_F`
59
+ :func:`tidy3d.plugins.smatrix.utils.compute_port_VI`
60
+ :func:`tidy3d.plugins.smatrix.utils.compute_power_delivered_by_port`
61
+ :func:`tidy3d.plugins.smatrix.utils.compute_power_wave_amplitudes`
62
+ :func:`tidy3d.plugins.smatrix.utils.s_to_z`
56
63
"""
57
64
58
65
modeler : TerminalComponentModeler = pd .Field (
@@ -140,84 +147,59 @@ def get_antenna_metrics_data(
140
147
Container with antenna parameters including directivity, gain, and radiation efficiency,
141
148
computed from the superposition of fields from all excited ports.
142
149
"""
143
- from tidy3d .plugins .smatrix .analysis .terminal import (
144
- compute_power_wave_amplitudes_at_each_port ,
145
- )
150
+ from tidy3d .plugins .smatrix .analysis .antenna import get_antenna_metrics_data
146
151
147
- # Use the first port as default if none specified
148
- if port_amplitudes is None :
149
- port_amplitudes = {self .modeler .ports [0 ].name : None }
150
- port_names = [port .name for port in self .modeler .ports ]
151
- # Check port names, and create map from port to amplitude
152
- port_dict = {}
153
- for key in port_amplitudes .keys ():
154
- port = self .modeler .get_port_by_name (port_name = key )
155
- port_dict [port ] = port_amplitudes [key ]
156
- # Get the radiation monitor, use first as default
157
- # if none specified
158
- if monitor_name is None :
159
- rad_mon = self .modeler .radiation_monitors [0 ]
160
- else :
161
- rad_mon = self .modeler .get_radiation_monitor_by_name (monitor_name )
162
-
163
- # Create data arrays for holding the superposition of all port power wave amplitudes
164
- f = list (rad_mon .freqs )
165
- coords = {"f" : f , "port" : port_names }
166
- a_sum = PortDataArray (np .zeros ((len (f ), len (port_names )), dtype = complex ), coords = coords )
167
- b_sum = a_sum .copy ()
168
- # Retrieve associated simulation data
169
- combined_directivity_data = None
170
- for port , amplitude in port_dict .items ():
171
- sim_data_port = self .data .data [port ]
172
- radiation_data = sim_data_port [rad_mon .name ]
173
-
174
- a , b = compute_power_wave_amplitudes_at_each_port (
175
- modeler = self .modeler ,
176
- port_reference_impedances = self .modeler .port_reference_impedances ,
177
- sim_data = sim_data_port ,
178
- )
179
- # Select a possible subset of frequencies
180
- a = a .sel (f = f )
181
- b = b .sel (f = f )
182
- a_raw = a .sel (port = port .name )
183
-
184
- if amplitude is None :
185
- # No scaling performed when amplitude is None
186
- scaled_directivity_data = sim_data_port [rad_mon .name ]
187
- scale_factor = 1.0
188
- else :
189
- scaled_directivity_data = self ._monitor_data_at_port_amplitude (
190
- port , sim_data_port , radiation_data , amplitude
191
- )
192
- scale_factor = amplitude / a_raw
193
- a = scale_factor * a
194
- b = scale_factor * b
195
-
196
- # Combine the possibly scaled directivity data and the power wave amplitudes
197
- if combined_directivity_data is None :
198
- combined_directivity_data = scaled_directivity_data
199
- else :
200
- combined_directivity_data = combined_directivity_data + scaled_directivity_data
201
- a_sum += a
202
- b_sum += b
203
-
204
- # Compute and add power measures to results
205
- power_incident = np .real (0.5 * a_sum * np .conj (a_sum )).sum (dim = "port" )
206
- power_reflected = np .real (0.5 * b_sum * np .conj (b_sum )).sum (dim = "port" )
207
- return AntennaMetricsData .from_directivity_data (
208
- combined_directivity_data , power_incident , power_reflected
152
+ antenna_metrics_data = get_antenna_metrics_data (
153
+ terminal_component_modeler_data = self ,
154
+ port_amplitudes = port_amplitudes ,
155
+ monitor_name = monitor_name ,
209
156
)
157
+ return antenna_metrics_data
210
158
211
159
@cached_property
212
160
def port_reference_impedances (self ) -> PortDataArray :
213
- """The reference impedance used at each port for definining power wave amplitudes."""
161
+ """Calculates the reference impedance for each port across all frequencies.
162
+
163
+ This function determines the characteristic impedance for every port defined
164
+ in the modeler. It handles two types of ports differently: for a
165
+ :class:`.WavePort`, the impedance is frequency-dependent and computed from
166
+ modal properties, while for other types like :class:`.LumpedPort`, the
167
+ impedance is a user-defined constant value.
168
+
169
+
170
+ Returns:
171
+ A data array containing the complex impedance for each port at each
172
+ frequency.
173
+ """
214
174
from tidy3d .plugins .smatrix .analysis .terminal import port_reference_impedances
215
175
216
176
return port_reference_impedances (self .modeler )
217
177
218
178
def compute_power_wave_amplitudes_at_each_port (
219
179
self , port_reference_impedances : PortDataArray , sim_data : SimulationData
220
180
) -> tuple [PortDataArray , PortDataArray ]:
181
+ """Computes power waves 'a' and 'b' at all ports from one simulation.
182
+
183
+ This function converts raw voltage (V) and current (I) at each port into
184
+ incident (a) and reflected (b) power wave amplitudes. The conversion uses
185
+ the formulas:
186
+ :math:`a = F (V + ZI)`
187
+ :math:`b = F (V - Z^*I)`
188
+ where :math:`Z` is the port impedance and :math:`F` is a normalization
189
+ factor. A sanity check ensures the real part of the reference impedance
190
+ is positive, flipping signs of V and Z if needed for physical consistency.
191
+
192
+ Args:
193
+ modeler: The modeler setup defining the ports.
194
+ port_reference_impedances: The characteristic impedance for each port
195
+ at each frequency.
196
+ sim_data: The raw results (fields, currents, etc.) from a single
197
+ simulation run with one port excited.
198
+
199
+ Returns:
200
+ A tuple containing two :class:`.PortDataArray` objects: the incident
201
+ power wave amplitudes 'a' and the reflected power wave amplitudes 'b'.
202
+ """
221
203
from tidy3d .plugins .smatrix .analysis .terminal import (
222
204
compute_power_wave_amplitudes_at_each_port ,
223
205
)
0 commit comments