API Reference

This page documents the public API of simpleLOMs.

Package

Top-level re-exports are documented under the submodule sections below (to avoid duplicate Sphinx object descriptions).

Simple Lumped Oscillator Models for superconducting quantum device design.

Parameters

params.py

Shared parameter dataclasses used across simpleLOMs.

Here we define CPWParams once. Every function that needs CPW geometry accepts a single CPWParams.

class simpleLOMs.params.CPWParams(w: float = 1.17e-05, s: float = 5.1e-06, t: float = 0.0, h: float = 0.0005, rho: float = 1e-19, ep_r: float = 11.45, has_metal_backside: bool = False, tand: float = 0.0)[source]

Bases: object

Physical geometry and material parameters for a Coplanar Waveguide (CPW).

w

Center conductor width (m). Default 11.7 µm.

Type:

float

s

Gap spacing between center conductor and ground plane (m). Default 5.1 µm.

Type:

float

t

Metal thickness (m). Set to 0 to ignore (for an ideal thin film). This quantity is generally on the order of 100-200 nm.

Type:

float

h

Substrate height (m). Default 500 µm.

Type:

float

rho

Metal resistivity (Ω·m). Set near 0 for superconducting limit.

Type:

float

ep_r

Substrate relative permittivity. Defaults to 11.45 (ultracold silicon).

Type:

float

has_metal_backside

Whether the substrate has a metal ground plane on its back side.

Type:

bool

tand

Loss tangent of the substrate. Set to 0 for a lossless superconducting circuit.

Type:

float

Examples

Use the defaults (ultracold silicon chip):
>>> cpw = CPWParams()
Override just the substrate:
>>> cpw = CPWParams(ep_r=11.9, has_metal_backside=False)
Pass into a network builder:
>>> net = cpw_resonator_network_2port(freq, d=7e-3, cpw_params=cpw, ...)
ep_r: float = 11.45
h: float = 0.0005
has_metal_backside: bool = False
rho: float = 1e-19
s: float = 5.1e-06
t: float = 0.0
tand: float = 0.0
w: float = 1.17e-05

System

system.py

Single home for device-level orchestration. Two clearly separated concerns:

§A DESIGN API (user-facing)

fit_lom(d, model=…) -> (L, C) fit_lom_hanger(d, Cc_tap=…) -> (L, C)

Pick a model, get its effective L, C from the CPW. No loads involved. Use fit_lom for inline resonators; fit_lom_hanger for notch / hanger LOMs. This is what user-facing tutorials should use.

§C ACCURACY-TESTING HARNESS (author-facing)

analyze_system / analyze_system_load_grid / run_accuracy_sweep*

Compares Foster/Optimized/Analytical against the CPW ground truth using reflection circle fits, including loaded-network hybridization shifts. This is the validation machinery — end users doing design do NOT need it.

§B in between holds the shared circle-fit / metric / residual helpers used by both. (Formerly split across system.py + load_sweeps.py; merged here so there is one system module. The generic parameter-sweep engine lives in sweeps.py.)

class simpleLOMs.system.PrefitContext(refined_freq: 'rf.Frequency', cpw_network: 'rf.Network', optimized_model: 'OptimizedFit', foster_model: 'FosterFit', analytical_model: 'AnalyticalFit', f0_cpw_s11: 'float', f0_cpw_s22: 'float', f0_cpw_s12: 'float', m_opt: 'dict', m_foster: 'dict', m_analytical: 'dict')[source]

Bases: object

analytical_model: AnalyticalFit
cpw_network: Network
f0_cpw_s11: float
f0_cpw_s12: float
f0_cpw_s22: float
foster_model: FosterFit
m_analytical: dict
m_foster: dict
m_opt: dict
optimized_model: OptimizedFit
refined_freq: Frequency
simpleLOMs.system.analyze_system(freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, Lload1: float, Cload1: float, Lload2: float, Cload2: float, cpw_params: CPWParams | None = None, Z0: float = 50.0, analytical_f_r: float | None = None, analytical_Z0: float | None = None, opt_config: OptimizationConfig | None = None, verbose: bool = False, shifted: bool = False) → dict[source]

Compare FosterFit, OptimizedFit, and AnalyticalFit against a CPW reference.

Uses reflection circle fits on S11 and S22 for f0 and kappa extraction.

analytical_f_r sets the bare (unloaded) resonance in Hz that anchors the analytical closed form; when omitted it is computed from the CPW geometry via simpleLOMs.networks.cpw.bare_cpw_resonance_hz() (no longer hardcoded to the 7 mm value). analytical_Z0 optionally overrides the impedance used in that closed form.

simpleLOMs.system.analyze_system_cf(freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, Lload1: float, Cload1: float, Lload2: float, Cload2: float, cpw_params: CPWParams | None = None, Z0: float = 50.0, analytical_f_r: float | None = None, analytical_Z0: float | None = None, opt_config: OptimizationConfig | None = None, verbose: bool = False, shifted: bool = False) → dict

Compare FosterFit, OptimizedFit, and AnalyticalFit against a CPW reference.

Uses reflection circle fits on S11 and S22 for f0 and kappa extraction.

analytical_f_r sets the bare (unloaded) resonance in Hz that anchors the analytical closed form; when omitted it is computed from the CPW geometry via simpleLOMs.networks.cpw.bare_cpw_resonance_hz() (no longer hardcoded to the 7 mm value). analytical_Z0 optionally overrides the impedance used in that closed form.

simpleLOMs.system.analyze_system_cf_new(*, freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, load1_freqs_hz: ndarray, load2_freqs_hz: ndarray, cpw_params: CPWParams | None = None, Z0: float = 50.0, analytical_Z0: float | None = None, analytical_f_r: float | None = None, opt_config: OptimizationConfig | None = None, verbose: bool = False, shifted: bool = False, Cload1_fixed: float = 6e-13, Cload2_fixed: float = 6e-13) → dict
simpleLOMs.system.analyze_system_load_grid(*, freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, load1_freqs_hz: ndarray, load2_freqs_hz: ndarray, cpw_params: CPWParams | None = None, Z0: float = 50.0, analytical_Z0: float | None = None, analytical_f_r: float | None = None, opt_config: OptimizationConfig | None = None, verbose: bool = False, shifted: bool = False, Cload1_fixed: float = 6e-13, Cload2_fixed: float = 6e-13) → dict[source]
simpleLOMs.system.evaluate_load_grid(*, freq: Frequency, prefit: PrefitContext, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, load1_freqs_hz: ndarray, load2_freqs_hz: ndarray, Cload1_fixed: float = 6e-13, Cload2_fixed: float = 6e-13, freq_loaded: Frequency | None = None, cpw_params: CPWParams | None = None, Z0: float = 50.0, shifted: bool = False) → list[dict][source]
simpleLOMs.system.fit_lom(d: float, model: str = 'optimized', *, Cc: float = 6e-15, Ctog: float = 1e-14, Cc1: float | None = None, Cc2: float | None = None, Ctog1: float | None = None, Ctog2: float | None = None, Z0: float = 50.0, cpw_params: CPWParams | None = None, freq: Frequency | None = None, opt_config: OptimizationConfig | None = None, analytical_f_r: float | None = None, analytical_Z0: float | None = None, return_model: bool = False)[source]

Fit the chosen lumped-oscillator model at resonator length d and return its effective (L, C).

This is the design-time entry point for a normal user: pick a model, get L, C from the CPW. No loads are involved — the load/sweep machinery in this module is a separate accuracy-testing path.

Parameters:
  • d (float) – Resonator length in metres.

  • model ({"optimized", "foster", "analytical"}) – Which LOM to fit. "optimized" (default) is the most accurate; "foster" is a fast closed form from geometry; "analytical" is a closed form anchored to the CPW’s resonance frequency.

  • Cc (float) – Coupling capacitance in Farads applied symmetrically to both ports. Used by the “optimized” and “analytical” references; “foster” is coupling-independent. For asymmetric loading, use Cc1/Cc2 instead.

  • Ctog (float) – Shunt-to-ground capacitance in Farads applied to both ports. Overridden per port by Ctog1/Ctog2.

  • Cc1 (float, optional) – Per-port coupling capacitances in Farads for an asymmetrically loaded resonator. Each defaults to Cc when not given, so leaving both unset reproduces the symmetric case. “foster” ignores these (it is coupling-independent).

  • Cc2 (float, optional) – Per-port coupling capacitances in Farads for an asymmetrically loaded resonator. Each defaults to Cc when not given, so leaving both unset reproduces the symmetric case. “foster” ignores these (it is coupling-independent).

  • Ctog1 (float, optional) – Per-port shunt-to-ground capacitances in Farads. Each defaults to Ctog when not given.

  • Ctog2 (float, optional) – Per-port shunt-to-ground capacitances in Farads. Each defaults to Ctog when not given.

  • Z0 (float) – Reference / feedline impedance in Ohms.

  • cpw_params (CPWParams, optional) – CPW geometry / material. Defaults to CPWParams().

  • freq (rf.Frequency, optional) – Frequency grid used to locate the resonance (must span the loaded fundamental). Defaults to a 4-12 GHz, 20,001-point grid. “foster” synthesises on it directly. “optimized” uses it only to find f0, then rebuilds the CPW reference on a dense window around f0 (~8 kHz/pt) for the least-squares fit, so a coarse or wide input grid still yields a physical (L, C). “analytical” ignores the grid for its anchor and instead uses the bare (unloaded) λ/2 resonance — see analytical_f_r. Narrow the span to isolate a specific mode.

  • opt_config (OptimizationConfig, optional) – Optimiser settings for model="optimized". Defaults to a quiet n_widths=4 config.

  • analytical_f_r (float, optional) – Bare (unloaded) resonance frequency in Hz used to anchor model="analytical". If omitted, it is computed from the CPW geometry with simpleLOMs.networks.cpw.bare_cpw_resonance_hz(). Anchoring to the bare line (not the loaded resonance) is what keeps the closed form from double-counting the Cc/Ctog loading that get_network re-applies. Ignored for other models.

  • analytical_Z0 (float, optional) – Characteristic impedance in Ohms of the line geometry used in the closed form for model="analytical" — not the 50 Ω port reference. If omitted, it is computed from the CPW geometry with simpleLOMs.networks.cpw.cpw_line_impedance(). Ignored for other models.

  • return_model (bool) – If True, return the fitted model instance instead of (L, C).

Returns:

(L, C) in Henries/Farads, or the fitted model if return_model.

Return type:

tuple[float, float] or BaseFit

Notes

For the “optimized” and “analytical” models the effective L, C absorb the coupling/ground capacitors, so they do depend on Cc/Ctog (the couplers pull the effective values); refit if the loading changes materially. Reusing a single fit across a coupling sweep is fine for the resonance frequency and loaded Q (which only need f_r and a measured linewidth) but not for Z_r/V_zpf. To get the readout linewidth, pair this with simpleLOMs.extract_f0_kappa() and simpleLOMs.resonator_readout_params().

simpleLOMs.system.fit_lom_hanger(d: float, *, Cc_tap: float = 3e-14, termination: str = 'open', Z0: float = 50.0, cpw_params: CPWParams | None = None, freq: Frequency | None = None, opt_config: OptimizationConfig | None = None, return_model: bool = False)[source]

Fit an effective (L, C) for a hanger / notch resonator against a CPW hanger ground truth (S21 dip).

Unlike fit_lom(), which optimises against an inline CPW topology, this builds a hanger CPW reference and runs HangerOptimizedFit so the lumped tank is calibrated for single-tap coupling — not rewired from an inline fit.

Parameters:
  • d (float) – Resonator length in metres.

  • Cc_tap (float) – Tap coupling capacitance in Farads between the through feedline and the hanging resonator.

  • termination ({"open", "short"}) – Far-end termination of the CPW hanger branch. "open" is λ/2 (default, matching the usual open–open inline mode family); "short" is λ/4.

  • Z0 (float) – Reference / feedline impedance in Ohms.

  • cpw_params (CPWParams, optional) – CPW geometry / material. Defaults to CPWParams().

  • freq (rf.Frequency, optional) – Frequency grid spanning the notch. Defaults to 1–12 GHz, 40_001 points (wider than the inline default so λ/4 short notches are also covered).

  • opt_config (OptimizationConfig, optional) – Optimiser settings. Defaults to a quiet S21-oriented config.

  • return_model (bool) – If True, return the fitted HangerOptimizedFit instead of (L, C).

Returns:

(L, C) in Henries/Farads, or the fitted model if return_model.

Return type:

tuple[float, float] or HangerOptimizedFit

simpleLOMs.system.fit_models_once(*, freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, cpw_params: CPWParams | None = None, Z0: float = 50.0, analytical_Z0: float | None = None, analytical_f_r: float | None = None, opt_config: OptimizationConfig | None = None, verbose: bool = False, shifted: bool = False) → PrefitContext[source]

Fit all three models once against the (unloaded) CPW and return a PrefitContext with their L/C, circle-fit f0/kappa metrics, and networks.

This is the load-free comparison core: it never touches loads, so it can be used on its own to compare LOMs against the CPW ground truth. The load grid below reuses one prefit across many load-frequency pairs.

simpleLOMs.system.load_from_freq(f_ghz: float, C: float = 6e-13) → tuple[float, float][source]
simpleLOMs.system.run_accuracy_sweep(sweep_params: dict, fixed_params: dict, save_path: str | None = None, skip_errors: bool = True, verbose: bool = True) → list[source]

Run analyze_system() over a grid of parameter combinations.

simpleLOMs.system.run_accuracy_sweep_cf(sweep_params: dict, fixed_params: dict, save_path: str | None = None, skip_errors: bool = True, verbose: bool = True) → list

Run analyze_system() over a grid of parameter combinations.

simpleLOMs.system.run_accuracy_sweep_cf_new(*, sweep_params: dict, fixed_params: dict, load1_freqs_hz: ndarray, load2_freqs_hz: ndarray, save_path: str | None = None, skip_errors: bool = True, verbose: bool = True, n_jobs: int = 1) → list
simpleLOMs.system.run_accuracy_sweep_cf_new_APR22(*, sweep_params: dict, fixed_params: dict, load1_freqs_hz: ndarray, load2_freqs_hz: ndarray, save_path: str | None = None, skip_errors: bool = True, verbose: bool = True, n_jobs: int = 1) → list

APR22 compatibility wrapper for the load-grid sweep runner.

simpleLOMs.system.run_accuracy_sweep_load_grid(*, sweep_params: dict, fixed_params: dict, load1_freqs_hz: ndarray, load2_freqs_hz: ndarray, save_path: str | None = None, skip_errors: bool = True, verbose: bool = True, n_jobs: int = 1) → list[source]
simpleLOMs.system.run_accuracy_sweep_load_grid_apr22(*, sweep_params: dict, fixed_params: dict, load1_freqs_hz: ndarray, load2_freqs_hz: ndarray, save_path: str | None = None, skip_errors: bool = True, verbose: bool = True, n_jobs: int = 1) → list[source]

APR22 compatibility wrapper for the load-grid sweep runner.

Analysis

analysis.py

Pure numerical analysis functions for extracting resonance frequencies and linewidths from S-parameter networks.

None of these functions build networks or do optimization — they only inspect existing rf.Network objects. This makes them easy to test independently and reuse across models.

simpleLOMs.analysis.circle_fit_f0_kappa(ntwk: Network, m: int = 0, n: int = 0, smooth_window: int | None = 51, smooth_polyorder: int = 3) → tuple[float, float][source]

Extract resonance frequency (f0) and linewidth (kappa) from a circle fit to S[m,n] in the complex plane (reflection S11/S22).

Returns:

  • f0 (float) – Resonance frequency in Hz.

  • kappa (float) – Linewidth (FWHM of the angular velocity peak) in Hz. NaN (with a RuntimeWarning) when the half-power points are not bracketed by the network’s frequency window — i.e. the line is wider than the window, or the resonance sits on its edge.

simpleLOMs.analysis.circle_fit_f0_kappa_windowed(ntwk: Network, m: int = 0, n: int = 0, span_factor: float = 1.5, min_points: int = 25, smooth_window: int | None = 51, smooth_polyorder: int = 3) → tuple[float, float][source]

