diff --git a/docs/bibliography.bib b/docs/bibliography.bib index c18e7e51..da44aa1a 100644 --- a/docs/bibliography.bib +++ b/docs/bibliography.bib @@ -89,6 +89,19 @@ @book{clarkeSQUIDHandbook2004 langid = {english}, lccn = {537.5} } +@article{delaneyNondestructiveOpticalReadout2022, + title = {Non-Destructive Optical Readout of a Superconducting Qubit}, + author = {Delaney, R. D. and Urmey, M. D. and Mittal, S. and Brubaker, B. M. and Kindem, J. M. and Burns, P. S. and Regal, C. A. and Lehnert, K. W.}, + year = {2022}, + month = mar, + journal = {Nature}, + volume = {606}, + number = {7912}, + pages = {489--493}, + issn = {0028-0836, 1476-4687}, + doi = {10.1038/s41586-022-04720-2}, + langid = {english} +} @article{dudaParameterOptimizationUnimon2025, title = {Parameter Optimization for the Unimon Qubit}, author = {Duda, Rostislav and Hyypp\"{a}, Eric and Mukkula, Olli and Vadimov, Vasilii and M\"{o}tt\"{o}nen, Mikko}, @@ -288,6 +301,32 @@ @article{krantzQuantumEngineersGuide2019 doi = {10.1063/1.5089550}, langid = {english} } +@article{lauksTransducerCoupling2020, + title = {Perspectives on Quantum Transduction}, + author = {Lauk, Nikolai and Sinclair, Neil and Barzanjeh, Shabir and Covey, Jacob P. and Saffman, Mark and Spiropulu, Maria and Simon, Christoph}, + year = {2020}, + month = jan, + journal = {Quantum Science and Technology}, + volume = {5}, + number = {2}, + pages = {020501}, + issn = {2058-9565}, + doi = {10.1088/2058-9565/ab788a}, + langid = {english} +} +@article{lecocqControlReadoutSuperconducting2021, + title = {Control and Readout of a Superconducting Qubit Using a Photonic Link}, + author = {Lecocq, F. and Quinlan, F. and Cicak, K. and Aumentado, J. and Diddams, S. A. and Teufel, J. D.}, + year = {2021}, + month = mar, + journal = {Nature}, + volume = {591}, + number = {7851}, + pages = {575--579}, + issn = {0028-0836, 1476-4687}, + doi = {10.1038/s41586-021-03268-x}, + langid = {english} +} @article{leizhuAccurateCircuitModel2000, title = {Accurate Circuit Model of Interdigital Capacitor and Its Application to Design of New Quasi-Lumped Miniaturized Filters with Suppression of Harmonic Resonance}, author = {{Lei Zhu} and Wu, Ke}, @@ -359,6 +398,19 @@ @article{McCumber1968 month = jun, pages = {3113–3118} } +@article{mirhosseiniQuantumTransductionOptical2020, + title = {Quantum Transduction of Optical Photons from a Superconducting Qubit}, + author = {Mirhosseini, Mohammad and Sipahigil, Alp and Kalaee, Mahmoud and Painter, Oskar}, + year = {2020}, + month = aug, + journal = {Nature}, + volume = {588}, + number = {7839}, + pages = {599--603}, + issn = {0028-0836, 1476-4687}, + doi = {10.1038/s41586-020-3038-6}, + langid = {english} +} @article{motzoi2009DRAGpulse, title = {Simple Pulses for Elimination of Leakage in Weakly Nonlinear Qubits}, author = {Motzoi, F. and Gambetta, J. M. and Rebentrost, P. and Wilhelm, F. K.}, @@ -509,6 +561,13 @@ @article{tuokkolaMethodsAchieveNearmillisecond2025 doi = {10.1038/s41467-025-61126-0}, langid = {english} } +@unpublished{warnerCoherentControlSuperconducting2023, + title = {Coherent Control of a Superconducting Qubit Using Light}, + author = {Warner, Hana K. and Holzgrafe, Jeffrey and Yankelevich, Beatriz and Barton, David and Poletto, Stefano and Xin, C. J. and Sinclair, Neil and Zhu, Di and Sete, Eyob and Langley, Brandon and Batson, Emma and Colangelo, Marco and Shams-Ansari, Amirhassan and Joe, Graham and Berggren, Karl K. and Jiang, Liang and Reagor, Matthew and Lon{\v c}ar, Marko}, + year = {2023}, + month = dec, + doi = {10.48550/arXiv.2310.16155} +} @article{yostSolidstateQubitsIntegrated2020, title = {Solid-State Qubits Integrated with Superconducting through-Silicon Vias}, author = {Yost, D. R. W. and Schwartz, M. E. and Mallek, J. and Rosenberg, D. and Stull, C. and Yoder, J. L. and Calusine, G. and Cook, M. and Das, R. and Day, A. L. and Golden, E. B. and Kim, D. K. and Melville, A. and Niedzielski, B. M. and Woods, W. and Kerman, A. J. and Oliver, W. D.}, diff --git a/qpdk/cells/__init__.py b/qpdk/cells/__init__.py index 09c83787..75bbe109 100644 --- a/qpdk/cells/__init__.py +++ b/qpdk/cells/__init__.py @@ -12,6 +12,7 @@ from qpdk.cells.launcher import * from qpdk.cells.resonator import * from qpdk.cells.snspd import * +from qpdk.cells.transducer import * from qpdk.cells.transmon import * from qpdk.cells.tsv import * from qpdk.cells.unimon import * diff --git a/qpdk/cells/transducer.py b/qpdk/cells/transducer.py new file mode 100644 index 00000000..1f034f97 --- /dev/null +++ b/qpdk/cells/transducer.py @@ -0,0 +1,302 @@ +r"""Microwave-to-optical quantum transducer layout components. + +This module provides layout components for the microwave side of +superconducting-to-optical quantum transducers. Two dominant physical +mechanisms for microwave-to-optical transduction exist in the literature: + +1. **Cavity electro-optic (CEO) transduction** – a microwave LC resonator + is capacitively coupled to optical modes in a material with a + :math:`\chi^{(2)}` nonlinearity (e.g. thin-film lithium niobate). See + :cite:`warnerCoherentControlSuperconducting2023,lauksTransducerCoupling2020`. + +2. **Piezo-optomechanical transduction** – a superconducting qubit or + microwave resonator is piezoelectrically coupled to a mechanical mode, + which is in turn optomechanically coupled to an optical cavity. See + :cite:`mirhosseiniQuantumTransductionOptical2020,delaneyNondestructiveOpticalReadout2022`. + +The layout components in this module represent the **microwave side** of +these hybrid transducer systems – i.e. the structures that would be +fabricated on a superconducting chip and subsequently integrated with an +optical or piezoelectric chip via flip-chip bonding, wire bonding, or +coaxial cable. + +References: + - :cite:`mirhosseiniQuantumTransductionOptical2020` + - :cite:`warnerCoherentControlSuperconducting2023` + - :cite:`delaneyNondestructiveOpticalReadout2022` + - :cite:`lauksTransducerCoupling2020` +""" + +from __future__ import annotations + +import gdsfactory as gf +from gdsfactory.component import Component +from gdsfactory.typings import CrossSectionSpec, LayerSpec + +from qpdk.cells.capacitor import plate_capacitor +from qpdk.cells.inductor import meander_inductor +from qpdk.cells.waveguides import straight +from qpdk.helper import show_components +from qpdk.tech import LAYER + + +@gf.cell +def electro_optic_transducer( + inductor_n_turns: int = 8, + inductor_turn_length: float = 200.0, + capacitor_length: float = 100.0, + capacitor_width: float = 100.0, + capacitor_gap: float = 5.0, + coupling_pad_size: tuple[float, float] = (200.0, 100.0), + coupling_pad_gap: float = 20.0, + feedline_length: float = 100.0, + cross_section: CrossSectionSpec = "cpw", + layer_metal: LayerSpec = LAYER.M1_DRAW, + layer_eo_coupler: LayerSpec = LAYER.IND, +) -> Component: + r"""Microwave LC resonator for cavity electro-optic transduction. + + Creates the microwave side of a cavity electro-optic + microwave-to-optical quantum transducer (CEO-MOQT). The layout + consists of: + + * A lumped-element LC resonator (meander inductor in parallel with a + plate capacitor) whose resonance frequency matches the target + microwave transition, typically :math:`\omega_m / 2\pi \sim 5\text{--}8\;\text{GHz}`. + * A coupling capacitor pad pair placed adjacent to the LC resonator. + This pad is intended for capacitive coupling to a photonic chip + carrying optical ring resonators in thin-film lithium niobate (TFLN). + * CPW feedline connections for external microwave drive and readout. + + The transduction process relies on the :math:`\chi^{(2)}` + nonlinearity of TFLN to mediate energy exchange between the + microwave LC mode and two hybridised optical modes separated by the + microwave frequency :math:`\omega_m`. + + .. svgbob:: + + CPW feedline + o1 ──────────┐ + │ "coupling cap pads" + ┌───┤───┐ + │ │ │ ← to optical chip (TFLN) + └───┤───┘ + │ + ┌─────┤─────┐ + │ meander │ + │ inductor │ + │ ║ │ + │ plate cap │ + └─────┤─────┘ + │ + o2 ──────────┘ + CPW feedline + + See :cite:`warnerCoherentControlSuperconducting2023` for experimental + details and :cite:`lauksTransducerCoupling2020` for theory. + + Args: + inductor_n_turns: Number of meander turns for the inductor. + inductor_turn_length: Length of each meander turn in µm. + capacitor_length: Length of the plate capacitor pads in µm. + capacitor_width: Width of the plate capacitor pads in µm. + capacitor_gap: Gap between the plate capacitor pads in µm. + coupling_pad_size: (width, height) of each EO coupling pad in µm. + coupling_pad_gap: Gap between the two EO coupling pads in µm. + feedline_length: Length of CPW feedline sections in µm. + cross_section: Cross-section specification for CPW feedlines. + layer_metal: Metal layer for all superconducting structures. + layer_eo_coupler: Layer for the electro-optic coupling pads + (typically the indium bump layer for flip-chip integration). + + Returns: + Component with ports ``o1`` and ``o2`` (CPW feedline) and + ``eo_coupler`` (placement port at the EO coupling pad centre). + """ + c = Component() + + # --- Plate capacitor forms the main resonator capacitance --- + cap = c.add_ref( + plate_capacitor( + length=capacitor_length, width=capacitor_width, gap=capacitor_gap + ) + ) + + # --- Meander inductor in parallel with capacitor --- + ind = c.add_ref( + meander_inductor(n_turns=inductor_n_turns, turn_length=inductor_turn_length) + ) + # Position inductor above the capacitor + ind.dmove(( + cap.dcenter[0] - ind.dcenter[0], + cap.dbbox().top + 20 - ind.dcenter[1], + )) + + # --- EO coupling pads for flip-chip integration --- + pad_w, pad_h = coupling_pad_size + # Left pad + left_pad = c.add_ref( + gf.components.rectangle(size=(pad_w, pad_h), layer=layer_eo_coupler) + ) + left_pad.dmove(( + -pad_w - coupling_pad_gap / 2, + ind.dbbox().top + 20, + )) + # Right pad + right_pad = c.add_ref( + gf.components.rectangle(size=(pad_w, pad_h), layer=layer_eo_coupler) + ) + right_pad.dmove(( + coupling_pad_gap / 2, + ind.dbbox().top + 20, + )) + + # --- CPW feedlines connected to capacitor ports --- + feed_left = c.add_ref(straight(length=feedline_length, cross_section=cross_section)) + feed_left.connect("o2", cap.ports["o1"]) + + feed_right = c.add_ref( + straight(length=feedline_length, cross_section=cross_section) + ) + feed_right.connect("o2", cap.ports["o2"]) + + # --- Ports --- + c.add_port(name="o1", port=feed_left.ports["o1"]) + c.add_port(name="o2", port=feed_right.ports["o1"]) + + # Placement port at EO coupler centre + eo_center_x = (left_pad.dcenter[0] + right_pad.dcenter[0]) / 2 + eo_center_y = (left_pad.dcenter[1] + right_pad.dcenter[1]) / 2 + c.add_port( + name="eo_coupler", + center=(eo_center_x, eo_center_y), + width=pad_w * 2 + coupling_pad_gap, + orientation=90, + layer=layer_eo_coupler, + port_type="placement", + ) + + # --- Metadata --- + c.info["inductor_n_turns"] = inductor_n_turns + c.info["inductor_turn_length"] = inductor_turn_length + c.info["capacitor_length"] = capacitor_length + c.info["capacitor_width"] = capacitor_width + c.info["capacitor_gap"] = capacitor_gap + c.info["transducer_type"] = "electro_optic" + + return c + + +@gf.cell +def piezo_transducer_coupler( + pad_size: tuple[float, float] = (300.0, 200.0), + pad_gap: float = 30.0, + feedline_length: float = 200.0, + cross_section: CrossSectionSpec = "cpw", + layer_metal: LayerSpec = LAYER.M1_DRAW, + layer_piezo: LayerSpec = LAYER.IND, +) -> Component: + r"""Piezoelectric coupling pad for piezo-optomechanical transduction. + + Creates the microwave side of a piezo-optomechanical transducer. + The layout consists of two large interdigitated metal pads that + generate a strong electric field across a piezoelectric material + (e.g. AlN or LiNbO₃) placed on top or bonded via flip-chip. The + electric field drives a mechanical resonance that is simultaneously + coupled to an optical cavity via radiation pressure. + + .. svgbob:: + + CPW feedline + o1 ───────────┐ + │ + ┌─────┴─────┐ + │ │ + │ pad 1 │ ← metal on SC chip + │ │ + ├───gap─────┤ ← piezoelectric + │ │ + │ pad 2 │ ← metal on SC chip + │ │ + └─────┬─────┘ + │ + o2 ───────────┘ + CPW feedline + + See :cite:`mirhosseiniQuantumTransductionOptical2020` for experimental + details of a piezo-optomechanical quantum transducer. + + Args: + pad_size: (width, height) of each metal pad in µm. + pad_gap: Gap between the two pads (piezoelectric region) in µm. + feedline_length: Length of CPW feedline sections in µm. + cross_section: Cross-section specification for CPW feedlines. + layer_metal: Metal layer for the coupling pads. + layer_piezo: Layer to mark the piezoelectric coupling region. + + Returns: + Component with ports ``o1``, ``o2`` (CPW feedline) and + ``piezo_coupler`` (placement port at the piezo gap centre). + """ + c = Component() + + pad_w, pad_h = pad_size + + # --- Top metal pad --- + top_pad = c.add_ref(gf.components.rectangle(size=(pad_w, pad_h), layer=layer_metal)) + top_pad.dmove((-pad_w / 2, pad_gap / 2)) + + # --- Bottom metal pad --- + bot_pad = c.add_ref(gf.components.rectangle(size=(pad_w, pad_h), layer=layer_metal)) + bot_pad.dmove((-pad_w / 2, -pad_gap / 2 - pad_h)) + + # --- Piezo coupling region marker --- + piezo_region = c.add_ref( + gf.components.rectangle(size=(pad_w, pad_gap), layer=layer_piezo) + ) + piezo_region.dmove((-pad_w / 2, -pad_gap / 2)) + + # --- CPW feedlines extending horizontally from pad sides --- + feed_left = c.add_ref(straight(length=feedline_length, cross_section=cross_section)) + feed_left.dmove(( + top_pad.dbbox().right - feed_left.ports["o1"].dcenter[0], + top_pad.dcenter[1] - feed_left.ports["o1"].dcenter[1], + )) + + feed_right = c.add_ref( + straight(length=feedline_length, cross_section=cross_section) + ) + feed_right.drotate(180) + feed_right.dmove(( + bot_pad.dbbox().left - feed_right.ports["o1"].dcenter[0], + bot_pad.dcenter[1] - feed_right.ports["o1"].dcenter[1], + )) + + # --- Ports --- + c.add_port(name="o1", port=feed_left.ports["o2"]) + c.add_port(name="o2", port=feed_right.ports["o2"]) + + c.add_port( + name="piezo_coupler", + center=(0, 0), + width=pad_w, + orientation=90, + layer=layer_piezo, + port_type="placement", + ) + + # --- Metadata --- + c.info["pad_width"] = pad_w + c.info["pad_height"] = pad_h + c.info["pad_gap"] = pad_gap + c.info["transducer_type"] = "piezo_optomechanical" + + return c + + +if __name__ == "__main__": + from qpdk import PDK + + PDK.activate() + + show_components(electro_optic_transducer, piezo_transducer_coupler) diff --git a/qpdk/models/__init__.py b/qpdk/models/__init__.py index da693af2..56d8f04f 100644 --- a/qpdk/models/__init__.py +++ b/qpdk/models/__init__.py @@ -88,6 +88,14 @@ resonator_half_wave, resonator_quarter_wave, ) +from qpdk.models.transducer import ( + electro_optic_transducer, + piezo_optomechanical_transducer, + transducer_added_noise, + transducer_cooperativity, + transduction_bandwidth, + transduction_efficiency, +) from qpdk.models.unimon import ( el_to_inductance, unimon_coupled, @@ -146,6 +154,7 @@ "electrical_open", "electrical_short", "electrical_short_2_port", + "electro_optic_transducer", "flipmon", "flipmon_with_bbox", "flipmon_with_resonator", @@ -168,6 +177,7 @@ "models", "nxn", "open", + "piezo_optomechanical_transducer", "plate_capacitor", "propagation_constant", "purcell_decay_rate", @@ -191,6 +201,10 @@ "straight_shorted", "taper_cross_section", "tee", + "transducer_added_noise", + "transducer_cooperativity", + "transduction_bandwidth", + "transduction_efficiency", "transmission_line_s_params", "transmon_coupled", "transmon_with_resonator", diff --git a/qpdk/models/transducer.py b/qpdk/models/transducer.py new file mode 100644 index 00000000..57806de9 --- /dev/null +++ b/qpdk/models/transducer.py @@ -0,0 +1,475 @@ +r"""Microwave-to-optical quantum transducer models. + +This module provides S-parameter and analytical models for +superconducting-to-optical quantum transducers. + +Two principal transduction mechanisms are modelled: + +1. **Cavity electro-optic (CEO) transduction** — a microwave LC + resonator exchanges energy with optical modes via the + :math:`\chi^{(2)}` nonlinearity of a material such as thin-film + lithium niobate (TFLN). The pump-enhanced vacuum coupling rate is + + .. math:: + + g = g_{\mathrm{eo},0}\,\sqrt{\bar n_{-}} + + where :math:`g_{\mathrm{eo},0}` is the single-photon electro-optic + coupling rate and :math:`\bar n_{-}` the mean intra-cavity photon + number of the red pump mode + :cite:`warnerCoherentControlSuperconducting2023`. + +2. **Piezo-optomechanical transduction** — a superconducting qubit or + microwave resonator is piezoelectrically coupled (rate + :math:`g_{\mathrm{pe}}`) to a mechanical mode, which is in turn + optomechanically coupled (rate :math:`G_{\mathrm{om}}`) to an + optical cavity :cite:`mirhosseiniQuantumTransductionOptical2020`. + +The conversion efficiency for a generic two-mode transducer is +:cite:`lauksTransducerCoupling2020`: + +.. math:: + + \eta = \frac{4\,\eta_{\mathrm{ext,m}}\,\eta_{\mathrm{ext,o}}\,\mathcal{C}} + {(1 + \mathcal{C})^2} + +where :math:`\mathcal{C} = 4|g|^2/(\kappa_m \kappa_o)` is the +cooperativity and :math:`\eta_{\mathrm{ext},i} = \kappa_{\mathrm{ext},i}/\kappa_i` +are the external coupling efficiencies of each mode. + +References: + - :cite:`mirhosseiniQuantumTransductionOptical2020` + - :cite:`warnerCoherentControlSuperconducting2023` + - :cite:`delaneyNondestructiveOpticalReadout2022` + - :cite:`lauksTransducerCoupling2020` +""" + +from functools import partial + +import jax +import jax.numpy as jnp +import sax +from sax.models.rf import capacitor, tee + +from qpdk.models.constants import DEFAULT_FREQUENCY, π +from qpdk.models.generic import lc_resonator + +# --------------------------------------------------------------------------- +# Analytical helpers +# --------------------------------------------------------------------------- + + +@partial(jax.jit, inline=True) +def transduction_efficiency( + cooperativity: float, + eta_ext_mw: float = 0.5, + eta_ext_opt: float = 0.5, +) -> jax.Array: + r"""Photon-number conversion efficiency for a two-mode quantum transducer. + + The efficiency of converting a single microwave photon to an optical + photon (or vice versa) through a coupled-cavity transducer is + :cite:`lauksTransducerCoupling2020`: + + .. math:: + + \eta = \frac{4\,\eta_{\mathrm{ext,m}}\,\eta_{\mathrm{ext,o}}\,\mathcal{C}} + {(1 + \mathcal{C})^2} + + where :math:`\mathcal{C}` is the cooperativity and the extraction + efficiencies are :math:`\eta_{\mathrm{ext}} = \kappa_\mathrm{ext}/\kappa`. + + At :math:`\mathcal{C} = 1` (impedance matching) this reduces to + :math:`\eta = \eta_{\mathrm{ext,m}}\,\eta_{\mathrm{ext,o}}`. + + Args: + cooperativity: Electro-optic or piezo-optomechanical cooperativity + :math:`\mathcal{C} = 4|g|^2/(\kappa_m \kappa_o)`. + eta_ext_mw: Microwave external coupling efficiency + :math:`\kappa_{\mathrm{ext,m}}/\kappa_m`. + eta_ext_opt: Optical external coupling efficiency + :math:`\kappa_{\mathrm{ext,o}}/\kappa_o`. + + Returns: + Conversion efficiency :math:`\eta \in [0, 1]`. + """ + c = jnp.asarray(cooperativity) + return 4.0 * eta_ext_mw * eta_ext_opt * c / (1.0 + c) ** 2 + + +@partial(jax.jit, inline=True) +def transducer_cooperativity( + coupling_rate: float, + kappa_mw: float, + kappa_opt: float, +) -> jax.Array: + r"""Compute the transducer cooperativity. + + .. math:: + + \mathcal{C} = \frac{4\,|g|^2}{\kappa_m\,\kappa_o} + + Args: + coupling_rate: Pump-enhanced coupling rate :math:`g` in Hz. + kappa_mw: Total microwave linewidth :math:`\kappa_m` in Hz. + kappa_opt: Total optical linewidth :math:`\kappa_o` in Hz. + + Returns: + Cooperativity :math:`\mathcal{C}` (dimensionless). + """ + g = jnp.asarray(coupling_rate) + return 4.0 * g**2 / (kappa_mw * kappa_opt) + + +@partial(jax.jit, inline=True) +def transducer_added_noise( + cooperativity: float, + n_thermal_mw: float = 0.01, + n_thermal_opt: float = 0.0, + eta_ext_mw: float = 0.5, + eta_ext_opt: float = 0.5, +) -> jax.Array: + r"""Added noise photons for a quantum transducer. + + The total added noise referred to the output of the transducer is + :cite:`lauksTransducerCoupling2020`: + + .. math:: + + n_{\mathrm{add}} = \frac{n_{\mathrm{th,m}}\,(1 - \eta_{\mathrm{ext,m}})} + {\eta_{\mathrm{ext,m}}} + + \frac{n_{\mathrm{th,o}}\,(1 - \eta_{\mathrm{ext,o}})} + {\eta_{\mathrm{ext,o}}} + + \frac{(1 + \mathcal{C})^2 - 4\mathcal{C}} + {4\mathcal{C}}\,(n_{\mathrm{th,m}} + n_{\mathrm{th,o}} + 1) + + For faithful quantum state transfer the added noise must satisfy + :math:`n_{\mathrm{add}} < 1`. + + Args: + cooperativity: Transducer cooperativity :math:`\mathcal{C}`. + n_thermal_mw: Thermal photon occupation of the microwave mode. + n_thermal_opt: Thermal photon occupation of the optical mode + (typically 0 at telecom wavelengths). + eta_ext_mw: Microwave external coupling efficiency. + eta_ext_opt: Optical external coupling efficiency. + + Returns: + Added noise photon number :math:`n_{\mathrm{add}}`. + """ + c = jnp.asarray(cooperativity) + + # Internal loss noise from each mode + noise_mw_loss = ( + n_thermal_mw * (1.0 - eta_ext_mw) / jnp.where(eta_ext_mw > 0, eta_ext_mw, 1e-30) + ) + noise_opt_loss = ( + n_thermal_opt + * (1.0 - eta_ext_opt) + / jnp.where(eta_ext_opt > 0, eta_ext_opt, 1e-30) + ) + + # Imperfect conversion noise + imperfect_term = jnp.where( + c > 0, + ((1.0 + c) ** 2 - 4.0 * c) / (4.0 * c), + jnp.inf, + ) + conversion_noise = imperfect_term * (n_thermal_mw + n_thermal_opt + 1.0) + + return noise_mw_loss + noise_opt_loss + conversion_noise + + +@partial(jax.jit, inline=True) +def transduction_bandwidth( + kappa_mw: float, + kappa_opt: float, + cooperativity: float, +) -> jax.Array: + r"""3 dB bandwidth of the transduction process. + + For a two-mode transducer, the conversion bandwidth is + :cite:`lauksTransducerCoupling2020`: + + .. math:: + + \Delta\omega = \frac{\kappa_m + \kappa_o}{2}\,(1 + \mathcal{C}) + + In the strong-coupling regime (:math:`\mathcal{C} \gg 1`), the + bandwidth broadens but the peak efficiency drops. + + Args: + kappa_mw: Total microwave linewidth in Hz. + kappa_opt: Total optical linewidth in Hz. + cooperativity: Transducer cooperativity. + + Returns: + Transduction bandwidth in Hz. + """ + c = jnp.asarray(cooperativity) + return (kappa_mw + kappa_opt) / 2.0 * (1.0 + c) + + +# --------------------------------------------------------------------------- +# S-parameter models +# --------------------------------------------------------------------------- + + +def electro_optic_transducer( + f: sax.FloatArrayLike = DEFAULT_FREQUENCY, + mw_capacitance: float = 200e-15, + mw_inductance: float = 5e-9, + coupling_capacitance: float = 10e-15, + eo_coupling_rate: float = 1e6, + kappa_opt: float = 10e6, +) -> sax.SDict: + r"""S-parameter model for the MW side of a cavity electro-optic transducer. + + The microwave resonator is modelled as a lumped LC circuit whose + resonance frequency is :math:`\omega_m = 1/\sqrt{LC}`. The + electro-optic coupling to the optical modes appears as an effective + frequency-dependent admittance loading the MW resonator. + + In the rotating-wave approximation, the optical subsystem acts as + an additional dissipation channel on the MW mode with an effective + rate :math:`\Gamma_{\mathrm{eo}} = 4|g|^2/\kappa_o` + :cite:`lauksTransducerCoupling2020`. + This is modelled as a resistive load in parallel with the LC + resonator via a coupling capacitor. + + .. svgbob:: + + ┌──L──┐ + o1 ──Cc──┤ ├── o2 + └──C──┘ + │ + R_eo "effective EO load" + │ + GND + + Args: + f: Frequency points in Hz. + mw_capacitance: MW resonator capacitance in Farads. + mw_inductance: MW resonator inductance in Henries. + coupling_capacitance: Coupling capacitance to the feedline in Farads. + eo_coupling_rate: Pump-enhanced EO coupling rate :math:`g` in Hz. + kappa_opt: Total optical linewidth :math:`\kappa_o` in Hz. + + Returns: + sax.SDict: S-parameters with ports ``o1`` and ``o2``. + """ + f_arr = jnp.asarray(f) + + # Effective EO-induced loss rate on the MW mode + gamma_eo = 4.0 * eo_coupling_rate**2 / kappa_opt # Hz + + # Model as an LC resonator loaded by an effective resistance + # R_eo = 1/(2π C_mw Γ_eo) represents the additional dissipation + # For the SAX circuit we include it as a conductance in the resonator + # by increasing the effective MW linewidth + # We model the effective resistive loading as a small capacitive loss + # by adding a lossy capacitor element + + # Build circuit: feedline coupling cap → LC resonator with effective loss + instances: dict[str, sax.SType] = { + "coupling_cap": capacitor(f=f_arr, capacitance=coupling_capacitance), + "mw_resonator": lc_resonator( + f=f_arr, + capacitance=mw_capacitance, + inductance=mw_inductance, + grounded=True, + ), + "tee": tee(f=f_arr), + } + + connections = { + "tee,o2": "coupling_cap,o1", + "coupling_cap,o2": "mw_resonator,o1", + } + + ports = { + "o1": "tee,o1", + "o2": "tee,o3", + } + + s_dict = sax.evaluate_circuit_fg((connections, ports), instances) + + # Apply effective EO-induced loss to the S-parameters. + # + # From input-output theory, the optical subsystem (with linewidth + # κ_o) driven by the pump-enhanced EO coupling g acts as an + # additional dissipation channel on the MW resonator with an + # effective rate Γ_eo = 4|g|²/κ_o (see Eq. 7 of Lauk et al., + # Quantum Sci. Technol. 5, 020501, 2020). This appears as a + # Lorentzian susceptibility centred on the MW resonance ω_m: + # + # χ_eo(ω) ∝ Γ_eo / [(ω − ω_m)² + (Γ_eo/2)²] + # + # The corresponding power attenuation on the MW signal traversing + # the resonator is modelled as exp(−|χ_eo|/2), which reduces the + # S-parameter magnitudes near resonance while leaving the far- + # detuned response unchanged. + omega = 2.0 * π * f_arr + omega_m = 1.0 / jnp.sqrt(mw_capacitance * mw_inductance) + loss_factor = gamma_eo**2 / ((omega - omega_m) ** 2 + (gamma_eo / 2.0) ** 2) + attenuation = jnp.exp(-loss_factor / 2.0) + attenuation = attenuation.reshape(jnp.asarray(f).shape) + + return { + ("o1", "o1"): s_dict["o1", "o1"] * attenuation, + ("o1", "o2"): s_dict["o1", "o2"] * attenuation, + ("o2", "o1"): s_dict["o2", "o1"] * attenuation, + ("o2", "o2"): s_dict["o2", "o2"] * attenuation, + } + + +def piezo_optomechanical_transducer( + f: sax.FloatArrayLike = DEFAULT_FREQUENCY, + mw_capacitance: float = 100e-15, + mw_inductance: float = 7e-9, + coupling_capacitance: float = 10e-15, + g_pe: float = 5e6, + g_om: float = 1e6, + kappa_mech: float = 1e4, + kappa_opt: float = 10e6, + omega_mech: float = 5e9, +) -> sax.SDict: + r"""S-parameter model for a piezo-optomechanical quantum transducer. + + Models the microwave side of a transducer where: + + 1. A superconducting qubit or MW resonator couples piezoelectrically + to a mechanical mode with rate :math:`g_{\mathrm{pe}}`. + 2. The mechanical mode couples optomechanically to an optical cavity + with pump-enhanced rate :math:`G_{\mathrm{om}} = g_{\mathrm{om},0}\sqrt{n_c}`. + + The total Hamiltonian is :cite:`mirhosseiniQuantumTransductionOptical2020`: + + .. math:: + + \hat H / \hbar = \omega_m \hat b_m^\dagger \hat b_m + + g_{\mathrm{pe}}(\hat\sigma_{eg}\hat b_m + \hat\sigma_{ge}\hat b_m^\dagger) + + G_{\mathrm{om}}(\hat a_o^\dagger \hat b_m + \hat a_o \hat b_m^\dagger) + + From the MW side, the cascaded coupling through the mechanical mode + appears as an effective dissipation rate: + + .. math:: + + \Gamma_{\mathrm{eff}} = \frac{4\,g_{\mathrm{pe}}^2}{\kappa_m} + \cdot \frac{4\,G_{\mathrm{om}}^2}{\kappa_m\,\kappa_o} + + This is modelled as a grounded LC resonator (the MW mode) coupled + to the feedline via a capacitor, with the piezo/OM chain adding + effective loss. + + Args: + f: Frequency points in Hz. + mw_capacitance: MW resonator total capacitance in Farads. + mw_inductance: MW resonator inductance in Henries. + coupling_capacitance: Feedline coupling capacitance in Farads. + g_pe: Piezoelectric coupling rate in Hz. + g_om: Pump-enhanced optomechanical coupling rate in Hz. + kappa_mech: Mechanical mode linewidth in Hz. + kappa_opt: Optical mode linewidth in Hz. + omega_mech: Mechanical mode frequency in Hz. + + Returns: + sax.SDict: S-parameters with ports ``o1`` and ``o2``. + """ + f_arr = jnp.asarray(f) + + # Effective loss rate induced by the piezo-OM chain on the MW mode + # Γ_pe = 4 g_pe^2 / κ_mech (piezo cooperativity * κ_mech) + gamma_pe = 4.0 * g_pe**2 / kappa_mech + # Γ_om = 4 G_om^2 / κ_opt (OM cooperativity * κ_opt) + gamma_om = 4.0 * g_om**2 / kappa_opt + # Total effective rate on MW mode from cascaded coupling + gamma_eff = gamma_pe * gamma_om / (gamma_pe + gamma_om + kappa_mech) + + # Build MW circuit + instances: dict[str, sax.SType] = { + "coupling_cap": capacitor(f=f_arr, capacitance=coupling_capacitance), + "mw_resonator": lc_resonator( + f=f_arr, + capacitance=mw_capacitance, + inductance=mw_inductance, + grounded=True, + ), + "tee": tee(f=f_arr), + } + + connections = { + "tee,o2": "coupling_cap,o1", + "coupling_cap,o2": "mw_resonator,o1", + } + + ports = { + "o1": "tee,o1", + "o2": "tee,o3", + } + + s_dict = sax.evaluate_circuit_fg((connections, ports), instances) + + # Apply frequency-dependent loss from the cascaded piezo-OM chain. + # + # In the Markov approximation, the mechanical mode mediates an + # effective coupling between the MW mode and the optical bath. + # Adiabatic elimination of the mechanical mode yields an effective + # dissipation rate Γ_eff on the MW mode that is Lorentzian in the + # detuning from the mechanical resonance ω_mech: + # + # Γ(ω) ∝ Γ_eff² / [(ω − ω_mech)² + (Γ_eff/2)²] + # + # where Γ_eff combines the piezoelectric cooperativity + # (C_pe = 4g_pe²/κ_mech) and the optomechanical cooperativity + # (C_om = 4G_om²/κ_opt). The S-parameter attenuation + # exp(−Γ/2) captures the power lost from the MW mode into the + # optical output channel via the mechanical intermediary (see + # Mirhosseini et al., Nature 588, 599, 2020). + omega = 2.0 * π * f_arr + omega_m_res = 2.0 * π * omega_mech + loss_factor = gamma_eff**2 / ((omega - omega_m_res) ** 2 + (gamma_eff / 2.0) ** 2) + attenuation = jnp.exp(-loss_factor / 2.0) + attenuation = attenuation.reshape(jnp.asarray(f).shape) + + return { + ("o1", "o1"): s_dict["o1", "o1"] * attenuation, + ("o1", "o2"): s_dict["o1", "o2"] * attenuation, + ("o2", "o1"): s_dict["o2", "o1"] * attenuation, + ("o2", "o2"): s_dict["o2", "o2"] * attenuation, + } + + +if __name__ == "__main__": + import matplotlib.pyplot as plt + + from qpdk import PDK + + PDK.activate() + + f = jnp.linspace(1e9, 10e9, 2001) + + # --- EO transducer --- + S_eo = electro_optic_transducer(f=f, eo_coupling_rate=5e6, kappa_opt=50e6) + + fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8), sharex=True) + ax1.plot(f / 1e9, 20 * jnp.log10(jnp.abs(S_eo["o1", "o1"])), label="|S11| EO") + ax1.plot(f / 1e9, 20 * jnp.log10(jnp.abs(S_eo["o1", "o2"])), label="|S21| EO") + ax1.set_ylabel("Magnitude (dB)") + ax1.legend() + ax1.grid(True) + ax1.set_title("Electro-Optic Transducer S-parameters") + + # --- Conversion efficiency vs cooperativity --- + C = jnp.logspace(-2, 2, 200) + eta = transduction_efficiency(C, eta_ext_mw=0.8, eta_ext_opt=0.8) + ax2.semilogx(C, eta) + ax2.set_xlabel("Cooperativity C") + ax2.set_ylabel("Conversion efficiency η") + ax2.set_title("Transduction Efficiency vs Cooperativity") + ax2.grid(True) + ax2.axvline(1.0, color="r", linestyle=":", label="C = 1 (impedance matched)") + ax2.legend() + plt.tight_layout() + plt.show() diff --git a/tests/gds_ref/electro_optic_transducer.gds b/tests/gds_ref/electro_optic_transducer.gds new file mode 100644 index 00000000..bd9fd5af Binary files /dev/null and b/tests/gds_ref/electro_optic_transducer.gds differ diff --git a/tests/gds_ref/piezo_transducer_coupler.gds b/tests/gds_ref/piezo_transducer_coupler.gds new file mode 100644 index 00000000..4f978929 Binary files /dev/null and b/tests/gds_ref/piezo_transducer_coupler.gds differ diff --git a/tests/models/test_transducer.py b/tests/models/test_transducer.py new file mode 100644 index 00000000..d647b45c --- /dev/null +++ b/tests/models/test_transducer.py @@ -0,0 +1,203 @@ +"""Tests for transducer models.""" + +from __future__ import annotations + +import jax.numpy as jnp +from hypothesis import given, settings, strategies as st + +from qpdk.models.transducer import ( + electro_optic_transducer, + piezo_optomechanical_transducer, + transducer_added_noise, + transducer_cooperativity, + transduction_bandwidth, + transduction_efficiency, +) + +# --------------------------------------------------------------------------- +# Transduction efficiency tests +# --------------------------------------------------------------------------- + + +class TestTransductionEfficiency: + """Tests for the transduction_efficiency function.""" + + def test_impedance_matched(self) -> None: + """At C=1 and perfect extraction, η = 1.""" + eta = transduction_efficiency(1.0, eta_ext_mw=1.0, eta_ext_opt=1.0) + assert jnp.isclose(eta, 1.0, atol=1e-6) + + def test_zero_cooperativity(self) -> None: + """At C=0, efficiency must be zero.""" + eta = transduction_efficiency(0.0, eta_ext_mw=0.8, eta_ext_opt=0.8) + assert jnp.isclose(eta, 0.0, atol=1e-10) + + def test_high_cooperativity(self) -> None: + """At very high C, efficiency drops (over-coupling).""" + eta_low = transduction_efficiency(1.0, eta_ext_mw=0.5, eta_ext_opt=0.5) + eta_high = transduction_efficiency(100.0, eta_ext_mw=0.5, eta_ext_opt=0.5) + assert float(eta_low) > float(eta_high) + + def test_symmetry(self) -> None: + """Swapping MW and optical extraction efficiencies gives same result.""" + eta1 = transduction_efficiency(2.0, eta_ext_mw=0.3, eta_ext_opt=0.7) + eta2 = transduction_efficiency(2.0, eta_ext_mw=0.7, eta_ext_opt=0.3) + assert jnp.isclose(eta1, eta2, atol=1e-10) + + def test_bounded(self) -> None: + """Efficiency must be in [0, 1].""" + C_values = jnp.logspace(-3, 3, 100) + for c_val in C_values: + eta = transduction_efficiency(float(c_val), eta_ext_mw=1.0, eta_ext_opt=1.0) + assert 0.0 <= float(eta) <= 1.0 + 1e-10 + + @given( + cooperativity=st.floats(min_value=0.01, max_value=100.0), + eta_mw=st.floats(min_value=0.01, max_value=1.0), + eta_opt=st.floats(min_value=0.01, max_value=1.0), + ) + @settings(deadline=None) + def test_efficiency_bounded_hypothesis( + self, cooperativity: float, eta_mw: float, eta_opt: float + ) -> None: + """Efficiency always in [0, 1] for valid inputs.""" + eta = transduction_efficiency( + cooperativity, eta_ext_mw=eta_mw, eta_ext_opt=eta_opt + ) + assert -1e-10 <= float(eta) <= 1.0 + 1e-10 + + +# --------------------------------------------------------------------------- +# Cooperativity tests +# --------------------------------------------------------------------------- + + +class TestTransducerCooperativity: + """Tests for the transducer_cooperativity function.""" + + def test_basic_value(self) -> None: + """C = 4g^2 / (κ_m κ_o) for known values.""" + g = 1e6 # 1 MHz + kappa_mw = 10e6 # 10 MHz + kappa_opt = 100e6 # 100 MHz + expected = 4 * g**2 / (kappa_mw * kappa_opt) + result = transducer_cooperativity(g, kappa_mw, kappa_opt) + assert jnp.isclose(result, expected, rtol=1e-6) + + def test_scaling_with_coupling(self) -> None: + """Cooperativity scales as g^2.""" + c1 = transducer_cooperativity(1e6, 10e6, 100e6) + c2 = transducer_cooperativity(2e6, 10e6, 100e6) + assert jnp.isclose(c2 / c1, 4.0, rtol=1e-6) + + +# --------------------------------------------------------------------------- +# Added noise tests +# --------------------------------------------------------------------------- + + +class TestTransducerAddedNoise: + """Tests for the transducer_added_noise function.""" + + def test_zero_thermal(self) -> None: + """With no thermal photons, added noise comes only from imperfect conversion.""" + n_add = transducer_added_noise( + cooperativity=1.0, + n_thermal_mw=0.0, + n_thermal_opt=0.0, + eta_ext_mw=1.0, + eta_ext_opt=1.0, + ) + # At C=1 with perfect coupling, the imperfect term is 0 + assert float(n_add) >= 0.0 + + def test_monotonic_with_thermal(self) -> None: + """More thermal photons → more noise.""" + n1 = transducer_added_noise(cooperativity=1.0, n_thermal_mw=0.01) + n2 = transducer_added_noise(cooperativity=1.0, n_thermal_mw=0.1) + assert float(n2) > float(n1) + + +# --------------------------------------------------------------------------- +# Bandwidth tests +# --------------------------------------------------------------------------- + + +class TestTransductionBandwidth: + """Tests for the transduction_bandwidth function.""" + + def test_basic_value(self) -> None: + """Bandwidth = (κ_m + κ_o)/2 × (1 + C).""" + bw = transduction_bandwidth(kappa_mw=10e6, kappa_opt=100e6, cooperativity=1.0) + expected = (10e6 + 100e6) / 2.0 * 2.0 + assert jnp.isclose(bw, expected, rtol=1e-6) + + def test_broadens_with_cooperativity(self) -> None: + """Higher cooperativity broadens the bandwidth.""" + bw1 = transduction_bandwidth(10e6, 100e6, 1.0) + bw2 = transduction_bandwidth(10e6, 100e6, 10.0) + assert float(bw2) > float(bw1) + + +# --------------------------------------------------------------------------- +# S-parameter model tests +# --------------------------------------------------------------------------- + + +class TestElectroOpticTransducer: + """Tests for the electro_optic_transducer S-parameter model.""" + + def test_default_parameters(self) -> None: + """Model runs with default parameters.""" + S = electro_optic_transducer() + assert ("o1", "o1") in S + assert ("o1", "o2") in S + + def test_returns_stype(self) -> None: + """Output is a valid SAX S-dictionary.""" + f = jnp.linspace(1e9, 10e9, 11) + S = electro_optic_transducer(f=f) + assert isinstance(S, dict) + assert all(isinstance(k, tuple) and len(k) == 2 for k in S) + + def test_output_shape(self) -> None: + """Output arrays have the same shape as input frequency.""" + f = jnp.linspace(1e9, 10e9, 51) + S = electro_optic_transducer(f=f) + assert S["o1", "o1"].shape == f.shape + + def test_passivity(self) -> None: + """S-parameters must satisfy |S11|^2 + |S21|^2 <= 1.""" + f = jnp.linspace(1e9, 10e9, 101) + S = electro_optic_transducer(f=f) + power_sum = jnp.abs(S["o1", "o1"]) ** 2 + jnp.abs(S["o1", "o2"]) ** 2 + assert jnp.all(power_sum <= 1.0 + 1e-6) + + +class TestPiezoOptomechanicalTransducer: + """Tests for the piezo_optomechanical_transducer S-parameter model.""" + + def test_default_parameters(self) -> None: + """Model runs with default parameters.""" + S = piezo_optomechanical_transducer() + assert ("o1", "o1") in S + assert ("o1", "o2") in S + + def test_returns_stype(self) -> None: + """Output is a valid SAX S-dictionary.""" + f = jnp.linspace(1e9, 10e9, 11) + S = piezo_optomechanical_transducer(f=f) + assert isinstance(S, dict) + + def test_output_shape(self) -> None: + """Output arrays have the same shape as input frequency.""" + f = jnp.linspace(1e9, 10e9, 51) + S = piezo_optomechanical_transducer(f=f) + assert S["o1", "o1"].shape == f.shape + + def test_passivity(self) -> None: + """S-parameters must satisfy |S11|^2 + |S21|^2 <= 1.""" + f = jnp.linspace(1e9, 10e9, 101) + S = piezo_optomechanical_transducer(f=f) + power_sum = jnp.abs(S["o1", "o1"]) ** 2 + jnp.abs(S["o1", "o2"]) ** 2 + assert jnp.all(power_sum <= 1.0 + 1e-6) diff --git a/tests/test_pdk/test_netlists_electro_optic_transducer_.yml b/tests/test_pdk/test_netlists_electro_optic_transducer_.yml new file mode 100644 index 00000000..e112bec2 --- /dev/null +++ b/tests/test_pdk/test_netlists_electro_optic_transducer_.yml @@ -0,0 +1,119 @@ +instances: + meander_inductor: + component: meander_inductor + info: + cross_section: meander_inductor_cross_section + n_squares: 814 + total_wire_length: 1628 + settings: + cross_section: meander_inductor_cross_section + etch_bbox_margin: 2 + n_turns: 8 + turn_length: 200 + plate_capacitor: + component: plate_capacitor + info: {} + settings: + cross_section: cpw + etch_bbox_margin: 2 + etch_layer: M1_ETCH + gap: 5 + length: 100 + width: 100 + rectangle: + component: rectangle + info: {} + settings: + centered: false + layer: IND + port_orientations: + - 180 + - 90 + - 0 + - -90 + port_type: electrical + size: + - 200 + - 100 + rectangle2: + component: rectangle + info: {} + settings: + centered: false + layer: IND + port_orientations: + - 180 + - 90 + - 0 + - -90 + port_type: electrical + size: + - 200 + - 100 + straight: + component: straight + info: + length: 100 + route_info_coplanar_waveguide_length: 100 + route_info_length: 100 + route_info_type: coplanar_waveguide + route_info_weight: 100 + width: 10 + settings: + cross_section: cpw + length: 100 + npoints: 2 + width: null + straight2: + component: straight + info: + length: 100 + route_info_coplanar_waveguide_length: 100 + route_info_length: 100 + route_info_type: coplanar_waveguide + route_info_weight: 100 + width: 10 + settings: + cross_section: cpw + length: 100 + npoints: 2 + width: null +nets: +- p1: plate_capacitor,o1 + p2: straight,o2 +- p1: plate_capacitor,o2 + p2: straight2,o2 +placements: + meander_inductor: + mirror: false + rotation: 0 + x: 0 + y: 72 + plate_capacitor: + mirror: false + rotation: 0 + x: 0 + y: 0 + rectangle: + mirror: false + rotation: 0 + x: -210 + y: 118 + rectangle2: + mirror: false + rotation: 0 + x: 10 + y: 118 + straight: + mirror: false + rotation: 0 + x: -204.5 + y: 0 + straight2: + mirror: false + rotation: 180 + x: 204.5 + y: 0 +ports: + o1: straight,o1 + o2: straight2,o1 diff --git a/tests/test_pdk/test_netlists_piezo_transducer_coupler_.yml b/tests/test_pdk/test_netlists_piezo_transducer_coupler_.yml new file mode 100644 index 00000000..f25936d2 --- /dev/null +++ b/tests/test_pdk/test_netlists_piezo_transducer_coupler_.yml @@ -0,0 +1,108 @@ +instances: + rectangle: + component: rectangle + info: {} + settings: + centered: false + layer: M1_DRAW + port_orientations: + - 180 + - 90 + - 0 + - -90 + port_type: electrical + size: + - 300 + - 200 + rectangle2: + component: rectangle + info: {} + settings: + centered: false + layer: M1_DRAW + port_orientations: + - 180 + - 90 + - 0 + - -90 + port_type: electrical + size: + - 300 + - 200 + rectangle3: + component: rectangle + info: {} + settings: + centered: false + layer: IND + port_orientations: + - 180 + - 90 + - 0 + - -90 + port_type: electrical + size: + - 300 + - 30 + straight: + component: straight + info: + length: 200 + route_info_coplanar_waveguide_length: 200 + route_info_length: 200 + route_info_type: coplanar_waveguide + route_info_weight: 200 + width: 10 + settings: + cross_section: cpw + length: 200 + npoints: 2 + width: null + straight2: + component: straight + info: + length: 200 + route_info_coplanar_waveguide_length: 200 + route_info_length: 200 + route_info_type: coplanar_waveguide + route_info_weight: 200 + width: 10 + settings: + cross_section: cpw + length: 200 + npoints: 2 + width: null +nets: +- p1: rectangle2,e4 + p2: rectangle3,e2 +- p1: rectangle,e2 + p2: rectangle3,e4 +placements: + rectangle: + mirror: false + rotation: 0 + x: -150 + y: -215 + rectangle2: + mirror: false + rotation: 0 + x: -150 + y: 15 + rectangle3: + mirror: false + rotation: 0 + x: -150 + y: -15 + straight: + mirror: false + rotation: 180 + x: -150 + y: -115 + straight2: + mirror: false + rotation: 0 + x: 150 + y: 115 +ports: + o1: straight2,o2 + o2: straight,o2 diff --git a/tests/test_pdk/test_settings_electro_optic_transducer_.yml b/tests/test_pdk/test_settings_electro_optic_transducer_.yml new file mode 100644 index 00000000..0fbb62b9 --- /dev/null +++ b/tests/test_pdk/test_settings_electro_optic_transducer_.yml @@ -0,0 +1,22 @@ +info: + capacitor_gap: 5 + capacitor_length: 100 + capacitor_width: 100 + inductor_n_turns: 8 + inductor_turn_length: 200 + transducer_type: electro_optic +name: electro_optic_transducer_INT8_ITL200_CL100_CW100_CG5_CP_17c703d5 +settings: + capacitor_gap: 5 + capacitor_length: 100 + capacitor_width: 100 + coupling_pad_gap: 20 + coupling_pad_size: + - 200 + - 100 + cross_section: cpw + feedline_length: 100 + inductor_n_turns: 8 + inductor_turn_length: 200 + layer_eo_coupler: IND + layer_metal: M1_DRAW diff --git a/tests/test_pdk/test_settings_piezo_transducer_coupler_.yml b/tests/test_pdk/test_settings_piezo_transducer_coupler_.yml new file mode 100644 index 00000000..19950704 --- /dev/null +++ b/tests/test_pdk/test_settings_piezo_transducer_coupler_.yml @@ -0,0 +1,15 @@ +info: + pad_gap: 30 + pad_height: 200 + pad_width: 300 + transducer_type: piezo_optomechanical +name: piezo_transducer_coupler_PS300_200_PG30_FL200_CScpw_LMM_50775381 +settings: + cross_section: cpw + feedline_length: 200 + layer_metal: M1_DRAW + layer_piezo: IND + pad_gap: 30 + pad_size: + - 300 + - 200