Source code for qpdk.models.resonator
"""Resonator models."""
from collections.abc import Callable
from functools import partial
import jax.numpy as jnp
import sax
import skrf
from jax._src.util import Array
from numpy.typing import NDArray
from skrf.media import Media
from qpdk.models.media import cpw_media_skrf
[docs]
def resonator_frequency(
length: float, media: Media, is_quarter_wave: bool = True
) -> NDArray:
r"""Calculate the resonance frequency of a quarter-wave resonator.
.. math::
f &= \frac{v_p}{4L} \text{ (quarter-wave resonator)} \\
f &= \frac{v_p}{2L} \text{ (half-wave resonator)}
There is some variation according to the frequency range specified for ``media`` due to how
:math:`v_p` is calculated in skrf. The phase velocity is given by :math:`v_p = i \cdot \omega / \gamma`,
where :math:`\gamma` is the complex propagation constant and :math:`\omega` is the angular frequency.
See :cite:`simonsCoplanarWaveguideCircuits2001,m.pozarMicrowaveEngineering2012` for details.
Args:
length: Length of the resonator in μm.
media: skrf media object defining the CPW (or other) properties.
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.
"""
coefficient = 4 if is_quarter_wave else 2 # Quarter-wave resonator
a = media.v_p / (coefficient * length * 1e-6)
return a.mean().real
[docs]
def quarter_wave_resonator_coupled_to_probeline(
media: Callable[[skrf.Frequency], Media],
f: skrf.NumberLike | Array | None = None,
coupling_capacitance: float = 15e-15,
length: float = 4000,
) -> sax.SDict:
"""Model for a quarter-wave coplanar waveguide resonator coupled to a probeline.
Args:
media: skrf media object defining the CPW (or other) properties.
f: Frequency in Hz at which to evaluate the S-parameters.
coupling_capacitance: Coupling capacitance in Farads.
length: Length of the resonator in μm.
Returns:
sax.SDict: S-parameters dictionary
"""
f = f if f is not None else jnp.array([1e9, 5e9])
media: Media = media(frequency=skrf.Frequency.from_f(f, unit="Hz")) # type: ignore
transmission_line = media.line(d=length, unit="um")
quarter_wave_resonator = transmission_line ** media.short()
coupling_capacitor = media.capacitor(coupling_capacitance, name="C_coupling")
resonator_coupled = coupling_capacitor**quarter_wave_resonator
probeline_factory = partial(media.line, d=5000, unit="um")
probeline = skrf.connect(
skrf.connect(probeline_factory(), 1, media.tee(), 0), 2, probeline_factory(), 0
)
all_network = skrf.connect(probeline, 1, resonator_coupled, 0)
sdict = {
("o1", "o1"): jnp.array(all_network.s[:, 0, 0]),
("o1", "o2"): jnp.array(all_network.s[:, 0, 1]),
}
return sax.reciprocal(sdict)
if __name__ == "__main__":
cpw = cpw_media_skrf(width=10, gap=6)(
frequency=skrf.Frequency(2, 9, 101, unit="GHz")
)
print(f"{cpw=!r}")
print(f"{cpw.z0.mean().real=!r}") # Characteristic impedance
res_freq = resonator_frequency(length=4000, media=cpw, is_quarter_wave=True)
print("Resonance frequency (quarter-wave):", res_freq / 1e9, "GHz")