Circle fit for networks on a fixed frequency grid (FEM exports, VNA traces, or models evaluated on such a grid for comparison).

circle_fit_f0_kappa smooths the circle phase over a fixed number of grid points. On the dense grids the package builds internally that span is far narrower than any linewidth, but on an externally supplied sweep it can exceed the physical kappa — the extracted linewidth then reflects the smoothing filter rather than the resonance. This variant uses the smoothed full-band fit only to locate the resonance, then re-extracts f0 and kappa from an unsmoothed fit restricted to f0 ± span_factor * kappa_estimate.

Parameters:
  • ntwk (rf.Network) – Network to analyse.

  • m (int) – S-parameter indices, as in circle_fit_f0_kappa.

  • n (int) – S-parameter indices, as in circle_fit_f0_kappa.

  • span_factor (float) – Half-width of the extraction window in units of the first-pass kappa estimate (which may be inflated; a generous window is harmless because the unsmoothed extraction is local).

  • min_points (int) – Minimum number of grid points in the window; widened symmetrically around the resonance if the first pass yields fewer.

  • smooth_window (int or None) – Smoothing window for the first-pass locating fit.

  • smooth_polyorder (int) – Polynomial order for the first-pass locating fit.

Returns:

  • f0 (float) – Resonance frequency in Hz.

  • kappa (float) – Linewidth in Hz, free of the smoothing-filter bias. NaN when the linewidth cannot be bracketed inside the supplied grid (see circle_fit_f0_kappa); callers that can re-simulate should retry with a wider window.

simpleLOMs.analysis.circle_fit_modes(ntwk: Network, m: int = 0, n: int = 0, n_modes: int = 3, prominence: float = None, min_spacing_hz: float = None, smooth_window: int | None = 51, smooth_polyorder: int = 3) → tuple[ndarray, ndarray][source]

Find multiple resonance modes in S[m,n] using the reflection circle fit.

Returns:

  • f0s (np.ndarray) – Mode frequencies in Hz, length n_modes (NaN-padded).

  • kappas (np.ndarray) – Mode linewidths in Hz, length n_modes (NaN-padded).

simpleLOMs.analysis.find_resonant_frequency(network: Network) → complex[source]
simpleLOMs.analysis.fwhm_from_res11(ntwk: Network) → float[source]

Linewidth from zero crossings of Re(S11).

Re(S11) crosses zero at the two half-power frequencies of the resonance. Uses linear interpolation between samples for accuracy.

Parameters:

ntwk (rf.Network)

Returns:

Linewidth (distance between the two zero crossings) in Hz.

Return type:

float

Raises:

ValueError – If fewer than two zero crossings are found.

simpleLOMs.analysis.fwhm_from_trace_db(ntwk: Network, m: int = 0, n: int = 0, kind: str = 'dip', smooth: int = None) → float[source]

Full-Width at Half Maximum (FWHM) from S-parameter magnitude in dB.

Uses crossing-interpolation to find the two frequencies where the magnitude crosses the half-depth level, giving a more accurate result than a pure index-based approach.

Parameters:
  • ntwk (rf.Network)

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • kind ({"dip", "peak"}) – “dip” — resonance appears as a downward dip (typical for S11/S22). “peak” — resonance appears as an upward peak (typical for S12/S21).

  • smooth (int or None) – Optional moving-average window length for noisy traces. Use an odd integer; None disables smoothing.

Returns:

FWHM linewidth in Hz.

Return type:

float

Raises:

ValueError – If two crossings at the half-depth level cannot be found.

simpleLOMs.analysis.notch_frequency(network: Network, m: int = 1, n: int = 0) → tuple[float, float][source]

Locate the deepest transmission notch in |S[m,n]|.

The returned frequency is refined below the frequency-grid spacing by fitting a parabola to |S|**2 through the three points straddling the minimum, so the result is not quantised to the grid. On the ~1 MHz-spaced grids used in the hanger tutorials this tightens the notch location from ±½ grid point (~0.5 MHz) to a fraction of a grid point; a deep notch is a sharp cusp rather than a true parabola, so a small sub-grid residual remains (it is not exact). The returned depth is the raw grid-point minimum |S[m,n]|.

Returns:

  • f_GHz (float) – Frequency of the deepest dip in GHz (sub-grid refined).

  • depth (float) – |S[m,n]| at the grid-point minimum (linear magnitude).

simpleLOMs.analysis.notches_below(network: Network, thresh: float = 0.5, m: int = 1, n: int = 0) → list[float][source]

Frequencies (GHz) of local |S[m,n]| minima below thresh.

A coarse multi-notch finder for multiplexed hanger spectra.

simpleLOMs.analysis.resonance(ntwk: Network, m: int = 0, n: int = 0, use_max: bool = False, method: str = 'min_re') → float[source]

Estimate resonance frequency from S[m,n].

Parameters:
  • ntwk (rf.Network)

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • use_max (bool) – Only used for method=’min_re’. If True, find frequency of maximum Re(S) instead of minimum.

  • method (str) –

    Resonance estimator. Supported:
    • ’min_re’ : min/max of Re(S)

    • ’circle_fit’ : circle fit in complex plane

Returns:

Resonance frequency in Hz.

Return type:

float

simpleLOMs.analysis.resonance_circle_fit(ntwk: Network, m: int = 0, n: int = 0, smooth_window: int | None = 51, smooth_polyorder: int = 3) → float[source]

Estimate resonance frequency from a circle fit to S[m,n] in the complex plane.

Strategy

  1. Fit a circle to the complex trace S[m,n](f).

  2. Compute the angle of each point about the fitted center.

  3. Take the frequency where |d(theta)/df| is largest.

This is usually a good reflection-based estimator for S11/S22.

param ntwk:

type ntwk:

rf.Network

param m:

S-parameter indices.

type m:

int

param n:

S-parameter indices.

type n:

int

param smooth_window:

Optional Savitzky-Golay smoothing window for theta before differentiation. Must be odd if provided.

type smooth_window:

int or None

param smooth_polyorder:

Polynomial order for Savitzky-Golay smoothing.

type smooth_polyorder:

int

returns:

Resonance frequency in Hz.

rtype:

float

simpleLOMs.analysis.resonance_from_res11(ntwk: Network) → float[source]

Resonance frequency from the minimum of Re(S11).

Thin convenience wrapper around resonance for the common single-port S11 case.

Parameters:

ntwk (rf.Network)

Returns:

Resonance frequency in Hz.

Return type:

float

simpleLOMs.analysis.resonance_from_s_max(network: Network, m: int = 0, n: int = 0) → float[source]

Resonance frequency from the dominant peak in |S[m,n]|.

Finds all peaks in the magnitude and returns the frequency of the largest one. Useful for transmission parameters (S12/S21) where the resonance appears as a peak rather than a dip.

Parameters:
  • network (rf.Network)

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

Returns:

Dominant resonance frequency in Hz.

Return type:

float

Raises:

ValueError – If no peaks are found in |S[m,n]|.

simpleLOMs.analysis.resonances(ntwk: Network, m: int = 0, n: int = 0, n_modes: int = 3, method: str = 'min_re', prominence: float = None, min_spacing_hz: float = None) → ndarray[source]

Estimate resonance frequencies for multiple modes from S[m,n].

Parameters:
  • ntwk (rf.Network)

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • n_modes (int) – Number of resonant modes to find.

  • method (str) –

    Resonance estimator. Supported:
    • ’min_re’ : finds n_modes minima of Re(S)

    • ’circle_fit’ : finds n_modes peaks of |dθ/df| from circle fit

  • prominence (float, optional) – Minimum peak prominence passed to scipy.signal.find_peaks. If None, defaults to 0.1 * (max - min) of the trace being searched.

  • min_spacing_hz (float, optional) – Minimum frequency separation between modes in Hz. If None, defaults to (f_max - f_min) / (10 * n_modes).

Returns:

Resonance frequencies in Hz, sorted ascending, length n_modes. If fewer than n_modes peaks are found, the array is padded with NaN.

Return type:

np.ndarray

simpleLOMs.analysis.resonances_from_s(network: Network, m: int = 0, n: int = 0) → ndarray[source]

Find all resonance frequencies from peaks in Re(S[m,n]).

Parameters:
  • network (rf.Network)

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

Returns:

Array of resonance frequencies in Hz.

Return type:

np.ndarray

simpleLOMs.analysis.resonances_from_s_max(network: Network, m: int = 0, n: int = 0) → ndarray[source]

Resonance frequencies from the peaks in |S[m,n]|.

Finds all peaks in the magnitude and returns their frequencies. Useful for transmission parameters (S12/S21) where the resonances appear as peaks rather than dips.

Parameters:
  • network (rf.Network)

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

Returns:

Array of resonance frequencies in Hz.

Return type:

np.ndarray

Raises:

ValueError – If no peaks are found in |S[m,n]|.

simpleLOMs.analysis.s_db(network: Network, m: int = 1, n: int = 0) → ndarray[source]

Return 20 log10 |S[m,n]| in dB for network.

simpleLOMs.analysis.stitch_shifted_freqs(*arrays: ndarray, dedup_tol_ghz: float = 0.05, return_sources: bool = False)[source]

Merge S11/S22 mode frequency lists, deduplicating nearby modes.

Models

models/base.py

Abstract base class for all LC fitting strategies.

Usage pattern

model = FosterFit(cpw_params=CPWParams()) # or OptimizedFit, AnalyticalFit model.fit(freq, d=7e-3, Cc1=…, Cc2=…) # runs the fitting algorithm net = model.get_network(freq, …) # build rf.Network from results params = model.get_params() # {“L”: …, “C”: …} assert model.is_fitted # True after fit()

class simpleLOMs.models.base.BaseFit[source]

Bases: ABC

Abstract base class for LC lumped-element fitting strategies.

All subclasses must implement fit(), get_network(), and get_params(). The is_fitted property is managed automatically by the base class once self.L and self.C are set by a subclass.

C: float | None = None

Effective capacitance in Farads — set by fit()

L: float | None = None

Effective inductance in Henries — set by fit()

abstractmethod fit(freq: Frequency, **kwargs) → None[source]

Run the fitting algorithm and store results in self.L and self.C.

After this method returns, self.is_fitted must be True.

Parameters:
  • freq (rf.Frequency) – Frequency sweep to use for network construction during fitting.

  • **kwargs – Subclass-specific parameters (e.g. d, Cc1, Cc2, data_ntw).

abstractmethod get_network(freq: Frequency, **kwargs) → Network[source]

Build and return an rf.Network using the fitted L and C values.

Must call self._require_fitted() at the start.

Parameters:
  • freq (rf.Frequency) – May differ from the freq used in fit() (e.g. a finer grid).

  • show (bool, optional) – If True, automatically plot the built network (default False). Defaults to False so batch callers (analyze_system, sweeps) do not spam figures.

  • reference (rf.Network, optional) – Reference network for overlay plots when show=True. OptimizedFit can fall back to the data_ntw stored during fit().

  • m (int, optional) – S-parameter indices for the auto-plot (0-based).

  • n (int, optional) – S-parameter indices for the auto-plot (0-based).

  • lom_label (str, optional) – Legend labels for the auto-plot.

  • data_label (str, optional) – Legend labels for the auto-plot.

  • save_path (str, optional) – If provided with show=True, save the figure to this path.

  • **kwargs – Subclass-specific parameters (e.g. Cc1, Cc2, Ctog1, Ctog2).

Return type:

rf.Network

abstractmethod get_params() → dict[source]

Return the fitted parameters as a plain dictionary.

At minimum returns {“L”: self.L, “C”: self.C}. Subclasses may include additional diagnostics.

Return type:

dict

property is_fitted: bool

True if fit() has been called and produced valid L and C values.

models/foster.py

FosterFit: admittance-slope (Foster synthesis) method for extracting the effective L and C of a CPW resonator.

Algorithm summary

  1. Build a 2-port CPW transmission line network (no coupling caps, just the bare line terminated at both ends with a high impedance).

  2. Compute the input admittance Yin(ω) seen at port 1 with the port 2 load in place:

    Yin = Y11 - Y12*Y21 / (Y22 + YL)

  3. Find the resonance frequency ω0 from the peak in Re(S22).

  4. At ω0, the imaginary part of Yin passes through zero with a positive slope (for a series-like resonance). The Foster synthesis theorem relates that slope to an equivalent LC:

    C_eq = 0.5 * dB/dω |_{ω=ω0} where B = Im(Yin) L_eq = 1 / (ω0² * C_eq)

  5. Store C_eq → self.C, L_eq → self.L.

class simpleLOMs.models.foster_fit.FosterFit(cpw_params: CPWParams = None, port_z0: float = 500.0)[source]

Bases: BaseFit

Lumped LC model via Foster admittance synthesis on a bare CPW line.

Parameters:
  • cpw_params (CPWParams, optional) – Physical geometry and material parameters for the CPW. Uses default CPWParams() (11.7 µm / 5.1 µm gap, ultracold Si) if not provided.

  • port_z0 (float, optional) – Port impedance used when building the bare CPW network for synthesis. Default 500 Ω (high impedance → weakly loaded line, closer to the unloaded resonator condition).

L

Fitted effective inductance in Henries. None before fit().

Type:

float or None

C

Fitted effective capacitance in Farads. None before fit().

Type:

float or None

yin

Complex input admittance array computed during fit(). Stored for diagnostics / plotting without recomputing.

Type:

np.ndarray or None

Examples

Basic usage:

from simpleLOMs.params import CPWParams
from simpleLOMs.models.foster import FosterFit
import skrf as rf

freq = rf.Frequency(4e9, 10e9, 10_001, unit="Hz")
cpw  = CPWParams(ep_r=11.45)

model = FosterFit(cpw_params=cpw)
model.fit(freq, d=7e-3)

print(model.get_params())
# {'L': 5.53e-10, 'C': 6.22e-13, 'f0_Hz': 8.58e9}

net = model.get_network(freq, Cc1=5e-15, Cc2=5e-15,
                        Ctog1=1e-14, Ctog2=1e-14)
fit(freq: Frequency, d: float, **kwargs) → None[source]

Run Foster synthesis on a bare CPW line of length d.

Computes the input admittance Yin(ω), finds ω0 from a peak in Re(S22), then extracts C_eq from the admittance slope and L_eq from the resonance constraint ω0² L C = 1.

Parameters:
  • freq (rf.Frequency) – Frequency sweep. Should span at least one resonance of the bare CPW line at length d.

  • d (float) – Physical resonator length in metres.

  • **kwargs – Ignored — included for a consistent BaseFit interface.

get_network(freq: Frequency, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, Z0: float = 50.0, show: bool = False, reference: Network = None, m: int = 0, n: int = 0, lom_label: str = 'FosterFit', data_label: str = 'CPW', save_path: str = None, **kwargs) → Network[source]

Build the 2-port LC LOM network using the Foster-synthesised L and C.

Uses the “with grounds” topology so that Ctog1/Ctog2 are included, matching the structure of the CPW model that was synthesised.

Parameters:
  • freq (rf.Frequency) – May differ from the freq used in fit().

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • Z0 (float) – Reference impedance in Ohms.

  • show (bool) – If True, automatically plot the built network (default False).

  • reference (rf.Network, optional) – Overlay reference used when show=True.

  • m (int) – S-parameter indices for the auto-plot.

  • n (int) – S-parameter indices for the auto-plot.

  • lom_label (str) – Legend labels for the auto-plot.

  • data_label (str) – Legend labels for the auto-plot.

  • save_path (str, optional) – Save path used when show=True.

Returns:

2-port LC network with ground capacitors.

Return type:

rf.Network

get_params() → dict[source]

Return fitted parameters.

Returns:

Keys: “L” (H), “C” (F), “f0_Hz” (resonance used for synthesis).

Return type:

dict

