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:
objectPhysical geometry and material parameters for a Coplanar Waveguide (CPW).
- 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:
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, ...)
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¶
- 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_rsets the bare (unloaded) resonance in Hz that anchors the analytical closed form; when omitted it is computed from the CPW geometry viasimpleLOMs.networks.cpw.bare_cpw_resonance_hz()(no longer hardcoded to the 7 mm value).analytical_Z0optionally 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_rsets the bare (unloaded) resonance in Hz that anchors the analytical closed form; when omitted it is computed from the CPW geometry viasimpleLOMs.networks.cpw.bare_cpw_resonance_hz()(no longer hardcoded to the 7 mm value).analytical_Z0optionally 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
dand return its effective(L, C).This is the design-time entry point for a normal user: pick a model, get
L, Cfrom 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/Cc2instead.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
Ccwhen 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
Ccwhen 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
Ctogwhen not given.Ctog2 (float, optional) – Per-port shunt-to-ground capacitances in Farads. Each defaults to
Ctogwhen 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 — seeanalytical_f_r. Narrow the span to isolate a specific mode.opt_config (OptimizationConfig, optional) – Optimiser settings for
model="optimized". Defaults to a quietn_widths=4config.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 withsimpleLOMs.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 thatget_networkre-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 withsimpleLOMs.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 ifreturn_model.- Return type:
Notes
For the “optimized” and “analytical” models the effective
L, Cabsorb the coupling/ground capacitors, so they do depend onCc/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 loadedQ(which only needf_rand a measured linewidth) but not forZ_r/V_zpf. To get the readout linewidth, pair this withsimpleLOMs.extract_f0_kappa()andsimpleLOMs.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 runsHangerOptimizedFitso 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
HangerOptimizedFitinstead of(L, C).
- Returns:
(L, C)in Henries/Farads, or the fitted model ifreturn_model.- Return type:
- 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
PrefitContextwith 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.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_kappasmooths 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 tof0 ± 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.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:
- 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:
- 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|**2through 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 belowthresh.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:
- 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¶
Fit a circle to the complex trace S[m,n](f).
Compute the angle of each point about the fitted center.
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:
- 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:
- Returns:
Dominant resonance frequency in Hz.
- Return type:
- 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]).
- 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:
- Returns:
Array of resonance frequencies in Hz.
- Return type:
np.ndarray
- Raises:
ValueError – If no peaks are found in |S[m,n]|.
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:
ABCAbstract 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.
- 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 thedata_ntwstored 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
models/foster.py¶
FosterFit: admittance-slope (Foster synthesis) method for extracting the effective L and C of a CPW resonator.
Algorithm summary¶
Build a 2-port CPW transmission line network (no coupling caps, just the bare line terminated at both ends with a high impedance).
Compute the input admittance Yin(ω) seen at port 1 with the port 2 load in place:
Yin = Y11 - Y12*Y21 / (Y22 + YL)
Find the resonance frequency ω0 from the peak in Re(S22).
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)
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:
BaseFitLumped 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).
- 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
- 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:
objectTuning 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}
- class simpleLOMs.models.optimized_fit.OptimizedFit(config: OptimizationConfig = None)[source]¶
Bases:
BaseFitLumped LC model via two-stage numerical optimisation.
- Parameters:
config (OptimizationConfig, optional) – Hyperparameters and residual options. Defaults to OptimizationConfig() (S11 + S22, no phase fitting).
- 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_ntwstored 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:
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:
BaseFitLumped 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=2case.
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.
- 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
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).
- 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
Ccin series with a parallel-LC tank whose far end is grounded:rail ── Cc ──┬── L ──┬── ground └── C ──┘The whole branch collapses to a single
ShuntAdmittancewithY = 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). PreferL, CfromHangerOptimizedFitwhen 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 atCtog = 0to land on the notch (the ~3% “reuse gap” is that mismatchedCtogloading, not the hanger-vs-inline boundary condition).- Parameters:
- 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.
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 whenget_networkre-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:
- 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
AnalyticalFitexpects (its λ/2 effective impedance is2 Z_line / π). Dispersion is weak, so a single frequency near the resonance is sufficient.
- 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_portcapacitors (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 buildercpw_resonator_network_2port(), whose ports connect through the fullCc1/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:
- 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_portcapacitors (1 fF by default), matching the loaded CPW builders — not through the fullCc1/Cc2as 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 length2 * n. A value of0(orNonefor the whole list) omits that ground cap — useCtogs=Nonefor a lumped chain whoseL, Calready absorb the grounds (e.g.OptimizedFit).cpw_params (CPWParams, optional) – CPW geometry for the
"cpw"segments. Defaults toCPWParams().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, obtainL, CfromHangerOptimizedFit(orfit_lom_hanger()), which fits against a CPW hanger. Rewiring an inlineOptimizedFit(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 (terminationdefaults 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) + 1of them: one before the first tap, one between each pair of taps, and one after the last. A value of0(orNonefor the whole list) makes that section an ideal wire —feed_lengths=Nonegives 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 toCPWParams().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:
BaseFitLumped LC hanger model via least-squares fit to a CPW hanger S21 notch.
Algorithm¶
Seed
(L, C)from Foster synthesis on the bare CPW lengthd.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.Stage 2 — windowed least_squares on
|S21|(and optionally a global phase) with a wide notch window, freeingLandC.
- 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, Cso 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_2portwithkind="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.
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
rcParamsand 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
symbolis None, returnsTitle (Unit)or justTitle. 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
yseries against a sharedxin a 1×2 figure.Per-panel titles default to
None(no title).titleis applied asfig.suptitleonly 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
yseries.xis 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. Optionalhline/vline/pointmark a design target inCOLOR_HIGHLIGHT(hline/vlineaccept 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
- 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/yand 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:
- 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
OptimizedFitinstance (readsget_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
- 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_resonancesandquantity="db").title (str, optional) – Axis / figure title. Default is a short
$|S_{mn}|$label whenpanelsis None; with a zoom panel, titles are omitted unless given (applied asfig.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 usescenter±half_width(GHz).center (float) – Zoom window for
panels="zoom".centerdefaults to the mid-band frequency of the first network when omitted.half_width (float) – Zoom window for
panels="zoom".centerdefaults 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_resonancesandquantity="db").title (str, optional) – Axis / figure title. Default is a short
$|S_{mn}|$label whenpanelsis None; with a zoom panel, titles are omitted unless given (applied asfig.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 usescenter±half_width(GHz).center (float) – Zoom window for
panels="zoom".centerdefaults to the mid-band frequency of the first network when omitted.half_width (float) – Zoom window for
panels="zoom".centerdefaults 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:
objectA 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)
- freq: Frequency¶
- opt_config: OptimizationConfig | None = None¶
- simpleLOMs.sweeps.measure_sweep(values, measure) dict[source]¶
Apply
measure(v) -> dictat each value and return column arrays.This is the small reusable helper used by the tutorials for knobs that are not
SweepConfigfields (e.g. a CPW gap viadataclasses.replace).
- 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.
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:
objectReadout / 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…) orsummary()for human-friendly values.
- 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 fixedCc_ref, (2) fitL, Cat that length, (3) interpolateC_cfrom aQ(C_c)sweep, (4) verify againstextract_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_0in 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 byanalyze_system.Loading may be symmetric or asymmetric. Pass
Cc/Ctogfor the common symmetric case (the same value on both ports), or give per-port overrides viaCc1/Cc2andCtog1/Ctog2for 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/Cc2pair.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 yieldskappa = NaN. If the refined extraction still fails, the window is doubled (a few attempts, capped at0.75 * f0) before giving up. Narrow-linewidth results are unaffected: the window never shrinks belowspan.n_fine (int) – Number of points in the refined grid.
Cc1 (float, optional) – Per-port coupling capacitances in Farads. Each defaults to
Ccwhen not given, so passing onlyCcreproduces symmetric loading.Cc2 (float, optional) – Per-port coupling capacitances in Farads. Each defaults to
Ccwhen not given, so passing onlyCcreproduces symmetric loading.Ctog1 (float, optional) – Per-port shunt-to-ground capacitances in Farads. Each defaults to
Ctogwhen not given.Ctog2 (float, optional) – Per-port shunt-to-ground capacitances in Farads. Each defaults to
Ctogwhen 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
yvalue.log (bool) – If True, interpolate in
log(y)/log(x)space (appropriate for power-law curves such asQ(C_c)).
- Returns:
Interpolated
xthat yieldstarget.- Return type:
- simpleLOMs.readout.resonator_readout_params(L: float, C: float, kappa_Hz: float | None = None) ReadoutParams[source]¶
Build
ReadoutParamsfrom an effective inductance and capacitance.This is the “last mile” from a fitted LOM to circuit-QED quantities: pass the
LandCany simpleLOMs model returns (model.L,model.C, ormodel.get_params()), optionally with a measured linewidth.- Parameters:
- Return type:
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:
objectA single circuit element.
- 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:
- class simpleLOMs.schematics.Net(id: str, ports: List[str] = <factory>)[source]¶
Bases:
objectA connection between component ports.
- 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:
objectA complete, renderable circuit netlist.
- class simpleLOMs.schematics.SchematicBuilder(title: str, description: str = '', source: str = '', annotations: Dict[str, Any] | None = None, groups: list | None = None)[source]¶
Bases:
objectAccumulate 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.- 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).
stackis an ordered list of element dicts (top-of-leg first), each{"type", "label", "value", ...}withtypein{"cap", "lc", "tline"}. Drawn bysimpleLOMs.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]¶
- 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".
- 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()).segmentsis a list of{"kind": "lc", "L": ..., "C": ...}or{"kind": "cpw", "d": ..., "termination": "short"|"open"}dicts;Ccshas 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 ** hangersin scikit-rf). Draws[P1] – Cc – … – CPW/LC chain – Cc – hang1 – hang2 – … – [P2]
Parameters match the corresponding pieces of
resonator_chain_schematic_2port()andhanger_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()).segmentsis a list of{"kind": "cpw", "d": ...}or{"kind": "lc", "L": ..., "C": ...}dicts,Ccshaslen+1entries andCtogs(optional) has2*lenentries; a0/Noneground cap is omitted, so passCtogs=Nonefor a lumped chain whoseL, Calready 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
schto 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:
objectA single circuit element.
- 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:
- class simpleLOMs.schematics.netlist.Net(id: str, ports: List[str] = <factory>)[source]¶
Bases:
objectA connection between component ports.
- 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:
objectA complete, renderable circuit netlist.
- 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".
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 railshunt_capacitor->ShuntAdmittance-> a shunt cap to groundlc_resonator->ShuntAdmittance-> a shunt parallel LC tankcpw.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:
objectAccumulate 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.- 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).
stackis an ordered list of element dicts (top-of-leg first), each{"type", "label", "value", ...}withtypein{"cap", "lc", "tline"}. Drawn bysimpleLOMs.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]¶
- 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()).segmentsis a list of{"kind": "lc", "L": ..., "C": ...}or{"kind": "cpw", "d": ..., "termination": "short"|"open"}dicts;Ccshas 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 ** hangersin scikit-rf). Draws[P1] – Cc – … – CPW/LC chain – Cc – hang1 – hang2 – … – [P2]
Parameters match the corresponding pieces of
resonator_chain_schematic_2port()andhanger_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()).segmentsis a list of{"kind": "cpw", "d": ...}or{"kind": "lc", "L": ..., "C": ...}dicts,Ccshaslen+1entries andCtogs(optional) has2*lenentries; a0/Noneground cap is omitted, so passCtogs=Nonefor a lumped chain whoseL, Calready 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.
- 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.
- 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.