From 73e52268a03935543627e1e9d8800d96cbe9e984 Mon Sep 17 00:00:00 2001 From: Helge Gehring <42973196+HelgeGehring@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:35:33 -0700 Subject: [PATCH] add coplanar wavegudie example --- docs/_toc.yml | 1 + .../examples/coplanar_waveguide.py | 140 ++++++++++++++++++ docs/references.bib | 14 ++ 3 files changed, 155 insertions(+) create mode 100644 docs/electronics/examples/coplanar_waveguide.py diff --git a/docs/_toc.yml b/docs/_toc.yml index 3c27db04..05c2e34c 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -42,6 +42,7 @@ parts: - file: photonics/examples/refinement.py - file: photonics/examples/propagation_loss.py - file: electronics/examples/capacitor.py + - file: electronics/examples/coplanar_waveguide.py - caption: Julia Examples chapters: diff --git a/docs/electronics/examples/coplanar_waveguide.py b/docs/electronics/examples/coplanar_waveguide.py new file mode 100644 index 00000000..2c4c8600 --- /dev/null +++ b/docs/electronics/examples/coplanar_waveguide.py @@ -0,0 +1,140 @@ +# --- +# jupyter: +# jupytext: +# formats: py:percent,md:myst +# text_representation: +# extension: .py +# format_name: percent +# format_version: '1.3' +# jupytext_version: 1.15.0 +# kernelspec: +# display_name: Python 3 +# name: python3 +# --- +# %% [markdown] +# # Coplanar waveguide + +# In this example we calculate effective epsilon of the coplanar waveguides from {cite}`Jansen1978` + +# %% tags=["hide-input"] + +from collections import OrderedDict + +import matplotlib.pyplot as plt +import numpy as np +import scipy.constants +import shapely +import shapely.ops +from shapely.geometry import LineString, box +from skfem import Basis, ElementTriP0 +from skfem.io.meshio import from_meshio +from tqdm import tqdm + +from femwell.maxwell.waveguide import compute_modes +from femwell.mesh import mesh_from_OrderedDict + + +# %% +def mesh_waveguide_1(filename, wsim, hclad, hsi, wcore_1, wcore_2, hcore, gap): + core_l = box(-wcore_1 - gap / 2, -hcore / 2, -gap / 2, hcore / 2) + core_r = box(gap / 2, -hcore / 2, wcore_2 + gap / 2, hcore / 2) + gap_b = box(-gap / 2, -hcore / 2, gap / 2, hcore / 2) + clad = box(-wsim / 2, -hcore / 2, wsim / 2, -hcore / 2 + hclad) + silicon = box(-wsim / 2, -hcore / 2, wsim / 2, -hcore / 2 - hsi) + + combined = shapely.ops.unary_union([core_l, core_r, clad, silicon]) + + polygons = OrderedDict( + surface=LineString(combined.exterior), + interface=LineString( + [ + (-wcore_1 - gap, -hcore / 2), + (wcore_2 + gap, -hcore / 2), + ] + ), + core_l_interface=core_l.exterior, + core_l=core_l, + core_r_interface=core_r.exterior, + core_r=core_r, + gap_b=gap_b, + clad=clad, + silicon=silicon, + ) + + resolutions = dict( + core_r={"resolution": 0.004, "distance": 2}, + core_l={"resolution": 0.004, "distance": 2}, + gap_b={"resolution": 0.004, "distance": 2}, + silicon={"resolution": 0.1, "distance": 5}, + interface={"resolution": 0.2, "distance": 1}, + ) + + return mesh_from_OrderedDict( + polygons, resolutions, filename=filename, default_resolution_max=30 + ) + + +# %% tags=["hide-output"] +frequencies = np.linspace(1e9, 18e9, 18) +gaps = [0.02, 0.06, 0.1, 0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8, 2] +epsilon_effs = np.zeros((len(gaps), len(frequencies), 2), dtype=complex) + +for i, gap in enumerate(tqdm(gaps)): + for j, frequency in enumerate(tqdm(frequencies, leave=False)): + mesh = from_meshio( + mesh_waveguide_1( + filename="mesh.msh", + wsim=30, + hclad=100, + hsi=0.64, + wcore_1=0.6, + wcore_2=0.6, + hcore=0.005, + gap=gap, + ) + ) + mesh = mesh.scaled((1e-3,) * 2) + + basis0 = Basis(mesh, ElementTriP0(), intorder=4) + epsilon = basis0.zeros().astype(complex) + epsilon[basis0.get_dofs(elements="silicon")] = 9.9 + 0.0005 + epsilon[basis0.get_dofs(elements="clad")] = 1.0 + epsilon[basis0.get_dofs(elements="gap_b")] = 1.0 + epsilon[basis0.get_dofs(elements="core_l")] = ( + 1 - 1j * 1 / (18e-6 * 1e-3) / scipy.constants.epsilon_0 / frequency + ) + epsilon[basis0.get_dofs(elements="core_r")] = ( + 1 - 1j * 1 / (18e-6 * 1e-3) / scipy.constants.epsilon_0 / frequency + ) + # basis0.plot(np.real(epsilon), colorbar=True).show() + + modes = compute_modes( + basis0, + epsilon, + wavelength=scipy.constants.speed_of_light / frequency, + mu_r=1, + num_modes=2, + metallic_boundaries=True, + ) + print("effective epsilons", modes.n_effs**2) + modes[0].show("E", part="real", plot_vectors=True, colorbar=True) + modes[1].show("E", part="real", plot_vectors=True, colorbar=True) + + epsilon_effs[i, j] = modes.n_effs**2 + +# %% tags=["hide-input"] +plt.xlabel("Frequency / Ghz") +plt.ylabel("Effective dielectric constant") + +for i, gap in enumerate(gaps): + plt.plot(frequencies / 1e9, epsilon_effs[i, :, 0].real) + plt.annotate( + xy=(frequencies[-1] / 1e9, epsilon_effs[i, :, 0].real[-1]), text=str(gap), va="center" + ) + + plt.plot(frequencies / 1e9, epsilon_effs[i, :, 1].real) + plt.annotate( + xy=(frequencies[-1] / 1e9, epsilon_effs[i, :, 1].real[-1]), text=str(gap), va="center" + ) + +plt.show() diff --git a/docs/references.bib b/docs/references.bib index db030778..da918943 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -328,3 +328,17 @@ @article{Klenner2016 month = may, pages = {11043} } +@article{Jansen1978, + title = {High-Speed Computation of Single and Coupled Microstrip Parameters Including Dispersion, High-Order Modes, Loss and Finite Strip Thickness}, + volume = {26}, + issn = {0018-9480}, + url = {http://dx.doi.org/10.1109/TMTT.1978.1129316}, + doi = {10.1109/tmtt.1978.1129316}, + number = {2}, + journal = {IEEE Transactions on Microwave Theory and Techniques}, + publisher = {Institute of Electrical and Electronics Engineers (IEEE)}, + author = {Jansen, R.H.}, + year = {1978}, + month = feb, + pages = {75–82} +}