Terminal (multi-pin) wave ports¶
A field solver reports modal S-parameters: one port per propagating mode of the port plane. Circuit work
(differential and common-mode analysis, a bias line as its own terminal, SPICE export) needs terminal S-parameters:
one port per conductor, voltage measured against a common ground, with a reference impedance you choose.
gsim.palace.terminal converts one into the other in post-processing, using for each port the terminal voltages and
currents of its modes. It is the standard multiconductor-line approach and it needs no change in Palace.
This page covers the transformation. Building the voltage and current matrices from Palace output and a cloud comparison on a coupled CPW follow in a separate change.
1. Why modal S is not terminal S¶
Take a pair of coupled signal lines over a common ground. A two-end simulation with one wave port per end and two modes returns a 4x4 modal S: (end 1 mode 1, end 1 mode 2, end 2 mode 1, end 2 mode 2). Mode 1 and mode 2 are generally neither "line A" nor "line B": they are the even-like and odd-like solutions, each with its own propagation constant and with voltage on both lines. A circuit that connects 50-ohm sources to line A and line B needs the 4x4 S in the order (A1, B1, A2, B2). The two are related by a linear map that depends on how each mode loads the two terminals. Running one wave port per signal conductor instead does not replace this map: each port face then only sees part of the cross-section, and its mode solve finds modes of a truncated problem rather than the coupled modes of the line.
2. Conventions and formulas¶
Time convention exp(+j w t), as in the rest of gsim. A physical port p has n_p terminals and n_p modes kept.
- Column
kofT_V[p]holds the terminal voltages (terminal minus the reference conductor) of modekfor a unit forward modal wave. ColumnkofT_I[p]holds the terminal currents flowing into the network for that wave. - Modal waves:
V = T_V (a + b)andI = T_I (a - b). - Terminal power waves for a real reference impedance
Zr:a_t = F (V + Zr I)andb_t = F (V - Zr I), withF = diag(1 / (2 sqrt(Zr))). For realZrpower waves and pseudo waves coincide. - With block-diagonal
T = diag(T_V[p])andW = diag(T_I[p]), andA = F (T + Zr W),B = F (T - Zr W):
S_t = (B + A S_m) (A + B S_m)^-1 (modal_to_terminal_s)
S_m = (A - S_t B)^-1 (S_t A - B) (terminal_to_modal_s)
- Port ordering: physical port by physical port, terminals (or modes) in column order inside each port. A two-end line is ordered (A1, B1, A2, B2) and its modal S is (end 1 mode 1, end 1 mode 2, end 2 mode 1, end 2 mode 2).
- Scaling column
kofT_VandT_Itogether by any complex constant leavesS_tunchanged whenS_mhas no cross-mode terms. The solver's modal normalisation therefore cancels; only the voltage/current shape of each mode matters. - The modal S of a uniform line is
[[0, E], [E, 0]]withE = diag(exp(-gamma_k * length))(uniform_line_modal_s).
z_ref may be a scalar, one value per terminal, or one value per frequency and terminal. It must be real and positive.
3. Degenerate modes¶
If several modes share a propagation constant (a homogeneous dielectric, or a symmetric layout), the solver may return
any basis of their subspace, and the mode order and mixing can change from run to run. Any basis of a degenerate
subspace gives the same terminal S. A special choice is the terminal-aligned basis R = T_V,cluster^-1, in which
each mode puts its voltage on one terminal only ("the combination that maximises the field on each terminal"); the
transformation does not need it. degenerate_mode_groups(n_eff, rtol=...) lists which modes share a propagation
constant at one frequency.
Checked on synthetic coupled lines (generic values, 700 um, 1-100 GHz, z_ref = 50 ohm). Errors are the largest
difference of the terminal S against an independent chain-matrix solution:
| case | bases tried | max abs error |
|---|---|---|
| homogeneous, 2 conductors, lossless | 5 random complex bases + aligned + eig |
7.9e-15 |
| homogeneous, 3 conductors, lossless | 5 random complex bases + aligned + eig |
1.1e-14 |
homogeneous, 2 conductors, lossy (R = aL, G = bC) |
5 random complex bases | 7.2e-15 |
| 3 conductors, one degenerate pair and one distinct mode | random 2x2 rotation inside the pair, 5 trials | 3.4e-14 |
Near degeneracy (C[0,0] scaled by 1 + delta, and a random symmetric perturbation of relative size delta): S_t
differs from the unperturbed S_t by about 1.1 * delta, i.e. it is continuous, and the modal route still agrees with
the chain matrix to 1e-14. Eigenvectors, by contrast, rotate by 6 to 49 degrees between rows when the perturbation
direction changes (as mesh noise does) while S_t moves by about delta. Mode identification is unreliable near
degeneracy; the terminal S is not. The same transformation also covers the non-degenerate case (for example even and odd
modes with different velocities), where rotating modes is not allowed.
4. Where T_V and T_I come from¶
- Voltages. Run a
BoundaryModeSimon the port plane with one voltage path per terminal, from the terminal to the reference conductor:add_port("A", voltage_path=[...])(the order ofadd_portcalls is the path index). Palace writes the complex voltage of each mode on each path tomode-V.csv;PalaceTextResults.mode_voltage(index, mode)reads it. Modes come withk_nandn_effinmode-kn.csv, from whichgamma = j * k0 * n_eff. - Currents. Use complex terminal currents from the saved mode fields (an Ampere contour around each terminal), or
the reaction route below. With the unconjugated reaction matrix
R = T_V^T T_I,T_I = T_V^{-T} R;currents_from_reaction(t_v, reaction)implements it. For distinct modes of a reciprocal lineRis diagonal (r_k = V_k^T I_k) and the vectorris enough. Within a degenerate group any basis is valid, and a mixed basis has off-diagonal reactions, so pass the full matrix there (or orthogonalise the group first). A quasi-TEM solve gives the same result fromT_I = (G + j w C) T_V Gamma^-1. - Warning: do not derive currents from power alone. If
T_Iis rebuilt from the complex voltages inmode-V.csvand the real power implied byZ_PV, i.e.r_kis replaced by2 P_k, the result is exact only without loss. On synthetic asymmetric coupled lines the terminal S error was:
| series resistance | r_k = V_k^T I_k (reaction) |
r_k = 2 P_k (power only) |
quasi-TEM admittance |
|---|---|---|---|
| lossless | 4.7e-15 | 4.7e-15 | 4.7e-15 |
| about 40 ohm/m | 7.0e-15 | 3.0e-4 | 6.9e-15 |
| about 2.6 kohm/m (on-chip metal) | 1.3e-14 | 1.9e-2 | 1.3e-14 |
A 2 % error is not acceptable for S-parameters, so take complex currents from the fields. (Numbers: synthetic lines, 700
um, 1-100 GHz, z_ref = 50 ohm; the power-only route needs a phase alignment of each voltage column, here the largest
entry made real.)
5. Grounds are part of the definition¶
Terminal voltages are measured against a reference conductor, and a line with N + 1 conductors has N quasi-TEM
modes. Floating outer grounds are therefore extra conductors: a GSSG line with floating grounds has three non-reference
conductors (two signals and one outer ground, with the other outer ground as the reference) and three modes, not two.
Either tie the grounds together (metal strips, a lower plane and continuous via stacks give one ground conductor, and
then two signal terminals and two modes), or declare the extra ground as a terminal. The T_V/T_I blocks must be
square: as many modes as terminals.
6. Mixed-mode output with scikit-rf¶
Terminal S feeds scikit-rf directly. For a two-end coupled pair ordered (A1, B1, A2, B2), Network.se2gmm(p=2) pairs
ports (0, 1) and (2, 3), puts the differential ports first and the common ports after, and defaults the reference
impedances to twice and half of the single-ended value. This replaces the one-wave-port-per-signal plus se2gmm
workaround of gsim#264 once terminal S is available. On a symmetric line the differential and common blocks match
DefinedGammaZ0 lines with 2 * Z_odd (at 100 ohm) and Z_even / 2 (at 25 ohm) to 1.5e-14 with no mode conversion
(|S_dc| <= 1e-15).
7. Limits¶
- Real, positive
z_refonly. Complex reference impedances are later work. - Cross-mode terms in the modal S (a mode on one end exciting another mode on the other end) must come from a multi-mode
port solve.
uniform_line_modal_shas none; with a mirror-symmetric layout they vanish. T_VandT_Ifrom a separate BoundaryMode run describe the port modes only when those modes are not degenerate, or when the cluster is treated as one group (section 3).- The blocks must be square and well conditioned:
modal_to_terminal_sraisesValueErrorifcond(T_V)orcond(T_I)exceeds 1e12 ("the modes do not span the terminals").
8. Example with synthetic data¶
A coupled pair over a common ground with series loss. The modes come from the eigenproblem of Z Y, the modal S is a
uniform line, and the result is checked against an independent chain-matrix solution and turned into mixed-mode S.
import numpy as np
import skrf
from scipy.linalg import expm
from skrf.network import z2s
from gsim.palace.terminal import modal_to_terminal_s, uniform_line_modal_s
# per-unit-length matrices of a coupled pair over a common ground (generic values)
L = np.array([[4.0e-7, 1.2e-7], [1.2e-7, 4.0e-7]]) # H/m
C = np.array([[1.6e-10, -0.5e-10], [-0.5e-10, 1.6e-10]]) # F/m
R = np.diag([40.0, 40.0]) # ohm/m
G = np.diag([2e-4, 2e-4]) # S/m
freq = np.linspace(1e9, 100e9, 41)
length = 700e-6 # m
# modes at each frequency: columns of t_v are the mode voltages, t_i = Y t_v / gamma
t_v, t_i, gamma = [], [], []
for w in 2 * np.pi * freq:
z_pul = R + 1j * w * L
y_pul = G + 1j * w * C
g2, v = np.linalg.eig(z_pul @ y_pul)
g = np.sqrt(g2)
g = np.where(g.real < 0, -g, g)
t_v.append(v)
t_i.append(y_pul @ v / g)
gamma.append(g)
t_v, t_i, gamma = np.array(t_v), np.array(t_i), np.array(gamma)
# modal S of the uniform line -> terminal S in the order (A1, B1, A2, B2)
s_modal = uniform_line_modal_s(gamma, length)
s_term = modal_to_terminal_s(s_modal, [t_v, t_v], [t_i, t_i], z_ref=50.0)
# independent reference: chain matrix expm([[0, -Z], [-Y, 0]] * length) -> Z -> S
z_mats = []
for w in 2 * np.pi * freq:
z_pul = R + 1j * w * L
y_pul = G + 1j * w * C
a = np.block([[np.zeros((2, 2)), -z_pul], [-y_pul, np.zeros((2, 2))]])
phi = expm(a * length)
p11, p12, p21, p22 = phi[:2, :2], phi[:2, 2:], phi[2:, :2], phi[2:, 2:]
p21i = np.linalg.inv(p21)
z_mats.append(
np.block([[-p21i @ p22, -p21i], [p12 - p11 @ p21i @ p22, -p11 @ p21i]])
)
s_ref = z2s(np.array(z_mats), z0=50.0, s_def="power")
print("max |S_terminal - S_chain| =", np.abs(s_term - s_ref).max())
# mixed-mode S with scikit-rf: differential ports first, then common ports
net = skrf.Network(f=freq, s=s_term, z0=50.0, f_unit="Hz")
mm = net.copy()
mm.se2gmm(p=2)
print("|S_dd21| at 50 GHz:", abs(mm.s[20, 1, 0]), " |S_cc21|:", abs(mm.s[20, 3, 2]))