class simpleLOMs.models.optimized_fit.OptimizationConfig(w0_window_frac: float = 1e-05, n_w0: int = 20, n_dense: int = 100, n_kappa: float = 0.75, n_widths: float = 1.0, max_nfev: int = 100, verbose: bool = False, fit_phase: bool = False, s_params: Sequence[str] = <factory>, weights: dict[str, float] | None=None)[source]

Bases: object

Tuning knobs for the two-stage OptimizedFit algorithm.

Core algorithm knobs

w0_window_fracfloat

Half-width of the ω0 scan window as a fraction of ω0_guess.

n_w0int

Number of ω0 grid points in the coarse scan.

n_denseint

Number of data points sampled around resonance in Stage 1.

n_kappafloat

Half-width of the dense sampling window in units of κ (linewidth).

n_widthsfloat

Half-width of each residual window in Stage 2, in units of κ.

max_nfevint

Maximum function evaluations for the Stage 2 least_squares call.

verbosebool

If True, least_squares prints iteration progress.

Residual configuration

fit_phasebool

If True, a global scalar phase φ is added to the free parameters so that the model prediction is e^{i·φ} · S_model. The fitted phase is stored in OptimizedFit.phase (radians) after fit().

s_paramssequence of str

Which S-parameter channels to include in Stage 2. Any non-empty subset of {“S11”, “S22”, “S21”, “S12”}. Default: (“S11”, “S22”).

weightsdict[str, float] or None

Manual per-channel weight multipliers applied after depth normalisation. None → equal weights (all 1.0). Example: {“S11”: 2.0, “S22”: 2.0, “S21”: 1.0}

channel_weight(name: str) → float[source]

Return the manual weight for a channel (default 1.0).

fit_phase: bool = False
max_nfev: int = 100
n_dense: int = 100
n_kappa: float = 0.75
n_w0: int = 20
n_widths: float = 1.0
s_params: Sequence[str]
verbose: bool = False
w0_window_frac: float = 1e-05
weights: dict[str, float] | None = None
class simpleLOMs.models.optimized_fit.OptimizedFit(config: OptimizationConfig = None)[source]

Bases: BaseFit

Lumped LC model via two-stage numerical optimisation.

Parameters:

config (OptimizationConfig, optional) – Hyperparameters and residual options. Defaults to OptimizationConfig() (S11 + S22, no phase fitting).

L

Fitted effective inductance in Henries.

Type:

float or None

C

Fitted effective capacitance in Farads.

Type:

float or None

phase

Fitted global phase in radians. None if config.fit_phase is False or before fit() is called.

Type:

float or None

scan_results

Diagnostic array from the Stage 1 ω0 scan, shape (n_w0, 4): columns are [ω0, Ceff, Leff, sse].

Type:

np.ndarray or None

Examples

from simpleLOMs.models.optimized_fit import OptimizedFit, OptimizationConfig

# Fit using only S21, with phase as a free parameter
cfg   = OptimizationConfig(s_params=["S21"], fit_phase=True)
model = OptimizedFit(config=cfg)
model.fit(freq, data_ntw=cpw_net, Cc1=3e-14, Cc2=7e-14,
          Ctog1=4e-14, Ctog2=6e-14, d=7e-3,
          cpw_params=cpw_params, Z0=50)
print(model)           # OptimizedFit(L=…, C=…, phase=…)
net = model.get_network(freq, Cc1=3e-14, Cc2=7e-14, Z0=50)
config: OptimizationConfig
fit(freq: Frequency, data_ntw: Network, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, d: float, cpw_params, Z0: float = 50.0, **kwargs) → None[source]

Two-stage optimisation to fit Leff, Ceff (and optionally phase) to data_ntw.

Stage 1: coarse Nelder-Mead scan over ω0, constrained Ceff.

Uses an explicitly constructed 1-port CPW network so that the Stage 1 data points come from a true single-port reflection measurement rather than a 2-port S11 view.

Stage 2: windowed least_squares refinement on the channels specified

in config.s_params.

Parameters:
  • freq (rf.Frequency) – Frequency grid for the optimisation (should be centred on the resonance with enough bandwidth to capture the linewidth).

  • data_ntw (rf.Network) – 2-port reference network (CPW model or measured data).

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • d (float) – Resonator length in metres.

  • cpw_params (CPWParams) – CPW geometry parameters.

  • Z0 (float) – Reference impedance in Ohms.

get_network(freq: Frequency, Cc1: float, Cc2: float, Z0: float = 50.0, with_grounds: bool = False, Ctog1: float = None, Ctog2: float = None, shifted: bool = False, show: bool = False, reference: Network = None, m: int = 0, n: int = 0, lom_label: str = 'OptimizedFit', data_label: str = 'CPW', save_path: str = None, **kwargs) → Network[source]

Build the 2-port LC LOM network from the optimised L and C.

Note: the optional fitted phase is not applied here because it is a calibration correction for the data, not a physical property of the LC network. Apply it separately if you need to compare against phase-corrected data:

net_s = net.s * np.exp(1j * model.phase)
Parameters:
  • freq (rf.Frequency)

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Z0 (float) – Reference impedance in Ohms.

  • with_grounds (bool) – If True, include Ctog1/Ctog2 shunt caps.

  • Ctog1 (float or None) – Required when with_grounds=True.

  • Ctog2 (float or None) – Required when with_grounds=True.

  • show (bool) – If True, automatically plot the built network (default False).

  • reference (rf.Network, optional) – Overlay reference. Defaults to the data_ntw stored during fit().

  • m (int) – S-parameter indices for the auto-plot.

  • n (int) – S-parameter indices for the auto-plot.

  • lom_label (str) – Legend labels for the auto-plot.

  • data_label (str) – Legend labels for the auto-plot.

  • save_path (str, optional) – Save path used when show=True.

Return type:

rf.Network

get_params() → dict[source]

Return fitted parameters and scan diagnostics.

Returns:

Keys: “L” (H), “C” (F), “phase” (rad or None),

”scan_results” (ndarray or None).

Return type:

dict

phase: float | None
plot_scan(show: bool = True, save_path: str = None)[source]

Plot Stage-1 ω₀ scan results (SSE vs resonant frequency).

Parameters:
  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, ax

scan_results: ndarray | None

models/analytical.py

AnalyticalFit: closed-form approximation for the effective L and C of a λ/2 CPW resonator.

Algorithm summary

For a half-wave (λ/2) CPW resonator the distributed line has a well-known lumped-element equivalent valid near the fundamental resonance:

C_r = π / (2 · ω_r · Z0) [effective capacitance] L_r = 1 / (ω_r² · C_r) [effective inductance]

where ω_r = 2π f_r is the angular resonance frequency and Z0 is the characteristic impedance of the CPW line.

This is the simplest of the three methods — no optimisation, no network simulation, just two formulas. It is fast and useful as a sanity check or initial guess, but it ignores the loading from coupling capacitors and ground capacitors.

Reference: standard microwave engineering result, see e.g. Pozar §6.

class simpleLOMs.models.analytical_fit.AnalyticalFit(mode: int = 2)[source]

Bases: BaseFit

Lumped LC model via the closed-form λ/2 CPW approximation.

Parameters:

mode (int, optional) – Wavelength-fraction selector for the effective capacitance, not a harmonic index: 2 for a half-wave (λ/2) resonator (default), 4 for a quarter-wave (λ/4). It enters as C_r = π / (mode · ω_r · Z0), so the λ/2 value C_r = π / (2·ω_r·Z0) is the mode=2 case.

L

Effective inductance in Henries. None before fit().

Type:

float or None

C

Effective capacitance in Farads. None before fit().

Type:

float or None

Examples

from simpleLOMs.models.analytical import AnalyticalFit
import skrf as rf

freq  = rf.Frequency(4e9, 10e9, 10_001, unit="Hz")
model = AnalyticalFit()

# Provide f_r and Z0 directly — no network needed
model.fit(freq, f_r=8.581e9, Z0=45.926)

print(model.get_params())
# {'L': 5.42e-10, 'C': 6.34e-13, 'f_r_Hz': 8.581e9, 'Z0': 45.926}

net = model.get_network(freq, Cc1=5e-15, Cc2=5e-15,
                        Ctog1=1e-14, Ctog2=1e-14)
fit(freq: Frequency, f_r: float, Z0: float, **kwargs) → None[source]

Compute L and C from the closed-form λ/2 approximation.

Parameters:
  • freq (rf.Frequency) – Frequency sweep (not used in the calculation itself, but kept for a consistent BaseFit interface).

  • f_r (float) – Resonance frequency in Hz.

  • Z0 (float) – Characteristic impedance of the CPW line in Ohms.

  • **kwargs – Ignored.

get_network(freq: Frequency, Cc1: float, Cc2: float, Z0: float = 50.0, with_grounds: bool = True, Ctog1: float = None, Ctog2: float = None, show: bool = False, reference: Network = None, m: int = 0, n: int = 0, lom_label: str = 'AnalyticalFit', data_label: str = 'CPW', save_path: str = None, **kwargs) → Network[source]

Build the 2-port LC LOM network from the analytical L and C.

Parameters:
  • freq (rf.Frequency)

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Z0 (float) – Reference impedance in Ohms.

  • with_grounds (bool) – If True (default), include Ctog shunt capacitors. The analytical model is typically compared alongside the full CPW topology so including the grounds is more representative.

  • Ctog1 (float or None) – Required when with_grounds=True.

  • Ctog2 (float or None) – Required when with_grounds=True.

  • show (bool) – If True, automatically plot the built network (default False).

  • reference (rf.Network, optional) – Overlay reference used when show=True.

  • m (int) – S-parameter indices for the auto-plot.

  • n (int) – S-parameter indices for the auto-plot.

  • lom_label (str) – Legend labels for the auto-plot.

  • data_label (str) – Legend labels for the auto-plot.

  • save_path (str, optional) – Save path used when show=True.

Return type:

rf.Network

get_params() → dict[source]

Return the analytically computed parameters.

Returns:

Keys: “L” (H), “C” (F), “f_r_Hz”, “Z0”.

Return type:

dict

Elements

elements.py

Primitive lumped-element circuit blocks built on top of scikit-rf. Each function returns an rf.Network (a 2-port element) that can be wired into an rf.Circuit connection list.

For netowrks built using these eleemnts see simpleLOMs/networks/.

simpleLOMs.elements.coupling_capacitor(C: float, freq: Frequency, name: str = 'cc', Z0: float = 50) → Network[source]

Series coupling capacitor.

Implemented as a SeriesImpedance with Z = 1 / (jωC).

Parameters:
  • C (float) – Capacitance in Farads.

  • freq (rf.Frequency) – Frequency sweep object.

  • name (str) – Label used inside rf.Circuit.

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port series capacitor network.

Return type:

rf.Network

simpleLOMs.elements.hanger_lc_branch(Cc: float, L: float, C: float, freq: Frequency, name: str = 'hang', Z0: float = 50) → Network[source]

A parallel-LC tank coupled to the signal rail through a series capacitor, hanging to ground — the lumped (“LOM”) version of a hanger / notch resonator.

The branch is a coupling capacitor Cc in series with a parallel-LC tank whose far end is grounded:

rail ── Cc ──┬── L ──┬── ground
             └── C ──┘

The whole branch collapses to a single ShuntAdmittance with

Y = 1 / (Z_Cc + Z_LC), Z_Cc = 1/(jωCc), Z_LC = 1 / (jωC + 1/(jωL)),

so it drops straight into the existing ladder machinery exactly like lc_resonator() (both are shunt 2-ports that pass the rail through while presenting an admittance to ground). Prefer L, C from HangerOptimizedFit when the target topology is a hanger. Reusing an inline LOM fit is only approximate unless the inline ground loading is matched to the hanger: a hanger tap has no shunt-to-ground caps, so an inline fit must be taken at Ctog = 0 to land on the notch (the ~3% “reuse gap” is that mismatched Ctog loading, not the hanger-vs-inline boundary condition).

Parameters:
  • Cc (float) – Coupling (tap) capacitance in Farads between the rail and the tank.

  • L (float) – Tank inductance in Henries.

  • C (float) – Tank capacitance in Farads.

  • freq (rf.Frequency) – Frequency sweep object.

  • name (str) – Label used inside rf.Circuit.

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port shunt network for the hanging LC branch.

Return type:

rf.Network

simpleLOMs.elements.lc_resonator(L: float, C: float, freq: Frequency, name: str = 'lc', Z0: float = 50) → Network[source]

Parallel LC resonator shunted to ground.

Implemented as a ShuntAdmittance with Y = jωC + 1/(jωL), the admittance of a parallel LC tank.

Parameters:
  • L (float) – Inductance in Henries.

  • C (float) – Capacitance in Farads.

  • freq (rf.Frequency) – Frequency sweep object.

  • name (str) – Label used inside rf.Circuit.

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port shunt parallel-LC network.

Return type:

rf.Network

simpleLOMs.elements.shunt_capacitor(C: float, freq: Frequency, name: str = 'ctog', Z0: float = 50) → Network[source]

Shunt (to-ground) capacitor.

Implemented as a ShuntAdmittance with Y = jωC.

Parameters:
  • C (float) – Capacitance in Farads.

  • freq (rf.Frequency) – Frequency sweep object.

  • name (str) – Label used inside rf.Circuit.

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port shunt capacitor network.

Return type:

rf.Network

Networks

networks/cpw.py

Network builders for CPW (Coplanar Waveguide) resonator topologies.

Each function takes a CPWParams dataclass for device geometry plus circuit-level parameters (coupling caps, frequency, etc.) and returns an rf.Network.

Topology overview

All networks follow the same chain:

[Port1] – Cc1 – Ctog1 – [CPW line] – Ctog2 – Cc2 – [Port2 or Open]

The “loaded” variants insert an LC resonator between the port and the coupling capacitor on each side:

[Port1] – cc_port1 – load1 – Cc1 – Ctog1 – [CPW line] – …

simpleLOMs.networks.cpw.bare_cpw_resonance_hz(d: float, cpw_params: CPWParams = None, *, f_lo: float = 1000000000.0, f_hi: float = 20000000000.0, n: int = 40001, port_z0: float = 500.0) → float[source]

Fundamental (λ/2) resonance frequency of a bare, unloaded CPW line.

This is the intrinsic open–open resonance of the transmission line itself, with no coupling or ground capacitors — the natural anchor frequency for the closed-form AnalyticalFit. Anchoring the analytical model here (rather than to the loaded circle-fit resonance, which already contains the Cc/Ctog pull) avoids double-counting the loading when get_network re-applies those capacitors.

A bare line is built from the CPW geometry, terminated in high-impedance ports, and the fundamental is located from the first peak in Re(S22) with a parabolic sub-sample refinement.

Parameters:
  • d (float) – Resonator length in metres.

  • cpw_params (CPWParams, optional) – CPW geometry / material. Defaults to CPWParams().

  • f_lo (float) – Search band in Hz (default 1–20 GHz, wide enough to contain the fundamental for the usual few-mm lengths).

  • f_hi (float) – Search band in Hz (default 1–20 GHz, wide enough to contain the fundamental for the usual few-mm lengths).

  • n (int) – Number of points in the search grid.

  • port_z0 (float) – High port impedance used to keep the line weakly loaded (default 500 Ω), matching the convention used by FosterFit.

Returns:

Bare fundamental resonance frequency in Hz.

Return type:

float

simpleLOMs.networks.cpw.cpw_line_impedance(cpw_params: CPWParams = None, f_hz: float = 8000000000.0) → float[source]

Characteristic impedance of the CPW line (Ohms) at frequency f_hz.

This is the impedance of the line geometry — distinct from the 50 Ω port/reference impedance — and is the impedance the closed-form AnalyticalFit expects (its λ/2 effective impedance is 2 Z_line / π). Dispersion is weak, so a single frequency near the resonance is sufficient.

Parameters:
  • cpw_params (CPWParams, optional) – CPW geometry / material. Defaults to CPWParams().

  • f_hz (float) – Evaluation frequency in Hz (default 8 GHz).

Returns:

Real part of the characteristic impedance in Ohms.

Return type:

float

