Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 81 additions & 52 deletions notebooks/workflow_3_cascaded_mzi.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"\n",
"Each filter stage is formed by 4 cascaded Mach-Zenhder Interferometers (MZIs) with predefined delays for the central wavelength. Symmetrical Direction Couplers (DCs) are used to mix the signals at the ends of the MZI arms. In order to facilitate fabrication, all DC gaps are kept equal, so the power transfer ratios are defined by the coupling length of the DCs.\n",
"\n",
"We will design each DC through 3D FDTD simulations to guarantee the desired power ratios, which have been calculated to provide maximally flat response. The S parameters computed through FDTD are latter used in the full circuit simulation along with models for staight and curved waveguide sections, leading to an accurate model that exhibits features similar to those found in experimental data."
"We will design each DC through 3D FDTD simulations to guarantee the desired power ratios, which have been calculated to provide maximally flat response. The S parameters computed through FDTD are later used in the full circuit simulation along with models for staight and curved waveguide sections, leading to an accurate model that exhibits features similar to those found in experimental data."
]
},
{
Expand Down Expand Up @@ -311,7 +311,7 @@
"\n",
"We calculate the group index for our waveguides through `tidy3d`'s local mode solver. Because we're interested in precise dispersion, we use a dense mesh and high precision in these calculations.\n",
"\n",
"The path length differences for the MZIs are $\\Delta L$, $2\\Delta L$, $L_\\pi - 2\\Delta L$, and $-2\\Delta L$, with $L_\\pi$ the length required for $\\pi$ phase shift (negative values indicate a delay in the opposite arm to positive values).\n"
"The path length differences for the MZIs are -$\\Delta L$, -$2\\Delta L$, $2\\Delta L + L_\\pi$, and $2\\Delta L$, with $L_\\pi$ the length required for $\\pi$ phase shift (negative values indicate a delay in the opposite arm to positive values).\n"
]
},
{
Expand Down Expand Up @@ -352,10 +352,10 @@
"length_delta = mzi_path_difference(waveguide_solver, ng, fsr)\n",
"length_pi = lda_c / (2 * ne)\n",
"mzi_deltas = (\n",
" length_delta,\n",
" 2 * length_delta,\n",
" length_pi - 2 * length_delta,\n",
" -length_delta,\n",
" -2 * length_delta,\n",
" 2 * length_delta + length_pi,\n",
" 2 * length_delta,\n",
")\n",
"print(f\"Path difference (ΔL = {length_delta}, Lπ = {length_pi}):\", mzi_deltas)"
]
Expand All @@ -380,7 +380,7 @@
"layout = gf.c.mzi_lattice(\n",
" coupler_gaps=(gap,) * len(lengths),\n",
" coupler_lengths=tuple(lengths),\n",
" delta_lengths=tuple([abs(x) for x in mzi_deltas]),\n",
" delta_lengths=mzi_deltas,\n",
" cross_section=\"strip\",\n",
")\n",
"layout.plot()"
Expand Down Expand Up @@ -613,29 +613,65 @@
"source": [
"import inspect\n",
"\n",
"def _unique_component_name(base_component: str, models: dict) -> str:\n",
" \"\"\"Return a component name like f'{base_component}_v{i}' that is not yet in models.\"\"\"\n",
" i = 0\n",
" new_component = f\"{base_component}_v{i}\"\n",
" while new_component in models:\n",
" i += 1\n",
" new_component = f\"{base_component}_v{i}\"\n",
" return new_component\n",
"\n",
"def _patch_netlist_block(netlist_block: dict, models: dict, models_to_patch: dict) -> None:\n",
" \"\"\"\n",
" Patch a single netlist block in-place.\n",
" Expects netlist_block to have an 'instances' dict.\n",
" \"\"\"\n",
" instances = netlist_block.get(\"instances\", {})\n",
" for instance_name, instance in instances.items():\n",
" component = instance.get(\"component\")\n",
" if component not in models_to_patch:\n",
" continue\n",
"\n",
" new_component = _unique_component_name(component, models)\n",
"\n",
" settings = instance.get(\"settings\", {})\n",
" settings_filtered = {\n",
" k: v\n",
" for k, v in settings.items()\n",
" if k in inspect.signature(models_to_patch[component]).parameters\n",
" }\n",
"\n",
" # Create a specialized model for this instance's settings\n",
" models[new_component] = models_to_patch[component](**settings_filtered)\n",
"\n",
" # Update the instance to reference the specialized model\n",
" instance.pop(\"settings\", None)\n",
" instance[\"component\"] = new_component\n",
"\n",
"def patch_netlist(netlist: dict, models: dict, models_to_patch: dict) -> tuple[dict, dict]:\n",
" \"\"\"\n",
" Patches either:\n",
" - a flat netlist: {'instances': {...}, 'connections': ..., 'ports': ...}\n",
" - or a recursive netlist: {'<block_name>': {'instances': {...}, ...}, ...}\n",
"\n",
" Mutates netlist + models in-place and returns them for convenience.\n",
" \"\"\"\n",
"\n",
" # Case 1: flat netlist block\n",
" if isinstance(netlist, dict) and \"instances\" in netlist:\n",
" _patch_netlist_block(netlist, models, models_to_patch)\n",
" return netlist, models\n",
"\n",
" # Case 2: recursive netlist: top-level dict of blocks\n",
" if isinstance(netlist, dict):\n",
" for netlist_name, netlist_block in netlist.items():\n",
" if not isinstance(netlist_block, dict):\n",
" continue\n",
" if \"instances\" in netlist_block:\n",
" _patch_netlist_block(netlist_block, models, models_to_patch)\n",
" return netlist, models\n",
"\n",
"def patch_netlist(netlist, models, models_to_patch):\n",
" instances = netlist[\"instances\"]\n",
" for name in instances:\n",
" model = instances[name]\n",
" if model[\"component\"] in models_to_patch:\n",
" component = model[\"component\"]\n",
" i = 0\n",
" new_component = f\"{component}_v{i}\"\n",
" while new_component in models:\n",
" i += 1\n",
" new_component = f\"{component}_v{i}\"\n",
" settings = model[\"settings\"]\n",
" settings_fitered = {\n",
" k: v\n",
" for k, v in settings.items()\n",
" if k in inspect.signature(models_to_patch[component]).parameters\n",
" }\n",
" models[new_component] = models_to_patch[model[\"component\"]](\n",
" **settings_fitered\n",
" )\n",
" del model[\"settings\"]\n",
" model[\"component\"] = new_component\n",
" return netlist, models\n",
"\n",
"\n",
Expand Down Expand Up @@ -720,29 +756,22 @@
"metadata": {},
"outputs": [],
"source": [
"# fig, ax = plt.subplots(1, 1, figsize=(12, 4))\n",
"# netlist, models = patch_netlist(\n",
"# netlist=layout.get_netlist(recursive=True),\n",
"# models={\"straight\": straight_model, \"bend_euler\": bend_model(cross_section=cross_section)},\n",
"# models_to_patch={\"coupler\": coupler_model},\n",
"# )\n",
"# circuit, _ = sax.circuit(netlist, models)\n",
"# lda = np.linspace(1.5, 1.6, 1001)\n",
"# s = circuit(wl=lda)\n",
"# ax.plot(lda, 20 * jnp.log10(jnp.abs(s[(\"o1\", \"o3\")])), label=\"Cross\")\n",
"# ax.plot(lda, 20 * jnp.log10(jnp.abs(s[(\"o1\", \"o4\")])), label=\"Thru\")\n",
"# ax.set_ylim(-30, 0)\n",
"# ax.set_xlabel(\"λ (µm)\")\n",
"# ax.legend()"
"fig, ax = plt.subplots(1, 1, figsize=(12, 4))\n",
"netlist, models = patch_netlist(\n",
" netlist=layout.get_netlist(recursive=True),\n",
" models={\"straight\": straight_model, \"bend_euler\": bend_model(cross_section=cross_section)},\n",
" models_to_patch={\"coupler\": coupler_model},\n",
")\n",
"circuit, _ = sax.circuit(netlist, models)\n",
"lda = np.linspace(1.5, 1.6, 1001)\n",
"s = circuit(wl=lda)\n",
"ax.plot(lda, 20 * jnp.log10(jnp.abs(s[(\"o1\", \"o3\")])), label=\"Cross\")\n",
"ax.plot(lda, 20 * jnp.log10(jnp.abs(s[(\"o1\", \"o4\")])), label=\"Thru\")\n",
"ax.axvline(lda_c, linestyle=\"dotted\")\n",
"ax.set_ylim(-30, 0)\n",
"ax.set_xlabel(\"λ (µm)\")\n",
"ax.legend()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "36",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand All @@ -751,7 +780,7 @@
"custom_cell_magics": "kql"
},
"kernelspec": {
"display_name": "base",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -765,7 +794,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.9"
"version": "3.12.8"
}
},
"nbformat": 4,
Expand Down
Loading