Skip to content

S-parameters Report

This report calculates scattering parameters, or S-parameters, which describe the input-output relationships between various ports of a device.

Mathematically, for each port \(n\) of the device, mufem projects the electric field amplitude \(\tilde{\mathbf{E}}\) (V/m), obtained from the simulation, on the waveguide mode \(m\) of the port. The S-parameter \(S_{nm}\) is

\[ S_{nm} = \frac{ \int_{\Gamma_n} \tilde{\mathbf{E}}_t \cdot \tilde{\mathbf{g}}_m\, d\Gamma }{ \int_{\Gamma_n} \tilde{\mathbf{e}}_{t,m} \cdot \tilde{\mathbf{g}}_m\, d\Gamma } - \delta_{mk}, \qquad \tilde{\mathbf{g}}_m = j\beta_m \tilde{\mathbf{e}}_{t,m} + \frac{1}{j\beta_m} \nabla_t \tilde{e}_{n,m}, \]

where:

  • \(\Gamma_n\) is the plane surface of the port \(n\),
  • \(\tilde{\mathbf{E}}_t\) is the component of \(\tilde{\mathbf{E}}\) tangential to \(\Gamma_n\),
  • \(\tilde{\mathbf{e}}_{t,m}\) and \(\tilde{e}_{n,m}\) are the transverse and longitudinal fields of the mode \(m\) (see Waveguide Input Port),
  • \(\beta_m\) is the propagation constant of the mode \(m\) (rad/m),
  • \(\nabla_t\) is the gradient in the plane of the port,
  • \(\tilde{\mathbf{g}}_m\) is proportional to the transverse magnetic field of the mode \(m\).

The products in the integrals do not use the complex conjugate. Thus, the formula is also correct for lossy modes. For TE and TM modes, \(\nabla_t \tilde{e}_{n,m} = 0\) and the formula becomes the overlap integral \(\int \tilde{\mathbf{E}}_t \cdot \tilde{\mathbf{e}}_{t,m}\, d\Gamma / \int \tilde{\mathbf{e}}_{t,m} \cdot \tilde{\mathbf{e}}_{t,m}\, d\Gamma\).

The index \(k\) in the Kronecker symbol \(\delta_{mk}\) is the index of the mode injected from the port \(n\). The Kronecker symbol is zero if the port \(n\) is an output port. So the Kronecker symbol \(\delta_{mk}\) subtracts the radiation that arrives through the port \(n\). You can then read the S-parameter as a reflection coefficient when the port of interest is also an input port. mufem scales all modes to a power of 1 W. Thus, \(S_{nm}\) is a power-wave S-parameter, referenced to the modal wave impedance of the port.

In real simulations, the length of the waveguide with an input or output port is always fixed. But you may want to know the phase of an S-parameter at a different distance inside the waveguide. Since we assume that the field inside the waveguide propagates as a steady-state mode, its phase at different distances is known. We can use this information to calculate the S-parameter at any distance other than the one at which this parameter was originally calculated. The corresponding formula is

\[ S_{nm}(l) = S_{nm}(l_0)\, e^{-2j \beta_m d}, \]

where \(\beta_m\) is the propagation constant of the mode \(m\) (rad/m) and \(d=l-l_0\) is the shift distance (m). Here, \(l_0\) is the original distance and \(l\) is the distance of interest. Use a negative value of \(d\) to move the reference plane from the port into the device. For example, use this to remove the length of a feed waveguide (de-embedding). The report applies the factor \(e^{-2j \beta_m d}\) to all S-parameters at the port \(n\). For a transmission coefficient, this is correct only if two conditions are true: the reference plane of the input port moves by the same distance, and the two ports have the same \(\beta_m\).

To generate an S-parameters report, give the report name, the boundary condition for a given port \(n\), and the number of modes to consider at this port (this number determines the range of the \(m\) index):

my_report = SParametersReport(
   name = "My S-parameters Report",
   condition = my_port_condition,
   nmodes = 3,
)

Optionally, you can also give the shift distance \(d\):

