Circuit Simulation with QPDK#

This notebook demonstrates how to perform circuit simulations using the qpdk models and the sax circuit solver. We will showcase individual components and then combine them to create a custom resonator circuit.

Hide code cell source

import sys

if "google.colab" in sys.modules:
    import subprocess

    print("Running in Google Colab. Installing quantum-rf-pdk...")
    subprocess.check_call([
        sys.executable,
        "-m",
        "pip",
        "install",
        "-q",
        "qpdk[models] @ git+https://github.com/gdsfactory/quantum-rf-pdk.git",
    ])

Hide code cell source

import jax.numpy as jnp
import sax
from matplotlib import pyplot as plt

from qpdk import PDK
from qpdk.models.generic import capacitor, inductor, tee
from qpdk.models.resonator import quarter_wave_resonator_coupled
from qpdk.models.waveguides import straight, straight_shorted
from qpdk.tech import coplanar_waveguide

PDK.activate()

Setup#

First, let’s define a frequency range for our simulations and create a coplanar waveguide (CPW) media that defines the transmission line properties.

# Define frequency range
freq = jnp.linspace(2e9, 8e9, 501)
freq_ghz = freq / 1e9

# Define CPW media
cross_section = coplanar_waveguide(width=10, gap=6)

Individual Component Models#

Let’s simulate some of the basic components available in qpdk.

Straight Waveguide#

Simulate a \(1\,\textrm{mm}\) straight waveguide

straight_wg = straight(f=freq, length=1000, cross_section=cross_section)

# Plot S-parameters
plt.figure()
plt.title("Straight Waveguide S-parameters")
plt.plot(freq_ghz, 20 * jnp.log10(jnp.abs(straight_wg["o1", "o2"])), label="$S_{21}$")
plt.plot(freq_ghz, 20 * jnp.log10(jnp.abs(straight_wg["o1", "o1"])), label="$S_{11}$")
plt.xlabel("Frequency [GHz]")
plt.ylabel("Magnitude [dB]")
plt.grid(True)
plt.legend()
plt.show()
../_images/42e1245ac7b22bd4fda895852764c81c16eac78e66bca8ab3a1ba3fa0708dd7c.svg

Capacitor#

Simulate a \(100\,\textrm{fF}\) capacitor

cap_val = 100e-15
cap = capacitor(f=freq, capacitance=cap_val, z0=50)

# Plot S-parameters
plt.figure()
plt.title(f"Capacitor S-parameters (C={cap_val * 1e15:.0f} fF)")
plt.plot(freq_ghz, 20 * jnp.log10(jnp.abs(cap["o1", "o2"])), label="$S_{21}$")
plt.plot(freq_ghz, 20 * jnp.log10(jnp.abs(cap["o1", "o1"])), label="$S_{11}$")
plt.xlabel("Frequency [GHz]")
plt.ylabel("Magnitude [dB]")
plt.grid(True)
plt.legend()
plt.show()
../_images/740459175dfbdd3ddcc55cbaa1e3112cc702354334b24048ab76be2057b26962.svg

Inductor#

Simulate a \(5\,\textrm{nH}\) inductor

ind_val = 5e-9
ind = inductor(f=freq, inductance=ind_val, z0=50)

# Plot S-parameters
plt.figure()
plt.title(f"Inductor S-parameters (L={ind_val * 1e9:.0f} nH)")
plt.plot(freq_ghz, 20 * jnp.log10(jnp.abs(ind["o1", "o2"])), label="$S_{21}$")
plt.plot(freq_ghz, 20 * jnp.log10(jnp.abs(ind["o1", "o1"])), label="$S_{11}$")
plt.xlabel("Frequency [GHz]")
plt.ylabel("Magnitude [dB]")
plt.grid(True)
plt.legend()
plt.show()
../_images/ee7ab226da611ac7f08a671acc642ecdd0905397ff16fbddaa2b1a36a975c31c.svg

Coupled Resonator Model#

Now let’s use a more complex, pre-built model for a coupled resonator.

# Simulate a coupled resonator
res = quarter_wave_resonator_coupled(
    f=freq,
    cross_section=cross_section,
    coupling_gap=0.3,
    coupling_straight_length=200,
    length=5000,
)

# Plot S-parameters
plt.figure()
plt.title("Coupled Resonator S-parameters")
plt.plot(
    freq_ghz,
    20 * jnp.log10(jnp.abs(res["coupling_o1", "coupling_o2"])),
    label="$S_{21}$",
)
plt.xlabel("Frequency [GHz]")
plt.ylabel("Magnitude [dB]")
plt.grid(True)
plt.legend()
plt.show()
../_images/d01bcd244c58418a554350a4c274a297483f868bbabd204f69798a051624476c.svg

Building a Custom Resonator Circuit#

We can use sax to build our own circuits from basic components. Let’s build a quarter-wave resonator capacitively coupled to a feedline.

The circuit is a feedline with a T-junction. A series combination of a capacitor and a shorted transmission line (the resonator) is connected to the T-junction as a shunt element.

# Define component settings
feedline_segment_length = 500  # um
resonator_length = 4000  # um
coupling_cap_val = 20e-15  # F

# Define models for sax circuit
models = {
    "straight": straight,
    "capacitor": capacitor,
    "straight_shorted": straight_shorted,
    "tee": tee,
}

# Define netlist
netlist = {
    "instances": {
        "feedline1": {
            "component": "straight",
            "settings": {"length": feedline_segment_length, "media": cross_section},
        },
        "feedline2": {
            "component": "straight",
            "settings": {"length": feedline_segment_length, "media": cross_section},
        },
        "cap": {
            "component": "capacitor",
            "settings": {"capacitance": coupling_cap_val, "z0": 50},
        },
        "res": {
            "component": "straight_shorted",
            "settings": {"length": resonator_length, "media": cross_section},
        },
        "tee": "tee",
    },
    "connections": {
        "feedline1,o2": "tee,o1",
        "tee,o2": "feedline2,o1",
        "tee,o3": "cap,o1",
        "cap,o2": "res,o1",
    },
    "ports": {
        "o1": "feedline1,o1",
        "o2": "feedline2,o2",
    },
}

# Create and run the circuit
custom_resonator_circuit, _ = sax.circuit(netlist=netlist, models=models)
custom_res_s_params = custom_resonator_circuit(f=freq)

# Plot S-parameters
plt.figure()
plt.title("Custom-built Resonator S-parameters")
plt.plot(
    freq_ghz,
    20 * jnp.log10(jnp.abs(custom_res_s_params["o1", "o2"])),
    label="$S_{21}$",
)
plt.xlabel("Frequency [GHz]")
plt.ylabel("Magnitude [dB]")
plt.grid(True)
plt.legend()
plt.show()
../_images/08d6c4bb8c0b0d824fee461a78f0eda36767649b7585479d9e74bfa682086ea7.svg