simpleLOMs.networks.cpw.cpw_resonator_loaded_network_2port(freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, Lload1: float, Cload1: float, Lload2: float, Cload2: float, cpw_params: CPWParams = None, Z0: float = 50, cc_port: float = 1e-15) → Network[source]

Two-port CPW resonator with an LC load on each port side.

The loads model external resonators (e.g. qubits or readout resonators) weakly coupled to each port via small series capacitors. The measurement ports probe the load nodes through weak cc_port capacitors (1 fF by default), so the resonance is set by the resonator + coupling + load, not by the 50 Ω terminations. Note this differs from the bare builder cpw_resonator_network_2port(), whose ports connect through the full Cc1/Cc2 — compare loaded vs bare only under the same probe convention (e.g. this builder with a negligible load as the bare reference).

Topology:
[Port1] – cc_port1 – load1 (shunt LC) – Cc1 – Ctog1 – [CPW line]

– Ctog2 – Cc2 – load2 (shunt LC) – cc_port2 – [Port2]

Parameters:
  • freq (rf.Frequency)

  • d (float) – Resonator length in metres.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • Lload1 (float) – Inductance (H) and capacitance (F) of the load on port 1 side.

  • Cload1 (float) – Inductance (H) and capacitance (F) of the load on port 1 side.

  • Lload2 (float) – Inductance (H) and capacitance (F) of the load on port 2 side.

  • Cload2 (float) – Inductance (H) and capacitance (F) of the load on port 2 side.

  • cpw_params (CPWParams, optional) – CPW geometry. Uses default CPWParams() if not provided.

  • Z0 (float) – Reference impedance in Ohms.

  • cc_port (float) – Weak probe capacitance in Farads between each port and its load node (default 1 fF).

Returns:

2-port loaded transmission network.

Return type:

rf.Network

simpleLOMs.networks.cpw.cpw_resonator_network(freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, cpw_params: CPWParams = None, Z0: float = 50) → Network[source]

Single-port CPW resonator (reflection measurement, port + open termination).

Topology:

[Port1] – Cc1 (series) – Ctog1 (shunt) – [CPW line] – Ctog2 (shunt) – Cc2 (shunt) – [Open]

Parameters:
  • freq (rf.Frequency)

  • d (float) – Physical resonator length in metres.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • cpw_params (CPWParams, optional) – CPW geometry. Uses default CPWParams() if not provided.

  • Z0 (float) – Reference impedance in Ohms.

Returns:

1-port reflection network.

Return type:

rf.Network

simpleLOMs.networks.cpw.cpw_resonator_network_2port(freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, cpw_params: CPWParams = None, Z0: float = 50) → Network[source]

Two-port CPW resonator (transmission measurement, port on each side).

Topology:

[Port1] – Cc1 (series) – Ctog1 (shunt) – [CPW line] – Ctog2 (shunt) – Cc2 (series) – [Port2]

Parameters:
  • freq (rf.Frequency)

  • d (float) – Physical resonator length in metres.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • cpw_params (CPWParams, optional) – CPW geometry. Uses default CPWParams() if not provided.

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port transmission network.

Return type:

rf.Network

simpleLOMs.networks.cpw.cpw_resonator_single_load_network_2port(freq: Frequency, d: float, Cc1: float, Ctog1: float, Ctog2: float, Lload1: float, Cload1: float, cpw_params: CPWParams = None, Z0: float = 50, cc_port: float = 1e-15) → Network[source]

Two-port CPW resonator with a single LC load on the port-1 side only.

The load models an external resonator (e.g. a qubit or readout resonator) weakly coupled to port 1 via a small series capacitor. Port 2 taps the line through a weak probe capacitor with no load and no coupling capacitor on its path.

Topology:
[Port1] – cc_port1 – load1 (shunt LC) – Cc1 – Ctog1 – [CPW line]

– Ctog2 – cc_port2 – [Port2]

Parameters:
  • freq (rf.Frequency)

  • d (float) – Resonator length in metres.

  • Cc1 (float) – Coupling capacitance on the port-1 side in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • Lload1 (float) – Inductance (H) and capacitance (F) of the load on the port-1 side.

  • Cload1 (float) – Inductance (H) and capacitance (F) of the load on the port-1 side.

  • cpw_params (CPWParams, optional) – CPW geometry. Uses default CPWParams() if not provided.

  • Z0 (float) – Reference impedance in Ohms.

  • cc_port (float) – Weak probe capacitance in Farads between each port and the network (default 1 fF).

Returns:

2-port loaded transmission network.

Return type:

rf.Network

networks/lc.py

Network builders for lumped-element LC resonator topologies.

Topology families

Basic 2-port:

[Port1] – Cc1 – [LC shunt] – Cc2 – [Port2]

With grounds (mirrors CPW Ctog capacitors):

[Port1] – Cc1 – Ctog1 – [LC shunt] – Ctog2 – Cc2 – [Port2]

Loaded variants insert an LC load (e.g. a qubit) on each port side:

[Port1] – cc_port – load – Cc1 – … – Cc2 – load – cc_port – [Port2]

simpleLOMs.networks.lc.lc_load_bare_network(Lload: float, Cload: float, Cc_port: float, freq: Frequency, Z0: float = 50) → Network[source]

Single isolated LC load resonator coupled to one port via Cc_port. Used to extract the ‘true’ bare frequency of a load as seen from the port, accounting for the capacitive loading of the coupler.

Topology:

[Port1] – Cc_port (series) – [LC shunt] – [Open]

Parameters:
  • Lload (float) – Inductance (H) and capacitance (F) of the load resonator.

  • Cload (float) – Inductance (H) and capacitance (F) of the load resonator.

  • Cc_port (float) – Coupling capacitance to the port (F).

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

Returns:

1-port reflection network.

Return type:

rf.Network

simpleLOMs.networks.lc.lc_load_dressed_network(Lload: float, Cload: float, Cc_port: float, Cc1: float, freq: Frequency, Z0: float = 50) → Network[source]
simpleLOMs.networks.lc.lc_load_dressed_network_2(Lload: float, Cload: float, Cc_port: float, Cc1: float, freq: Frequency, Z0: float = 50) → Network[source]

Isolated LC load with both port coupler and CPW coupler attached, to extract the ‘dressed’ bare frequency accounting for capacitive loading from both sides.

Topology:

[Port1] – Cc_port (series) – [LC shunt] – Cc1 (series) – [Open]

Parameters:
  • Lload (float) – Inductance (H) and capacitance (F) of the load resonator.

  • Cload (float) – Inductance (H) and capacitance (F) of the load resonator.

  • Cc_port (float) – Port coupling capacitance (F) — hardcoded as 1e-15 in your topology.

  • Cc1 (float) – CPW-side coupling capacitance (F).

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

Returns:

1-port reflection network.

Return type:

rf.Network

simpleLOMs.networks.lc.lc_resonator_loaded_network_2port(Leff: float, Ceff: float, Cc1: float, Cc2: float, Lload1: float, Cload1: float, Lload2: float, Cload2: float, freq: Frequency, Z0: float = 50, cc_port: float = 1e-15) → Network[source]

Two-port LC resonator with LC loads on each port side.

Topology:

[Port1] – cc_port1 – load1 – Cc1 – [LC shunt] – Cc2 – load2 – cc_port2 – [Port2]

The ports probe the load nodes through weak cc_port capacitors (1 fF by default), matching the loaded CPW builders — not through the full Cc1/Cc2 as in the bare builders.

Parameters:
  • Leff (float) – Effective inductance (H) and capacitance (F) of the main resonator.

  • Ceff (float) – Effective inductance (H) and capacitance (F) of the main resonator.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Lload1 (float) – Load resonator on port 1 side.

  • Cload1 (float) – Load resonator on port 1 side.

  • Lload2 (float) – Load resonator on port 2 side.

  • Cload2 (float) – Load resonator on port 2 side.

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port loaded transmission network.

Return type:

rf.Network

simpleLOMs.networks.lc.lc_resonator_loaded_network_2port_shifted(Leff: float, Ceff: float, Cc1: float, Cc2: float, Lload1: float, Cload1: float, Lload2: float, Cload2: float, freq: Frequency, Z0: float = 50) → Network[source]

Two-port loaded LC resonator with π-phase correction on S21/S12.

Identical to lc_resonator_loaded_network_2port but negates S21/S12 to account for the missing half-wave CPW phase. See lc_resonator_network_2port_shifted for full explanation.

Topology:

[Port1] – cc_port1 – load1 – Cc1 – [LC shunt] – Cc2 – load2 – cc_port2 – [Port2] (then S21, S12 negated)

simpleLOMs.networks.lc.lc_resonator_loaded_network_with_grounds_2port(Leff: float, Ceff: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, Lload1: float, Cload1: float, Lload2: float, Cload2: float, freq: Frequency, Z0: float = 50, cc_port: float = 1e-15) → Network[source]

Two-port LC resonator with both ground capacitors and LC loads.

This is the most complete LC LOM topology: it includes the shunt Ctog capacitors that model CPW ground geometry AND external load resonators on each port side.

Topology:

[Port1] – cc_port1 – load1 – Cc1 – Ctog1 – [LC shunt] – Ctog2 – Cc2 – load2 – cc_port2 – [Port2]

Parameters:
  • Leff (float) – Effective inductance (H) and capacitance (F) of the main resonator.

  • Ceff (float) – Effective inductance (H) and capacitance (F) of the main resonator.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • Lload1 (float) – Load resonator on port 1 side.

  • Cload1 (float) – Load resonator on port 1 side.

  • Lload2 (float) – Load resonator on port 2 side.

  • Cload2 (float) – Load resonator on port 2 side.

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port fully-loaded transmission network with ground caps.

Return type:

rf.Network

simpleLOMs.networks.lc.lc_resonator_network(Leff: float, Ceff: float, Cc1: float, Cc2: float, freq: Frequency, Z0: float = 50) → Network[source]

Single-port LC resonator (reflection measurement).

Topology:

[Port1] – Cc1 (series) – [LC shunt] – Cc2 (shunt to open) – [Open]

Parameters:
  • Leff (float) – Effective inductance (H) and capacitance (F) of the LC resonator.

  • Ceff (float) – Effective inductance (H) and capacitance (F) of the LC resonator.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

Returns:

1-port reflection network.

Return type:

rf.Network

simpleLOMs.networks.lc.lc_resonator_network_2port(Leff: float, Ceff: float, Cc1: float, Cc2: float, freq: Frequency, Z0: float = 50) → Network[source]

Two-port LC resonator (transmission measurement).

Topology:

[Port1] – Cc1 (series) – [LC shunt] – Cc2 (series) – [Port2]

Parameters:
  • Leff (float) – Effective inductance (H) and capacitance (F) of the LC resonator.

  • Ceff (float) – Effective inductance (H) and capacitance (F) of the LC resonator.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port transmission network.

Return type:

rf.Network

simpleLOMs.networks.lc.lc_resonator_network_2port_shifted(Leff: float, Ceff: float, Cc1: float, Cc2: float, freq: Frequency, Z0: float = 50) → Network[source]

Two-port LC resonator with π-phase correction on S21/S12.

Identical to lc_resonator_network_2port but negates the off-diagonal S-matrix elements to account for the π electrical phase that a half-wave CPW resonator accumulates at resonance. A lumped LC shunt has no transmission line length so it does not pick up this phase naturally; the correction restores the correct sign convention for comparison against CPW reference networks.

Topology:

[Port1] – Cc1 (series) – [LC shunt] – Cc2 (series) – [Port2] (then S21, S12 negated)

simpleLOMs.networks.lc.lc_resonator_network_with_grounds_2port(Leff: float, Ceff: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, freq: Frequency, Z0: float = 50) → Network[source]

Two-port LC resonator with shunt-to-ground capacitors on each side.

These Ctog capacitors mirror the geometry of the CPW model, where the ground capacitance at each gap is an important feature of the distributed line.

Topology:

[Port1] – Cc1 – Ctog1 (shunt) – [LC shunt] – Ctog2 (shunt) – Cc2 – [Port2]

Parameters:
  • Leff (float) – Effective inductance (H) and capacitance (F) of the LC resonator.

  • Ceff (float) – Effective inductance (H) and capacitance (F) of the LC resonator.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port transmission network with ground capacitances.

Return type:

rf.Network

simpleLOMs.networks.lc.lc_resonator_single_load_network_2port(Leff: float, Ceff: float, Cc1: float, Lload1: float, Cload1: float, freq: Frequency, Z0: float = 50, cc_port: float = 1e-15) → Network[source]

Two-port LC resonator with LC loads on each port side.

Topology:

[Port1] – cc_port1 – load1 – Cc1 – [LC shunt] – Cc2 – load2 – cc_port2 – [Port2]

Parameters:
  • Leff (float) – Effective inductance (H) and capacitance (F) of the main resonator.

  • Ceff (float) – Effective inductance (H) and capacitance (F) of the main resonator.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Lload1 (float) – Load resonator on port 1 side.

  • Cload1 (float) – Load resonator on port 1 side.

  • Lload2 (float) – Load resonator on port 2 side.

  • Cload2 (float) – Load resonator on port 2 side.

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

  • cc_port (float) – Weak probe capacitance in Farads on each port (default 1 fF).

Returns:

2-port loaded transmission network.

Return type:

rf.Network

simpleLOMs.networks.lc.lc_resonator_single_load_network_with_grounds_2port(Leff: float, Ceff: float, Cc1: float, Ctog1: float, Ctog2: float, Lload1: float, Cload1: float, freq: Frequency, Z0: float = 50, cc_port: float = 1e-15) → Network[source]

Two-port LC resonator with both ground capacitors and LC loads.

This is the most complete LC LOM topology: it includes the shunt Ctog capacitors that model CPW ground geometry AND external load resonators on each port side.

Topology:

[Port1] – cc_port1 – load1 – Cc1 – Ctog1 – [LC shunt] – Ctog2 – Cc2 – load2 – cc_port2 – [Port2]

Parameters:
  • Leff (float) – Effective inductance (H) and capacitance (F) of the main resonator.

  • Ceff (float) – Effective inductance (H) and capacitance (F) of the main resonator.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • Lload1 (float) – Load resonator on port 1 side.

  • Cload1 (float) – Load resonator on port 1 side.

  • Lload2 (float) – Load resonator on port 2 side.

  • Cload2 (float) – Load resonator on port 2 side.

  • freq (rf.Frequency)

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port fully-loaded transmission network with ground caps.

Return type:

rf.Network

networks/chain.py

Network builder for a chain of capacitively-coupled resonators — the “resonator network” that Tutorial 3 builds.

A single resonator in this project is the ladder

– Cc – Ctog – [segment] – Ctog – Cc –

where [segment] is either a CPW transmission line (the ground truth) or a lumped parallel-LC tank (a fitted LOM). A chain strings several of these together, sharing one coupling capacitor between neighbours:

[P1] – Cc0 – Ctog0 – seg0 – Ctog1 – Cc1 – Ctog2 – seg1 – Ctog3 – Cc2 – … – CcN – [P2]

This one builder covers every chain Tutorial 3 needs:

  • all-CPW segments -> the distributed ground-truth network,

  • all-LC segments -> the reassembled lumped network,

  • any mixture -> swap individual resonators as you like.

Because OptimizedFit folds the ground capacitance into its effective L, C (see the topology note in Tutorial 2), the lumped chain is built with no Ctog caps — just pass Ctogs=None (the default) and only the coupling capacitors survive between the LC tanks.

simpleLOMs.networks.chain.resonator_chain_network_2port(freq: Frequency, segments: Sequence[Dict[str, Any]], Ccs: Sequence[float], Ctogs: Sequence[float] | None = None, cpw_params: CPWParams = None, Z0: float = 50) → Network[source]

Two-port chain of capacitively-coupled resonators.

Topology:

[P1] -- Cc[0] -- Ctog[0] -- seg[0] -- Ctog[1] -- Cc[1] -- Ctog[2]
        -- seg[1] -- Ctog[3] -- Cc[2] -- ... -- Cc[n] -- [P2]

Each segment is flanked by two shunt-to-ground capacitors and separated from its neighbours by a shared coupling capacitor.

