Source code for qpdk.models.resonator

"""Resonators."""

from typing import Any

import jax.numpy as jnp
import sax
from gdsfactory.typings import CrossSectionSpec
from sax.models.rf import capacitor, electrical_open, electrical_short, tee

from qpdk.helper import deprecated
from qpdk.models.constants import DEFAULT_FREQUENCY, c_0
from qpdk.models.couplers import cpw_cpw_coupling_capacitance
from qpdk.models.cpw import (
    cpw_parameters,
    cpw_z0_from_cross_section,
    get_cpw_dimensions,
)
from qpdk.models.waveguides import straight, straight_shorted


[docs] def quarter_wave_resonator_coupled( f: sax.FloatArrayLike = DEFAULT_FREQUENCY, length: float = 5000.0, coupling_gap: float = 0.27, coupling_straight_length: float = 20, cross_section: CrossSectionSpec = "cpw", ) -> sax.SDict: """Model for a quarter-wave coplanar waveguide resonator coupled to a probeline. Args: cross_section: The cross-section of the CPW. f: Frequency in Hz at which to evaluate the S-parameters. length: Total length of the resonator in μm. coupling_gap: Gap between the resonator and the probeline in μm. coupling_straight_length: Length of the coupling section in μm. Returns: sax.SDict: S-parameters dictionary """ f_arr = jnp.asarray(f) instances = { "resonator": resonator_coupled( f=f_arr, length=length, coupling_gap=coupling_gap, coupling_straight_length=coupling_straight_length, cross_section=cross_section, open_start=True, open_end=False, ), "short": electrical_short(f=f_arr), } connections = { "resonator,resonator_o2": "short,o1", } ports = { "coupling_o1": "resonator,coupling_o1", "coupling_o2": "resonator,coupling_o2", "resonator_o1": "resonator,resonator_o1", } return sax.evaluate_circuit_fg((connections, ports), instances)
[docs] def resonator_coupled( f: sax.FloatArrayLike = DEFAULT_FREQUENCY, length: float = 5000.0, coupling_gap: float = 0.27, coupling_straight_length: float = 20, cross_section: CrossSectionSpec = "cpw", open_start: bool = True, open_end: bool = False, ) -> sax.SDict: """Model for a coplanar waveguide resonator coupled to a probeline. Args: cross_section: The cross-section of the CPW. f: Frequency in Hz at which to evaluate the S-parameters. length: Total length of the resonator in μm. coupling_gap: Gap between the resonator and the probeline in μm. coupling_straight_length: Length of the coupling section in μm. open_start: If True, adds an electrical open at the start. open_end: If True, adds an electrical open at the end. Returns: sax.SDict: S-parameters dictionary with 4 ports. """ f_arr = jnp.asarray(f) capacitor_settings = { "capacitance": cpw_cpw_coupling_capacitance( f_arr, coupling_straight_length, coupling_gap, cross_section ), "z0": cpw_z0_from_cross_section(cross_section, f_arr), } instances = { "coupling_1": straight( f=f_arr, length=coupling_straight_length / 2, cross_section=cross_section ), "coupling_2": straight( f=f_arr, length=coupling_straight_length / 2, cross_section=cross_section ), "resonator_1": straight( f=f_arr, length=coupling_straight_length / 2, cross_section=cross_section ), "resonator_2": straight( f=f_arr, length=length - coupling_straight_length / 2, cross_section=cross_section, ), "tee_1": tee(f=f_arr), "tee_2": tee(f=f_arr), "capacitor": capacitor(f=f_arr, **capacitor_settings), } connections = { "coupling_1,o2": "tee_1,o1", "coupling_2,o1": "tee_1,o2", "resonator_1,o2": "tee_2,o1", "resonator_2,o1": "tee_2,o2", "tee_1,o3": "capacitor,o1", "tee_2,o3": "capacitor,o2", } ports = { "coupling_o1": "coupling_1,o1", "coupling_o2": "coupling_2,o2", } if open_start: instances["open_start_term"] = electrical_open(f=f_arr, n_ports=2) connections["resonator_1,o1"] = "open_start_term,o1" ports["resonator_o1"] = "open_start_term,o2" else: ports["resonator_o1"] = "resonator_1,o1" if open_end: instances["open_end_term"] = electrical_open(f=f_arr, n_ports=2) connections["resonator_2,o2"] = "open_end_term,o1" ports["resonator_o2"] = "open_end_term,o2" else: ports["resonator_o2"] = "resonator_2,o2" return sax.evaluate_circuit_fg((connections, ports), instances)
[docs] def resonator_frequency( *, length: float, epsilon_eff: float | None = None, media: Any = None, cross_section: CrossSectionSpec = "cpw", is_quarter_wave: bool = True, ) -> float: r"""Calculate the resonance frequency of a quarter- or half-wave CPW resonator. .. math:: \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 :math:`v_p = c_0 / \sqrt{\varepsilon_{\mathrm{eff}}}`. See :cite:`simonsCoplanarWaveguideCircuits2001,m.pozarMicrowaveEngineering2012` for details. Args: length: Length of the resonator in μm. epsilon_eff: Effective permittivity. If ``None`` (default), computed from *cross_section* using :func:`~qpdk.models.cpw.cpw_parameters`. media: Deprecated. Use *epsilon_eff* or *cross_section* instead. cross_section: Cross-section specification (used only when *epsilon_eff* and *media* are not provided). is_quarter_wave: If True, calculates for a quarter-wave resonator; if False, for a half-wave resonator. default is True. Returns: float: Resonance frequency in Hz. """ if epsilon_eff is None: if media is not None: deprecated( "The 'media' argument is deprecated. Use 'epsilon_eff' or 'cross_section' instead." )(lambda: None)() epsilon_eff = float(jnp.real(jnp.mean(media.ep_r))) else: width, gap = get_cpw_dimensions(cross_section) epsilon_eff, _z0 = cpw_parameters(width, gap) v_p = c_0 / jnp.sqrt(epsilon_eff) coefficient = 4 if is_quarter_wave else 2 return float(jnp.squeeze(v_p / (coefficient * length * 1e-6)))
[docs] def resonator( f: sax.FloatArrayLike = DEFAULT_FREQUENCY, length: sax.Float = 1000, cross_section: CrossSectionSpec = "cpw", ) -> sax.SType: """S-parameter model for a simple transmission line resonator. Args: f: Array of frequency points in Hz length: Physical length in µm cross_section: The cross-section of the waveguide. Returns: sax.SType: S-parameters dictionary """ return straight(f=f, length=length, cross_section=cross_section)
[docs] def resonator_half_wave( f: sax.FloatArrayLike = DEFAULT_FREQUENCY, length: sax.Float = 1000, cross_section: CrossSectionSpec = "cpw", ) -> sax.SType: """S-parameter model for a half-wave resonator (open at both ends). Args: f: Array of frequency points in Hz length: Physical length in µm cross_section: The cross-section of the waveguide. Returns: sax.SType: S-parameters dictionary """ return straight(f=f, length=length, cross_section=cross_section)
[docs] def resonator_quarter_wave( f: sax.FloatArrayLike = DEFAULT_FREQUENCY, length: sax.Float = 1000, cross_section: CrossSectionSpec = "cpw", ) -> sax.SType: """S-parameter model for a quarter-wave resonator (shorted at one end). Args: f: Array of frequency points in Hz length: Physical length in µm cross_section: The cross-section of the waveguide. Returns: sax.SType: S-parameters dictionary """ return straight_shorted(f=f, length=length, cross_section=cross_section)