Coverage for qpdk / models / qubit.py: 87%
91 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 17:50 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 17:50 +0000
1"""Qubit LC resonator models.
3This module provides LC resonator models for superconducting transmon qubits
4and coupled qubit systems. The models are based on the standard LC resonator
5formulation with appropriate grounding configurations.
7For double-pad transmon qubits, we use an ungrounded LC resonator since
8the two islands are floating. For shunted transmon qubits, one island is
9grounded, so we use a grounded LC resonator.
11The helper functions convert between qubit Hamiltonian parameters (charging
12energy :math:`E_C`, Josephson energy :math:`E_J`, coupling strength :math:`g`) and the
13corresponding circuit parameters (capacitance, inductance).
15References:
16 - :cite:`kochChargeinsensitiveQubitDesign2007a`
17 - :cite:`gaoPhysicsSuperconductingMicrowave2008`
18"""
20import math
21from functools import partial
23import jax
24import jax.numpy as jnp
25import sax
26from sax.models.rf import capacitor, electrical_short, tee
28from qpdk.models.constants import DEFAULT_FREQUENCY, Φ_0, e, h
29from qpdk.models.generic import lc_resonator, lc_resonator_coupled
30from qpdk.models.waveguides import straight_shorted
33@partial(jax.jit, inline=True)
34def ec_to_capacitance(ec_ghz: float) -> float:
35 r"""Convert charging energy :math:`E_C` to total capacitance :math:`C_\Sigma`.
37 The charging energy is related to capacitance by:
39 .. math::
41 E_C = \frac{e^2}{2 C_\Sigma}
43 where :math:`e` is the electron charge.
45 Args:
46 ec_ghz: Charging energy in GHz.
48 Returns:
49 Total capacitance in Farads.
51 Example:
52 >>> C = ec_to_capacitance(0.2) # 0.2 GHz (200 MHz) charging energy
53 >>> print(f"{C * 1e15:.1f} fF") # ~96 fF
54 """
55 ec_joules = ec_ghz * 1e9 * h # Convert GHz to Joules
56 return e**2 / (2 * ec_joules)
59@partial(jax.jit, inline=True)
60def ej_to_inductance(ej_ghz: float) -> float:
61 r"""Convert Josephson energy :math:`E_J` to Josephson inductance :math:`L_\text{J}`.
63 The Josephson energy is related to inductance by:
65 .. math::
67 E_J = \frac{\Phi_0^2}{4 \pi^2 L_\text{J}} = \frac{(\hbar / 2e)^2}{L_\text{J}}
69 This is equivalent to:
71 .. math::
73 L_\text{J} = \frac{\Phi_0}{2 \pi I_c}
75 where :math:`I_c` is the critical current and :math:`\Phi_0` is the magnetic flux quantum.
77 Args:
78 ej_ghz: Josephson energy in GHz.
80 Returns:
81 Josephson inductance in Henries.
83 Example:
84 >>> L = ej_to_inductance(20.0) # 20 GHz Josephson energy
85 >>> print(f"{L * 1e9:.2f} nH") # ~1.0 nH
86 """
87 ej_joules = ej_ghz * 1e9 * h # Convert GHz to Joules
88 return Φ_0**2 / (4 * math.pi**2 * ej_joules)
91el_to_inductance = ej_to_inductance
94@partial(jax.jit, inline=True)
95def coupling_strength_to_capacitance(
96 g_ghz: float,
97 c_sigma: float,
98 c_r: float,
99 f_q_ghz: float,
100 f_r_ghz: float,
101) -> jax.Array:
102 r"""Convert coupling strength :math:`g` to coupling capacitance :math:`C_c`.
104 In the dispersive limit (:math:`g \ll f_q, f_r`), the coupling strength
105 can be related to a coupling capacitance via:
107 .. math::
109 g \approx \frac{1}{2} \frac{C_c}{\sqrt{C_\Sigma C_r}} \sqrt{f_q f_r}
111 Solving for :math:`C_c`:
113 .. math::
115 C_c = \frac{2g}{\sqrt{f_q f_r}} \sqrt{C_\Sigma C_r}
117 See :cite:`Savola2023,krantzQuantumEngineersGuide2019` for details.
119 Args:
120 g_ghz: Coupling strength in GHz.
121 c_sigma: Total qubit capacitance in Farads.
122 c_r: Total resonator capacitance in Farads.
123 f_q_ghz: Qubit frequency in GHz.
124 f_r_ghz: Resonator frequency in GHz.
126 Returns:
127 Coupling capacitance in Farads.
129 Example:
130 >>> C_c = coupling_strength_to_capacitance(
131 ... g_ghz=0.1,
132 ... c_sigma=100e-15, # 100 fF
133 ... c_r=50e-15, # 50 fF
134 ... f_q_ghz=5.0,
135 ... f_r_ghz=7.0,
136 ... )
137 >>> print(f"{C_c * 1e15:.2f} fF")
138 """
139 # Use frequencies directly (already in GHz, ratio is dimensionless)
140 sqrt_freq = jnp.sqrt(f_q_ghz * f_r_ghz)
141 sqrt_c = jnp.sqrt(c_sigma * c_r)
142 return 2 * g_ghz / sqrt_freq * sqrt_c
145@partial(jax.jit, inline=True)
146def fluxonium(
147 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
148 capacitance: float = 10e-15,
149 josephson_inductance: float = 10e-9,
150 superinductance: float = 500e-9,
151 ground_capacitance: float = 0.0,
152) -> sax.SDict:
153 r"""S-parameter model for a fluxonium qubit.
155 A fluxonium qubit consists of a Josephson junction shunted by a large
156 superinductance and a capacitor. In the linear regime, this is modeled
157 as a parallel LCL circuit.
159 For an accurate microwave model reflecting the real physical layout,
160 the circuit is treated as ungrounded (floating) with optional symmetric
161 parasitic capacitances connecting both ends to ground :cite:`nguyen_blueprint_2019`.
163 .. svgbob::
165 ┌────── C ──────┐
166 o1 ──┼────── Lj ─────┼── o2
167 ├────── Ls ─────┤
168 │ │
169 Cg Cg
170 │ │
171 GND GND
173 Note:
174 The total shunt capacitance `capacitance` should include the pads,
175 junction capacitance, and parasitic meander capacitance. Spurious
176 array self-resonance (SR) modes can be phenomenologically modeled
177 by adding to the shunt capacitance or using a multimode model.
179 Args:
180 f: Array of frequency points in Hz.
181 capacitance: Total shunt capacitance :math:`C_\Sigma` in Farads.
182 josephson_inductance: Josephson inductance :math:`L_\text{J}` in Henries.
183 superinductance: Superinductance :math:`L_\text{s}` in Henries.
184 ground_capacitance: Parasitic capacitance to ground :math:`C_g` at each port in Farads.
186 Returns:
187 sax.SDict: S-parameters dictionary with ports o1 and o2.
188 """
189 # Combine the two inductors in parallel: L = (L1 * L2) / (L1 + L2)
190 L_total = (josephson_inductance * superinductance) / (
191 josephson_inductance + superinductance
192 )
193 return lc_resonator(
194 f=f,
195 capacitance=capacitance,
196 inductance=L_total,
197 grounded=False,
198 ground_capacitance=ground_capacitance,
199 )
202@partial(jax.jit, inline=True)
203def fluxonium_with_bbox(
204 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
205 capacitance: float = 10e-15,
206 josephson_inductance: float = 10e-9,
207 superinductance: float = 500e-9,
208 ground_capacitance: float = 0.0,
209) -> sax.SType:
210 """S-parameter model for a fluxonium qubit with bounding box ports.
212 This model is the same as :func:`fluxonium`.
214 Returns:
215 sax.SType: S-parameters dictionary.
216 """
217 return fluxonium(
218 f=f,
219 capacitance=capacitance,
220 josephson_inductance=josephson_inductance,
221 superinductance=superinductance,
222 ground_capacitance=ground_capacitance,
223 )
226@partial(jax.jit, inline=True)
227def double_island_transmon(
228 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
229 capacitance: float = 100e-15,
230 inductance: float = 7e-9,
231 ground_capacitance: float = 0.0,
232) -> sax.SDict:
233 r"""LC resonator model for a double-island transmon qubit.
235 A double-island transmon has two superconducting islands connected by
236 Josephson junctions, with both islands floating (not grounded). This is
237 modeled as an ungrounded parallel LC resonator.
239 The qubit frequency is approximately:
241 .. math::
243 f_q \approx \frac{1}{2\pi} \sqrt{8 E_J E_C} - E_C
245 For the LC model, the resonance frequency is:
247 .. math::
249 f_r = \frac{1}{2\pi\sqrt{LC}}
251 Use :func:`ec_to_capacitance` and :func:`ej_to_inductance` to convert
252 from qubit Hamiltonian parameters.
254 .. svgbob::
256 o1 ──┬──L──┬── o2
257 │ │
258 └──C──┘
260 Args:
261 f: Array of frequency points in Hz.
262 capacitance: Total capacitance :math:`C_\Sigma` of the qubit in Farads.
263 inductance: Josephson inductance :math:`L_\text{J}` in Henries.
264 ground_capacitance: Parasitic capacitance to ground :math:`C_g` at each port in Farads.
266 Returns:
267 sax.SDict: S-parameters dictionary with ports o1 and o2.
268 """
269 return lc_resonator(
270 f=f,
271 capacitance=capacitance,
272 inductance=inductance,
273 grounded=False,
274 ground_capacitance=ground_capacitance,
275 )
278@partial(jax.jit, inline=True)
279def double_island_transmon_with_bbox(
280 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
281 capacitance: float = 100e-15,
282 inductance: float = 7e-9,
283 ground_capacitance: float = 0.0,
284) -> sax.SType:
285 """LC resonator model for a double-island transmon qubit with bounding box ports.
287 This model is the same as :func:`double_island_transmon`.
289 Returns:
290 sax.SType: S-parameters dictionary.
291 """
292 return double_island_transmon(
293 f=f,
294 capacitance=capacitance,
295 inductance=inductance,
296 ground_capacitance=ground_capacitance,
297 )
300@partial(jax.jit, inline=True)
301def flipmon(
302 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
303 capacitance: float = 100e-15,
304 inductance: float = 7e-9,
305 ground_capacitance: float = 0.0,
306) -> sax.SType:
307 r"""LC resonator model for a flipmon qubit.
309 This model is identical to :func:`double_island_transmon`.
311 Returns:
312 sax.SType: S-parameters dictionary.
313 """
314 return double_island_transmon(
315 f=f,
316 capacitance=capacitance,
317 inductance=inductance,
318 ground_capacitance=ground_capacitance,
319 )
322@partial(jax.jit, inline=True)
323def flipmon_with_bbox(
324 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
325 capacitance: float = 100e-15,
326 inductance: float = 7e-9,
327 ground_capacitance: float = 0.0,
328) -> sax.SType:
329 """LC resonator model for a flipmon qubit with bounding box ports.
331 This model is the same as :func:`flipmon`.
333 Returns:
334 sax.SType: S-parameters dictionary.
335 """
336 return flipmon(
337 f=f,
338 capacitance=capacitance,
339 inductance=inductance,
340 ground_capacitance=ground_capacitance,
341 )
344@partial(jax.jit, inline=True)
345def shunted_transmon(
346 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
347 capacitance: float = 100e-15,
348 inductance: float = 7e-9,
349 ground_capacitance: float = 0.0,
350) -> sax.SDict:
351 r"""LC resonator model for a shunted transmon qubit.
353 A shunted transmon has one island grounded and the other island connected
354 to the junction. This is modeled as a grounded parallel LC resonator.
356 The qubit frequency is approximately:
358 .. math::
360 f_q \approx \frac{1}{2\pi} \sqrt{8 E_J E_C} - E_C
362 For the LC model, the resonance frequency is:
364 .. math::
366 f_r = \frac{1}{2\pi\sqrt{LC}}
368 Use :func:`ec_to_capacitance` and :func:`ej_to_inductance` to convert
369 from qubit Hamiltonian parameters.
371 .. svgbob::
373 o1 ──┬──L──┬──.
374 │ │ | "2-port ground"
375 └──C──┘ |
376 "o2"
378 Args:
379 f: Array of frequency points in Hz.
380 capacitance: Total capacitance :math:`C_\Sigma` of the qubit in Farads.
381 inductance: Josephson inductance :math:`L_\text{J}` in Henries.
382 ground_capacitance: Parasitic capacitance to ground :math:`C_g` at the floating port in Farads.
384 Returns:
385 sax.SDict: S-parameters dictionary with ports o1 and o2.
386 """
387 return lc_resonator(
388 f=f,
389 capacitance=capacitance,
390 inductance=inductance,
391 grounded=True,
392 ground_capacitance=ground_capacitance,
393 )
396@partial(jax.jit, static_argnames=["grounded"])
397def transmon_coupled(
398 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
399 capacitance: float = 100e-15,
400 inductance: float = 1e-9,
401 grounded: bool = False,
402 ground_capacitance: float = 0.0,
403 coupling_capacitance: float = 10e-15,
404 coupling_inductance: float = 0.0,
405) -> sax.SDict:
406 r"""Coupled transmon qubit model.
408 This model extends the basic transmon qubit by adding a coupling network
409 consisting of a parallel capacitor and/or inductor. This can represent
410 capacitive or inductive coupling between qubits or between a qubit and
411 a readout resonator.
413 The coupling network is connected in series with the LC resonator:
415 .. svgbob::
417 +──Lc──+ +──L──+
418 o1 ──│ │────| │─── o2 or grounded o2
419 +──Cc──+ +──C──+
420 "LC resonator"
422 For capacitive coupling (common for qubit-resonator coupling):
423 - Set ``coupling_capacitance`` to the coupling capacitor value
424 - Set ``coupling_inductance=0.0``
426 For inductive coupling (common for flux-tunable coupling):
427 - Set ``coupling_inductance`` to the coupling inductor value
428 - Set ``coupling_capacitance=0.0`` (or small value)
430 Use :func:`coupling_strength_to_capacitance` to convert from the
431 qubit-resonator coupling strength :math:`g` to the coupling capacitance.
433 Args:
434 f: Array of frequency points in Hz.
435 capacitance: Total capacitance :math:`C_\Sigma` of the qubit in Farads.
436 inductance: Josephson inductance :math:`L_\text{J}` in Henries.
437 grounded: If True, the qubit is a shunted transmon (grounded).
438 If False, it is a double-pad transmon (ungrounded).
439 ground_capacitance: Parasitic capacitance to ground :math:`C_g` in Farads.
440 coupling_capacitance: Coupling capacitance :math:`C_c` in Farads.
441 coupling_inductance: Coupling inductance :math:`L_c` in Henries.
443 Returns:
444 sax.SDict: S-parameters dictionary with ports o1 and o2.
445 """
446 return lc_resonator_coupled(
447 f=f,
448 capacitance=capacitance,
449 inductance=inductance,
450 grounded=grounded,
451 ground_capacitance=ground_capacitance,
452 coupling_capacitance=coupling_capacitance,
453 coupling_inductance=coupling_inductance,
454 )
457@partial(jax.jit)
458def fluxonium_coupled(
459 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
460 capacitance: float = 10e-15,
461 josephson_inductance: float = 10e-9,
462 superinductance: float = 500e-9,
463 ground_capacitance: float = 0.0,
464 coupling_capacitance: float = 10e-15,
465 coupling_inductance: float = 0.0,
466) -> sax.SDict:
467 r"""Coupled fluxonium qubit model.
469 This model adds a coupling network to the fluxonium model.
471 Args:
472 f: Array of frequency points in Hz.
473 capacitance: Total shunt capacitance :math:`C_\Sigma` in Farads.
474 josephson_inductance: Josephson inductance :math:`L_\text{J}` in Henries.
475 superinductance: Superinductance :math:`L_\text{s}` in Henries.
476 ground_capacitance: Parasitic capacitance to ground :math:`C_g` in Farads.
477 coupling_capacitance: Coupling capacitance :math:`C_c` in Farads.
478 coupling_inductance: Coupling inductance :math:`L_c` in Henries.
480 Returns:
481 sax.SDict: S-parameters dictionary with ports o1 and o2.
482 """
483 L_total = (josephson_inductance * superinductance) / (
484 josephson_inductance + superinductance
485 )
486 return lc_resonator_coupled(
487 f=f,
488 capacitance=capacitance,
489 inductance=L_total,
490 grounded=False,
491 ground_capacitance=ground_capacitance,
492 coupling_capacitance=coupling_capacitance,
493 coupling_inductance=coupling_inductance,
494 )
497def fluxonium_with_resonator(
498 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
499 capacitance: float = 10e-15,
500 josephson_inductance: float = 10e-9,
501 superinductance: float = 500e-9,
502 ground_capacitance: float = 0.0,
503 resonator_length: float = 5000.0,
504 resonator_cross_section: str = "cpw",
505 coupling_capacitance: float = 10e-15,
506) -> sax.SDict:
507 r"""Model for a fluxonium qubit coupled to a quarter-wave resonator.
509 Args:
510 f: Array of frequency points in Hz.
511 capacitance: Total shunt capacitance :math:`C_\Sigma` in Farads.
512 josephson_inductance: Josephson inductance :math:`L_\text{J}` in Henries.
513 superinductance: Superinductance :math:`L_\text{s}` in Henries.
514 ground_capacitance: Parasitic capacitance to ground :math:`C_g` in Farads.
515 resonator_length: Length of the quarter-wave resonator in µm.
516 resonator_cross_section: Cross-section specification for the resonator.
517 coupling_capacitance: Coupling capacitance between qubit and resonator in Farads.
519 Returns:
520 sax.SDict: S-parameters dictionary.
521 """
522 f = jnp.asarray(f)
523 resonator = straight_shorted(
524 f=f,
525 length=resonator_length,
526 cross_section=resonator_cross_section,
527 )
528 qubit = fluxonium(
529 f=f,
530 capacitance=capacitance,
531 josephson_inductance=josephson_inductance,
532 superinductance=superinductance,
533 ground_capacitance=ground_capacitance,
534 )
535 coupling_cap = capacitor(f=f, capacitance=coupling_capacitance)
536 tee_junction = tee(f=f)
537 terminator = electrical_short(f=f, n_ports=1)
539 instances: dict[str, sax.SType] = {
540 "resonator": resonator,
541 "qubit": qubit,
542 "coupling_capacitor": coupling_cap,
543 "tee": tee_junction,
544 "terminator": terminator,
545 }
547 connections = {
548 "resonator,o1": "tee,o1",
549 "resonator,o2": "terminator,o1",
550 "tee,o2": "coupling_capacitor,o1",
551 "coupling_capacitor,o2": "qubit,o1",
552 }
554 ports = {
555 "o1": "tee,o3",
556 "o2": "qubit,o2",
557 }
559 return sax.evaluate_circuit_fg((connections, ports), instances)
562def qubit_with_resonator(
563 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
564 qubit_capacitance: float = 100e-15,
565 qubit_inductance: float = 1e-9,
566 qubit_grounded: bool = False,
567 resonator_length: float = 5000.0,
568 resonator_cross_section: str = "cpw",
569 coupling_capacitance: float = 10e-15,
570) -> sax.SDict:
571 r"""Model for a transmon qubit coupled to a quarter-wave resonator.
573 This model corresponds to the layout function
574 :func:`~qpdk.cells.derived.transmon_with_resonator.transmon_with_resonator`.
576 The model combines:
577 - A transmon qubit (LC resonator)
578 - A quarter-wave coplanar waveguide resonator
579 - A coupling capacitor connecting the qubit to the resonator
581 .. svgbob::
583 "quarter-wave resonator"
584 (straight_shorted)
585 │
586 o1 ── tee ─┤
587 │
588 +── Cc ── qubit ── o2
590 The qubit can be either:
591 - A double-island transmon (``qubit_grounded=False``): both islands floating
592 - A shunted transmon (``qubit_grounded=True``): one island grounded
594 Use :func:`ec_to_capacitance` and :func:`ej_to_inductance` to convert
595 from qubit Hamiltonian parameters (:math:`E_C`, :math:`E_J`) to circuit parameters.
597 Note:
598 This function is not JIT-compiled because it depends on :func:`~straight_shorted`,
599 which internally uses cpw_parameters for transmission line modeling.
601 Args:
602 f: Array of frequency points in Hz.
603 qubit_capacitance: Total capacitance :math:`C_\Sigma` of the qubit in Farads.
604 Convert from charging energy using :func:`ec_to_capacitance`.
605 qubit_inductance: Josephson inductance :math:`L_\text{J}` in Henries.
606 Convert from Josephson energy using :func:`ej_to_inductance`.
607 qubit_grounded: If True, the qubit is a shunted transmon (grounded).
608 If False, it is a double-island transmon (ungrounded).
609 resonator_length: Length of the quarter-wave resonator in µm.
610 resonator_cross_section: Cross-section specification for the resonator.
611 coupling_capacitance: Coupling capacitance between qubit and resonator in
612 Farads. Use :func:`coupling_strength_to_capacitance` to convert from
613 qubit-resonator coupling strength :math:`g`.
615 Returns:
616 sax.SDict: S-parameters dictionary with ports ``o1`` (resonator input)
617 and ``o2`` (qubit ground or floating).
618 """
619 f = jnp.asarray(f)
621 # Create instances for circuit composition
622 resonator = straight_shorted(
623 f=f,
624 length=resonator_length,
625 cross_section=resonator_cross_section,
626 )
627 qubit_func = shunted_transmon if qubit_grounded else double_island_transmon
628 qubit = qubit_func(
629 f=f,
630 capacitance=qubit_capacitance,
631 inductance=qubit_inductance,
632 )
633 coupling_cap = capacitor(f=f, capacitance=coupling_capacitance)
634 tee_junction = tee(f=f)
635 # Use a 1-port short to terminate the internally shorted resonator end
636 # to avoid dangling ports in the circuit evaluation.
637 # Also short the grounded qubit's o2 port
638 terminator = electrical_short(f=f, n_ports=2 if qubit_grounded else 1)
640 instances: dict[str, sax.SType] = {
641 "resonator": resonator,
642 "qubit": qubit,
643 "coupling_capacitor": coupling_cap,
644 "tee": tee_junction,
645 "terminator": terminator,
646 }
648 # Connect: resonator -- tee -- capacitor -- qubit
649 # The tee splits the resonator signal to the coupling capacitor
650 connections = {
651 "resonator,o1": "tee,o1",
652 "resonator,o2": "terminator,o1", # Explicitly terminate
653 "tee,o2": "coupling_capacitor,o1",
654 "coupling_capacitor,o2": "qubit,o1",
655 }
657 if qubit_grounded:
658 connections["qubit,o2"] = "terminator,o2"
660 ports = {
661 "o1": "tee,o3", # External port for resonator coupling
662 }
663 if not qubit_grounded:
664 ports["o2"] = "qubit,o2" # Qubit floating port
666 return sax.evaluate_circuit_fg((connections, ports), instances)
669def flipmon_with_resonator(
670 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
671 qubit_capacitance: float = 100e-15,
672 qubit_inductance: float = 1e-9,
673 resonator_length: float = 5000.0,
674 resonator_cross_section: str = "cpw",
675 coupling_capacitance: float = 10e-15,
676) -> sax.SDict:
677 """Model for a flipmon qubit coupled to a quarter-wave resonator.
679 This model is identical to :func:`qubit_with_resonator` but the qubit is set to floating.
681 Returns:
682 sax.SDict: S-parameters dictionary.
683 """
684 return qubit_with_resonator(
685 f=f,
686 qubit_capacitance=qubit_capacitance,
687 qubit_inductance=qubit_inductance,
688 qubit_grounded=False, # Flipmon is ungrounded
689 resonator_length=resonator_length,
690 resonator_cross_section=resonator_cross_section,
691 coupling_capacitance=coupling_capacitance,
692 )
695def double_island_transmon_with_resonator(
696 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
697 qubit_capacitance: float = 100e-15,
698 qubit_inductance: float = 1e-9,
699 resonator_length: float = 5000.0,
700 resonator_cross_section: str = "cpw",
701 coupling_capacitance: float = 10e-15,
702) -> sax.SDict:
703 """Model for a double-island transmon qubit coupled to a quarter-wave resonator.
705 This model is identical to :func:`qubit_with_resonator` but the qubit is set to floating.
707 Returns:
708 sax.SDict: S-parameters dictionary.
709 """
710 return qubit_with_resonator(
711 f=f,
712 qubit_capacitance=qubit_capacitance,
713 qubit_inductance=qubit_inductance,
714 qubit_grounded=False,
715 resonator_length=resonator_length,
716 resonator_cross_section=resonator_cross_section,
717 coupling_capacitance=coupling_capacitance,
718 )
721def transmon_with_resonator(
722 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
723 qubit_capacitance: float = 100e-15,
724 qubit_inductance: float = 1e-9,
725 qubit_grounded: bool = False,
726 resonator_length: float = 5000.0,
727 resonator_cross_section: str = "cpw",
728 coupling_capacitance: float = 10e-15,
729) -> sax.SDict:
730 """Model for a transmon qubit coupled to a quarter-wave resonator.
732 This model is identical to :func:`qubit_with_resonator`.
734 Returns:
735 sax.SDict: S-parameters dictionary.
736 """
737 return qubit_with_resonator(
738 f=f,
739 qubit_capacitance=qubit_capacitance,
740 qubit_inductance=qubit_inductance,
741 qubit_grounded=qubit_grounded,
742 resonator_length=resonator_length,
743 resonator_cross_section=resonator_cross_section,
744 coupling_capacitance=coupling_capacitance,
745 )
748@partial(jax.jit, inline=True)
749def xmon_transmon(
750 f: sax.FloatArrayLike = DEFAULT_FREQUENCY,
751 capacitance: float = 100e-15,
752 inductance: float = 7e-9,
753) -> sax.SType:
754 """LC resonator model for an Xmon style transmon qubit.
756 An Xmon transmon is typically shunted, so this model wraps :func:`shunted_transmon`.
758 Returns:
759 sax.SType: S-parameters dictionary.
760 """
761 return shunted_transmon(
762 f=f,
763 capacitance=capacitance,
764 inductance=inductance,
765 )
768# Aliases for backward compatibility or to match cell naming
769double_pad_transmon = double_island_transmon
770double_pad_transmon_with_bbox = double_island_transmon_with_bbox
771double_pad_transmon_with_resonator = double_island_transmon_with_resonator
774if __name__ == "__main__":
775 from typing import TypedDict
777 import matplotlib.pyplot as plt
779 from qpdk import PDK
781 class _QubitConfig(TypedDict):
782 """Configuration for a qubit type in the demo plot."""
784 label: str
785 grounded: bool
786 linestyle: str
788 PDK.activate()
790 f = jnp.linspace(1e9, 10e9, 2001)
792 # Calculate bare qubit resonance frequency
793 C_q = 100e-15
794 L_q = 7e-9
795 f_q_bare = 1 / (2 * jnp.pi * jnp.sqrt(L_q * C_q))
797 configs: list[_QubitConfig] = [
798 {"label": "Shunted Transmon", "grounded": True, "linestyle": "-"},
799 {"label": "Double Island Transmon", "grounded": False, "linestyle": "--"},
800 ]
802 fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8), sharex=True)
804 for config in configs:
805 S_coupled = qubit_with_resonator(
806 f=f,
807 qubit_capacitance=C_q,
808 qubit_inductance=L_q,
809 qubit_grounded=config["grounded"],
810 resonator_length=5000.0,
811 resonator_cross_section="cpw",
812 coupling_capacitance=20e-15,
813 )
815 s11 = S_coupled["o1", "o1"]
816 s11_mag = 20 * jnp.log10(jnp.abs(s11))
817 s11_phase = jnp.unwrap(jnp.angle(s11))
819 # Plot S11 magnitude
820 ax1.plot(
821 f / 1e9,
822 s11_mag,
823 label=f"$|S_{{11}}|$ {config['label']}",
824 linestyle=config["linestyle"],
825 )
827 # Plot S11 phase
828 ax2.plot(
829 f / 1e9,
830 s11_phase,
831 label=f"$\\angle S_{{11}}$ {config['label']}",
832 linestyle=config["linestyle"],
833 )
835 for ax in (ax1, ax2):
836 ax.axvline(
837 f_q_bare / 1e9,
838 color="r",
839 linestyle=":",
840 label=rf"Bare Qubit ($f_q = {f_q_bare / 1e9:.3f}$ GHz)",
841 )
842 ax.grid(True)
843 ax.legend()
845 ax2.set_xlabel("Frequency (GHz)")
846 ax1.set_ylabel("Magnitude (dB)")
847 ax2.set_ylabel("Phase (rad)")
848 fig.suptitle(
849 rf"Qubit Coupled to Quarter-Wave Resonator ($C_q=${C_q * 1e15:.0f} fF, $L_q=${L_q * 1e9:.0f} nH)"
850 )
851 plt.tight_layout()
852 plt.show()