Coverage for qpdk / models / junction.py: 100%
35 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-14 10:27 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-14 10:27 +0000
1"""Josephson junction Models."""
3import warnings
4from functools import partial
6import jax
7import jax.numpy as jnp
8import sax
9from sax.models.rf import admittance
11from qpdk.models.constants import DEFAULT_FREQUENCY, Φ_0
14def _warn_if_overbiased(ib: float, ic: float) -> None:
15 """Host callback to warn if bias current exceeds critical current."""
16 if jnp.any(jnp.abs(ib) >= ic):
17 warnings.warn(
18 "DC bias |I_b| >= I_c detected. Linearized RCSJ model is invalid in the voltage state. "
19 "Please check your 'ib' and 'ic' ('ic_tot', 'flux', 'asymmetry') inputs.",
20 RuntimeWarning,
21 stacklevel=0,
22 )
25@partial(jax.jit, inline=True)
26def josephson_junction(
27 *,
28 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
29 ic: sax.Float = 1e-6,
30 capacitance: sax.Float = 5e-15,
31 resistance: sax.Float = 10e3,
32 ib: sax.Float = 0.0,
33) -> sax.SDict:
34 r"""Josephson junction (RCSJ) small-signal Sax model.
36 Linearized RCSJ model consisting of a bias-dependent Josephson inductance
37 in parallel with capacitance and resistance.
39 Valid in the superconducting (zero-voltage) state and for small AC signals.
41 Default capacitance taken from :cite:`shcherbakovaFabricationMeasurementsHybrid2015`.
43 See :cite:`McCumber1968` for details.
45 Args:
46 f: Array of frequency points in Hz
47 ic: Critical current :math:`I_c` in Amperes
48 capacitance: Junction capacitance :math:`C` in Farads
49 resistance: Shunt resistance :math:`R` in Ohms
50 ib: DC bias current :math:`I_b` in Amperes (:math:`\|I_b\| < I_c`)
52 Returns:
53 sax.SDict: S-parameters dictionary
54 """
55 jax.debug.callback(_warn_if_overbiased, ib, ic)
57 ω = 2 * jnp.pi * jnp.asarray(f)
59 # Bias-dependent phase factor
60 # jnp.clip ensures we don't get NaNs during compilation tracing or slightly overbiased states
61 cos_Φ_0 = jnp.sqrt(jnp.clip(1.0 - (ib / ic) ** 2, a_min=1e-10))
63 # Josephson inductance
64 Lⱼ = Φ_0 / (2 * jnp.pi * ic * cos_Φ_0)
66 # Admittances (parallel RCSJ)
67 Y_R = 1 / resistance
68 Y_C = 1j * ω * capacitance
69 Y_L = 1 / (1j * ω * Lⱼ)
71 # Total admittance
72 Y_JJ = Y_R + Y_C + Y_L
74 return admittance(f=f, y=Y_JJ)
77@partial(jax.jit, inline=True)
78def squid_junction(
79 *,
80 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
81 ic_tot: sax.Float = 2e-6,
82 asymmetry: sax.Float = 0.0,
83 capacitance: sax.Float = 10e-15,
84 resistance: sax.Float = 5e3,
85 ib: sax.Float = 0.0,
86 flux: sax.Float = 0.0,
87) -> sax.SDict:
88 r"""DC SQUID small-signal Sax model in the zero-screening limit.
90 Treats the DC SQUID as a single effective RCSJ whose critical current is
91 tunable by an external magnetic flux. Assumes negligible loop geometric inductance.
93 See :cite:`kochChargeinsensitiveQubitDesign2007a` and :cite:`tinkhamIntroductionSuperconductivity2015`
94 for details on asymmetric SQUIDs and effective Josephson inductance.
96 Args:
97 f: Array of frequency points in Hz
98 ic_tot: Total critical current sum :math:`I_{c1} + I_{c2}` in Amperes
99 asymmetry: Junction asymmetry :math:`(I_{c1} - I_{c2}) / I_{c,tot}`
100 capacitance: Total SQUID capacitance :math:`C_1 + C_2` in Farads
101 resistance: Total SQUID shunt resistance :math:`R_1 || R_2` in Ohms
102 ib: DC bias current :math:`I_b` in Amperes
103 flux: External magnetic flux :math:`\Phi_{ext}` in Webers
105 Returns:
106 sax.SDict: S-parameters dictionary
107 """
108 ω = 2 * jnp.pi * jnp.asarray(f)
110 # Normalized flux
111 phi_reduced = jnp.pi * flux / Φ_0
113 # Flux-tunable critical current for an asymmetric SQUID
114 ic_squid = ic_tot * jnp.sqrt(
115 jnp.cos(phi_reduced) ** 2 + (asymmetry**2) * jnp.sin(phi_reduced) ** 2
116 )
118 jax.debug.callback(_warn_if_overbiased, ib, ic_squid)
120 # Bias-dependent phase factor
121 # Guard against ic_squid == 0 (e.g. symmetric SQUID at half-flux quantum)
122 ratio_sq = jnp.where(
123 ic_squid > 0, (ib / jnp.where(ic_squid > 0, ic_squid, 1.0)) ** 2, 0.0
124 )
125 cos_Φ_0_eff = jnp.sqrt(jnp.clip(1.0 - ratio_sq, a_min=1e-10))
127 # Effective Josephson inductance (will go to inf when ic_squid == 0)
128 Lⱼ_eff = Φ_0 / (2 * jnp.pi * jnp.where(ic_squid > 0, ic_squid, 1e-20) * cos_Φ_0_eff)
130 # Admittances (parallel RCSJ)
131 Y_R = 1 / resistance
132 Y_C = 1j * ω * capacitance
133 # Guard against division by zero in Y_L if L_j_eff somehow goes to zero or Y_L -> 0 if L_j_eff is inf
134 Y_L = jnp.where(ic_squid > 0, 1 / (1j * ω * Lⱼ_eff), 0j)
136 # Total SQUID admittance
137 Y_SQUID = Y_R + Y_C + Y_L
139 return admittance(f=f, y=Y_SQUID)
142if __name__ == "__main__":
143 import matplotlib.pyplot as plt
145 sax.set_port_naming_strategy("optical")
147 f = jnp.linspace(1e9, 10e9, 500)
148 s = josephson_junction(f=f, ic=1e-6, capacitance=50e-15, resistance=10e3, ib=0.5e-6)
149 plt.figure()
150 plt.plot(f / 1e9, jnp.abs(s[("o1", "o1")]), label="|S11|")
151 plt.plot(f / 1e9, jnp.abs(s[("o1", "o2")]), label="|S12|")
152 plt.plot(f / 1e9, jnp.abs(s[("o2", "o2")]), label="|S22|")
153 plt.xlabel("Frequency [GHz]")
154 plt.ylabel("Magnitude")
155 plt.legend()
156 plt.title("Josephson Junction S-parameters")
157 plt.show()