Parameters:
  • freq (rf.Frequency)

  • segments (sequence of dict) –

    One dict per resonator. Each is either

    • {"kind": "cpw", "d": <length_m>} — a CPW transmission line, or

    • {"kind": "lc", "L": <H>, "C": <F>} — a lumped parallel-LC tank.

  • Ccs (sequence of float) – Coupling capacitances in Farads. Length must be len(segments) + 1 (one before each segment plus one after the last).

  • Ctogs (sequence of float, optional) – Shunt-to-ground capacitances in Farads, two per segment ([left0, right0, left1, right1, ...]), so length 2 * n. A value of 0 (or None for the whole list) omits that ground cap — use Ctogs=None for a lumped chain whose L, C already absorb the grounds (e.g. OptimizedFit).

  • cpw_params (CPWParams, optional) – CPW geometry for the "cpw" segments. Defaults to CPWParams().

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port transmission network for the whole chain.

Return type:

rf.Network

networks/hanger.py

Network builder for hanger / notch resonators — resonators that hang off a continuous through feedline, rather than sitting inline on the rail the way the resonators in simpleLOMs.networks.chain do.

Topology:

[P1] ───┬──────────────┬───────────── [P2]      ← through feedline
        │              │
       Cc[0]          Cc[1]                       ← tap coupling caps
        │              │
     [seg 0]        [seg 1]                       ← resonator, to ground
        │              │
       ─┴─            ─┴─   (ground)

The signal travels past each resonator, so each one puts a notch (dip) in the transmission S21 at its resonance instead of a peak.

Each hanging resonator is one of

  • {"kind": "lc",  "L": <H>, "C": <F>}
    — a lumped parallel-LC tank (the LOM branch). Built with

    simpleLOMs.elements.hanger_lc_branch(). For best accuracy, obtain L, C from HangerOptimizedFit (or fit_lom_hanger()), which fits against a CPW hanger. Rewiring an inline OptimizedFit (L, C) into a hanger is a convenient approximation (few-percent notch error), not an identity.

  • {"kind": "cpw", "d": <length_m>, "termination": "short" | "open"}
    — a distributed CPW line (the ground-truth branch). A short-terminated

    line is the usual λ/4 hanger; an open-terminated line is the λ/2 variant.

Electrically each branch (tap Cc in series with the grounded resonator) collapses to a single ShuntAdmittance, so a hanger drops straight into the same ladder assembly the rest of the package already uses.

simpleLOMs.networks.hanger.hanger_resonator_network_2port(freq: Frequency, segments: Sequence[Dict[str, Any]], Ccs: Sequence[float], feed_lengths: Sequence[float] | None = None, cpw_params: CPWParams = None, Z0: float = 50) → Network[source]

Two-port through feedline with one or more resonators hanging off it.

Parameters:
  • freq (rf.Frequency)

  • segments (sequence of dict) –

    One dict per hanging resonator. Each is either

    • {"kind": "lc",  "L": <H>, "C": <F>} — a lumped LC tank, or

    • {"kind": "cpw", "d": <length_m>, "termination": "short"|"open"} — a distributed CPW line (termination defaults to "short").

  • Ccs (sequence of float) – Tap coupling capacitances in Farads, one per segment (len(Ccs) == len(segments)).

  • feed_lengths (sequence of float, optional) – CPW feedline lengths in metres, len(segments) + 1 of them: one before the first tap, one between each pair of taps, and one after the last. A value of 0 (or None for the whole list) makes that section an ideal wire — feed_lengths=None gives a fully ideal feedline (a single-hanger notch demo needs nothing more).

  • cpw_params (CPWParams, optional) – CPW geometry for the "cpw" branches and any non-zero feedline sections. Defaults to CPWParams().

  • Z0 (float) – Reference impedance in Ohms.

Returns:

2-port transmission network for the feedline plus its hangers.

Return type:

rf.Network

models/hanger_optimized_fit.py

HangerOptimizedFit: numerical optimisation of effective L, C against a hanger / notch CPW ground-truth network (S21 dip), rather than an inline transmission resonator.

This is the hanger counterpart to OptimizedFit. Inline OptimizedFit remains unchanged; do not rewire its (L, C) into a hanger when accuracy matters — fit against the hanger topology instead.

class simpleLOMs.models.hanger_optimized_fit.HangerOptimizedFit(config: OptimizationConfig | None = None)[source]

Bases: BaseFit

Lumped LC hanger model via least-squares fit to a CPW hanger S21 notch.

Algorithm

  1. Seed (L, C) from Foster synthesis on the bare CPW length d.

  2. Stage 1 — 1-D notch match: hold the Foster tank impedance Z = sqrt(L/C) fixed and scan the bare tank frequency so the LC hanger notch lands on the CPW notch.

  3. Stage 2 — windowed least_squares on |S21| (and optionally a global phase) with a wide notch window, freeing L and C.

param config:

Reuses the same knobs as inline OptimizedFit (n_widths, max_nfev, fit_phase, …). Channel selection is ignored — residuals always target S21.

type config:

OptimizationConfig, optional

fit(freq: Frequency, data_ntw: Network, Cc_tap: float, d: float, cpw_params, termination: str = 'open', Z0: float = 50.0, **kwargs) → None[source]

Fit L, C so an LC hanger reproduces the CPW hanger S21 notch.

Parameters:
  • freq (rf.Frequency) – Optimisation grid (should span the notch with enough points).

  • data_ntw (rf.Network) – 2-port CPW hanger reference (typically from hanger_resonator_network_2port with kind="cpw").

  • Cc_tap (float) – Tap coupling capacitance in Farads (same value used in the GT).

  • d (float) – Resonator length in metres (used to seed Foster L, C).

  • cpw_params (CPWParams) – CPW geometry for the Foster seed.

  • termination ({"open", "short"}) – Far-end termination of the reference hanger (API / documentation; already encoded in data_ntw).

  • Z0 (float) – Reference impedance in Ohms.

get_network(freq: Frequency, Cc_tap: float | None = None, Z0: float | None = None, show: bool = False, reference: Network | None = None, m: int = 1, n: int = 0, lom_label: str = 'HangerOptimizedFit', data_label: str = 'CPW hanger', save_path: str | None = None, **kwargs) → Network[source]

Build the fitted LC hanger 2-port network.

get_params() → dict[source]

Return the fitted parameters as a plain dictionary.

At minimum returns {“L”: self.L, “C”: self.C}. Subclasses may include additional diagnostics.

Return type:

dict

Plotting

plotting.py

Plotting functions for notebooks or scripts after running fits.

Axis labels follow the convention Title, $variable$ (Unit) when a named physical quantity is plotted (e.g. Resonant frequency, $f_0$ (GHz)). Residual / expression-style labels keep bare math with no title prefix.

simpleLOMs.plotting.apply_style() → None[source]

(Re)apply the shared simpleLOMs figure style to plt.rcParams.

Importing this module already applies the style once. Call this if some other code (or a notebook cell) has since clobbered rcParams and you want the standard look back.

simpleLOMs.plotting.axis_label(title: str, symbol: str | None = None, unit: str | None = None) → str[source]

Format an axis label as Title, $symbol$ (Unit).

This is the house convention for every named physical quantity. If symbol is None, returns Title (Unit) or just Title. Pure expression-style labels (e.g. Re(S11)) keep bare math and do not use this helper.

simpleLOMs.plotting.fancy_plot(lom_network: Network, data_network: Network, m: int = 0, n: int = 0, lom_label: str = 'LOM', data_label: str = 'Data', title: str = None, show: bool = True, save_path: str = None)

Overlay Re and Im of a fitted LOM network against a reference (data/CPW).

Parameters:
  • lom_network (rf.Network) – The fitted lumped-element model.

  • data_network (rf.Network) – The reference (measured or CPW simulation).

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • lom_label (str) – Legend labels.

  • data_label (str) – Legend labels.

  • title (str, optional) – Super-title for the figure.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional) – If provided, save the figure to this path.

Return type:

fig, axes

simpleLOMs.plotting.fancy_plot_all_models(networks: dict[str, Network], m: int = 0, n: int = 0, quantity: str = 're', title: str = None, xlim: tuple = None, show: bool = True, save_path: str = None)

Plot one S-parameter quantity for multiple networks on a single axes.

Useful for comparing CPW, FosterFit, OptimizedFit, and AnalyticalFit in one call.

Parameters:
  • networks (dict[str, rf.Network]) – Mapping of label → network.

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • quantity ({"re", "im", "db", "abs"}) – Which quantity to plot.

  • title (str, optional) – Plot title.

  • xlim (tuple, optional) – (fmin, fmax) in GHz to zoom the frequency axis around a resonance. When omitted the full frequency span of the networks is shown.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, ax

simpleLOMs.plotting.plot_all_models(networks: dict[str, Network], m: int = 0, n: int = 0, quantity: str = 're', title: str = None, xlim: tuple = None, show: bool = True, save_path: str = None)[source]

Plot one S-parameter quantity for multiple networks on a single axes.

Useful for comparing CPW, FosterFit, OptimizedFit, and AnalyticalFit in one call.

Parameters:
  • networks (dict[str, rf.Network]) – Mapping of label → network.

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • quantity ({"re", "im", "db", "abs"}) – Which quantity to plot.

  • title (str, optional) – Plot title.

  • xlim (tuple, optional) – (fmin, fmax) in GHz to zoom the frequency axis around a resonance. When omitted the full frequency span of the networks is shown.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, ax

simpleLOMs.plotting.plot_complex_network_comparison(network1: Network, network2: Network, label1: str = 'Network 1', label2: str = 'Network 2', color1: str = '#1f77b4', color2: str = '#d62728', title: str = None, show: bool = True, save_path: str = None)[source]

Compare two networks in magnitude, phase, and IQ plane (S21).

simpleLOMs.plotting.plot_curve_pair(x, y0, y1, *, xlabel: str | None = None, ylabel0: str | None = None, ylabel1: str | None = None, title0: str | None = None, title1: str | None = None, title: str | None = None, xscale: str = 'linear', yscale: str = 'linear', yscale0: str | None = None, yscale1: str | None = None, color0=None, color1=None, marker: str = 'o-', grid: bool = True, show: bool = True, save_path: str | None = None)[source]

Plot two y series against a shared x in a 1×2 figure.

Per-panel titles default to None (no title). title is applied as fig.suptitle only when given.

Return type:

fig, axes

simpleLOMs.plotting.plot_curves(x=None, *ys, xlabel: str | None = None, ylabel: str | None = None, title: str | None = None, xscale: str = 'linear', yscale: str = 'linear', color=None, colors=None, fmt: str | None = None, ax=None, grid: bool = True, xlim=None, ylim=None, hline=None, vline=None, point=None, show: bool = True, save_path: str | None = None, **plot_kwargs)[source]

Plot one or more y series.

x is a shared abscissa. Each positional series may be an array, (y, label), (y, label, style_dict), or (x, y, label, style_dict) for an independent frequency / parameter axis. Optional hline / vline / point mark a design target in COLOR_HIGHLIGHT (hline/vline accept a scalar or a sequence).

Return type:

fig, ax

simpleLOMs.plotting.plot_error_heatmap(results_grid: list[list[dict]], param1_values, param2_values, param1_label: str, param2_label: str, model: str, metric: str, param1_scale: float = 1.0, param2_scale: float = 1.0, param1_unit: str = '', param2_unit: str = '', vmin: float = None, vmax: float = None, cmap: str = 'RdBu_r', title: str = None, ax=None, show: bool = True, save_path: str = None)[source]

Heatmap of signed percent error from a 2D grid of analyze_system() runs.

Return type:

matplotlib.image.AxesImage

simpleLOMs.plotting.plot_error_heatmap_trio(results_grid: list[list[dict | None]], param1_values, param2_values, param1_label: str, param2_label: str, metric: str, param1_scale: float = 1.0, param2_scale: float = 1.0, param1_unit: str = '', param2_unit: str = '', cmap: str = 'RdBu_r', title: str = None, show: bool = True, save_path: str = None)[source]

Three-panel error heatmap for optimized / foster / analytical.

simpleLOMs.plotting.plot_fit_residuals(data_ntw, lom_networks: dict, m: int = 0, n: int = 0, title: str = None, show: bool = True, save_path: str = None)

Plot the complex residual S_lom - S_data for one or more LOM networks.

Residuals are shown as Re and Im separately. A perfect fit is a flat zero line.

Parameters:
  • data_ntw (rf.Network) – Reference (CPW or measured) network.

  • lom_networks (dict[str, rf.Network]) – Mapping of label → fitted LOM network.

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • title (str, optional)

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, axes

simpleLOMs.plotting.plot_fit_summary(results: dict, port: str = 's11', title: str = None, show: bool = True, save_path: str = None)

Three-panel summary of fitting quality for all three LC models vs CPW.

Panels:

Left — Overlay of Re(S) for CPW + all three models Centre — f₀ and κ percent errors as a grouped bar chart Right — Complex residual magnitude |S_lom - S_cpw| across the window

Parameters:
  • results (dict) – Output dict from analyze_system().

  • port ({"s11", "s22"}) – Which reflection port to summarise.

  • title (str, optional)

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, axes

simpleLOMs.plotting.plot_heatmaps(x, y, grids: dict, *, xlabel: str | None = None, ylabel: str | None = None, cbar_label: str | None = None, title: str | None = None, titles: dict | None = None, norm: str = 'log', cmap: str = 'viridis', xscale: str = 'log', yscale: str = 'log', show: bool = True, save_path: str | None = None)[source]

Side-by-side heatmaps of 2-D grids that share x / y and a color scale.

Parameters:
  • x (array-like) – Bin centers along each axis (e.g. coupling capacitances in fF). Cell edges are inferred from midpoints (log or linear spacing).

  • y (array-like) – Bin centers along each axis (e.g. coupling capacitances in fF). Cell edges are inferred from midpoints (log or linear spacing).

  • grids (dict[str, ndarray]) – Mapping of panel label → 2-D array with shape (len(y), len(x)).

  • xlabel (str, optional) – Axis / colorbar labels.

  • ylabel (str, optional) – Axis / colorbar labels.

  • cbar_label (str, optional) – Axis / colorbar labels.

  • title (str, optional) – Figure super-title (default: none).

  • titles (dict, optional) – Optional per-panel title overrides keyed like grids.

  • norm ({"log", "linear"}) – Shared color normalization across panels.

  • cmap – Matplotlib colormap and axis scales.

  • xscale – Matplotlib colormap and axis scales.

  • yscale – Matplotlib colormap and axis scales.

Return type:

fig, axes

simpleLOMs.plotting.plot_lom_vs_data(lom_network: Network, data_network: Network, m: int = 0, n: int = 0, lom_label: str = 'LOM', data_label: str = 'Data', title: str = None, show: bool = True, save_path: str = None)[source]

Overlay Re and Im of a fitted LOM network against a reference (data/CPW).

Parameters:
  • lom_network (rf.Network) – The fitted lumped-element model.

  • data_network (rf.Network) – The reference (measured or CPW simulation).

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • lom_label (str) – Legend labels.

  • data_label (str) – Legend labels.

  • title (str, optional) – Super-title for the figure.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional) – If provided, save the figure to this path.

Return type:

fig, axes

simpleLOMs.plotting.plot_lom_vs_data_re_im(lom_network: Network, data_network: Network, m: int = 0, n: int = 0, lom_label: str = 'LOM', data_label: str = 'Data', title: str = None, show: bool = True, save_path: str = None)

Overlay Re and Im of a fitted LOM network against a reference (data/CPW).

Parameters:
  • lom_network (rf.Network) – The fitted lumped-element model.

  • data_network (rf.Network) – The reference (measured or CPW simulation).

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • lom_label (str) – Legend labels.

  • data_label (str) – Legend labels.

  • title (str, optional) – Super-title for the figure.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional) – If provided, save the figure to this path.

Return type:

fig, axes

simpleLOMs.plotting.plot_pole_fit(network: Network, pole: complex, title: str = None, show: bool = True, save_path: str = None)[source]

Plot magnitude, phase, and IQ circle for a pole fit of S21.

