Models#
airbridge#
- qpdk.models.airbridge(f=5000000000.0, cpw_width=10.0, bridge_width=10.0, airgap_height=3.0, loss_tangent=1.2e-08)[source]#
S-parameter model for a superconducting CPW airbridge.
The airbridge is modeled as a lumped lossy shunt admittance (accounting for dielectric loss and shunt capacitance) embedded between two sections of transmission line that represent the physical footprint of the bridge.
Parallel plate capacitor model is as done in [CMK+14] The default value for the loss tangent \(\tan\,\delta\) is also taken from there.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
cpw_width (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Width of the CPW center conductor in µm.
bridge_width (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Width of the airbridge in µm.
airgap_height (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Height of the airgap in µm.
loss_tangent (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Dielectric loss tangent of the supporting layer/residues.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import airbridge
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = airbridge(f=freq)
plt.figure()
plt.title("airbridge", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
bend_circular#
- qpdk.models.bend_circular(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a circular bend, wrapped to
straight().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import bend_circular
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = bend_circular(f=freq)
plt.figure()
plt.title("bend_circular", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
bend_euler#
- qpdk.models.bend_euler(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for an Euler bend, wrapped to
straight().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import bend_euler
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = bend_euler(f=freq)
plt.figure()
plt.title("bend_euler", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
bend_s#
- qpdk.models.bend_s(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for an S-bend, wrapped to
straight().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import bend_s
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = bend_s(f=freq)
plt.figure()
plt.title("bend_s", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
coupler_ring#
- qpdk.models.coupler_ring(f=5000000000.0, length=20.0, gap=0.27, cross_section='cpw')[source]#
S-parameter model for two coupled coplanar waveguides in a ring configuration.
The implementation is the same as straight coupler for now.
TODO: Fetch coupling capacitance from a curved simulation library.
- Parameters:
f (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Array of frequency points in Hz
length (int | float) – Physical length of coupling section in µm
gap (int | float) – Gap between the coupled waveguides in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the CPW.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import coupler_ring
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = coupler_ring(f=freq)
plt.figure()
plt.title("coupler_ring", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
coupler_straight#
- qpdk.models.coupler_straight(f=5000000000.0, length=20.0, gap=0.27, cross_section='cpw')[source]#
S-parameter model for two coupled coplanar waveguides,
coupler_straight().- Parameters:
f (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Array of frequency points in Hz
length (int | float) – Physical length of coupling section in µm
gap (int | float) – Gap between the coupled waveguides in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the CPW.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
o2──────▲───────o3 │gap o1──────▼───────o4
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import coupler_straight
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = coupler_straight(f=freq)
plt.figure()
plt.title("coupler_straight", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
coupling_strength_to_capacitance#
- qpdk.models.coupling_strength_to_capacitance(g_ghz, c_sigma, c_r, f_q_ghz, f_r_ghz)[source]#
Convert coupling strength \(g\) to coupling capacitance \(C_c\).
In the dispersive limit (\(g \ll f_q, f_r\)), the coupling strength can be related to a coupling capacitance via:
\[g \approx \frac{1}{2} \frac{C_c}{\sqrt{C_\Sigma C_r}} \sqrt{f_q f_r}\]Solving for \(C_c\):
\[C_c = \frac{2g}{\sqrt{f_q f_r}} \sqrt{C_\Sigma C_r}\]See [KKY+19, Sav23] for details.
- Parameters:
g_ghz (float) – Coupling strength in GHz.
c_sigma (float) – Total qubit capacitance in Farads.
c_r (float) – Total resonator capacitance in Farads.
f_q_ghz (float) – Qubit frequency in GHz.
f_r_ghz (float) – Resonator frequency in GHz.
- Returns:
Coupling capacitance in Farads.
- Return type:
Array
Example
>>> C_c = coupling_strength_to_capacitance( ... g_ghz=0.1, ... c_sigma=100e-15, # 100 fF ... c_r=50e-15, # 50 fF ... f_q_ghz=5.0, ... f_r_ghz=7.0, ... ) >>> print(f"{C_c * 1e15:.2f} fF")
cpw_cpw_coupling_capacitance#
- qpdk.models.cpw_cpw_coupling_capacitance(f, length, gap, cross_section)[source]#
Calculate the coupling capacitance between two parallel CPWs.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Frequency array in Hz.
length (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – The coupling length in µm.
gap (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – The gap between the two center conductors in µm.
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the CPW.
- Returns:
The total coupling capacitance in Farads.
- Return type:
float | Array
cpw_epsilon_eff#
- qpdk.models.cpw_epsilon_eff(w, s, h, ep_r)[source]#
Effective permittivity of a CPW on a finite-height substrate.
Uses conformal mapping (Simons [Sim01], Eq. 2.37; Ghione & Naldi [GN84]):
\[\begin{aligned} k_0 &= \frac{w}{w + 2s} \\ k_1 &= \frac{\sinh(\pi w / 4h)} {\sinh\bigl(\pi(w + 2s) / 4h\bigr)} \\ q_1 &= \frac{K(k_1^2)\,/\,K(1 - k_1^2)} {K(k_0^2)\,/\,K(1 - k_0^2)} \\ \varepsilon_{\mathrm{eff}} &= 1 + \frac{q_1\,(\varepsilon_r - 1)}{2} \end{aligned}\]where \(K\) is the complete elliptic integral of the first kind in the parameter convention (\(m = k^2\)).
- Parameters:
w (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Centre-conductor width (m).
s (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Gap to ground plane (m).
h (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Substrate height (m).
ep_r (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Relative permittivity of the substrate.
- Returns:
Effective permittivity (dimensionless).
- Return type:
Array
cpw_parameters#
- qpdk.models.cpw_parameters(width, gap)[source]#
Compute effective permittivity and characteristic impedance for a CPW.
Uses the JAX-jittable functions from
qpdk.models.cpwwith the PDK layer stack (substrate height, conductor thickness, material permittivity).Conductor thickness corrections follow Gupta, Garg, Bahl & Bhartia [GGBB96] (§7.3, Eqs. 7.98-7.100).
- Parameters:
width (float) – Centre-conductor width in µm.
gap (float) – Gap between centre conductor and ground plane in µm.
- Returns:
(ep_eff, z0)— effective permittivity (dimensionless) and characteristic impedance (Ω).- Return type:
tuple[float, float]
cpw_thickness_correction#
- qpdk.models.cpw_thickness_correction(w, s, t, ep_eff)[source]#
Apply conductor thickness correction to CPW ε_eff and Z₀.
First-order correction from Gupta, Garg, Bahl & Bhartia [GGBB96] (§7.3, Eqs. 7.98-7.100):
\[\Delta &= \frac{1.25\,t}{\pi} \left(1 + \ln\\frac{4\pi w}{t}\right) \\ k_e &= k_0 + (1 - k_0^2)\,\frac{\Delta}{2s} \\ \varepsilon_{\mathrm{eff},t} &= \varepsilon_{\mathrm{eff}} - \frac{0.7\,(\varepsilon_{\mathrm{eff}} - 1)\,t/s} {K(k_0^2)/K(1-k_0^2) + 0.7\,t/s} \\ Z_{0,t} &= \frac{30\pi} {\sqrt{\varepsilon_{\mathrm{eff},t}}\; K(k_e^2)/K(1-k_e^2)}\]- Parameters:
w (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Centre-conductor width (m).
s (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Gap to ground plane (m).
t (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Conductor thickness (m).
ep_eff (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Uncorrected effective permittivity.
- Returns:
(ep_eff_t, z0_t)— thickness-corrected effective permittivity and characteristic impedance (Ω).- Return type:
tuple[Array, Array]
cpw_z0#
- qpdk.models.cpw_z0(w, s, ep_eff)[source]#
Characteristic impedance of a CPW.
\[Z_0 = \frac{30\,\pi} {\sqrt{\varepsilon_{\mathrm{eff}}}\; K(k_0^2)\,/\,K(1 - k_0^2)}\](Simons [Sim01], Eq. 2.38.)
Note that our \(w\) and \(s\) correspond to Simons’ \(s\) and \(w\), respectively.
- Parameters:
w (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Centre-conductor width (m).
s (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Gap to ground plane (m).
ep_eff (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Effective permittivity (see
cpw_epsilon_eff()).
- Returns:
Characteristic impedance (Ω).
- Return type:
Array
cpw_z0_from_cross_section#
- qpdk.models.cpw_z0_from_cross_section(cross_section, f=None)[source]#
Characteristic impedance of a CPW defined by a layout cross-section.
- Parameters:
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – A gdsfactory cross-section specification.
f (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray | None) – Frequency array (Hz). Used only to determine the output shape; the impedance is frequency-independent in the quasi-static model.
- Returns:
Characteristic impedance broadcast to the shape of f (Ω).
- Return type:
Array
dispersive_shift#
- qpdk.models.dispersive_shift(ω_t_ghz, ω_r_ghz, α_ghz, g_ghz)[source]#
Compute the dispersive shift numerically.
Evaluates the second-order dispersive shift for a transmon coupled to a resonator. Uses the analytical formula derived from perturbation theory (without the rotating wave approximation) [KYG+07, BGGW21]:
\[\chi = \frac{2g^2}{\Delta - \alpha} - \frac{2g^2}{\Delta} - \frac{2g^2}{\omega_t + \omega_r + \alpha} + \frac{2g^2}{\omega_t + \omega_r}\]where \(\Delta = \omega_t - \omega_r\). The first two terms give the rotating-wave-approximation (RWA) contribution
\[\chi_\text{RWA} = \frac{2 \alpha g^2}{\Delta(\Delta - \alpha)}\]and the last two are corrections from the counter-rotating terms.
All parameters are in GHz, and the returned value is also in GHz.
- Parameters:
ω_t_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Transmon frequency in GHz.
ω_r_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Resonator frequency in GHz.
α_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Transmon anharmonicity in GHz (positive value).
g_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Coupling strength in GHz.
- Returns:
Dispersive shift \(\chi\) in GHz.
- Return type:
float | Array
Example
>>> χ = dispersive_shift(5.0, 7.0, 0.2, 0.1) >>> print(f"χ = {χ * 1e3:.2f} MHz")
dispersive_shift_to_coupling#
- qpdk.models.dispersive_shift_to_coupling(χ_ghz, ω_t_ghz, ω_r_ghz, α_ghz)[source]#
Compute the coupling strength from a target dispersive shift.
Inverts the dispersive shift relation to find the coupling strength \(g\) required to achieve a desired \(\chi\). Uses only the dominant rotating-wave term [KYG+07]:
\[g \approx \sqrt{\frac{-\chi\,\Delta\,(\Delta - \alpha)}{2\alpha}}\]where \(\Delta = \omega_t - \omega_r\).
Note
The expression under the square root may be negative when the sign of the target \(\chi\) is inconsistent with the detuning and anharmonicity (e.g., positive \(\chi\) with \(\Delta < 0\)). In that case the absolute value is taken so that the returned coupling strength is always real and non-negative, but the caller should verify self-consistency via
dispersive_shift().- Parameters:
χ_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Target dispersive shift in GHz (typically negative).
ω_t_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Transmon frequency in GHz.
ω_r_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Resonator frequency in GHz.
α_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Transmon anharmonicity in GHz (positive value; the physical anharmonicity of a transmon is negative, but following the Hamiltonian convention used throughout this module, \(\alpha\) is taken as positive).
- Returns:
Coupling strength \(g\) in GHz.
- Return type:
float | Array
Example
>>> g = dispersive_shift_to_coupling(-0.001, 5.0, 7.0, 0.2) >>> print(f"g = {g * 1e3:.1f} MHz")
double_island_transmon#
- qpdk.models.double_island_transmon(f=5000000000.0, capacitance=1e-13, inductance=7e-09)[source]#
LC resonator model for a double-island transmon qubit.
A double-island transmon has two superconducting islands connected by Josephson junctions, with both islands floating (not grounded). This is modeled as an ungrounded parallel LC resonator.
The qubit frequency is approximately:
\[f_q \approx \frac{1}{2\pi} \sqrt{8 E_J E_C} - E_C\]For the LC model, the resonance frequency is:
\[f_r = \frac{1}{2\pi\sqrt{LC}}\]Use
ec_to_capacitance()andej_to_inductance()to convert from qubit Hamiltonian parameters.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
capacitance (float) – Total capacitance \(C_\Sigma\) of the qubit in Farads.
inductance (float) – Josephson inductance \(L_\text{J}\) in Henries.
- Returns:
S-parameters dictionary with ports o1 and o2.
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import double_island_transmon
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = double_island_transmon(f=freq)
plt.figure()
plt.title("double_island_transmon", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
double_island_transmon_with_bbox#
- qpdk.models.double_island_transmon_with_bbox(f=5000000000.0, capacitance=1e-13, inductance=7e-09)[source]#
LC resonator model for a double-island transmon qubit with bounding box ports.
This model is the same as
double_island_transmon().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
capacitance (float)
inductance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import double_island_transmon_with_bbox
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = double_island_transmon_with_bbox(f=freq)
plt.figure()
plt.title("double_island_transmon_with_bbox", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
double_island_transmon_with_resonator#
- qpdk.models.double_island_transmon_with_resonator(f=5000000000.0, qubit_capacitance=1e-13, qubit_inductance=1e-09, resonator_length=5000.0, resonator_cross_section='cpw', coupling_capacitance=1e-14)[source]#
Model for a double-island transmon qubit coupled to a quarter-wave resonator.
This model is identical to
qubit_with_resonator()but the qubit is set to floating.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
qubit_capacitance (float)
qubit_inductance (float)
resonator_length (float)
resonator_cross_section (str)
coupling_capacitance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import double_island_transmon_with_resonator
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = double_island_transmon_with_resonator(f=freq)
plt.figure()
plt.title("double_island_transmon_with_resonator", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
double_pad_transmon#
- qpdk.models.double_pad_transmon(f=5000000000.0, capacitance=1e-13, inductance=7e-09)#
LC resonator model for a double-island transmon qubit.
A double-island transmon has two superconducting islands connected by Josephson junctions, with both islands floating (not grounded). This is modeled as an ungrounded parallel LC resonator.
The qubit frequency is approximately:
\[f_q \approx \frac{1}{2\pi} \sqrt{8 E_J E_C} - E_C\]For the LC model, the resonance frequency is:
\[f_r = \frac{1}{2\pi\sqrt{LC}}\]Use
ec_to_capacitance()andej_to_inductance()to convert from qubit Hamiltonian parameters.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
capacitance (float) – Total capacitance \(C_\Sigma\) of the qubit in Farads.
inductance (float) – Josephson inductance \(L_\text{J}\) in Henries.
- Returns:
S-parameters dictionary with ports o1 and o2.
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import double_pad_transmon
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = double_pad_transmon(f=freq)
plt.figure()
plt.title("double_pad_transmon", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
double_pad_transmon_with_bbox#
- qpdk.models.double_pad_transmon_with_bbox(f=5000000000.0, capacitance=1e-13, inductance=7e-09)#
LC resonator model for a double-island transmon qubit with bounding box ports.
This model is the same as
double_island_transmon().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
capacitance (float)
inductance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import double_pad_transmon_with_bbox
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = double_pad_transmon_with_bbox(f=freq)
plt.figure()
plt.title("double_pad_transmon_with_bbox", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
double_pad_transmon_with_resonator#
- qpdk.models.double_pad_transmon_with_resonator(f=5000000000.0, qubit_capacitance=1e-13, qubit_inductance=1e-09, resonator_length=5000.0, resonator_cross_section='cpw', coupling_capacitance=1e-14)#
Model for a double-island transmon qubit coupled to a quarter-wave resonator.
This model is identical to
qubit_with_resonator()but the qubit is set to floating.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
qubit_capacitance (float)
qubit_inductance (float)
resonator_length (float)
resonator_cross_section (str)
coupling_capacitance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import double_pad_transmon_with_resonator
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = double_pad_transmon_with_resonator(f=freq)
plt.figure()
plt.title("double_pad_transmon_with_resonator", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
ec_to_capacitance#
- qpdk.models.ec_to_capacitance(ec_ghz)[source]#
Convert charging energy \(E_C\) to total capacitance \(C_\Sigma\).
The charging energy is related to capacitance by:
\[E_C = \frac{e^2}{2 C_\Sigma}\]where \(e\) is the electron charge.
- Parameters:
ec_ghz (float) – Charging energy in GHz.
- Returns:
Total capacitance in Farads.
- Return type:
float
Example
>>> C = ec_to_capacitance(0.2) # 0.2 GHz (200 MHz) charging energy >>> print(f"{C * 1e15:.1f} fF") # ~96 fF
ej_ec_to_frequency_and_anharmonicity#
- qpdk.models.ej_ec_to_frequency_and_anharmonicity(ej_ghz, ec_ghz)[source]#
Convert \(E_J\) and \(E_C\) to qubit frequency and anharmonicity.
Uses the standard transmon approximations [KYG+07]:
\[\begin{aligned} \omega_q &\approx \sqrt{8 E_J E_C} - E_C \\ \alpha &\approx E_C \end{aligned}\]Note
The physical anharmonicity of a transmon is negative (\(\alpha = -E_C\)), but the Hamiltonian convention used in this module and in pymablock takes \(\alpha\) as positive.
- Parameters:
ej_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Josephson energy in GHz.
ec_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Charging energy in GHz.
- Returns:
Tuple of
(ω_q_ghz, α_ghz).- Return type:
tuple[float | Array, float | Array]
Example
>>> ω_q, α = ej_ec_to_frequency_and_anharmonicity(20.0, 0.2) >>> print(f"ω_q = {ω_q:.2f} GHz, α = {α:.1f} GHz")
ej_to_inductance#
- qpdk.models.ej_to_inductance(ej_ghz)[source]#
Convert Josephson energy \(E_J\) to Josephson inductance \(L_\text{J}\).
The Josephson energy is related to inductance by:
\[E_J = \frac{\Phi_0^2}{4 \pi^2 L_\text{J}} = \frac{(\hbar / 2e)^2}{L_\text{J}}\]This is equivalent to:
\[L_\text{J} = \frac{\Phi_0}{2 \pi I_c}\]where \(I_c\) is the critical current and \(\Phi_0\) is the magnetic flux quantum.
- Parameters:
ej_ghz (float) – Josephson energy in GHz.
- Returns:
Josephson inductance in Henries.
- Return type:
float
Example
>>> L = ej_to_inductance(20.0) # 20 GHz Josephson energy >>> print(f"{L * 1e9:.2f} nH") # ~1.0 nH
electrical_short_2_port#
- qpdk.models.electrical_short_2_port(f=5000000000.0)[source]#
Electrical short 2-port connection Sax model.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import electrical_short_2_port
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = electrical_short_2_port(f=freq)
plt.figure()
plt.title("electrical_short_2_port", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
flipmon#
- qpdk.models.flipmon(f=5000000000.0, capacitance=1e-13, inductance=7e-09)[source]#
LC resonator model for a flipmon qubit.
This model is identical to
double_island_transmon().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
capacitance (float)
inductance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import flipmon
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = flipmon(f=freq)
plt.figure()
plt.title("flipmon", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
flipmon_with_bbox#
- qpdk.models.flipmon_with_bbox(f=5000000000.0, capacitance=1e-13, inductance=7e-09)[source]#
LC resonator model for a flipmon qubit with bounding box ports.
This model is the same as
flipmon().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
capacitance (float)
inductance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import flipmon_with_bbox
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = flipmon_with_bbox(f=freq)
plt.figure()
plt.title("flipmon_with_bbox", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
flipmon_with_resonator#
- qpdk.models.flipmon_with_resonator(f=5000000000.0, qubit_capacitance=1e-13, qubit_inductance=1e-09, resonator_length=5000.0, resonator_cross_section='cpw', coupling_capacitance=1e-14)[source]#
Model for a flipmon qubit coupled to a quarter-wave resonator.
This model is identical to
qubit_with_resonator()but the qubit is set to floating.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
qubit_capacitance (float)
qubit_inductance (float)
resonator_length (float)
resonator_cross_section (str)
coupling_capacitance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import flipmon_with_resonator
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = flipmon_with_resonator(f=freq)
plt.figure()
plt.title("flipmon_with_resonator", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
indium_bump#
- qpdk.models.indium_bump(f=5000000000.0, bump_height=10.0)[source]#
S-parameter model for an indium bump, wrapped to
straight().TODO: add a constant loss channel for indium bumps.
- Parameters:
f (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Array of frequency points in Hz
bump_height (float) – Physical height (length) of the indium bump in µm.
- Returns:
S-parameters dictionary
- Return type:
sax.SType
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import indium_bump
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = indium_bump(f=freq)
plt.figure()
plt.title("indium_bump", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
interdigital_capacitor#
- qpdk.models.interdigital_capacitor(*, f=5000000000.0, fingers=4, finger_length=20.0, finger_gap=2.0, thickness=5.0, cross_section='cpw')[source]#
Interdigital capacitor Sax model.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
fingers (int) – Total number of fingers (must be >= 2)
finger_length (float) – Length of each finger in μm
finger_gap (float) – Gap between adjacent fingers in μm
thickness (float) – Thickness of fingers in μm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – Cross-section specification
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import interdigital_capacitor
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = interdigital_capacitor(f=freq)
plt.figure()
plt.title("interdigital_capacitor", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
josephson_junction#
- qpdk.models.josephson_junction(*, f=5000000000.0, ic=1e-06, capacitance=5e-15, resistance=10000.0, ib=0.0)[source]#
Josephson junction (RCSJ) small-signal Sax model.
Linearized RCSJ model consisting of a bias-dependent Josephson inductance in parallel with capacitance and resistance.
Valid in the superconducting (zero-voltage) state and for small AC signals.
Default capacitance taken from [SFS+15].
See [McC68] for details.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
ic (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Critical current \(I_c\) in Amperes
capacitance (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Junction capacitance \(C\) in Farads
resistance (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Shunt resistance \(R\) in Ohms
ib (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – DC bias current \(I_b\) in Amperes (\(\|I_b\| < I_c\))
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import josephson_junction
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = josephson_junction(f=freq)
plt.figure()
plt.title("josephson_junction", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
launcher#
- qpdk.models.launcher(f=5000000000.0, straight_length=200.0, taper_length=100.0, cross_section_big=None, cross_section_small='cpw')[source]#
S-parameter model for a launcher, effectively a straight section followed by a taper.
- Parameters:
f (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Array of frequency points in Hz
straight_length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Length of the straight section in µm.
taper_length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Length of the taper section in µm.
cross_section_big (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection | None) – Cross-section for the wide section.
cross_section_small (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – Cross-section for the narrow section.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
lc_resonator#
- qpdk.models.lc_resonator(f=5000000000.0, capacitance=1e-13, inductance=1e-09, grounded=False)[source]#
LC resonator Sax model with capacitor and inductor in parallel.
The resonance frequency is given by:
If grounded=True, a 2-port short is connected to port o2:
\[f_r = \frac{1}{2 \pi \sqrt{LC}}\]For theory and relation to superconductors, see [Gao08].
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
capacitance (float) – Capacitance of the resonator in Farads.
inductance (float) – Inductance of the resonator in Henries.
grounded (bool) – If True, add a 2-port ground to the second port.
- Returns:
S-parameters dictionary with ports o1 and o2.
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import lc_resonator
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = lc_resonator(f=freq)
plt.figure()
plt.title("lc_resonator", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
lc_resonator_coupled#
- qpdk.models.lc_resonator_coupled(f=5000000000.0, capacitance=1e-13, inductance=1e-09, grounded=False, coupling_capacitance=1e-14, coupling_inductance=0.0)[source]#
Coupled LC resonator Sax model.
This model extends the basic LC resonator by adding a coupling network consisting of a parallel capacitor and inductor connected to one port of the LC resonator via a tee junction.
The resonance frequency of the main LC resonator is given by:
\[f_r = \frac{1}{2 \pi \sqrt{LC}}\]The coupling network modifies the effective coupling to the resonator.
Where \(L_\text{c}\) and \(C_\text{c}\) are the coupling inductance and capacitance, respectively.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
capacitance (float) – Capacitance of the main resonator in Farads.
inductance (float) – Inductance of the main resonator in Henries.
grounded (bool) – If True, the resonator is grounded.
coupling_capacitance (float) – Coupling capacitance in Farads.
coupling_inductance (float) – Coupling inductance in Henries.
- Returns:
S-parameters dictionary with ports o1 and o2.
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import lc_resonator_coupled
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = lc_resonator_coupled(f=freq)
plt.figure()
plt.title("lc_resonator_coupled", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
measurement_induced_dephasing#
- qpdk.models.measurement_induced_dephasing(χ_ghz, κ_ghz, n_bar)[source]#
Estimate measurement-induced dephasing rate.
During dispersive readout, photons in the resonator cause additional dephasing of the qubit [BGGW21, GBS+06]:
\[\Gamma_\phi = \frac{8 \chi^2 \bar{n}}{\kappa}\]where \(\bar{n}\) is the mean photon number in the resonator.
- Parameters:
χ_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Dispersive shift in GHz.
κ_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Resonator linewidth in GHz.
n_bar (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Mean photon number in the resonator during measurement.
- Returns:
Measurement-induced dephasing rate in GHz.
- Return type:
float | Array
Example
>>> Γ_φ = measurement_induced_dephasing(-0.001, 0.001, 5.0) >>> print(f"Γ_φ = {Γ_φ * 1e6:.1f} kHz")
microstrip_epsilon_eff#
- qpdk.models.microstrip_epsilon_eff(w, h, ep_r)[source]#
Effective permittivity of a microstrip line.
Uses the Hammerstad-Jensen [HJ80] formula as given in Pozar [MP12] (Eq. 3.195-3.196):
\[\varepsilon_{\mathrm{eff}} = \frac{\varepsilon_r + 1}{2} + \frac{\varepsilon_r - 1}{2} \left(\frac{1}{\sqrt{1 + 12\,h/w}} + 0.04\,(1 - w/h)^2\;\Theta(1 - w/h)\right)\]where the last term contributes only for narrow strips (\(w/h < 1\)).
- Parameters:
w (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Strip width (m).
h (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Substrate height (m).
ep_r (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Relative permittivity of the substrate.
- Returns:
Effective permittivity (dimensionless).
- Return type:
Array
microstrip_thickness_correction#
- qpdk.models.microstrip_thickness_correction(w, h, t, ep_r, ep_eff)[source]#
Conductor thickness correction for a microstrip line.
Uses the widely-adopted Schneider correction as presented in Pozar [MP12] (§3.8) and Gupta et al. [GGBB96]:
\[w_e &= w + \frac{t}{\pi} \ln\frac{4e}{\sqrt{(t/h)^2 + (t/(w\pi + 1.1t\pi))^2}} \\ \varepsilon_{\mathrm{eff},t} &= \varepsilon_{\mathrm{eff}} - \frac{(\varepsilon_r - 1)\,t/h} {4.6\,\sqrt{w/h}}\]Then the corrected \(Z_0\) is computed with the effective width \(w_e\) and corrected \(\varepsilon_{\mathrm{eff},t}\).
- Parameters:
w (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Strip width (m).
h (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Substrate height (m).
t (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Conductor thickness (m).
ep_r (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Relative permittivity of the substrate.
ep_eff (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Uncorrected effective permittivity.
- Returns:
(w_eff, ep_eff_t, z0_t)— effective width (m), thickness-corrected effective permittivity, and characteristic impedance (Ω).- Return type:
tuple[Array, Array, Array]
microstrip_z0#
- qpdk.models.microstrip_z0(w, h, ep_eff)[source]#
Characteristic impedance of a microstrip line.
Uses the Hammerstad-Jensen [HJ80] approximation as given in Pozar [MP12] (Eq. 3.197-3.198):
\[Z_0 = \begin{cases} \displaystyle\frac{60}{\sqrt{\varepsilon_{\mathrm{eff}}}} \ln\!\left(\frac{8h}{w} + \frac{w}{4h}\right) & w/h \le 1 \\[6pt] \displaystyle\frac{120\pi} {\sqrt{\varepsilon_{\mathrm{eff}}}\, \bigl[w/h + 1.393 + 0.667\ln(w/h + 1.444)\bigr]} & w/h \ge 1 \end{cases}\]- Parameters:
w (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Strip width (m).
h (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Substrate height (m).
ep_eff (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Effective permittivity (see
microstrip_epsilon_eff()).
- Returns:
Characteristic impedance (Ω).
- Return type:
Array
nxn#
- qpdk.models.nxn(f=5000000000.0, west=1, east=1, north=1, south=1)[source]#
NxN junction model using tee components.
This model creates an N-port divider/combiner by chaining 3-port tee junctions. All ports are connected to a single node.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
west (int) – Number of ports on the west side.
east (int) – Number of ports on the east side.
north (int) – Number of ports on the north side.
south (int) – Number of ports on the south side.
- Returns:
S-parameters dictionary with ports o1, o2, …, oN.
- Return type:
sax.SType
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import nxn
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = nxn(f=freq)
plt.figure()
plt.title("nxn", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
open#
- qpdk.models.open(*, f=5000000000.0, n_ports=1)#
Electrical open connection Sax model.
Useful for specifying some ports to remain open while not exposing them for connections in circuits.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
n_ports (int) – Number of ports to set as opened
- Returns:
S-dictionary where \(S = I_\text{n\_ports}\)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]]
References
[@pozar2012]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import open
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = open(f=freq)
plt.figure()
plt.title("open", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
plate_capacitor#
- qpdk.models.plate_capacitor(*, f=5000000000.0, length=26.0, width=5.0, gap=7.0, cross_section='cpw')[source]#
Plate capacitor Sax model.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (float) – Length of the capacitor pad in μm
width (float) – Width of the capacitor pad in μm
gap (float) – Gap between plates in μm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – Cross-section specification
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import plate_capacitor
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = plate_capacitor(f=freq)
plt.figure()
plt.title("plate_capacitor", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
propagation_constant#
- qpdk.models.propagation_constant(f, ep_eff, tand=0.0, ep_r=1.0)[source]#
Complex propagation constant of a quasi-TEM transmission line.
For the general lossy case (Pozar [MP12], §3.8):
\[\gamma = \alpha_d + j\,\beta\]where the dielectric attenuation is
\[\alpha_d = \frac{\pi f}{c_0} \frac{\varepsilon_r}{\sqrt{\varepsilon_{\mathrm{eff}}}} \frac{\varepsilon_{\mathrm{eff}} - 1} {\varepsilon_r - 1} \tan\delta\]and the phase constant is
\[\beta = \frac{2\pi f}{c_0}\,\sqrt{\varepsilon_{\mathrm{eff}}}\]For a superconducting line (\(\tan\delta = 0\)) the propagation is purely imaginary: \(\gamma = j\beta\).
- Parameters:
f (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Frequency (Hz).
ep_eff (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Effective permittivity.
tand (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Dielectric loss tangent (default 0 — lossless).
ep_r (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Substrate relative permittivity (only needed when
tand > 0).
- Returns:
Complex propagation constant \(\gamma\) (1/m).
- Return type:
Array
purcell_decay_rate#
- qpdk.models.purcell_decay_rate(g_ghz, ω_t_ghz, ω_r_ghz, κ_ghz)[source]#
Estimate the Purcell decay rate of a transmon through a resonator.
The Purcell effect limits qubit lifetime when coupled to a lossy resonator. In the dispersive regime [BGGW21, HSJ+08]:
\[\gamma_\text{Purcell} = \kappa \left(\frac{g}{\Delta}\right)^2\]where \(\kappa\) is the resonator decay rate and \(\Delta = \omega_t - \omega_r\).
- Parameters:
g_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Coupling strength in GHz.
ω_t_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Transmon frequency in GHz.
ω_r_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Resonator frequency in GHz.
κ_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Resonator linewidth (decay rate) in GHz.
- Returns:
Purcell decay rate in GHz.
- Return type:
float | Array
Example
>>> γ = purcell_decay_rate(0.1, 5.0, 7.0, 0.001) >>> T_purcell = 1 / (γ * 1e9) >>> print(f"T_Purcell = {T_purcell * 1e6:.0f} µs")
quarter_wave_resonator_coupled#
- qpdk.models.quarter_wave_resonator_coupled(f=5000000000.0, length=5000.0, coupling_gap=0.27, coupling_straight_length=20, cross_section='cpw')[source]#
Model for a quarter-wave coplanar waveguide resonator coupled to a probeline.
- Parameters:
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the CPW.
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Frequency in Hz at which to evaluate the S-parameters.
length (float) – Total length of the resonator in μm.
coupling_gap (float) – Gap between the resonator and the probeline in μm.
coupling_straight_length (float) – Length of the coupling section in μm.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import quarter_wave_resonator_coupled
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = quarter_wave_resonator_coupled(f=freq)
plt.figure()
plt.title("quarter_wave_resonator_coupled", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
qubit_with_resonator#
- qpdk.models.qubit_with_resonator(f=5000000000.0, qubit_capacitance=1e-13, qubit_inductance=1e-09, qubit_grounded=False, resonator_length=5000.0, resonator_cross_section='cpw', coupling_capacitance=1e-14)[source]#
Model for a transmon qubit coupled to a quarter-wave resonator.
This model corresponds to the layout function
transmon_with_resonator().The model combines: - A transmon qubit (LC resonator) - A quarter-wave coplanar waveguide resonator - A coupling capacitor connecting the qubit to the resonator
The qubit can be either: - A double-island transmon (
qubit_grounded=False): both islands floating - A shunted transmon (qubit_grounded=True): one island groundedUse
ec_to_capacitance()andej_to_inductance()to convert from qubit Hamiltonian parameters (\(E_C\), \(E_J\)) to circuit parameters.Note
This function is not JIT-compiled because it depends on
straight_shorted(), which internally uses cpw_parameters for transmission line modeling.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
qubit_capacitance (float) – Total capacitance \(C_\Sigma\) of the qubit in Farads. Convert from charging energy using
ec_to_capacitance().qubit_inductance (float) – Josephson inductance \(L_\text{J}\) in Henries. Convert from Josephson energy using
ej_to_inductance().qubit_grounded (bool) – If True, the qubit is a shunted transmon (grounded). If False, it is a double-island transmon (ungrounded).
resonator_length (float) – Length of the quarter-wave resonator in µm.
resonator_cross_section (str) – Cross-section specification for the resonator.
coupling_capacitance (float) – Coupling capacitance between qubit and resonator in Farads. Use
coupling_strength_to_capacitance()to convert from qubit-resonator coupling strength \(g\).
- Returns:
- S-parameters dictionary with ports
o1(resonator input) and
o2(qubit ground or floating).
- S-parameters dictionary with ports
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import qubit_with_resonator
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = qubit_with_resonator(f=freq)
plt.figure()
plt.title("qubit_with_resonator", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
rectangle#
- qpdk.models.rectangle(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a rectangular section, wrapped to
straight().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import rectangle
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = rectangle(f=freq)
plt.figure()
plt.title("rectangle", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
resonator#
- qpdk.models.resonator(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a simple transmission line resonator.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SType
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import resonator
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = resonator(f=freq)
plt.figure()
plt.title("resonator", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
resonator_coupled#
- qpdk.models.resonator_coupled(f=5000000000.0, length=5000.0, coupling_gap=0.27, coupling_straight_length=20, cross_section='cpw', open_start=True, open_end=False)[source]#
Model for a coplanar waveguide resonator coupled to a probeline.
- Parameters:
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the CPW.
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Frequency in Hz at which to evaluate the S-parameters.
length (float) – Total length of the resonator in μm.
coupling_gap (float) – Gap between the resonator and the probeline in μm.
coupling_straight_length (float) – Length of the coupling section in μm.
open_start (bool) – If True, adds an electrical open at the start.
open_end (bool) – If True, adds an electrical open at the end.
- Returns:
S-parameters dictionary with 4 ports.
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import resonator_coupled
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = resonator_coupled(f=freq)
plt.figure()
plt.title("resonator_coupled", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
resonator_frequency#
- qpdk.models.resonator_frequency(*, length, epsilon_eff=None, media=None, cross_section='cpw', is_quarter_wave=True)[source]#
Calculate the resonance frequency of a quarter- or half-wave CPW resonator.
\[\begin{aligned} f &= \frac{v_p}{4L} \mathtt{ (quarter-wave resonator)} \\ f &= \frac{v_p}{2L} \mathtt{ (half-wave resonator)} \end{aligned}\]The phase velocity is \(v_p = c_0 / \sqrt{\varepsilon_{\mathrm{eff}}}\).
See [MP12, Sim01] for details.
- Parameters:
length (float) – Length of the resonator in μm.
epsilon_eff (float | None) – Effective permittivity. If
None(default), computed from cross_section usingcpw_parameters().media (Any) – Deprecated. Use epsilon_eff or cross_section instead.
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – Cross-section specification (used only when epsilon_eff and media are not provided).
is_quarter_wave (bool) – If True, calculates for a quarter-wave resonator; if False, for a half-wave resonator. default is True.
- Returns:
Resonance frequency in Hz.
- Return type:
float
resonator_half_wave#
- qpdk.models.resonator_half_wave(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a half-wave resonator (open at both ends).
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SType
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import resonator_half_wave
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = resonator_half_wave(f=freq)
plt.figure()
plt.title("resonator_half_wave", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
resonator_linewidth_from_q#
- qpdk.models.resonator_linewidth_from_q(ω_r_ghz, q_ext)[source]#
Compute resonator linewidth from external quality factor.
Converts external quality factor to linewidth (half-linewidth at half-maximum) [MP12, GopplFB+08]:
\[\kappa = \frac{\omega_r}{Q_\text{ext}}\]- Parameters:
ω_r_ghz (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – Resonator frequency in GHz.
q_ext (float | Array | ndarray | bool | number | bool | int | complex | TypedNdArray) – External quality factor.
- Returns:
Resonator linewidth \(\kappa\) in GHz.
- Return type:
float | Array
Example
>>> κ = resonator_linewidth_from_q(7.0, 10_000) >>> print(f"κ = {κ * 1e6:.1f} kHz")
resonator_quarter_wave#
- qpdk.models.resonator_quarter_wave(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a quarter-wave resonator (shorted at one end).
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SType
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import resonator_quarter_wave
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = resonator_quarter_wave(f=freq)
plt.figure()
plt.title("resonator_quarter_wave", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
short#
- qpdk.models.short(*, f=5000000000.0, n_ports=1)#
Electrical short connection Sax model.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
n_ports (int) – Number of ports to set as shorted
- Returns:
S-dictionary where \(S = -I_\text{n\_ports}\)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]]
References
[@pozar2012]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import short
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = short(f=freq)
plt.figure()
plt.title("short", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
short_2_port#
- qpdk.models.short_2_port(f=5000000000.0)#
Electrical short 2-port connection Sax model.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import short_2_port
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = short_2_port(f=freq)
plt.figure()
plt.title("short_2_port", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
shunted_transmon#
- qpdk.models.shunted_transmon(f=5000000000.0, capacitance=1e-13, inductance=7e-09)[source]#
LC resonator model for a shunted transmon qubit.
A shunted transmon has one island grounded and the other island connected to the junction. This is modeled as a grounded parallel LC resonator.
The qubit frequency is approximately:
\[f_q \approx \frac{1}{2\pi} \sqrt{8 E_J E_C} - E_C\]For the LC model, the resonance frequency is:
\[f_r = \frac{1}{2\pi\sqrt{LC}}\]Use
ec_to_capacitance()andej_to_inductance()to convert from qubit Hamiltonian parameters.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
capacitance (float) – Total capacitance \(C_\Sigma\) of the qubit in Farads.
inductance (float) – Josephson inductance \(L_\text{J}\) in Henries.
- Returns:
S-parameters dictionary with ports o1 and o2.
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import shunted_transmon
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = shunted_transmon(f=freq)
plt.figure()
plt.title("shunted_transmon", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
squid_junction#
- qpdk.models.squid_junction(*, f=5000000000.0, ic_tot=2e-06, asymmetry=0.0, capacitance=1e-14, resistance=5000.0, ib=0.0, flux=0.0)[source]#
DC SQUID small-signal Sax model in the zero-screening limit.
Treats the DC SQUID as a single effective RCSJ whose critical current is tunable by an external magnetic flux. Assumes negligible loop geometric inductance.
See [KYG+07] and [Tin15] for details on asymmetric SQUIDs and effective Josephson inductance.
- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
ic_tot (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Total critical current sum \(I_{c1} + I_{c2}\) in Amperes
asymmetry (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Junction asymmetry \((I_{c1} - I_{c2}) / I_{c,tot}\)
capacitance (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Total SQUID capacitance \(C_1 + C_2\) in Farads
resistance (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Total SQUID shunt resistance \(R_1 || R_2\) in Ohms
ib (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – DC bias current \(I_b\) in Amperes
flux (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – External magnetic flux \(\Phi_{ext}\) in Webers
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import squid_junction
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = squid_junction(f=freq)
plt.figure()
plt.title("squid_junction", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
straight#
- qpdk.models.straight(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a straight coplanar waveguide.
Computes S-parameters analytically using conformal-mapping CPW theory following Simons [Sim01] (ch. 2) and the Qucs-S CPW model (Qucs technical documentation, §12.4). Conductor thickness corrections use the first-order model of Gupta, Garg, Bahl, and Bhartia [GGBB96].
The propagation constant and characteristic impedance are evaluated with pure-JAX functions (see
qpdk.models.cpw) so the model composes withjax.jit,jax.grad, andjax.vmap.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import straight
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = straight(f=freq)
plt.figure()
plt.title("straight", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
straight_double_open#
- qpdk.models.straight_double_open(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a straight waveguide with open ends.
Note
Ports
o1ando2are internally open-circuited and should not be used. They are provided to match the number of ports in the layout component.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SType
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import straight_double_open
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = straight_double_open(f=freq)
plt.figure()
plt.title("straight_double_open", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
straight_microstrip#
- qpdk.models.straight_microstrip(f=5000000000.0, length=1000, width=10.0, h=500.0, t=0.2, ep_r=11.45, tand=0.0)[source]#
S-parameter model for a straight microstrip transmission line.
Computes S-parameters analytically using the Hammerstad-Jensen [HJ80] closed-form expressions for effective permittivity and characteristic impedance, as described in Pozar [MP12] (ch. 3, §3.8). Conductor thickness corrections follow Gupta et al. [GGBB96] (§2.2.4).
All computation is done with pure-JAX functions (see
qpdk.models.cpw) so the model composes withjax.jit,jax.grad, andjax.vmap.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm.
width (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Strip width in µm.
h (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Substrate height in µm.
t (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Conductor thickness in µm (default 0.2 µm = 200 nm).
ep_r (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Relative permittivity of the substrate (default 11.45 for Si).
tand (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Dielectric loss tangent (default 0 — lossless).
- Returns:
S-parameters dictionary.
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import straight_microstrip
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = straight_microstrip(f=freq)
plt.figure()
plt.title("straight_microstrip", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
straight_open#
- qpdk.models.straight_open(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a straight waveguide with one open end.
Note
The port
o2is internally open-circuited and should not be used. It is provided to match the number of ports in the layout component.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SType
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import straight_open
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = straight_open(f=freq)
plt.figure()
plt.title("straight_open", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
straight_shorted#
- qpdk.models.straight_shorted(f=5000000000.0, length=1000, cross_section='cpw')[source]#
S-parameter model for a straight waveguide with one shorted end.
This may be used to model a quarter-wave coplanar waveguide resonator.
Note
The port
o2is internally shorted and should not be used. It seems to be a Sax limitation that we need to define at least two ports.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – The cross-section of the waveguide.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import straight_shorted
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = straight_shorted(f=freq)
plt.figure()
plt.title("straight_shorted", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
taper_cross_section#
- qpdk.models.taper_cross_section(f=5000000000.0, length=1000, cross_section_1='cpw', cross_section_2='cpw', n_points=50)[source]#
S-parameter model for a cross-section taper using linear interpolation.
- Parameters:
f (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Array of frequency points in Hz
length (Annotated[float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)]) – Physical length in µm
cross_section_1 (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – Cross-section for the start of the taper.
cross_section_2 (CrossSection | str | dict[str, Any] | Callable[[...], CrossSection] | SymmetricalCrossSection | DCrossSection) – Cross-section for the end of the taper.
n_points (int) – Number of segments to divide the taper into for simulation.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import taper_cross_section
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = taper_cross_section(f=freq)
plt.figure()
plt.title("taper_cross_section", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
transmission_line_s_params#
- qpdk.models.transmission_line_s_params(gamma, z0, length, z_ref=None)[source]#
S-parameters of a uniform transmission line (ABCD→S conversion).
The ABCD matrix of a line with characteristic impedance \(Z_0\), propagation constant \(\gamma\), and length \(\ell\) is
\[\begin{pmatrix} A & B \\ C & D \end{pmatrix} = \begin{pmatrix} \cosh\theta & Z_0\sinh\theta \\ \sinh\theta / Z_0 & \cosh\theta \end{pmatrix}, \quad \theta = \gamma\,\ell.\]Converting to S-parameters referenced to \(Z_{\mathrm{ref}}\) (Pozar [MP12], Table 4.2):
\[\begin{aligned} S_{11} &= \frac{A + B/Z_{\mathrm{ref}} - C\,Z_{\mathrm{ref}} - D} {A + B/Z_{\mathrm{ref}} + C\,Z_{\mathrm{ref}} + D} \\ S_{21} &= \frac{2} {A + B/Z_{\mathrm{ref}} + C\,Z_{\mathrm{ref}} + D} \end{aligned}\]When
z_refisNonethe reference impedance defaults toz0(matched case), giving \(S_{11} = 0\) and \(S_{21} = e^{-\gamma\ell}\).- Parameters:
gamma (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Complex propagation constant (1/m).
z0 (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Characteristic impedance (Ω).
length (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Physical length (m).
z_ref (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray | None) – Reference (port) impedance (Ω). Defaults to
z0.
- Returns:
(S11, S21)— complex S-parameter arrays.- Return type:
tuple[Array, Array]
transmon_coupled#
- qpdk.models.transmon_coupled(f=5000000000.0, capacitance=1e-13, inductance=1e-09, grounded=False, coupling_capacitance=1e-14, coupling_inductance=0.0)[source]#
Coupled transmon qubit model.
This model extends the basic transmon qubit by adding a coupling network consisting of a parallel capacitor and/or inductor. This can represent capacitive or inductive coupling between qubits or between a qubit and a readout resonator.
The coupling network is connected in series with the LC resonator:
- For capacitive coupling (common for qubit-resonator coupling):
Set
coupling_capacitanceto the coupling capacitor valueSet
coupling_inductance=0.0
- For inductive coupling (common for flux-tunable coupling):
Set
coupling_inductanceto the coupling inductor valueSet
coupling_capacitance=0.0(or small value)
Use
coupling_strength_to_capacitance()to convert from the qubit-resonator coupling strength \(g\) to the coupling capacitance.- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)]) – Array of frequency points in Hz.
capacitance (float) – Total capacitance \(C_\Sigma\) of the qubit in Farads.
inductance (float) – Josephson inductance \(L_\text{J}\) in Henries.
grounded (bool) – If True, the qubit is a shunted transmon (grounded). If False, it is a double-pad transmon (ungrounded).
coupling_capacitance (float) – Coupling capacitance \(C_c\) in Farads.
coupling_inductance (float) – Coupling inductance \(L_c\) in Henries.
- Returns:
S-parameters dictionary with ports o1 and o2.
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import transmon_coupled
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = transmon_coupled(f=freq)
plt.figure()
plt.title("transmon_coupled", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
transmon_with_resonator#
- qpdk.models.transmon_with_resonator(f=5000000000.0, qubit_capacitance=1e-13, qubit_inductance=1e-09, qubit_grounded=False, resonator_length=5000.0, resonator_cross_section='cpw', coupling_capacitance=1e-14)[source]#
Model for a transmon qubit coupled to a quarter-wave resonator.
This model is identical to
qubit_with_resonator().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
qubit_capacitance (float)
qubit_inductance (float)
qubit_grounded (bool)
resonator_length (float)
resonator_cross_section (str)
coupling_capacitance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import transmon_with_resonator
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = transmon_with_resonator(f=freq)
plt.figure()
plt.title("transmon_with_resonator", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
tsv#
- qpdk.models.tsv(f=5000000000.0, via_height=1000.0)[source]#
S-parameter model for a through-silicon via (TSV), wrapped to
straight().TODO: add a constant loss channel for TSVs.
- Parameters:
f (Array | ndarray | bool | number | bool | int | float | complex | TypedNdArray) – Array of frequency points in Hz
via_height (float) – Physical height (length) of the TSV in µm.
- Returns:
S-parameters dictionary
- Return type:
sax.SDict
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import tsv
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = tsv(f=freq)
plt.figure()
plt.title("tsv", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
xmon_transmon#
- qpdk.models.xmon_transmon(f=5000000000.0, capacitance=1e-13, inductance=7e-09)[source]#
LC resonator model for an Xmon style transmon qubit.
An Xmon transmon is typically shunted, so this model wraps
shunted_transmon().- Parameters:
f (Annotated[Array | ndarray | Annotated[Annotated[int | integer, PlainValidator(func=~sax.saxtypes.core.val_int, json_schema_input_type=~typing.Any)] | float | floating, PlainValidator(func=~sax.saxtypes.core.val_float, json_schema_input_type=~typing.Any)], floating, PlainValidator(func=~sax.saxtypes.core.val_float_array, json_schema_input_type=~typing.Any)])
capacitance (float)
inductance (float)
- Return type:
dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.singlemode.val_port, json_schema_input_type=~typing.Any)], int]] | dict[tuple[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)]], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)]] | tuple[Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array | ndarray, signedinteger, 1, PlainValidator(func=~sax.saxtypes.core.val_int_array_1d, json_schema_input_type=~typing.Any)], Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]] | tuple[Annotated[Array, complexfloating, PlainValidator(func=~sax.saxtypes.core.val_complex_array, json_schema_input_type=~typing.Any)], dict[Annotated[str, PlainValidator(func=~sax.saxtypes.multimode.val_port_mode, json_schema_input_type=~typing.Any)], int]]
import jax.numpy as jnp
import matplotlib.pyplot as plt
from qpdk.models import xmon_transmon
from qpdk import PDK
PDK.activate()
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9
s_model = xmon_transmon(f=freq)
plt.figure()
plt.title("xmon_transmon", fontsize=14)
for (pout, pin), sij in s_model.items():
i = int(pout[-1]) # "o2" -> 2
j = int(pin[-1]) # "o1" -> 1
if i >= j:
plt.plot(
freq_ghz,
20 * jnp.log10(jnp.abs(sij)),
label = "$S_{" + str(i) + str(j) + "}$"
)
plt.xlabel("Frequency [GHz]", fontsize=12)
plt.ylabel("Magnitude [dB]", fontsize=12)
plt.grid(True)
plt.legend()
plt.show()
(Source code, png, hires.png, pdf)
References#
Alexandre Blais, Arne L. Grimsmo, S. M. Girvin, and Andreas Wallraff. Circuit quantum electrodynamics. Reviews of Modern Physics, 93(2):025005, May 2021. doi:10.1103/RevModPhys.93.025005.
Zijun Chen, A. Megrant, J. Kelly, R. Barends, J. Bochmann, Yu Chen, B. Chiaro, A. Dunsworth, E. Jeffrey, J. Y. Mutus, P. J. J. O'Malley, C. Neill, P. Roushan, D. Sank, A. Vainsencher, J. Wenner, T. C. White, A. N. Cleland, and John M. Martinis. Fabrication and characterization of aluminum airbridges for superconducting microwave circuits. Applied Physics Letters, February 2014. doi:10.1063/1.4863745.
J. Gambetta, A. Blais, D. I. Schuster, A. Wallraff, L. Frunzio, J. Majer, M. H. Devoret, S. M. Girvin, and R. J. Schoelkopf. Qubit-photon interactions in a cavity: measurement-induced dephasing and number splitting. Physical Review A, 74(4):042318, October 2006. doi:10.1103/PhysRevA.74.042318.
Jiansong Gao. The Physics of Superconducting Microwave Resonators. PhD thesis, California Institute of Technology, 2008. doi:10.7907/RAT0-VM75.
G. Ghione and C. Naldi. Analytical formulas for coplanar lines in hybrid and monolithic MICs. Electronics Letters, 20(4):179–181, February 1984. doi:10.1049/el:19840120.
Kuldip C. Gupta, R. Garg, I. Bahl, and P. Bhartia. Microstrip Lines and Slotlines. Artech House, Boston, 2. ed edition, 1996. ISBN 978-0-89006-766-6.
M. Göppl, A. Fragner, M. Baur, R. Bianchetti, S. Filipp, J. M. Fink, P. J. Leek, G. Puebla, L. Steffen, and A. Wallraff. Coplanar waveguide resonators for circuit quantum electrodynamics. Journal of Applied Physics, 104(11):113904, December 2008. doi:10.1063/1.3010859.
E. Hammerstad and O. Jensen. Accurate Models for Microstrip Computer-Aided Design. In 1980 IEEE MTT-S International Microwave Symposium Digest, 407–409. Washington, DC, USA, 1980. IEEE. doi:10.1109/MWSYM.1980.1124303.
A. A. Houck, J. A. Schreier, B. R. Johnson, J. M. Chow, Jens Koch, J. M. Gambetta, D. I. Schuster, L. Frunzio, M. H. Devoret, S. M. Girvin, and R. J. Schoelkopf. Controlling the spontaneous emission of a superconducting transmon qubit. Physical Review Letters, 101(8):080502, August 2008. doi:10.1103/PhysRevLett.101.080502.
Jens Koch, Terri M. Yu, Jay Gambetta, A. A. Houck, D. I. Schuster, J. Majer, Alexandre Blais, M. H. Devoret, S. M. Girvin, and R. J. Schoelkopf. Charge-insensitive qubit design derived from the Cooper pair box. Physical Review A, 76(4):042319, October 2007. doi:10.1103/PhysRevA.76.042319.
P. Krantz, M. Kjaergaard, F. Yan, T. P. Orlando, S. Gustavsson, and W. D. Oliver. A quantum engineer's guide to superconducting qubits. Applied Physics Reviews, 6(2):021318, June 2019. doi:10.1063/1.5089550.
David M. Pozar. Microwave Engineering. John Wiley & Sons, Inc., 4 edition, 2012. ISBN 978-0-470-63155-3.
D. E. McCumber. Effect of ac impedance on dc voltage-current characteristics of superconductor weak-link junctions. Journal of Applied Physics, 39(7):3113–3118, June 1968. doi:10.1063/1.1656743.
Niko Savola. Design and modelling of long-coherence qubits using energy participation ratios. Master's thesis, Aalto University, February 2023. URL: http://urn.fi/URN:NBN:fi:aalto-202305213270.
A V Shcherbakova, K G Fedorov, K V Shulga, V V Ryazanov, V V Bolginov, V A Oboznov, S V Egorov, V O Shkolnikov, M J Wolf, D Beckmann, and A V Ustinov. Fabrication and measurements of hybrid Nb/Al Josephson junctions and flux qubits with \mkbibemph \ensuremath \pi -shifters. Superconductor Science and Technology, 28(2):025009, February 2015. doi:10.1088/0953-2048/28/2/025009.
Rainee Simons. Coplanar Waveguide Circuits, Components, and Systems. Number v. 165 in Wiley Series in Microwave and Optical Engineering. Wiley Interscience, New York, 2001. ISBN 978-0-471-46393-1. doi:10.1002/0471224758.
Michael Tinkham. Introduction to Superconductivity. Dover Books on Physics. Dover Publ, Mineola, NY, 2 ed edition, 2015. ISBN 978-0-486-43503-9.