my_report = SParametersReport(
   name = "My S-parameters Report",
   condition = my_port_condition,
   nmodes = 3,
   shift_distance = 1e-2,
)

The evaluate() method returns a complex matrix with one row and nmodes columns. The column \(m\) contains \(S_{nm}\):

s = my_report.evaluate().to_numpy()  # complex array, shape (1, nmodes)
s_fundamental = s[0, 0]

If two modes of the port have almost the same propagation constant (a relative difference less than 1%), mufem writes a warning to the log. For such degenerate modes, the port eigensolver can select a different combination of the modes than the input port. Thus, the S-parameters of these modes can be unreliable.

Scattering Matrix and Touchstone Export

To get the full scattering matrix of an \(N\)-port device, run one solve for each input port. In each solve, one port is a Waveguide Input Port and all other ports are Waveguide Output Ports. The report at port \(n\) then gives the column of the input port \(m\). The example below calculates the S-matrix of a four-port magic tee:

import numpy as np

S = np.zeros((Nf, n_ports, n_ports), dtype=complex)

for m in range(n_ports):  # input port
    conditions = [
        WaveguideInputPortCondition(f"Port{n + 1}", port_markers[n], 0)
        if n == m
        else WaveguideOutputPortCondition(f"Port{n + 1}", port_markers[n])
        for n in range(n_ports)
    ]
    model.clear_conditions()
    model.add_conditions([condition_pec] + conditions)

    sim.get_report_manager().clear_reports()
    reports = [
        SParametersReport(f"ReportPort{n + 1}", condition, 1, shift_distance=-Lz)
        for n, condition in enumerate(conditions)
    ]
    sim.get_report_manager().add_reports(reports)

    for i in range(Nf):  # frequency sweep
        model.set_frequency(frequencies[i])
        runner.advance(1)
        for n, report in enumerate(reports):
            S[i, n, m] = report.evaluate().to_numpy()[0, 0]

RF circuit simulators and vector network analyzer software read N-port data in the Touchstone format (file extension .sNp, for example .s4p). mufem does not have a Touchstone writer. You can write the file with a short Python function. The Touchstone 1.1 rules are [1]:

  • Lines that start with ! are comments.
  • The option line # GHz S RI R 50 gives the frequency unit, the parameter type (S), the number format (RI: real and imaginary part), and the reference impedance in Ohm.
  • Each frequency point starts a new line with the frequency, followed by the matrix entries. A line has a maximum of four complex values.
  • For two ports, the order is \(S_{11}, S_{21}, S_{12}, S_{22}\). For more ports, each matrix row starts on a new line.
def write_touchstone(file_path, frequencies, s_matrix, comments=()):
    n_ports = s_matrix.shape[1]
    lines = [f"!{comment}" for comment in comments]
    lines.append("# GHz S RI R 50")

    for frequency, s in zip(frequencies, s_matrix):
        if n_ports == 2:
            rows = [[s[0, 0], s[1, 0], s[0, 1], s[1, 1]]]  # S11 S21 S12 S22
        else:
            rows = [s[row, :] for row in range(n_ports)]  # row by row

        chunks = [row[i : i + 4] for row in rows for i in range(0, len(row), 4)]
        for index, chunk in enumerate(chunks):
            prefix = f"{frequency / 1e9: .8e}" if index == 0 else " " * 15
            pairs = " ".join(f"{v.real: .8e} {v.imag: .8e}" for v in chunk)
            lines.append(f"{prefix} {pairs}")

    with open(file_path, "w") as file:
        file.write("\n".join(lines) + "\n")


write_touchstone("MagicTee.s4p", frequencies, S, comments=["Magic Tee"])

Note

The mufem S-parameters are referenced to the modal wave impedance of each port, not to 50 Ohm. The value R 50 in the option line is only a nominal label. Write this in a comment line of the file.

References

[1] Touchstone File Format Specification, Rev. 1.1, EIA/IBIS Open Forum, 2002, https://ibis.org/connector/touchstone_spec11.pdf

Usage Examples