simpleLOMs.plotting.plot_re_im(network: Network, m: int = 0, n: int = 0, title: str = None, show: bool = True, save_path: str = None)[source]

Plot Re(S[m,n]) and Im(S[m,n]) side by side.

Parameters:
  • network (rf.Network)

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • title (str, optional) – Super-title for the figure.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional) – If provided, save the figure to this path.

Return type:

fig, axes

simpleLOMs.plotting.plot_residuals(data_ntw, lom_networks: dict, m: int = 0, n: int = 0, title: str = None, show: bool = True, save_path: str = None)[source]

Plot the complex residual S_lom - S_data for one or more LOM networks.

Residuals are shown as Re and Im separately. A perfect fit is a flat zero line.

Parameters:
  • data_ntw (rf.Network) – Reference (CPW or measured) network.

  • lom_networks (dict[str, rf.Network]) – Mapping of label → fitted LOM network.

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • title (str, optional)

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, axes

simpleLOMs.plotting.plot_s_residual(networks: dict, ref: Network, m: int = 1, n: int = 0, title: str = None, ylabel: str = None, xlim=None, quantity: str = 'db', show: bool = True, save_path: str = None)[source]

Plot Δ|S_mn| of each network relative to a reference network.

Parameters:
  • networks (dict[str, rf.Network]) – Mapping of label → network to compare against ref.

  • ref (rf.Network) – Reference network (e.g. HFSS or CPW ground truth).

  • m (int) – S-parameter indices (0-based). Default S21 as s[:, 1, 0].

  • n (int) – S-parameter indices (0-based). Default S21 as s[:, 1, 0].

  • title (str, optional) – Axis title (default: none).

  • ylabel (str, optional) – Override default residual ylabel.

  • xlim (tuple, optional) – (fmin, fmax) in GHz.

  • quantity ({"db", "abs"}) – Residual of dB magnitudes or linear magnitudes.

  • show – Standard finish options.

  • save_path – Standard finish options.

Return type:

fig, ax

simpleLOMs.plotting.plot_scan(model_or_scan, title: str = None, show: bool = True, save_path: str = None)[source]

Plot OptimizedFit Stage-1 ω₀ scan (SSE vs resonant frequency).

Parameters:
  • model_or_scan (OptimizedFit or array-like) – An OptimizedFit instance (reads get_params()["scan_results"]) or a raw scan array of shape (n_w0, 4) with columns [ω0, Ceff, Leff, sse].

  • title (str, optional) – Axis title. Default is a short technical Stage-1 label.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, ax

simpleLOMs.plotting.plot_shift_errors(results: dict, title: str = None, show: bool = True, save_path: str = None)[source]

Grouped bar chart of hybridized mode shift errors vs CPW reference.

simpleLOMs.plotting.plot_summary(results: dict, port: str = 's11', title: str = None, show: bool = True, save_path: str = None)[source]

Three-panel summary of fitting quality for all three LC models vs CPW.

Panels:

Left — Overlay of Re(S) for CPW + all three models Centre — f₀ and κ percent errors as a grouped bar chart Right — Complex residual magnitude |S_lom - S_cpw| across the window

Parameters:
  • results (dict) – Output dict from analyze_system().

  • port ({"s11", "s22"}) – Which reflection port to summarise.

  • title (str, optional)

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, axes

simpleLOMs.plotting.plot_transmission(networks: dict, m: int = 0, n: int = 1, annotate_resonances: bool = False, prominence: float = 3.0, title: str = None, quantity: str = 'db', ylabel: str = None, xlim=None, panels=None, center: float = None, half_width: float = 0.35, show: bool = True, save_path: str = None)[source]

Plot |S_mn| for one or more networks.

Parameters:
  • networks (dict[str, rf.Network]) – Mapping of label → network.

  • m (int) – S-parameter indices (0-based). Default S21 (0,1).

  • n (int) – S-parameter indices (0-based). Default S21 (0,1).

  • annotate_resonances (bool) – If True, marks each resonance with a vertical line and frequency label. Default False — annotations are opt-in because automatic dip detection is unreliable for multi-mode / chain spectra.

  • prominence (float) – Minimum prominence in dB for peak/dip detection (used only when annotate_resonances and quantity="db").

  • title (str, optional) – Axis / figure title. Default is a short $|S_{mn}|$ label when panels is None; with a zoom panel, titles are omitted unless given (applied as fig.suptitle).

  • quantity ({"db", "abs"}) – Plot 20 log10 |S| (default) or linear magnitude.

  • ylabel (str, optional) – Override the default y-axis label.

  • xlim (tuple, optional) – (fmin, fmax) in GHz for a single-panel plot.

  • panels ({None, "zoom"}) – If "zoom", draw full-band and zoomed panels side by side. Zoom uses center ± half_width (GHz).

  • center (float) – Zoom window for panels="zoom". center defaults to the mid-band frequency of the first network when omitted.

  • half_width (float) – Zoom window for panels="zoom". center defaults to the mid-band frequency of the first network when omitted.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, ax or fig, axes

simpleLOMs.plotting.plot_transmission_spectrum(networks: dict, m: int = 0, n: int = 1, annotate_resonances: bool = False, prominence: float = 3.0, title: str = None, quantity: str = 'db', ylabel: str = None, xlim=None, panels=None, center: float = None, half_width: float = 0.35, show: bool = True, save_path: str = None)

Plot |S_mn| for one or more networks.

Parameters:
  • networks (dict[str, rf.Network]) – Mapping of label → network.

  • m (int) – S-parameter indices (0-based). Default S21 (0,1).

  • n (int) – S-parameter indices (0-based). Default S21 (0,1).

  • annotate_resonances (bool) – If True, marks each resonance with a vertical line and frequency label. Default False — annotations are opt-in because automatic dip detection is unreliable for multi-mode / chain spectra.

  • prominence (float) – Minimum prominence in dB for peak/dip detection (used only when annotate_resonances and quantity="db").

  • title (str, optional) – Axis / figure title. Default is a short $|S_{mn}|$ label when panels is None; with a zoom panel, titles are omitted unless given (applied as fig.suptitle).

  • quantity ({"db", "abs"}) – Plot 20 log10 |S| (default) or linear magnitude.

  • ylabel (str, optional) – Override the default y-axis label.

  • xlim (tuple, optional) – (fmin, fmax) in GHz for a single-panel plot.

  • panels ({None, "zoom"}) – If "zoom", draw full-band and zoomed panels side by side. Zoom uses center ± half_width (GHz).

  • center (float) – Zoom window for panels="zoom". center defaults to the mid-band frequency of the first network when omitted.

  • half_width (float) – Zoom window for panels="zoom". center defaults to the mid-band frequency of the first network when omitted.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional)

Return type:

fig, ax or fig, axes

simpleLOMs.plotting.upgraded_plot_lom_vs_data_re_im(lom_network: Network, data_network: Network, m: int = 0, n: int = 0, lom_label: str = 'LOM', data_label: str = 'Data', title: str = None, show: bool = True, save_path: str = None)

Overlay Re and Im of a fitted LOM network against a reference (data/CPW).

Parameters:
  • lom_network (rf.Network) – The fitted lumped-element model.

  • data_network (rf.Network) – The reference (measured or CPW simulation).

  • m (int) – S-parameter indices (0-based).

  • n (int) – S-parameter indices (0-based).

  • lom_label (str) – Legend labels.

  • data_label (str) – Legend labels.

  • title (str, optional) – Super-title for the figure.

  • show (bool) – If True (default), call plt.show().

  • save_path (str, optional) – If provided, save the figure to this path.

Return type:

fig, axes

Sweeps

class simpleLOMs.sweeps.SweepConfig(cpw_params: CPWParams, freq: Frequency, d: float, Cc1: float, Cc2: float, Ctog1: float, Ctog2: float, Lload1: float, Cload1: float, Lload2: float, Cload2: float, Z0: float = 50.0, analytical_Z0: float | None = None, opt_config: OptimizationConfig | None = None)[source]

Bases: object

A complete snapshot of a device and its operating conditions.

Every parameter that any sweep might want to vary is a field here. The sweep machinery calls dataclasses.replace(config, field=new_value) to create a modified copy at each sweep point — the original is never mutated.

Parameters:
  • cpw_params (CPWParams) – Physical geometry of the CPW line.

  • freq (rf.Frequency) – Frequency sweep used for network construction. Should be wide enough to contain all resonances of interest.

  • d (float) – Resonator length in metres.

  • Cc1 (float) – Coupling capacitances in Farads.

  • Cc2 (float) – Coupling capacitances in Farads.

  • Ctog1 (float) – Shunt-to-ground capacitances in Farads.

  • Ctog2 (float) – Shunt-to-ground capacitances in Farads.

  • Lload1 (float) – Inductance (H) and capacitance (F) of the load on port 1 side.

  • Cload1 (float) – Inductance (H) and capacitance (F) of the load on port 1 side.

  • Lload2 (float) – Inductance (H) and capacitance (F) of the load on port 2 side.

  • Cload2 (float) – Inductance (H) and capacitance (F) of the load on port 2 side.

  • Z0 (float) – Reference impedance in Ohms (default 50 Ω).

  • analytical_Z0 (float or None) – Characteristic impedance used in the AnalyticalFit formula. If None, Z0 is used.

  • opt_config (OptimizationConfig or None) – Hyperparameters for OptimizedFit. Uses defaults if None.

Examples

Creating a base config:

base = SweepConfig(
    cpw_params=CPWParams(),
    freq=rf.Frequency(4e9, 12e9, 10_001, unit="Hz"),
    d=7e-3,
    Cc1=5e-15, Cc2=5e-15,
    Ctog1=1e-14, Ctog2=1e-14,
    Lload1=5e-10, Cload1=6e-13,
    Lload2=5e-10, Cload2=6e-13,
)

Manually overriding one field:

longer = dataclasses.replace(base, d=9e-3)
Cc1: float
Cc2: float
Cload1: float
Cload2: float
Ctog1: float
Ctog2: float
Lload1: float
Lload2: float
Z0: float = 50.0
analytical_Z0: float | None = None
cpw_params: CPWParams
d: float
freq: Frequency
opt_config: OptimizationConfig | None = None
simpleLOMs.sweeps.measure_sweep(values, measure) → dict[source]

Apply measure(v) -> dict at each value and return column arrays.

This is the small reusable helper used by the tutorials for knobs that are not SweepConfig fields (e.g. a CPW gap via dataclasses.replace).

Parameters:
  • values (array-like) – Sweep points.

  • measure (callable) – measure(v) must return a dict of scalar results.

Returns:

One array per measured key, plus "value" holding the swept inputs.

Return type:

dict[str, np.ndarray]

simpleLOMs.sweeps.sweep(param: str, values: ndarray, base_config: SweepConfig, extract: list[str], model: str = 'cpw', refit: bool | None = None) → DataFrame[source]

Sweep a single parameter across a range of values and extract quantities.

At each sweep point, the chosen model is either rebuilt from scratch (for CPW or when the swept parameter changes L/C) or reuses the L/C fitted at the first sweep point (for Cc, Ctog, and load parameters).

Parameters:
  • param (str) – Name of the SweepConfig field to vary. Must be an attribute of SweepConfig, e.g. “d”, “Cc1”, “Cc2”, “Ctog1”, “Lload1”, “Cload1”. Use “Lload1_Lload2” or “Cload1_Cload2” to sweep both loads together.

  • values (np.ndarray) – Array of values for the swept parameter.

  • base_config (SweepConfig) – Fixed device state. Not mutated.

  • extract (list of str) –

    Quantities to compute at each sweep point. Supported values:

    ”f0_s11”

    S11 resonance frequency (GHz)

    ”f0_s22”

    S22 resonance frequency (GHz)

    ”kappa_s11”

    S11 linewidth / FWHM (MHz)

    ”kappa_s22”

    S22 linewidth / FWHM (MHz)

    ”Q_s11”

    Quality factor from S11 = f0 / kappa

    ”Q_s22”

    Quality factor from S22

  • model (str) – Which model to use: “cpw” (default), “foster”, “optimized”, or “analytical”.

  • refit (bool or None) – Whether to re-fit the LC model at every sweep point. None (default) means automatic: refit when sweeping a parameter in {d, cpw_params}, reuse L/C otherwise. Setting refit=True forces refitting at every point (slower but safer when sweeping Cc1/Cc2 with OptimizedFit). Setting refit=False always reuses the first-point L/C (fastest).

Returns:

One row per sweep point. Columns are the swept parameter value plus all requested extract quantities.

Return type:

pd.DataFrame

Examples

Sweep resonator length with CPW ground truth:

df = sweep("d", np.linspace(5e-3, 10e-3, 20), base,
           extract=["f0_s11", "kappa_s11"])

Sweep coupling cap with FosterFit (reuses L/C — fast):

df = sweep("Cc1", np.linspace(1e-15, 20e-15, 30), base,
           extract=["f0_s11", "kappa_s11", "Q_s11"],
           model="foster")
simpleLOMs.sweeps.sweep_coupling(Cc_values: ndarray, base_config: SweepConfig, extract: list[str] = None, model: str = 'cpw', symmetric: bool = True, refit: bool = False) → DataFrame[source]

Sweep coupling capacitor(s).

Parameters:
  • Cc_values (np.ndarray) – Array of coupling capacitance values in Farads.

  • base_config (SweepConfig)

  • extract (list of str, optional) – Defaults to [“f0_s11”, “kappa_s11”, “Q_s11”] if not provided.

  • model (str) – “cpw” (default), “foster”, “optimized”, or “analytical”.

  • symmetric (bool) – If True (default), sweeps Cc1 and Cc2 together. If False, sweeps only Cc1 and leaves Cc2 fixed.

  • refit (bool) – Whether to re-fit the LC model at every point. Default False because Cc does not change L or C — reusing is valid and fast. Set to True if you suspect OptimizedFit is sensitive to Cc during Stage 1 (unlikely but possible for very asymmetric coupling).

Returns:

Columns: “Cc” (the swept value), plus all extract quantities.

Return type:

pd.DataFrame

simpleLOMs.sweeps.sweep_length(d_values: ndarray, base_config: SweepConfig, extract: list[str] = None, model: str = 'cpw') → DataFrame[source]

Sweep resonator length d.

Always refits the model at every point because d directly sets L and C.

Parameters:
  • d_values (np.ndarray) – Array of resonator lengths in metres.

  • base_config (SweepConfig)

  • extract (list of str, optional) – Defaults to [“f0_s11”, “kappa_s11”] if not provided.

  • model (str) – “cpw” (default), “foster”, “optimized”, or “analytical”.

Returns:

Columns: “d”, plus all extract quantities.

Return type:

pd.DataFrame

simpleLOMs.sweeps.sweep_load_frequency(f_load_values: ndarray, base_config: SweepConfig, extract: list[str] = None, model: str = 'cpw', side: str = 'both', load_impedance: float = 50.0, refit: bool = False) → DataFrame[source]

Sweep the bare load resonance frequency.

Converts each target frequency to a (L, C) pair by fixing the load characteristic impedance Z_load = sqrt(L/C), then sweeping C = 1/(ω²L).

Parameters:
  • f_load_values (np.ndarray) – Array of target load resonance frequencies in Hz.

  • base_config (SweepConfig)

  • extract (list of str, optional) – Defaults to [“f0_s11”, “shift_mode1”, “shift_mode2”, “shift_mode3”].

  • model (str) – “cpw” (default), “foster”, “optimized”, or “analytical”.

  • side ({"both", "1", "2"}) – Which load to sweep. “both” sweeps load 1 and load 2 together (useful when the two loads are identical, e.g. symmetric qubits).

  • load_impedance (float) – Characteristic impedance of the load resonator in Ohms. Used to fix L from Z_load = sqrt(L/C) → L = Z_load / ω₀. Default 50 Ω.

  • refit (bool) – Whether to re-fit the LC model at every point. Default False.

Returns:

Columns: “f_load_GHz” (the swept load frequency in GHz), “Lload” (H), “Cload” (F), plus all extract quantities.

Return type:

pd.DataFrame

Readout

readout.py

Translate a fitted lumped oscillator model (LOM) into the readout / circuit-QED figures of merit that superconducting-qubit designers actually work with.

Every model in simpleLOMs (FosterFit, OptimizedFit, AnalyticalFit) reduces a distributed CPW resonator to an effective inductance L and capacitance C. Those two numbers, plus the loaded linewidth kappa extracted from an S-parameter fit, are enough to compute the quantities a designer targets:

  • resonance frequency f_r = 1 / (2 pi sqrt(L C))

  • characteristic impedance Z_r = sqrt(L / C)

  • loaded quality factor Q = f_r / kappa

  • photon lifetime tau = 1 / (2 pi kappa)

  • zero-point voltage V_zpf = sqrt(hbar omega_r / (2 C))

  • zero-point current I_zpf = sqrt(hbar omega_r / (2 L))

This module is a thin, well-tested layer on top of what the models already return – it does not do any fitting itself. Use resonator_readout_params() when you already have L and C (e.g. from model.get_params()), and extract_f0_kappa() when you want to measure f_r and kappa directly from a device geometry via a robust circle fit.

Examples

From a fitted model:

from simpleLOMs import FosterFit, CPWParams, resonator_readout_params

model = FosterFit(cpw_params=CPWParams())
model.fit(freq, d=7e-3)
rp = resonator_readout_params(model.L, model.C, kappa_Hz=2.4e6)
print(rp)                      # human-readable summary
print(rp.Z_r_ohm, rp.Q)       # individual quantities

Measuring f_r and kappa straight from geometry:

from simpleLOMs import CPWParams, extract_f0_kappa

f0, kappa = extract_f0_kappa(CPWParams(), d=7e-3, Cc=6e-15)
simpleLOMs.readout.HBAR = 1.054571817e-34

Reduced Planck constant (J s).

class simpleLOMs.readout.ReadoutParams(L: float, C: float, kappa_Hz: float | None = None)[source]

Bases: object

Readout / circuit-QED figures of merit for a single lumped resonator mode.

All stored quantities are in SI base units. Use the derived properties (f_r_GHz, Z_r_ohm …) or summary() for human-friendly values.

L

Effective inductance (H).

Type:

float

C

Effective capacitance (F).

Type:

float

kappa_Hz

Loaded linewidth (FWHM) in Hz. None if no linewidth was supplied, in which case the loss-dependent quantities (Q, tau_photon) are None.

Type:

float or None

C: float
property I_zpf: float

Zero-point current fluctuation sqrt(hbar omega_r / 2L) (A).

L: float
property Q: float | None

Loaded quality factor Q = f_r / kappa, or None if kappa is unknown.

property V_zpf: float

Zero-point voltage fluctuation sqrt(hbar omega_r / 2C) (V).

property Z_r_ohm: float

Characteristic impedance Z_r = sqrt(L / C) (Ohms).

property f_r_GHz: float

Resonance frequency in GHz.

property f_r_Hz: float

Resonance frequency f_r = omega_r / 2 pi (Hz).

kappa_Hz: float | None = None
property omega_r: float

Angular resonance frequency omega_r = 1/sqrt(L C) (rad/s).

summary() → str[source]

Return a multi-line, unit-annotated summary string.

property tau_photon_s: float | None

Photon lifetime tau = 1 / (2 pi kappa) (s), where kappa is the FWHM linewidth. This is the 1/e energy-decay time of the mode. Returns None if kappa is unknown.

simpleLOMs.readout.design_resonator(target_f_GHz: float, target_Q: float, cpw: CPWParams, *, freq: Frequency | None = None, model: str = 'optimized', d_range: tuple[float, float] = (0.0055, 0.009), Cc_range: tuple[float, float] = (2e-15, 1.4e-14), n: int = 6, Cc_ref: float = 6e-15, Ctog: float = 1e-14, Z0: float = 50.0) → tuple[float, float, float, ReadoutParams][source]

Choose resonator length and coupling to hit a target frequency and loaded Q.

Sequentially: (1) interpolate length from an f_0(d) sweep at fixed Cc_ref, (2) fit L, C at that length, (3) interpolate C_c from a Q(C_c) sweep, (4) verify against extract_f0_kappa.

Parameters:
  • target_f_GHz (float) – Desired resonant frequency in GHz.

  • target_Q (float) – Desired loaded quality factor.

  • cpw (CPWParams) – CPW geometry / material.

  • freq (rf.Frequency, optional) – Frequency grid for fit_lom. Defaults to 4–12 GHz, 8001 points.

  • model (str) – LOM used for L, C (default "optimized").

  • d_range (tuple) – Sweep bounds for length (m) and coupling (F).

  • Cc_range (tuple) – Sweep bounds for length (m) and coupling (F).

  • n (int) – Number of sweep points per axis.

  • Cc_ref (float) – Reference coupling used during the length → frequency sweep.

  • Ctog – Passed through to extract_f0_kappa / fit_lom.

  • Z0 – Passed through to extract_f0_kappa / fit_lom.

Returns:

Designed length (m), coupling (F), achieved f_0 in GHz, and readout report at the designed point.

Return type:

d, Cc, f0_GHz, ReadoutParams

simpleLOMs.readout.extract_f0_kappa(cpw_params: CPWParams, d: float, Cc: float | None = None, Ctog: float = 1e-14, Z0: float = 50.0, f_lo: float = 4000000000.0, f_hi: float = 12000000000.0, n_coarse: int = 20001, span: float = 400000000.0, n_fine: int = 120001, *, Cc1: float | None = None, Cc2: float | None = None, Ctog1: float | None = None, Ctog2: float | None = None) → tuple[float, float][source]

Measure the loaded resonance frequency and linewidth of a CPW resonator directly from its geometry, using a robust two-stage circle fit.

A single wide frequency grid usually cannot resolve a sub-MHz linewidth, so this function first locates the resonance on a coarse grid, then re-simulates a narrow window around it on a fine grid before extracting kappa. This is the same coarse-then-refine strategy used internally by analyze_system.

Loading may be symmetric or asymmetric. Pass Cc/Ctog for the common symmetric case (the same value on both ports), or give per-port overrides via Cc1/Cc2 and Ctog1/Ctog2 for an asymmetric device. The reflection circle fit probes the more strongly coupled port: both ports see the same loaded (f0, kappa), and the stronger port’s larger resonance circle is far more robust against the coupling background at extreme asymmetry.

Parameters:
  • cpw_params (CPWParams) – CPW geometry / material parameters.

  • d (float) – Resonator length in metres.

  • Cc (float, optional) – Coupling capacitance in Farads applied symmetrically to both ports. Provide this or the per-port Cc1/Cc2 pair.

  • Ctog (float) – Shunt-to-ground capacitance in Farads applied to both ports. Default 1e-14. Overridden per port by Ctog1/Ctog2.

  • Z0 (float) – Reference / feedline impedance in Ohms. Default 50.

  • f_lo (float) – Bounds of the coarse search grid in Hz. Default 4-12 GHz.

  • f_hi (float) – Bounds of the coarse search grid in Hz. Default 4-12 GHz.

  • n_coarse (int) – Number of points in the coarse grid.

  • span (float) – Minimum half-width of the refined window around the coarse f0, in Hz. The actual window is max(span, 5 * kappa_coarse) — a strongly coupled resonance can be ~1 GHz wide, and a fixed narrow window then clips the dip and yields kappa = NaN. If the refined extraction still fails, the window is doubled (a few attempts, capped at 0.75 * f0) before giving up. Narrow-linewidth results are unaffected: the window never shrinks below span.

  • n_fine (int) – Number of points in the refined grid.

  • Cc1 (float, optional) – Per-port coupling capacitances in Farads. Each defaults to Cc when not given, so passing only Cc reproduces symmetric loading.

  • Cc2 (float, optional) – Per-port coupling capacitances in Farads. Each defaults to Cc when not given, so passing only Cc reproduces symmetric loading.

  • Ctog1 (float, optional) – Per-port shunt-to-ground capacitances in Farads. Each defaults to Ctog when not given.

  • Ctog2 (float, optional) – Per-port shunt-to-ground capacitances in Farads. Each defaults to Ctog when not given.

Returns:

  • f0 (float) – Loaded resonance frequency in Hz.

  • kappa (float) – Loaded linewidth (FWHM) in Hz.

Examples

>>> f0, kappa = extract_f0_kappa(CPWParams(), d=7e-3, Cc=6e-15)
>>> 7e9 < f0 < 9e9
True

Asymmetric coupling (a stronger tap on port 2):

>>> f0, kappa = extract_f0_kappa(CPWParams(), d=7e-3, Cc1=6e-15, Cc2=1.2e-14)
simpleLOMs.readout.invert_monotonic(x, y, target: float, *, log: bool = False) → float[source]

Invert a monotonic y(x) curve by interpolation.

Parameters:
  • x (array-like) – Sampled independent and dependent values (need not be sorted).

  • y (array-like) – Sampled independent and dependent values (need not be sorted).

  • target (float) – Desired y value.

  • log (bool) – If True, interpolate in log(y) / log(x) space (appropriate for power-law curves such as Q(C_c)).

Returns:

Interpolated x that yields target.

Return type:

float

simpleLOMs.readout.resonator_readout_params(L: float, C: float, kappa_Hz: float | None = None) → ReadoutParams[source]

Build ReadoutParams from an effective inductance and capacitance.

This is the “last mile” from a fitted LOM to circuit-QED quantities: pass the L and C any simpleLOMs model returns (model.L, model.C, or model.get_params()), optionally with a measured linewidth.

Parameters:
  • L (float) – Effective inductance in Henries.

  • C (float) – Effective capacitance in Farads.

  • kappa_Hz (float, optional) – Loaded linewidth (FWHM) in Hz. If given, the returned object also exposes Q and tau_photon_s.

Return type:

ReadoutParams

Examples

>>> rp = resonator_readout_params(5.5e-10, 6.2e-13, kappa_Hz=2.4e6)
>>> round(rp.Z_r_ohm, 1)
29.8
>>> round(rp.Q)
3591

Schematics

Optional circuit-diagram generation (import simpleLOMs.schematics; not re-exported from the top-level package).

simpleLOMs.schematics

Optional circuit-diagram generation for the networks built in simpleLOMs.networks.

Produces clean, white-background schematics that show the capacitance and inductance values, rendered as a zoomable interactive object (scroll to zoom, drag to pan) either as a standalone HTML file or inline in a Jupyter notebook.

Quick start

from simpleLOMs.schematics import cpw_schematic_2port from simpleLOMs import CPWParams import skrf as rf

freq = rf.Frequency(4, 10, 4001, “GHz”) sch = cpw_schematic_2port(

d=7e-3, Cc1=5e-15, Cc2=5e-15, Ctog1=1e-14, Ctog2=1e-14, cpw_params=CPWParams(ep_r=11.45), freq=freq, annotations={“f0_GHz”: 7.918, “QL”: 52},

) sch.save_html(“circuit.html”) # zoomable, white background sch.save_svg(“circuit.svg”) # static vector sch.save_json(“schematic.json”) # portable netlist sch # renders inline & zoomable in Jupyter

The intermediate Schematic is JSON-serialisable and round-trips with the schematic.json schema already used in the notebooks.

class simpleLOMs.schematics.Component(id: str, type: str, label: str = '', value: str = '', ports: List[str] = <factory>, group: str | None = None, orient: str = 'series', props: Dict[str, ~typing.Any]=<factory>)[source]

Bases: object

A single circuit element.

id

Unique identifier (e.g. "Cc1").

Type:

str

type

One of port | cap | ind | lc | tline | ground | node | open | res.

Type:

str

label

Human-readable name drawn next to the symbol.

Type:

str

value

Pre-formatted display string (e.g. "5 fF"). May be empty.

Type:

str

ports

Port names on this component (used to build nets).

Type:

list[str]

group

Optional group id for collapsing sub-circuits.

Type:

str | None

orient

"series" (sits on the rail) or "shunt" (hangs to ground).

Type:

str

props

Optional structured values (e.g. {"L": 5e-10, "C": 6e-13}) used by the renderer for multi-value symbols such as parallel LC tanks.

Type:

dict

group: str | None = None
id: str
label: str = ''
orient: str = 'series'
ports: List[str]
props: Dict[str, Any]
type: str
value: str = ''
class simpleLOMs.schematics.Net(id: str, ports: List[str] = <factory>)[source]

Bases: object

A connection between component ports.

id: str
ports: List[str]
class simpleLOMs.schematics.Schematic(meta: Dict[str, ~typing.Any]=<factory>, groups: Dict[str, ~typing.Any]]=<factory>, components: List[Component] = <factory>, nets: List[Net] = <factory>, annotations: Dict[str, ~typing.Any]=<factory>)[source]

Bases: object

A complete, renderable circuit netlist.

annotations: Dict[str, Any]
components: List[Component]
classmethod from_dict(d: Dict[str, Any]) → Schematic[source]
classmethod from_json(text: str) → Schematic[source]
groups: List[Dict[str, Any]]
classmethod load_json(path: str | Path) → Schematic[source]
meta: Dict[str, Any]
nets: List[Net]
save_html(path: str | Path, **kwargs) → Path[source]
save_json(path: str | Path) → Path[source]
save_svg(path: str | Path, **kwargs) → Path[source]
to_dict() → Dict[str, Any][source]
to_html(**kwargs) → str[source]

Render to a self-contained, zoomable HTML document.

to_json(indent: int = 2) → str[source]
to_svg(**kwargs) → str[source]

Render to a standalone SVG string (white background).

class simpleLOMs.schematics.SchematicBuilder(title: str, description: str = '', source: str = '', annotations: Dict[str, Any] | None = None, groups: list | None = None)[source]

Bases: object

Accumulate a ladder network left-to-right and emit a Schematic.

Series elements (port, series_cap, tline) advance the rail; shunt elements (shunt_cap, shunt_lc) hang to ground at the current node. Nets are tracked for interchange but layout only needs component order + orient.

build() → Schematic[source]
open(id: str = 'OPEN', label: str = 'open') → SchematicBuilder[source]
port(id: str, label: str | None = None, Z0: float = 50.0, group: str | None = None) → SchematicBuilder[source]
series_cap(id: str, C: float, label: str | None = None, group: str | None = None) → SchematicBuilder[source]
shunt_branch(id: str, stack: list, group: str | None = None) → SchematicBuilder[source]

A shunt leg holding several stacked elements (rail -> ground).

stack is an ordered list of element dicts (top-of-leg first), each {"type", "label", "value", ...} with type in {"cap", "lc", "tline"}. Drawn by simpleLOMs.schematics.render_svg._sym_branch_shunt(). This is the hanger / notch resonator leg: a coupling cap stacked above the resonator.

shunt_cap(id: str, C: float, label: str | None = None, group: str | None = None) → SchematicBuilder[source]
shunt_lc(id: str, L: float, C: float, label: str | None = None, group: str | None = None) → SchematicBuilder[source]
tline(id: str, length: float, Z0: float | None = None, label: str = 'CPW', group: str | None = None) → SchematicBuilder[source]
simpleLOMs.schematics.cpw_loaded_schematic_2port(d, Cc1, Cc2, Ctog1, Ctog2, Lload1, Cload1, Lload2, Cload2, cpw_params=None, freq=None, Z0=50, cc_port=1e-15, annotations=None, title=None) → Schematic[source]

2-port loaded CPW with an LC tank on each port side.

simpleLOMs.schematics.cpw_schematic(d, Cc1, Cc2, Ctog1, Ctog2, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

1-port CPW: P1 — Cc1 — Ctog1 — CPW — Ctog2 — Cc2(shunt) — open.

simpleLOMs.schematics.cpw_schematic_2port(d, Cc1, Cc2, Ctog1, Ctog2, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

2-port CPW: P1 — Cc1 — Ctog1 — CPW — Ctog2 — Cc2 — P2.

simpleLOMs.schematics.cpw_single_load_schematic_2port(d, Cc1, Ctog1, Ctog2, Lload1, Cload1, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

2-port CPW with a single LC load on the port-1 side.

simpleLOMs.schematics.format_eng(value: float, unit: str = '', decimals: int = 2) → str[source]

Format a number with an SI prefix, e.g. format_eng(5e-15, "F") -> "5.00 fF".

Parameters:
  • value (float) – The physical quantity in base SI units.

  • unit (str) – Unit symbol appended after the prefix (e.g. "F", "H", "m").

  • decimals (int) – Number of digits after the decimal point (default 2).

simpleLOMs.schematics.hanger_resonator_schematic_2port(segments, Ccs, feed_lengths=None, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

Resonators hanging off a through feedline (mirrors simpleLOMs.networks.hanger.hanger_resonator_network_2port()).

segments is a list of {"kind": "lc", "L": ..., "C": ...} or {"kind": "cpw", "d": ..., "termination": "short"|"open"} dicts; Ccs has one tap coupling cap per segment. Each hanger is drawn as a shunt branch: the tap cap stacked above the resonator, hanging to ground.

simpleLOMs.schematics.hybrid_schematic_2port(inline_segments, inline_Ccs, hanger_segments, hanger_Ccs, inline_Ctogs=None, feed_lengths=None, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

Inline (series) chain cascaded with hanger taps on one rail.

Mirrors the hybrid cascade used when an inline Purcell / chain network is joined to a hanger feedline (inline ** hangers in scikit-rf). Draws

[P1] – Cc – … – CPW/LC chain – Cc – hang1 – hang2 – … – [P2]

Parameters match the corresponding pieces of resonator_chain_schematic_2port() and hanger_resonator_schematic_2port().

simpleLOMs.schematics.lc_loaded_schematic_2port(Leff, Ceff, Cc1, Cc2, Lload1, Cload1, Lload2, Cload2, Z0=50, annotations=None, title=None) → Schematic[source]

2-port loaded LC with an LC tank on each port side.

simpleLOMs.schematics.lc_loaded_with_grounds_schematic_2port(Leff, Ceff, Cc1, Cc2, Ctog1, Ctog2, Lload1, Cload1, Lload2, Cload2, Z0=50, annotations=None, title=None) → Schematic[source]

Full 2-port LC: loads, coupling caps, ground caps, and the LC tank.

simpleLOMs.schematics.lc_schematic(Leff, Ceff, Cc1, Cc2, Z0=50, annotations=None, title=None) → Schematic[source]

1-port LC: P1 — Cc1 — [LC] — Cc2(shunt) — open.

simpleLOMs.schematics.lc_schematic_2port(Leff, Ceff, Cc1, Cc2, Z0=50, annotations=None, title=None) → Schematic[source]

2-port LC: P1 — Cc1 — [LC] — Cc2 — P2.

simpleLOMs.schematics.lc_with_grounds_schematic_2port(Leff, Ceff, Cc1, Cc2, Ctog1, Ctog2, Z0=50, annotations=None, title=None) → Schematic[source]

2-port LC: P1 — Cc1 — Ctog1 — [LC] — Ctog2 — Cc2 — P2.

simpleLOMs.schematics.resonator_chain_schematic_2port(segments, Ccs, Ctogs=None, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

Chain of capacitively-coupled resonators (mirrors simpleLOMs.networks.chain.resonator_chain_network_2port()).

segments is a list of {"kind": "cpw", "d": ...} or {"kind": "lc", "L": ..., "C": ...} dicts, Ccs has len+1 entries and Ctogs (optional) has 2*len entries; a 0/None ground cap is omitted, so pass Ctogs=None for a lumped chain whose L, C already absorb the grounds. Each resonator is drawn as its own labelled group.

simpleLOMs.schematics.schematic_to_html(sch: Schematic, title: str | None = None, height: int = 360) → str[source]

Full standalone HTML page with a zoomable schematic.

simpleLOMs.schematics.schematic_to_iframe(sch: Schematic, height: int = 380) → str[source]

HTML for inline Jupyter display: a sandboxed iframe running the viewer.

simpleLOMs.schematics.schematic_to_svg(sch: Schematic, scale: float = 1.0, standalone: bool = True) → str[source]

Render sch to an SVG string with a white background.

schematics/netlist.py

Portable, JSON-serialisable intermediate representation (IR) for circuit schematics.

This formalises the ad-hoc schematic.json schema that the Quantum Metal to Circuit notebook already emits, so anything that reads or writes that file keeps working. A Schematic is a plain data object: the network builders in simpleLOMs.schematics.builders produce one, and the renderers in simpleLOMs.schematics.render_svg / simpleLOMs.schematics.viewer consume one.

Layout model

Every topology in this project is a ladder network: a horizontal signal rail carrying series elements (ports, coupling capacitors, transmission lines), with shunt elements (ground capacitors, LC resonators) hanging down to ground at the nodes between them. Each Component therefore records an orient of "series" or "shunt"; the renderer walks the components in order and needs no general graph-layout solver. nets are still emitted for interchange/compatibility but are not required for drawing.

class simpleLOMs.schematics.netlist.Component(id: str, type: str, label: str = '', value: str = '', ports: List[str] = <factory>, group: str | None = None, orient: str = 'series', props: Dict[str, ~typing.Any]=<factory>)[source]

Bases: object

A single circuit element.

id

Unique identifier (e.g. "Cc1").

Type:

str

type

One of port | cap | ind | lc | tline | ground | node | open | res.

Type:

str

label

Human-readable name drawn next to the symbol.

Type:

str

value

Pre-formatted display string (e.g. "5 fF"). May be empty.

Type:

str

ports

Port names on this component (used to build nets).

Type:

list[str]

group

Optional group id for collapsing sub-circuits.

Type:

str | None

orient

"series" (sits on the rail) or "shunt" (hangs to ground).

Type:

str

props

Optional structured values (e.g. {"L": 5e-10, "C": 6e-13}) used by the renderer for multi-value symbols such as parallel LC tanks.

Type:

dict

group: str | None = None
id: str
label: str = ''
orient: str = 'series'
ports: List[str]
props: Dict[str, Any]
type: str
value: str = ''
class simpleLOMs.schematics.netlist.Net(id: str, ports: List[str] = <factory>)[source]

Bases: object

A connection between component ports.

id: str
ports: List[str]
class simpleLOMs.schematics.netlist.Schematic(meta: Dict[str, ~typing.Any]=<factory>, groups: Dict[str, ~typing.Any]]=<factory>, components: List[Component] = <factory>, nets: List[Net] = <factory>, annotations: Dict[str, ~typing.Any]=<factory>)[source]

Bases: object

A complete, renderable circuit netlist.

annotations: Dict[str, Any]
components: List[Component]
classmethod from_dict(d: Dict[str, Any]) → Schematic[source]
classmethod from_json(text: str) → Schematic[source]
groups: List[Dict[str, Any]]
classmethod load_json(path: str | Path) → Schematic[source]
meta: Dict[str, Any]
nets: List[Net]
save_html(path: str | Path, **kwargs) → Path[source]
save_json(path: str | Path) → Path[source]
save_svg(path: str | Path, **kwargs) → Path[source]
to_dict() → Dict[str, Any][source]
to_html(**kwargs) → str[source]

Render to a self-contained, zoomable HTML document.

to_json(indent: int = 2) → str[source]
to_svg(**kwargs) → str[source]

Render to a standalone SVG string (white background).

simpleLOMs.schematics.netlist.format_eng(value: float, unit: str = '', decimals: int = 2) → str[source]

Format a number with an SI prefix, e.g. format_eng(5e-15, "F") -> "5.00 fF".

Parameters:
  • value (float) – The physical quantity in base SI units.

  • unit (str) – Unit symbol appended after the prefix (e.g. "F", "H", "m").

  • decimals (int) – Number of digits after the decimal point (default 2).

schematics/builders.py

Turn the same parameters that the network builders in simpleLOMs.networks take into a renderable Schematic.

These “mirror-builders” intentionally re-state each fixed topology (the same chain documented in the networks/*.py docstrings) rather than introspecting the returned rf.Network — the L/C values are baked into skrf’s S-matrices and cannot be recovered cleanly, so the schematic is built directly from the physical parameters the user passed.

Convention (matches the skrf elements)

  • coupling_capacitor -> SeriesImpedance -> a series cap on the rail

  • shunt_capacitor -> ShuntAdmittance -> a shunt cap to ground

  • lc_resonator -> ShuntAdmittance -> a shunt parallel LC tank

  • cpw.line -> a series transmission line

class simpleLOMs.schematics.builders.SchematicBuilder(title: str, description: str = '', source: str = '', annotations: Dict[str, Any] | None = None, groups: list | None = None)[source]

Bases: object

Accumulate a ladder network left-to-right and emit a Schematic.

Series elements (port, series_cap, tline) advance the rail; shunt elements (shunt_cap, shunt_lc) hang to ground at the current node. Nets are tracked for interchange but layout only needs component order + orient.

build() → Schematic[source]
open(id: str = 'OPEN', label: str = 'open') → SchematicBuilder[source]
port(id: str, label: str | None = None, Z0: float = 50.0, group: str | None = None) → SchematicBuilder[source]
series_cap(id: str, C: float, label: str | None = None, group: str | None = None) → SchematicBuilder[source]
shunt_branch(id: str, stack: list, group: str | None = None) → SchematicBuilder[source]

A shunt leg holding several stacked elements (rail -> ground).

stack is an ordered list of element dicts (top-of-leg first), each {"type", "label", "value", ...} with type in {"cap", "lc", "tline"}. Drawn by simpleLOMs.schematics.render_svg._sym_branch_shunt(). This is the hanger / notch resonator leg: a coupling cap stacked above the resonator.

shunt_cap(id: str, C: float, label: str | None = None, group: str | None = None) → SchematicBuilder[source]
shunt_lc(id: str, L: float, C: float, label: str | None = None, group: str | None = None) → SchematicBuilder[source]
tline(id: str, length: float, Z0: float | None = None, label: str = 'CPW', group: str | None = None) → SchematicBuilder[source]
simpleLOMs.schematics.builders.cpw_loaded_schematic_2port(d, Cc1, Cc2, Ctog1, Ctog2, Lload1, Cload1, Lload2, Cload2, cpw_params=None, freq=None, Z0=50, cc_port=1e-15, annotations=None, title=None) → Schematic[source]

2-port loaded CPW with an LC tank on each port side.

simpleLOMs.schematics.builders.cpw_schematic(d, Cc1, Cc2, Ctog1, Ctog2, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

1-port CPW: P1 — Cc1 — Ctog1 — CPW — Ctog2 — Cc2(shunt) — open.

simpleLOMs.schematics.builders.cpw_schematic_2port(d, Cc1, Cc2, Ctog1, Ctog2, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

2-port CPW: P1 — Cc1 — Ctog1 — CPW — Ctog2 — Cc2 — P2.

simpleLOMs.schematics.builders.cpw_single_load_schematic_2port(d, Cc1, Ctog1, Ctog2, Lload1, Cload1, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

2-port CPW with a single LC load on the port-1 side.

simpleLOMs.schematics.builders.hanger_resonator_schematic_2port(segments, Ccs, feed_lengths=None, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

Resonators hanging off a through feedline (mirrors simpleLOMs.networks.hanger.hanger_resonator_network_2port()).

segments is a list of {"kind": "lc", "L": ..., "C": ...} or {"kind": "cpw", "d": ..., "termination": "short"|"open"} dicts; Ccs has one tap coupling cap per segment. Each hanger is drawn as a shunt branch: the tap cap stacked above the resonator, hanging to ground.

simpleLOMs.schematics.builders.hybrid_schematic_2port(inline_segments, inline_Ccs, hanger_segments, hanger_Ccs, inline_Ctogs=None, feed_lengths=None, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

Inline (series) chain cascaded with hanger taps on one rail.

Mirrors the hybrid cascade used when an inline Purcell / chain network is joined to a hanger feedline (inline ** hangers in scikit-rf). Draws

[P1] – Cc – … – CPW/LC chain – Cc – hang1 – hang2 – … – [P2]

Parameters match the corresponding pieces of resonator_chain_schematic_2port() and hanger_resonator_schematic_2port().

simpleLOMs.schematics.builders.lc_loaded_schematic_2port(Leff, Ceff, Cc1, Cc2, Lload1, Cload1, Lload2, Cload2, Z0=50, annotations=None, title=None) → Schematic[source]

2-port loaded LC with an LC tank on each port side.

simpleLOMs.schematics.builders.lc_loaded_with_grounds_schematic_2port(Leff, Ceff, Cc1, Cc2, Ctog1, Ctog2, Lload1, Cload1, Lload2, Cload2, Z0=50, annotations=None, title=None) → Schematic[source]

Full 2-port LC: loads, coupling caps, ground caps, and the LC tank.

simpleLOMs.schematics.builders.lc_schematic(Leff, Ceff, Cc1, Cc2, Z0=50, annotations=None, title=None) → Schematic[source]

1-port LC: P1 — Cc1 — [LC] — Cc2(shunt) — open.

simpleLOMs.schematics.builders.lc_schematic_2port(Leff, Ceff, Cc1, Cc2, Z0=50, annotations=None, title=None) → Schematic[source]

2-port LC: P1 — Cc1 — [LC] — Cc2 — P2.

simpleLOMs.schematics.builders.lc_with_grounds_schematic_2port(Leff, Ceff, Cc1, Cc2, Ctog1, Ctog2, Z0=50, annotations=None, title=None) → Schematic[source]

2-port LC: P1 — Cc1 — Ctog1 — [LC] — Ctog2 — Cc2 — P2.

simpleLOMs.schematics.builders.resonator_chain_schematic_2port(segments, Ccs, Ctogs=None, cpw_params=None, freq=None, Z0=50, annotations=None, title=None) → Schematic[source]

Chain of capacitively-coupled resonators (mirrors simpleLOMs.networks.chain.resonator_chain_network_2port()).

segments is a list of {"kind": "cpw", "d": ...} or {"kind": "lc", "L": ..., "C": ...} dicts, Ccs has len+1 entries and Ctogs (optional) has 2*len entries; a 0/None ground cap is omitted, so pass Ctogs=None for a lumped chain whose L, C already absorb the grounds. Each resonator is drawn as its own labelled group.

Utilities

utils.py

Ease of use functions for processing and viewing data.

simpleLOMs.utils.format_comparison_table(rows, headers) → str[source]

Format an aligned plain-text comparison table.

Parameters:
  • rows (sequence of sequences) – Data rows; each cell is already a string or will be str()-converted.

  • headers (sequence of str) – Column headers (same length as each row).

Returns:

Multi-line table suitable for print.

Return type:

str

simpleLOMs.utils.make_params_table(results: dict) → DataFrame[source]

Summarize fitted L and C for all three models as a tidy DataFrame.

Parameters:

results (dict) – Output from analyze_system().

Returns:

Indexed by model name, columns L (H) and C (F).

Return type:

pd.DataFrame

simpleLOMs.utils.make_results_table(results: dict, round_decimals: int = 4) → DataFrame[source]

Summarise analyze_system() output as a tidy DataFrame.

Rows are models (CPW, Optimized, Foster, Analytical). Columns are f₀, κ, and percent errors for S11 and S22.

Parameters:
  • results (dict) – Output from analyze_system().

  • round_decimals (int) – Decimal places to round to. Default 4.

Returns:

Indexed by model name.

Return type:

pd.DataFrame

simpleLOMs.utils.make_shift_error_table(results: dict, round_decimals: int = 3) → DataFrame[source]

Signed percent shift errors vs CPW reference for all three models.

Parameters:
  • results (dict) – Output from analyze_system().

  • round_decimals (int)

Returns:

Rows are modes, columns are models.

Return type:

pd.DataFrame

simpleLOMs.utils.make_shift_table(results: dict, port: str = 'S11', round_decimals: int = 5) → DataFrame[source]

Hybridised mode frequencies for all models as a tidy DataFrame.

Parameters:
  • results (dict) – Output from analyze_system().

  • port ({"S11", "S22"})

  • round_decimals (int)

Returns:

Rows are modes, columns are models.

Return type:

pd.DataFrame