import%20marimo%0A%0A__generated_with%20%3D%20%220.18.4%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20from%20_notebook_template%20import%20inject_css%0A%0A%20%20%20%20inject_css(mo)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20from%20_notebook_template%20import%20make_doc_helpers%0A%0A%20%20%20%20doc_badges%2C%20doc_callout_html%2C%20doc_callout_list%20%3D%20make_doc_helpers(mo)%0A%20%20%20%20return%20doc_badges%2C%20doc_callout_html%2C%20doc_callout_list%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20from%20_notebook_template%20import%20make_section_tabs%0A%0A%20%20%20%20section_tabs%2C%20view_state%2C%20set_view%20%3D%20make_section_tabs(mo)%0A%20%20%20%20section_tabs%0A%20%20%20%20return%20set_view%2C%20view_state%0A%0A%0A%40app.cell%0Adef%20_(view_state)%3A%0A%20%20%20%20view%20%3D%20view_state()%0A%20%20%20%20show_overview%20%3D%20view%20in%20%5B%22All%22%2C%20%22Overview%22%5D%0A%20%20%20%20show_theory%20%3D%20view%20in%20%5B%22All%22%2C%20%22Theory%22%5D%0A%20%20%20%20show_interactive%20%3D%20view%20in%20%5B%22All%22%2C%20%22Interactive%22%5D%0A%20%20%20%20show_layout_section%20%3D%20view%20in%20%5B%22All%22%2C%20%22Layout%22%5D%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20show_interactive%2C%0A%20%20%20%20%20%20%20%20show_layout_section%2C%0A%20%20%20%20%20%20%20%20show_overview%2C%0A%20%20%20%20%20%20%20%20show_theory%2C%0A%20%20%20%20%20%20%20%20view%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20doc_badges%2C%0A%20%20%20%20show_interactive%2C%0A%20%20%20%20show_layout_section%2C%0A%20%20%20%20show_overview%2C%0A%20%20%20%20show_theory%2C%0A%20%20%20%20view%2C%0A)%3A%0A%20%20%20%20doc_badges(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22Notebook%20view%3A%20%3Cstrong%3E%7Bview%7D%3C%2Fstrong%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Flags%3A%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22overview%3D%7Bshow_overview%7D%2C%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22theory%3D%7Bshow_theory%7D%2C%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22interactive%3D%7Bshow_interactive%7D%2C%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22layout%3D%7Bshow_layout_section%7D%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20from%20_style%20import%20header%0A%0A%20%20%20%20header(%0A%20%20%20%20%20%20%20%20mo%2C%0A%20%20%20%20%20%20%20%20title%3D%22MZI%20modelling%22%2C%0A%20%20%20%20%20%20%20%20subtitle%3D(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Build%20intuition%20for%20a%20Mach%E2%80%93Zehnder%20interferometer%20(MZI)%2C%20derive%20its%20transfer%20function%2C%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22and%20connect%20one%20key%20layout%20parameter%20(%CE%94L)%20to%20a%20measurable%20signature%20(FSR).%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22We%E2%80%99ll%20also%20preview%20how%20this%20maps%20to%20layout%2C%20but%20layout%20work%20happens%20in%20the%20next%20lesson.%22%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20badges%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Week%202%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Lab%20companion%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Interference%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Transfer%20functions%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%221550%20nm%20(default)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Simphony%20(optional)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Layout%20bridge%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20toc%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Overview%22%2C%20%22overview%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Glossary%22%2C%20%22glossary%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Theory%22%2C%20%22theory%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Interactive%22%2C%20%22interactive%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Layout%22%2C%20%22layout%22)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20build%3D%222025-12-14%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20from%20_notebook_template%20import%20make_health_refresh_button%0A%0A%20%20%20%20health_refresh%20%3D%20make_health_refresh_button(mo)%0A%20%20%20%20return%20(health_refresh%2C)%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_html%2C%20health_refresh%2C%20mo)%3A%0A%20%20%20%20from%20_notebook_template%20import%20safe_editing_panel%0A%0A%20%20%20%20safe_editing_panel(%0A%20%20%20%20%20%20%20%20mo%2C%0A%20%20%20%20%20%20%20%20doc_callout_html%2C%0A%20%20%20%20%20%20%20%20health_refresh%2C%0A%20%20%20%20%20%20%20%20restore_command%3D%22git%20-C%20Photonics-Bootcamp%20restore%20marimo_course%2Flessons%2Fw02_mzi_modelling.py%22%2C%0A%20%20%20%20%20%20%20%20external_check_command%3D%22python3%20marimo_course%2Flessons%2Fcheck_notebook_health.py%20marimo_course%2Flessons%2Fw02_mzi_modelling.py%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_list%2C%20mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Roadmap%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22How%20this%20notebook%20fits%20together%22%2C%0A%20%20%20%20%20%20%20%20ordered%3DTrue%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3EAnalytic%20model%3A%3C%2Fstrong%3E%20derive%20a%20simple%20MZI%20transfer%20function%20from%20interference.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3ECircuit%20model%20(Simphony%20%2B%20SAX)%3A%3C%2Fstrong%3E%20build%20the%20same%20MZI%20from%20component%20(compact)%20models%20and%20compare.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3ELayout%20(gdsfactory)%3A%3C%2Fstrong%3E%20transition%20from%20%E2%80%9Cresponse%20vs%20wavelength%E2%80%9D%20to%20%E2%80%9Cgeometry%20you%20can%20export%20as%20GDS%E2%80%9D.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22warning%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Quickstart%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Running%20and%20troubleshooting%22%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22If%20you%20don%E2%80%99t%20see%20plots%2C%20make%20sure%20you%E2%80%99re%20in%20%3Cstrong%3EApp%20view%3C%2Fstrong%3E%20(not%20just%20the%20code%20editor)%2C%20then%20restart%2Fre-run%20the%20app.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22If%20%3Cstrong%3ESimphony%3C%2Fstrong%3E%20isn%E2%80%99t%20available%2C%20the%20analytic%20model%20still%20works%3B%20use%20%3Cem%3EView%20%E2%86%92%20Analytic%20only%3C%2Fem%3E.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Units%3A%20the%20plot%20shows%20wavelength%20in%20%3Cstrong%3Enm%3C%2Fstrong%3E%3B%20internal%20calculations%20use%20%3Cstrong%3E%C2%B5m%3C%2Fstrong%3E.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Expected%20outputs%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22What%20%E2%80%9Cworking%E2%80%9D%20looks%20like%20(in%20lab)%22%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22An%20interactive%20transmission%20plot%20that%20changes%20when%20you%20move%20%3Cstrong%3E%CE%94L%3C%2Fstrong%3E.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22FSR%20decreases%20when%20%CE%94L%20increases%20(approximately%20inverse%20proportional).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Optional%20overlay%20with%20a%20Simphony%2FSAX%20curve%20if%20the%20compact-model%20libraries%20are%20available.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22A%20gdsfactory%20MZI%20layout%20preview%20(SVG)%20and%20a%20button%20to%20export%20a%20%3Cstrong%3EGDS%3C%2Fstrong%3E.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20set_view%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20go_interactive%20%3D%20mo.ui.button(%0A%20%20%20%20%20%20%20%20value%3D0%2C%0A%20%20%20%20%20%20%20%20kind%3D%22success%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Go%20to%20Interactive%20section%22%2C%0A%20%20%20%20%20%20%20%20on_click%3Dlambda%20v%3A%20(set_view(%22Interactive%22)%2C%20(v%20or%200)%20%2B%201)%5B-1%5D%2C%0A%20%20%20%20)%0A%20%20%20%20go_layout%20%3D%20mo.ui.button(%0A%20%20%20%20%20%20%20%20value%3D0%2C%0A%20%20%20%20%20%20%20%20kind%3D%22neutral%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Go%20to%20Layout%20section%22%2C%0A%20%20%20%20%20%20%20%20on_click%3Dlambda%20v%3A%20(set_view(%22Layout%22)%2C%20(v%20or%200)%20%2B%201)%5B-1%5D%2C%0A%20%20%20%20)%0A%20%20%20%20mo.hstack(%5Bgo_interactive%2C%20go_layout%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_badges%2C%20doc_callout_html%2C%20health_refresh)%3A%0A%20%20%20%20from%20_notebook_template%20import%20notebook_self_check_view%0A%0A%20%20%20%20_self_check_view%20%3D%20notebook_self_check_view(%0A%20%20%20%20%20%20%20%20doc_badges%3Ddoc_badges%2C%0A%20%20%20%20%20%20%20%20doc_callout_html%3Ddoc_callout_html%2C%0A%20%20%20%20%20%20%20%20notebook_path%3D__file__%2C%0A%20%20%20%20%20%20%20%20refresh_token%3Dhealth_refresh.value%2C%0A%20%20%20%20)%0A%20%20%20%20_self_check_view%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_html%2C%20mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%3Ca%20id%3D%22overview%22%3E%3C%2Fa%3E%0A%20%20%20%20%23%23%20What%20is%20an%20MZI%20(and%20why%20do%20we%20start%20here)%3F%0A%0A%20%20%20%20A%20**Mach%E2%80%93Zehnder%20interferometer%20(MZI)**%20is%20a%20small%20optical%20circuit%20that%20turns%20a%20**phase%20difference**%0A%20%20%20%20between%20two%20paths%20into%20a%20**measurable%20power%20difference**.%0A%0A%20%20%20%20At%20a%20high%20level%3A%0A%20%20%20%201.%20A%20**splitter**%20divides%20the%20input%20light%20into%20two%20waveguides%20(two%20*arms*).%0A%20%20%20%202.%20The%20arms%20accumulate%20a%20**relative%20phase%20difference**%20(often%20because%20one%20arm%20is%20longer%20by%20%CE%94L).%0A%20%20%20%203.%20A%20**combiner**%20recombines%20the%20two%20fields%2C%20and%20they%20**interfere**%20at%20the%20outputs.%0A%0A%20%20%20%20**Why%20MZIs%20are%20useful**%0A%20%20%20%20-%20**Sensing%3A**%20small%20phase%20shifts%20(temperature%2C%20strain%2C%20cladding%20index)%20become%20intensity%20changes.%0A%20%20%20%20-%20**Modulation%2Fswitching%3A**%20if%20you%20can%20tune%20phase%20(thermal%2Felectrical)%2C%20an%20MZI%20becomes%20an%20optical%20modulator%2Fswitch.%0A%20%20%20%20-%20**A%20reusable%20building%20block%3A**%20many%20larger%20photonic%20circuits%20are%20built%20from%20couplers%20%2B%20phase%20shifters%20%2B%20MZIs.%0A%0A%20%20%20%20**Why%20we%20choose%20MZIs%20as%20the%20first%20layout**%0A%20%20%20%20-%20They%20use%20standard%20PDK%20primitives%20you%E2%80%99ll%20need%20all%20semester%20(splitters%2Fcombiners%2C%20waveguides%2C%20routing).%0A%20%20%20%20-%20There%E2%80%99s%20a%20clean%2C%20testable%20signature%3A%20the%20arm%20length%20difference%20**%CE%94L%20sets%20the%20fringe%20spacing%20(FSR)**.%0A%20%20%20%20-%20They%20expose%20key%20layout%20skills%20early%3A%20ports%2C%20symmetry%2C%20routing%20discipline%2C%20and%20tolerance%20to%20fabrication%20errors.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Learning%20goals%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22What%20you%20should%20be%20able%20to%20do%20after%20this%20notebook%22%2C%0A%20%20%20%20%20%20%20%20html%3D%22%22%22%0A%20%20%20%20%20%20%20%20%3Cul%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3EExplain%20how%20interference%20converts%20a%20phase%20difference%20into%20a%20power%20difference.%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3ECompute%20the%20ideal%20transfer%20function%20for%20a%2050%2F50%20MZI.%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3ERelate%20a%20layout%20parameter%20(%CE%94L)%20to%20a%20measurable%20spectral%20feature%20(FSR).%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%3C%2Ful%3E%0A%20%20%20%20%20%20%20%20%3Cp%3E%0A%20%20%20%20%20%20%20%20%20%20This%20is%20a%20%3Cstrong%3Elab%20companion%3C%2Fstrong%3E%20notebook.%20For%20graded%20work%20and%20%E2%80%9Cturn-in%E2%80%9D%20items%2C%20use%0A%20%20%20%20%20%20%20%20%20%20%3Ccode%3Emarimo_course%2Fassignments%2Fhw02_mzi_modelling.py%3C%2Fcode%3E.%0A%20%20%20%20%20%20%20%20%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%22%22%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%3Ca%20id%3D%22glossary%22%3E%3C%2Fa%3E%0A%20%20%20%20%23%23%20Key%20terms%20(quick%20glossary)%0A%0A%20%20%20%20-%20**%CE%94L**%3A%20physical%20path-length%20difference%20between%20the%20two%20arms%20(%C2%B5m).%0A%20%20%20%20-%20**%CE%BB**%3A%20wavelength%20(%C2%B5m%20here).%0A%20%20%20%20-%20**n_eff**%3A%20(phase)%20effective%20index%20used%20in%20the%20toy%20phase%20term.%0A%20%20%20%20-%20**n_g**%3A%20group%20index%20(sets%20fringe%20spacing%20%2F%20FSR).%0A%20%20%20%20-%20**FSR**%3A%20free%20spectral%20range%2C%20the%20wavelength%20spacing%20between%20fringes.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20What%20is%20gdsfactory%20(and%20why%20are%20we%20using%20it)%3F%0A%0A%20%20%20%20**gdsfactory**%20is%20a%20Python%20library%20for%20building%20**parametric%20photonic%20layouts**.%0A%20%20%20%20Instead%20of%20drawing%20every%20waveguide%20and%20bend%20by%20hand%2C%20you%20describe%20a%20circuit%20using%20reusable%20components%0A%20%20%20%20and%20parameters%2C%20and%20gdsfactory%20generates%20a%20**GDS**%20layout%20for%20you.%0A%0A%20%20%20%20A%20useful%20mental%20model%3A%0A%20%20%20%20-%20A%20**Component**%20is%20a%20layout%20cell%20(like%20a%20reusable%20block).%0A%20%20%20%20-%20Components%20have%20named%20**ports**%20(optical%2Felectrical%20connection%20points).%0A%20%20%20%20-%20You%20can%20**compose**%20components%2C%20route%20between%20ports%2C%20and%20then%20**export%20GDS**.%0A%0A%20%20%20%20**How%20we%E2%80%99ll%20use%20gdsfactory%20in%20Week%202**%0A%20%20%20%20-%20Build%20a%20simple%20MZI%20layout%20from%20standard%20building%20blocks%20(splitter%2Fcombiner%20%2B%20waveguides).%0A%20%20%20%20-%20Tie%20a%20*layout%20parameter*%20(%CE%94L)%20to%20a%20*measurable%20prediction*%20(FSR)%20from%20the%20analytic%20model.%0A%20%20%20%20-%20Export%20a%20GDS%20file%20you%20can%20inspect%20in%20KLayout%20and%20eventually%20adapt%20to%20PDK-accurate%20cells%20for%20openEBL.%0A%0A%20%20%20%20In%20this%20notebook%2C%20gdsfactory%20is%20used%20for%20a%20small%20%E2%80%9Cconcrete%20layout%E2%80%9D%20example%20near%20the%20end.%0A%20%20%20%20The%20more%20detailed%20layout%20workflow%20lives%20in%20%60marimo_course%2Flessons%2Fw02_pdk_mzi_layout.py%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_html%2C%20mo%2C%20show_theory)%3A%0A%20%20%20%20mo.stop(not%20show_theory)%0A%20%20%20%20from%20textwrap%20import%20dedent%20as%20_dedent%0A%0A%20%20%20%20theory_md%20%3D%20mo.md(_dedent(r%22%22%22%0A%20%20%20%20%3Ca%20id%3D%22theory%22%3E%3C%2Fa%3E%0A%20%20%20%20%23%23%20Analytic%20MZI%20model%0A%0A%20%20%20%20In%20this%20notebook%20we'll%20consider%20a%20symmetric%2050%2F50%20MZI%20with%3A%0A%0A%20%20%20%20-%20Two%20identical%2050%2F50%20couplers.%0A%20%20%20%20-%20One%20arm%20longer%20than%20the%20other%20by%20a%20physical%20length%20difference%20%CE%94L%20(in%20%C2%B5m).%0A%20%20%20%20-%20A%20constant%20phase%20index%20parameter%20%60n_eff%60%20(toy%20model%3B%20we%E2%80%99ll%20refine%20this%20later).%0A%0A%20%20%20%20A%20simple%20schematic%20is%3A%0A%0A%20%20%20%20%60%60%60text%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20upper%20arm%20(longer%20path%20by%20%CE%94L)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%8C%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%90%0A%20%20%20%20Input%20%E2%94%80%E2%94%80%20%E2%96%B6%E2%94%82%2050%2F50%20%20%E2%94%82%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%90%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%94%E2%94%80%E2%94%80%E2%94%80%E2%94%AC%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%98%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%20short%20arm%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%0A%20%20%20%20%20Output%201%20%E2%94%8C%E2%94%80%E2%94%80%E2%94%80%E2%94%B4%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%90%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%0A%20%20%20%20%20%20%20%20%E2%97%80%20%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%82%20%2050%2F50%20%E2%94%82%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%98%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%94%E2%94%80%E2%94%80%E2%94%80%E2%94%AC%E2%94%80%E2%94%80%E2%94%80%E2%94%80%E2%94%98%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%94%82%20Output%202%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E2%96%BC%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20The%20phase%20difference%20between%20the%20two%20arms%20is%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5CDelta%20%5Cphi(%5Clambda)%20%3D%20%5Cfrac%7B2%20%5Cpi%20n_%7B%5Cmathrm%7Beff%7D%7D%20%5C%2C%20%5CDelta%20L%7D%7B%5Clambda%7D%2C%0A%20%20%20%20%24%24%0A%0A%20%20%20%20where%20%CE%BB%20and%20%CE%94L%20are%20expressed%20in%20the%20same%20units%20(here%2C%20%C2%B5m).%0A%0A%20%20%20%20%23%23%23%20Where%20the%20phase%20difference%20comes%20from%0A%0A%20%20%20%20A%20guided%20mode%20in%20a%20waveguide%20accumulates%20phase%20according%20to%20the%20propagation%20constant%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbeta(%5Clambda)%20%3D%20%5Cfrac%7B2%5Cpi%20n_%7B%5Cmathrm%7Beff%7D%7D(%5Clambda)%7D%7B%5Clambda%7D.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Over%20a%20physical%20path%20length%20%24L%24%2C%20the%20phase%20is%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cphi(%5Clambda)%20%3D%20%5Cbeta(%5Clambda)%5C%2CL.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20For%20two%20arms%20with%20lengths%20%24L_1%24%20and%20%24L_2%24%2C%20the%20*relative*%20phase%20is%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5CDelta%20%5Cphi(%5Clambda)%20%3D%20%5Cphi_2%20-%20%5Cphi_1%20%3D%20%5Cbeta(%5Clambda)%5C%2C(L_2%20-%20L_1)%20%3D%20%5Cbeta(%5Clambda)%5C%2C%5CDelta%20L.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20%23%23%23%20From%20fields%20to%20power%20transmission%20(ideal%2050%2F50%20model)%0A%0A%20%20%20%20Treat%20each%20coupler%20as%20an%20ideal%2050%2F50%20%E2%80%9Cbeam%20splitter%E2%80%9D%20acting%20on%20the%20complex%20field%20amplitudes%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Bbmatrix%7D%0A%20%20%20%20E_1%20%5C%5C%5C%5C%0A%20%20%20%20E_2%0A%20%20%20%20%5Cend%7Bbmatrix%7D%0A%20%20%20%20%3D%0A%20%20%20%20%5Cfrac%7B1%7D%7B%5Csqrt%7B2%7D%7D%0A%20%20%20%20%5Cbegin%7Bbmatrix%7D%0A%20%20%20%201%20%26%201%20%5C%5C%5C%5C%0A%20%20%20%201%20%26%20-1%0A%20%20%20%20%5Cend%7Bbmatrix%7D%0A%20%20%20%20%5Cbegin%7Bbmatrix%7D%0A%20%20%20%20E_%7B%5Cmathrm%7Bin%7D%7D%20%5C%5C%5C%5C%0A%20%20%20%200%0A%20%20%20%20%5Cend%7Bbmatrix%7D%0A%20%20%20%20%5CRightarrow%0A%20%20%20%20E_1%20%3D%20%5Cfrac%7BE_%7B%5Cmathrm%7Bin%7D%7D%7D%7B%5Csqrt%7B2%7D%7D%2C%5C%3B%0A%20%20%20%20E_2%20%3D%20%5Cfrac%7BE_%7B%5Cmathrm%7Bin%7D%7D%7D%7B%5Csqrt%7B2%7D%7D.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20After%20propagation%20through%20the%20two%20arms%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20E_1'%20%3D%20%5Cfrac%7BE_%7B%5Cmathrm%7Bin%7D%7D%7D%7B%5Csqrt%7B2%7D%7D%20e%5E%7Bi%5Cphi_1%7D%2C%5Cquad%0A%20%20%20%20E_2'%20%3D%20%5Cfrac%7BE_%7B%5Cmathrm%7Bin%7D%7D%7D%7B%5Csqrt%7B2%7D%7D%20e%5E%7Bi%5Cphi_2%7D.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20second%2050%2F50%20coupler%20recombines%20them%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbegin%7Bbmatrix%7D%0A%20%20%20%20E_%7B%5Cmathrm%7Bthrough%7D%7D%20%5C%5C%5C%5C%0A%20%20%20%20E_%7B%5Cmathrm%7Bcross%7D%7D%0A%20%20%20%20%5Cend%7Bbmatrix%7D%0A%20%20%20%20%3D%0A%20%20%20%20%5Cfrac%7B1%7D%7B%5Csqrt%7B2%7D%7D%0A%20%20%20%20%5Cbegin%7Bbmatrix%7D%0A%20%20%20%201%20%26%201%20%5C%5C%5C%5C%0A%20%20%20%201%20%26%20-1%0A%20%20%20%20%5Cend%7Bbmatrix%7D%0A%20%20%20%20%5Cbegin%7Bbmatrix%7D%0A%20%20%20%20E_1'%20%5C%5C%5C%5C%0A%20%20%20%20E_2'%0A%20%20%20%20%5Cend%7Bbmatrix%7D.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20So%20the%20through-port%20field%20is%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20E_%7B%5Cmathrm%7Bthrough%7D%7D%0A%20%20%20%20%3D%20%5Cfrac%7BE_%7B%5Cmathrm%7Bin%7D%7D%7D%7B2%7D%5Cleft(e%5E%7Bi%5Cphi_1%7D%20%2B%20e%5E%7Bi%5Cphi_2%7D%5Cright)%0A%20%20%20%20%3D%20E_%7B%5Cmathrm%7Bin%7D%7D%5C%2Ce%5E%7Bi(%5Cphi_1%2B%5Cphi_2)%2F2%7D%5Ccos%5Cleft(%5Cfrac%7B%5CDelta%5Cphi%7D%7B2%7D%5Cright).%0A%20%20%20%20%24%24%0A%0A%20%20%20%20The%20(normalized)%20through-port%20power%20transmission%20is%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20T_%7B%5Cmathrm%7Bideal%7D%7D(%5Clambda)%0A%20%20%20%20%3D%20%5Cfrac%7B%7CE_%7B%5Cmathrm%7Bthrough%7D%7D%7C%5E2%7D%7B%7CE_%7B%5Cmathrm%7Bin%7D%7D%7C%5E2%7D%0A%20%20%20%20%3D%20%5Ccos%5E2%5Cleft(%5Cfrac%7B%5CDelta%5Cphi(%5Clambda)%7D%7B2%7D%5Cright)%0A%20%20%20%20%3D%20%5Cfrac%7B1%7D%7B2%7D%5Cleft(1%20%2B%20%5Ccos%20%5CDelta%20%5Cphi(%5Clambda)%5Cright).%0A%20%20%20%20%24%24%0A%0A%20%20%20%20(The%20other%20output%20is%20complementary%3A%20%24T_%7B%5Cmathrm%7Bcross%7D%7D%20%3D%20%5Csin%5E2(%5CDelta%5Cphi%2F2)%20%3D%20%5Cfrac%7B1%7D%7B2%7D(1-%5Ccos%5CDelta%5Cphi)%24.%20Different%20coupler%20sign%20conventions%20simply%20swap%20which%20port%20you%20call%20%E2%80%9Cthrough%E2%80%9D%20vs%20%E2%80%9Ccross%E2%80%9D.)%0A%0A%20%20%20%20%23%23%23%20Linking%20%CE%94L%20to%20fringe%20spacing%20(FSR)%0A%0A%20%20%20%20Around%20a%20center%20wavelength%20%CE%BB%E2%82%80%2C%20a%20useful%20rule%20of%20thumb%20is%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathrm%7BFSR%7D%20%5Capprox%20%5Cfrac%7B%5Clambda_0%5E2%7D%7Bn_g%20%5C%2C%20%5CDelta%20L%7D%2C%0A%20%20%20%20%24%24%0A%0A%20%20%20%20where%20**n_g**%20is%20the%20group%20index.%20(This%20is%20why%20**n_eff**%20shows%20up%20in%20phase%2C%20but%20**n_g**%20shows%20up%20in%20FSR.)%0A%0A%20%20%20%20%23%23%23%23%20Derivation%3A%20where%20the%20FSR%20rule-of-thumb%20comes%20from%0A%0A%20%20%20%20Key%20idea%3A%20**adjacent%20fringes%20occur%20when%20the%20relative%20phase%20changes%20by**%20%242%5Cpi%24.%0A%0A%20%20%20%20Write%20the%20wavelength-dependent%20propagation%20constant%20as%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cbeta(%5Clambda)%3D%5Cfrac%7B2%5Cpi%7D%7B%5Clambda%7Dn_%5Cmathrm%7Beff%7D(%5Clambda)%2C%0A%20%20%20%20%24%24%0A%0A%20%20%20%20so%20the%20arm%20phase%20difference%20is%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5CDelta%5Cphi(%5Clambda)%3D%5Cbeta(%5Clambda)%5C%2C%5CDelta%20L.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20A%20%E2%80%9Cfringe-to-fringe%E2%80%9D%20step%20in%20wavelength%20(the%20FSR)%20is%20the%20smallest%20%24%5CDelta%5Clambda%24%20such%20that%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5CDelta%5Cphi(%5Clambda%2B%5CDelta%5Clambda)-%5CDelta%5Cphi(%5Clambda)%3D2%5Cpi.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20For%20small%20%24%5CDelta%5Clambda%24%20we%20linearize%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cfrac%7Bd%5CDelta%5Cphi%7D%7Bd%5Clambda%7D%5C%2C%5CDelta%5Clambda%20%5Capprox%202%5Cpi%0A%20%20%20%20%5Cquad%5CRightarrow%5Cquad%0A%20%20%20%20%5CDelta%5Clambda%20%5Capprox%20%5Cfrac%7B2%5Cpi%7D%7B%5CDelta%20L%5C%2C%5Cleft%7Cd%5Cbeta%2Fd%5Clambda%5Cright%7C%7D.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Now%20differentiate%20%24%5Cbeta(%5Clambda)%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cfrac%7Bd%5Cbeta%7D%7Bd%5Clambda%7D%0A%20%20%20%20%3D%5Cfrac%7Bd%7D%7Bd%5Clambda%7D%5Cleft(%5Cfrac%7B2%5Cpi%7D%7B%5Clambda%7Dn_%5Cmathrm%7Beff%7D(%5Clambda)%5Cright)%0A%20%20%20%20%3D%5Cfrac%7B2%5Cpi%7D%7B%5Clambda%5E2%7D%5Cleft(%5Clambda%5Cfrac%7Bdn_%5Cmathrm%7Beff%7D%7D%7Bd%5Clambda%7D-n_%5Cmathrm%7Beff%7D%5Cright).%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Define%20the%20**group%20index**%0A%0A%20%20%20%20%24%24%0A%20%20%20%20n_g%20%5Cequiv%20n_%5Cmathrm%7Beff%7D-%5Clambda%5Cfrac%7Bdn_%5Cmathrm%7Beff%7D%7D%7Bd%5Clambda%7D%2C%0A%20%20%20%20%24%24%0A%0A%20%20%20%20which%20makes%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cleft%7C%5Cfrac%7Bd%5Cbeta%7D%7Bd%5Clambda%7D%5Cright%7C%3D%5Cfrac%7B2%5Cpi%7D%7B%5Clambda%5E2%7Dn_g.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Substituting%20gives%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Cmathrm%7BFSR%7D%3D%5CDelta%5Clambda%20%5Capprox%20%5Cfrac%7B%5Clambda%5E2%7D%7Bn_g%5C%2C%5CDelta%20L%7D.%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Evaluated%20at%20%24%5Clambda%3D%5Clambda_0%24%2C%20this%20is%20the%20rule-of-thumb%20used%20in%20the%20notebook.%0A%0A%20%20%20%20In%20frequency%20units%20the%20same%20idea%20gives%20%24%5CDelta%20f%20%5Capprox%20c%2F(n_g%5C%2C%5CDelta%20L)%24%2C%20which%20is%20why%20this%20is%20often%20quoted%20as%20an%20%E2%80%9Cinverse%20length%E2%80%9D%20relationship.%0A%0A%20%20%20%20Later%20lessons%20will%20introduce%20group%20index%20and%20propagation%20loss%20in%20a%20more%20realistic%20way.%0A%20%20%20%20%22%22%22))%0A%20%20%20%20theory_note%20%3D%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%22warning%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Note%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22%3Ccode%3En_eff%3C%2Fcode%3E%20vs%20%3Ccode%3En_g%3C%2Fcode%3E%22%2C%0A%20%20%20%20%20%20%20%20html%3D%22%22%22%0A%20%20%20%20%20%20%20%20%3Cp%3E%0A%20%20%20%20%20%20%20%20%20%20The%20phase%20term%20uses%20%3Cstrong%3Eeffective%20index%3C%2Fstrong%3E%20(%3Ccode%3En_eff%3C%2Fcode%3E)%2C%20but%20the%20fringe%20spacing%20(FSR)%20depends%20on%0A%20%20%20%20%20%20%20%20%20%20%3Cstrong%3Egroup%20index%3C%2Fstrong%3E%20(%3Ccode%3En_g%3C%2Fcode%3E).%20In%20a%20dispersive%20waveguide%2C%20these%20are%20not%20the%20same.%0A%20%20%20%20%20%20%20%20%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%22%22%22%2C%0A%20%20%20%20)%0A%20%20%20%20mo.vstack(%5Btheory_md%2C%20theory_note%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_html%2C%20mo%2C%20show_interactive%2C%20show_theory)%3A%0A%20%20%20%20mo.stop(not%20(show_theory%20or%20show_interactive))%0A%20%20%20%20interactive_anchor%20%3D%20mo.md('%3Ca%20id%3D%22interactive%22%3E%3C%2Fa%3E')%20if%20show_interactive%20else%20mo.md(%22%22)%0A%20%20%20%20verify_callout%20%3D%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%22exercise%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Verify%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Use%20the%20plot%20to%20confirm%20the%20derivation%22%2C%0A%20%20%20%20%20%20%20%20html%3D%22%22%22%0A%20%20%20%20%20%20%20%20%3Col%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3ESwitch%20to%20the%20%3Cstrong%3EInteractive%3C%2Fstrong%3E%20section%20using%20the%20%3Cem%3ENotebook%20sections%3C%2Fem%3E%20tabs.%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3ESet%20%3Cstrong%3E%CE%94L%20%3D%2010%20%C2%B5m%3C%2Fstrong%3E%20and%20note%20the%20displayed%20%3Cstrong%3EFSR%20estimate%3C%2Fstrong%3E.%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3EDouble%20%CE%94L%20to%20%3Cstrong%3E20%20%C2%B5m%3C%2Fstrong%3E.%20Prediction%3A%20the%20FSR%20should%20be%20roughly%20%3Cstrong%3Ehalf%3C%2Fstrong%3E.%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3EUse%20the%20%3Cstrong%3EFSR%20measurement%20tool%3C%2Fstrong%3E%20(enter%20two%20adjacent%20maxima%20wavelengths)%20to%20measure%20the%20FSR%20and%20compare.%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3EChange%20%3Cstrong%3Ebase%20arm%20length%3C%2Fstrong%3E%20(both%20arms%20equally).%20In%20the%20ideal%20model%2C%20the%20FSR%20should%20not%20change%20%E2%80%94%20explain%20why%20in%20one%20sentence.%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%3C%2Fol%3E%0A%20%20%20%20%20%20%20%20%3Cp%3E%3Csmall%3E%0A%20%20%20%20%20%20%20%20%20%20Tip%3A%20if%20you%20don%E2%80%99t%20see%20at%20least%20~2%20fringes%2C%20increase%20the%20spectrum%20span%20or%20increase%20%CE%94L.%0A%20%20%20%20%20%20%20%20%3C%2Fsmall%3E%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%22%22%22%2C%0A%20%20%20%20)%0A%20%20%20%20mo.vstack(%5Binteractive_anchor%2C%20verify_callout%5D)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_html%2C%20mo%2C%20show_theory)%3A%0A%20%20%20%20mo.stop(not%20show_theory)%0A%20%20%20%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Concept%20check%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Three%20quick%20checks%20before%20moving%20on%22%2C%0A%20%20%20%20%20%20%20%20html%3D%22%22%22%0A%20%20%20%20%20%20%20%20%3Col%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20In%20the%20ideal%20analytic%20model%20here%2C%20which%20knob%20mostly%20changes%20the%20%3Cem%3Efringe%20spacing%3C%2Fem%3E%20(FSR)%3A%20%3Cstrong%3E%CE%94L%3C%2Fstrong%3E%20or%20%3Cstrong%3En%3Csub%3Eeff%3C%2Fsub%3E%3C%2Fstrong%3E%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cdetails%3E%3Csummary%3E%3Cem%3EAnswer%3C%2Fem%3E%3C%2Fsummary%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cp%3E%3Cstrong%3E%CE%94L%3C%2Fstrong%3E%20(and%20%3Cstrong%3En%3Csub%3Eg%3C%2Fsub%3E%3C%2Fstrong%3E)%20set%20the%20spacing%3B%20%3Cstrong%3En%3Csub%3Eeff%3C%2Fsub%3E%3C%2Fstrong%3E%20mostly%20shifts%20the%20phase%20%2F%20where%20the%20fringes%20land.%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdetails%3E%0A%20%20%20%20%20%20%20%20%20%20%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20Why%20does%20the%20FSR%20formula%20use%20%3Cstrong%3En%3Csub%3Eg%3C%2Fsub%3E%3C%2Fstrong%3E%20instead%20of%20%3Cstrong%3En%3Csub%3Eeff%3C%2Fsub%3E%3C%2Fstrong%3E%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cdetails%3E%3Csummary%3E%3Cem%3EAnswer%3C%2Fem%3E%3C%2Fsummary%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cp%3EFSR%20comes%20from%20how%20quickly%20phase%20changes%20with%20wavelength%2C%20which%20depends%20on%20dispersion%20(a%20derivative)%3B%20that%20derivative%20is%20captured%20by%20the%20%3Cstrong%3Egroup%20index%3C%2Fstrong%3E.%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdetails%3E%0A%20%20%20%20%20%20%20%20%20%20%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20If%20the%20Simphony%2FSAX%20curve%20(when%20available)%20doesn%E2%80%99t%20match%20the%20analytic%20curve%20perfectly%2C%20name%20%3Cem%3Eone%3C%2Fem%3E%20likely%20reason.%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cdetails%3E%3Csummary%3E%3Cem%3EAnswer%3C%2Fem%3E%3C%2Fsummary%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cp%3ECommon%20causes%3A%20splitter%2Fcoupler%20model%20conventions%2C%20wavelength-dependent%20component%20responses%2C%20dispersion%2C%20and%20loss%20(depending%20on%20models).%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdetails%3E%0A%20%20%20%20%20%20%20%20%20%20%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%3C%2Fol%3E%0A%20%20%20%20%20%20%20%20%22%22%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20os%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20altair%20as%20alt%0A%20%20%20%20import%20polars%20as%20pl%0A%20%20%20%20import%20base64%20as%20b64%0A%20%20%20%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20gf%20%3D%20None%0A%20%20%20%20gf_import_error%20%3D%20%22%22%0A%20%20%20%20if%20os.environ.get(%22PB_SKIP_GF%22)%20%3D%3D%20%221%22%3A%0A%20%20%20%20%20%20%20%20gf_import_error%20%3D%20%22PB_SKIP_GF%3D1%22%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20import%20gdsfactory%20as%20gf%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20exc%3A%20%20%23%20pragma%3A%20no%20cover%20-%20depends%20on%20environment%0A%20%20%20%20%20%20%20%20%20%20%20%20gf_import_error%20%3D%20f%22%7Btype(exc).__name__%7D%3A%20%7Bexc%7D%22%0A%20%20%20%20return%20Path%2C%20alt%2C%20b64%2C%20gf%2C%20gf_import_error%2C%20mo%2C%20np%2C%20pl%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20import%20ast%0A%0A%20%20%20%20_ALLOWED_FUNCS%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22sin%22%2C%0A%20%20%20%20%20%20%20%20%22cos%22%2C%0A%20%20%20%20%20%20%20%20%22tan%22%2C%0A%20%20%20%20%20%20%20%20%22exp%22%2C%0A%20%20%20%20%20%20%20%20%22sqrt%22%2C%0A%20%20%20%20%20%20%20%20%22log%22%2C%0A%20%20%20%20%20%20%20%20%22log10%22%2C%0A%20%20%20%20%20%20%20%20%22abs%22%2C%0A%20%20%20%20%20%20%20%20%22where%22%2C%0A%20%20%20%20%20%20%20%20%22clip%22%2C%0A%20%20%20%20%20%20%20%20%22min%22%2C%0A%20%20%20%20%20%20%20%20%22max%22%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20_ALLOWED_NODES%20%3D%20(%0A%20%20%20%20%20%20%20%20ast.Expression%2C%0A%20%20%20%20%20%20%20%20ast.BinOp%2C%0A%20%20%20%20%20%20%20%20ast.UnaryOp%2C%0A%20%20%20%20%20%20%20%20ast.Call%2C%0A%20%20%20%20%20%20%20%20ast.Name%2C%0A%20%20%20%20%20%20%20%20ast.Load%2C%0A%20%20%20%20%20%20%20%20ast.Constant%2C%0A%20%20%20%20%20%20%20%20ast.IfExp%2C%0A%20%20%20%20%20%20%20%20ast.Compare%2C%0A%20%20%20%20%20%20%20%20ast.BoolOp%2C%0A%20%20%20%20%20%20%20%20ast.And%2C%0A%20%20%20%20%20%20%20%20ast.Or%2C%0A%20%20%20%20%20%20%20%20ast.Not%2C%0A%20%20%20%20%20%20%20%20ast.USub%2C%0A%20%20%20%20%20%20%20%20ast.UAdd%2C%0A%20%20%20%20%20%20%20%20ast.Add%2C%0A%20%20%20%20%20%20%20%20ast.Sub%2C%0A%20%20%20%20%20%20%20%20ast.Mult%2C%0A%20%20%20%20%20%20%20%20ast.Div%2C%0A%20%20%20%20%20%20%20%20ast.Pow%2C%0A%20%20%20%20%20%20%20%20ast.Mod%2C%0A%20%20%20%20%20%20%20%20ast.Eq%2C%0A%20%20%20%20%20%20%20%20ast.NotEq%2C%0A%20%20%20%20%20%20%20%20ast.Lt%2C%0A%20%20%20%20%20%20%20%20ast.LtE%2C%0A%20%20%20%20%20%20%20%20ast.Gt%2C%0A%20%20%20%20%20%20%20%20ast.GtE%2C%0A%20%20%20%20)%0A%0A%20%20%20%20def%20safe_math_eval(expression%3A%20str%2C%20env%3A%20dict)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Evaluate%20a%20restricted%20math%20expression%20(no%20attrs%2Fimports%2Fsubscripts).%22%22%22%0A%0A%20%20%20%20%20%20%20%20tree%20%3D%20ast.parse(expression%2C%20mode%3D%22eval%22)%0A%0A%20%20%20%20%20%20%20%20for%20node%20in%20ast.walk(tree)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20isinstance(node%2C%20ast.Attribute)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%22Attribute%20access%20is%20not%20allowed%20(use%20sin%2Fcos%2F...%20directly).%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20isinstance(node%2C%20ast.Subscript)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%22Indexing%20is%20not%20allowed%20in%20the%20playground.%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20isinstance(node%2C%20ast.Call)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20isinstance(node.func%2C%20ast.Name)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%22Only%20direct%20function%20calls%20are%20allowed%20(e.g.%2C%20cos(...)).%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20node.func.id%20not%20in%20_ALLOWED_FUNCS%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(f%22Function%20%60%7Bnode.func.id%7D%60%20is%20not%20allowed.%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20node.keywords%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%22Keyword%20arguments%20are%20not%20allowed.%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20isinstance(node%2C%20ast.Name)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20node.id%20not%20in%20env%20and%20node.id%20not%20in%20_ALLOWED_FUNCS%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(f%22Unknown%20symbol%20%60%7Bnode.id%7D%60.%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20isinstance(node%2C%20_ALLOWED_NODES)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(f%22Unsupported%20syntax%3A%20%7Btype(node).__name__%7D.%22)%0A%0A%20%20%20%20%20%20%20%20safe_globals%20%3D%20%7B%22__builtins__%22%3A%20%7B%7D%7D%0A%20%20%20%20%20%20%20%20safe_locals%20%3D%20dict(env)%0A%20%20%20%20%20%20%20%20safe_locals.update(%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22sin%22%3A%20np.sin%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22cos%22%3A%20np.cos%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22tan%22%3A%20np.tan%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22exp%22%3A%20np.exp%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22sqrt%22%3A%20np.sqrt%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22log%22%3A%20np.log%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22log10%22%3A%20np.log10%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22abs%22%3A%20np.abs%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22where%22%3A%20np.where%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22clip%22%3A%20np.clip%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22min%22%3A%20np.minimum%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22max%22%3A%20np.maximum%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20code%20%3D%20compile(tree%2C%20%22%3Cstudent-expression%3E%22%2C%20%22eval%22)%0A%20%20%20%20%20%20%20%20return%20eval(code%2C%20safe_globals%2C%20safe_locals)%20%20%23%20noqa%3A%20S307%20(restricted%20env)%0A%20%20%20%20return%20(safe_math_eval%2C)%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20def%20fsr_estimate_nm(wl0_um%3A%20float%2C%20ng%3A%20float%2C%20delta_length_um%3A%20float)%20-%3E%20float%20%7C%20None%3A%0A%20%20%20%20%20%20%20%20if%20delta_length_um%20%3C%3D%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%20%20%20%20return%20(wl0_um%20*%20wl0_um)%20%2F%20(ng%20*%20delta_length_um)%20*%201e3%0A%0A%20%20%20%20def%20phase_slope_rad_per_nm(wl0_um%3A%20float%2C%20ng%3A%20float%2C%20delta_length_um%3A%20float)%20-%3E%20float%20%7C%20None%3A%0A%20%20%20%20%20%20%20%20if%20delta_length_um%20%3C%3D%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20None%0A%20%20%20%20%20%20%20%20%23%20%7Cd%CE%94%CF%86%2Fd%CE%BB%7C%20%E2%89%88%202%CF%80%20n_g%20%CE%94L%20%2F%20%CE%BB0%5E2%2C%20with%20%CE%BB0%20and%20%CE%94L%20in%20%C2%B5m.%0A%20%20%20%20%20%20%20%20return%20(2%20*%20np.pi%20*%20ng%20*%20delta_length_um%20%2F%20(wl0_um**2))%20%2F%201e3%0A%0A%20%20%20%20def%20neff_linear_from_ng(%0A%20%20%20%20%20%20%20%20wl_um%3A%20np.ndarray%2C%20wl0_um%3A%20float%2C%20n_eff0%3A%20float%2C%20ng%3A%20float%0A%20%20%20%20)%20-%3E%20tuple%5Bnp.ndarray%2C%20float%5D%3A%0A%20%20%20%20%20%20%20%20%23%20n_g%20%3D%20n_eff%20-%20%CE%BB%20dn_eff%2Fd%CE%BB%20%20%E2%87%92%20%20dn_eff%2Fd%CE%BB%20%3D%20(n_eff%20-%20n_g)%2F%CE%BB%0A%20%20%20%20%20%20%20%20dn_eff_dlambda_per_um%20%3D%20(n_eff0%20-%20ng)%20%2F%20wl0_um%0A%20%20%20%20%20%20%20%20n_eff_lambda%20%3D%20n_eff0%20%2B%20dn_eff_dlambda_per_um%20*%20(wl_um%20-%20wl0_um)%0A%20%20%20%20%20%20%20%20return%20n_eff_lambda%2C%20float(dn_eff_dlambda_per_um)%0A%20%20%20%20return%20fsr_estimate_nm%2C%20neff_linear_from_ng%2C%20phase_slope_rad_per_nm%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20def%20_local_maxima_indices(y%3A%20np.ndarray)%20-%3E%20np.ndarray%3A%0A%20%20%20%20%20%20%20%20%22%22%22Return%20indices%20i%20where%20y%5Bi%5D%20is%20a%20strict%20local%20maximum.%22%22%22%0A%20%20%20%20%20%20%20%20y%20%3D%20np.asarray(y%2C%20dtype%3Dfloat).reshape(-1)%0A%20%20%20%20%20%20%20%20if%20y.size%20%3C%203%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20np.array(%5B%5D%2C%20dtype%3Dint)%0A%20%20%20%20%20%20%20%20left%20%3D%20y%5B1%3A-1%5D%20%3E%20y%5B%3A-2%5D%0A%20%20%20%20%20%20%20%20right%20%3D%20y%5B1%3A-1%5D%20%3E%3D%20y%5B2%3A%5D%0A%20%20%20%20%20%20%20%20idx%20%3D%20np.where(left%20%26%20right)%5B0%5D%20%2B%201%0A%20%20%20%20%20%20%20%20return%20idx.astype(int)%0A%0A%20%20%20%20def%20auto_fsr_from_curve(%0A%20%20%20%20%20%20%20%20*%2C%0A%20%20%20%20%20%20%20%20wl_nm%3A%20np.ndarray%2C%0A%20%20%20%20%20%20%20%20y%3A%20np.ndarray%2C%0A%20%20%20%20%20%20%20%20wl0_nm%3A%20float%2C%0A%20%20%20%20)%20-%3E%20dict%3A%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20Detect%20adjacent%20maxima%20and%20estimate%20FSR%20near%20wl0.%0A%0A%20%20%20%20%20%20%20%20Returns%20keys%3A%0A%20%20%20%20%20%20%20%20%20%20ok%3A%20bool%0A%20%20%20%20%20%20%20%20%20%20message%3A%20str%0A%20%20%20%20%20%20%20%20%20%20lam1_nm%2C%20lam2_nm%2C%20fsr_nm%3A%20float%7CNone%0A%20%20%20%20%20%20%20%20%20%20n_peaks%3A%20int%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20wl_nm%20%3D%20np.asarray(wl_nm%2C%20dtype%3Dfloat).reshape(-1)%0A%20%20%20%20%20%20%20%20y%20%3D%20np.asarray(y%2C%20dtype%3Dfloat).reshape(-1)%0A%20%20%20%20%20%20%20%20if%20wl_nm.size%20!%3D%20y.size%20or%20wl_nm.size%20%3C%205%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22ok%22%3A%20False%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22message%22%3A%20%22Curve%20data%20unavailable%20(need%20arrays%20of%20the%20same%20length).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22lam1_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22lam2_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22fsr_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22n_peaks%22%3A%200%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20idx%20%3D%20_local_maxima_indices(y)%0A%20%20%20%20%20%20%20%20if%20idx.size%20%3C%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22ok%22%3A%20False%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22message%22%3A%20%22Could%20not%20find%20at%20least%20two%20maxima%20(try%20increasing%20%CE%94L%20or%20spectrum%20span).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22lam1_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22lam2_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22fsr_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22n_peaks%22%3A%20int(idx.size)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%23%20Filter%20out%20maxima%20that%20are%20effectively%20flat%20due%20to%20numerical%20issues.%0A%20%20%20%20%20%20%20%20y_min%20%3D%20float(np.nanmin(y))%0A%20%20%20%20%20%20%20%20y_max%20%3D%20float(np.nanmax(y))%0A%20%20%20%20%20%20%20%20y_rng%20%3D%20max(y_max%20-%20y_min%2C%200.0)%0A%20%20%20%20%20%20%20%20eps%20%3D%201e-9%20if%20y_rng%20%3D%3D%200%20else%201e-6%20*%20y_rng%0A%20%20%20%20%20%20%20%20idx%20%3D%20np.array(%5Bi%20for%20i%20in%20idx%20if%20(y%5Bi%5D%20-%20max(y%5Bi%20-%201%5D%2C%20y%5Bi%20%2B%201%5D))%20%3E%20eps%5D%2C%20dtype%3Dint)%0A%20%20%20%20%20%20%20%20if%20idx.size%20%3C%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22ok%22%3A%20False%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22message%22%3A%20%22Found%20maxima%20but%20they%20are%20too%20flat%20to%20measure%20reliably.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22lam1_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22lam2_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22fsr_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22n_peaks%22%3A%20int(idx.size)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20peaks_nm%20%3D%20wl_nm%5Bidx%5D%0A%20%20%20%20%20%20%20%20peaks_nm%20%3D%20peaks_nm%5Bnp.argsort(peaks_nm)%5D%0A%20%20%20%20%20%20%20%20if%20peaks_nm.size%20%3C%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22ok%22%3A%20False%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22message%22%3A%20%22Could%20not%20compute%20peak%20spacing%20(unexpected).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22lam1_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22lam2_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22fsr_nm%22%3A%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22n_peaks%22%3A%20int(peaks_nm.size)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20mids%20%3D%20(peaks_nm%5B%3A-1%5D%20%2B%20peaks_nm%5B1%3A%5D)%20%2F%202.0%0A%20%20%20%20%20%20%20%20k%20%3D%20int(np.argmin(np.abs(mids%20-%20float(wl0_nm))))%0A%20%20%20%20%20%20%20%20lam1%20%3D%20float(peaks_nm%5Bk%5D)%0A%20%20%20%20%20%20%20%20lam2%20%3D%20float(peaks_nm%5Bk%20%2B%201%5D)%0A%20%20%20%20%20%20%20%20fsr%20%3D%20float(abs(lam2%20-%20lam1))%0A%0A%20%20%20%20%20%20%20%20return%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22ok%22%3A%20True%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22message%22%3A%20%22OK%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22lam1_nm%22%3A%20lam1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22lam2_nm%22%3A%20lam2%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22fsr_nm%22%3A%20fsr%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22n_peaks%22%3A%20int(peaks_nm.size)%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20return%20(auto_fsr_from_curve%2C)%0A%0A%0A%40app.cell%0Adef%20_(gf%2C%20gf_import_error%2C%20mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20blocks%20%3D%20%5Bmo.md(%22%23%23%20gdsfactory%20quick%20check%22)%5D%0A%20%20%20%20if%20gf%20is%20None%3A%0A%20%20%20%20%20%20%20%20blocks.append(mo.md(%22%60gdsfactory%60%20is%20not%20available%20in%20this%20environment.%22))%0A%20%20%20%20%20%20%20%20if%20gf_import_error%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20blocks.append(mo.md(f%22Details%3A%20%60%7Bgf_import_error%7D%60%22))%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20gf_version%20%3D%20getattr(gf%2C%20%22__version__%22%2C%20None)%0A%20%20%20%20%20%20%20%20if%20gf_version%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(f%22%60gdsfactory%60%20version%20(this%20environment)%3A%20**%7Bgf_version%7D**%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Minimal%20usage%20example%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%60%60python%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20import%20gdsfactory%20as%20gf%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c%20%3D%20gf.components.mzi(delta_length%3D50)%20%20%23%20%C2%B5m%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c.write_gds(%22mzi.gds%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20mo.vstack(blocks)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(doc_callout_html%2C%20doc_callout_list%2C%20mo%2C%20show_interactive)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Interactive%20MZI%20spectrum%0A%0A%20%20%20%20Use%20the%20controls%20to%20explore%20how%20**%CE%94L**%20sets%20the%20**fringe%20spacing**%20(FSR).%0A%20%20%20%20You%20can%20compare%20a%20simple%20analytic%20model%20to%20an%20optional%20**Simphony%2FSAX%20circuit%20model**%20built%20from%20compact%20component%20models%20(if%20available%20in%20your%20environment).%0A%20%20%20%20%22%22%22)%0A%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22openEBL%20context%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Default%20band%20and%20why%22%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22This%20course%E2%80%99s%20first%20openEBL%20design%20targets%20the%20**1550%20nm%20band**%20by%20default%20(e.g.%2C%20TE%201550%20grating-coupler%20cells%20in%20the%20SiEPIC%20EBeam%20PDK).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22So%20the%20default%20center%20wavelength%20here%20is%20**%CE%BB0%20%E2%89%88%201550%20nm**.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Advanced%20option%3A%20explore%20**1310%20nm**%20by%20switching%20the%20wavelength%20band%20under%20**Controls%20%E2%86%92%20Advanced**.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Assumptions%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22What%20this%20plot%20is%20(and%20isn%E2%80%99t)%22%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3EIdeal%20analytic%20curve%3A%3C%2Fstrong%3E%20lossless%2C%20perfect%2050%2F50%20couplers%2C%20and%20a%20simplified%20phase%20term%20with%20a%20constant%20%3Ccode%3En_eff%3C%2Fcode%3E.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3EFSR%20physics%3A%3C%2Fstrong%3E%20the%20rule-of-thumb%20comes%20from%20the%20condition%20%E2%80%9Cadjacent%20fringes%20%E2%86%94%20%CE%94%CF%86%20changes%20by%202%CF%80%E2%80%9D%20and%20uses%20%3Ccode%3En_g%3C%2Fcode%3E%20(group%20index).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3EWhat%E2%80%99s%20missing%3A%3C%2Fstrong%3E%20wavelength-dependent%20dispersion%20in%20%3Ccode%3En_eff(%CE%BB)%3C%2Fcode%3E%2C%20propagation%20loss%2C%20and%20non-ideal%20couplers%20(unless%20you%20use%20the%20Simphony%2FSAX%20view).%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%22warning%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Why%20two%20curves%3F%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Analytic%20vs%20circuit%20compact-model%20simulation%22%2C%0A%20%20%20%20%20%20%20%20html%3D%22%22%22%0A%20%20%20%20%20%20%20%20%3Cul%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3E%3Cstrong%3EAnalytic%3C%2Fstrong%3E%3A%20ideal%2C%20lossless%2C%20and%20uses%20a%20simple%20phase%20term%20with%20a%20tunable%20%3Ccode%3En_eff%3C%2Fcode%3E.%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3E%3Cstrong%3ESimphony%2FSAX%3C%2Fstrong%3E%3A%20assembles%20an%20MZI%20from%20wavelength-dependent%20component%20models%20(splitter%20%2B%20waveguides%20%2B%20combiner).%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%3C%2Ful%3E%0A%20%20%20%20%20%20%20%20%3Cp%3E%0A%20%20%20%20%20%20%20%20%20%20Differences%20typically%20come%20from%20dispersion%2C%20the%20specific%20splitter%2Fcoupler%20model%2C%20and%20model%20conventions.%0A%20%20%20%20%20%20%20%20%20%20Use%20the%20%3Ccode%3En_eff%3C%2Fcode%3E%20tuning%20knob%20to%20align%20the%20analytic%20fringe%20spacing%20near%20%CE%BB0.%0A%20%20%20%20%20%20%20%20%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%22%22%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Concept%20check%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Quick%20questions%20before%20you%20touch%20the%20sliders%22%2C%0A%20%20%20%20%20%20%20%20html%3D%22%22%22%0A%20%20%20%20%20%20%20%20%3Col%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20If%20you%20%3Cstrong%3Edouble%20%CE%94L%3C%2Fstrong%3E%2C%20does%20the%20FSR%20get%20bigger%2C%20smaller%2C%20or%20stay%20the%20same%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cdetails%3E%3Csummary%3E%3Cem%3EAnswer%3C%2Fem%3E%3C%2Fsummary%3E%3Cp%3ESmaller%20(approximately%20halves)%2C%20because%20FSR%20%E2%88%9D%201%2F%CE%94L.%3C%2Fp%3E%3C%2Fdetails%3E%0A%20%20%20%20%20%20%20%20%20%20%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cli%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20If%20you%20change%20the%20%3Cstrong%3Ebase%20arm%20length%3C%2Fstrong%3E%20(both%20arms%20equally)%2C%20does%20the%20FSR%20change%20in%20the%20ideal%20analytic%20model%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cdetails%3E%3Csummary%3E%3Cem%3EAnswer%3C%2Fem%3E%3C%2Fsummary%3E%3Cp%3ENo.%20Only%20the%20%3Cem%3Edifference%3C%2Fem%3E%20%CE%94L%20changes%20the%20interference%20period.%3C%2Fp%3E%3C%2Fdetails%3E%0A%20%20%20%20%20%20%20%20%20%20%3C%2Fli%3E%0A%20%20%20%20%20%20%20%20%3C%2Fol%3E%0A%20%20%20%20%20%20%20%20%22%22%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22exercise%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Exercise%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22FSR%20vs%20%CE%94L%20(mini-lab)%22%2C%0A%20%20%20%20%20%20%20%20ordered%3DTrue%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Set%20%CE%94L%20to%2010%20%C2%B5m%20and%20estimate%20the%20FSR%20from%20the%20plot%20(distance%20between%20adjacent%20maxima).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Double%20%CE%94L.%20Predict%20the%20new%20FSR%20using%20the%20rule%20of%20thumb%2C%20then%20verify%20it%20on%20the%20plot.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Change%20the%20base%20arm%20length.%20Does%20the%20FSR%20change%20in%20the%20ideal%20analytic%20model%3F%20Why%20or%20why%20not%3F%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20base_length%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D100.0%2C%0A%20%20%20%20%20%20%20%20stop%3D20000.0%2C%0A%20%20%20%20%20%20%20%20value%3D5000.0%2C%0A%20%20%20%20%20%20%20%20step%3D100.0%2C%0A%20%20%20%20%20%20%20%20label%3D%22Base%20arm%20length%20(%C2%B5m)%22%2C%0A%20%20%20%20)%0A%20%20%20%20delta_length%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D0.0%2C%0A%20%20%20%20%20%20%20%20stop%3D500.0%2C%0A%20%20%20%20%20%20%20%20value%3D10.0%2C%0A%20%20%20%20%20%20%20%20step%3D1.0%2C%0A%20%20%20%20%20%20%20%20label%3D%22%CE%94L%20(%C2%B5m%2C%20path%20length%20difference)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20base_length%2C%20delta_length%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20param_preset%20%3D%20mo.ui.dropdown(%0A%20%20%20%20%20%20%20%20options%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Custom%20(use%20sliders)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Reset%20to%20defaults%20(%CE%94L%3D10%20%C2%B5m)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%CE%94L%20%3D%2025%20%C2%B5m%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%CE%94L%20%3D%2050%20%C2%B5m%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%CE%94L%20%3D%20100%20%C2%B5m%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20value%3D%22Custom%20(use%20sliders)%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Parameter%20preset%20(overrides%20%CE%94L%20slider)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(param_preset%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20spectrum_center%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D1.50%2C%0A%20%20%20%20%20%20%20%20stop%3D1.60%2C%0A%20%20%20%20%20%20%20%20value%3D1.55%2C%0A%20%20%20%20%20%20%20%20step%3D0.001%2C%0A%20%20%20%20%20%20%20%20label%3D%22Spectrum%20center%20%CE%BB0%20(%C2%B5m%2C%201550%20band)%22%2C%0A%20%20%20%20)%0A%20%20%20%20wl_band%20%3D%20mo.ui.radio(%0A%20%20%20%20%20%20%20%20options%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%221550%20nm%20(default)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%221310%20nm%20(advanced)%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20value%3D%221550%20nm%20(default)%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Wavelength%20band%22%2C%0A%20%20%20%20%20%20%20%20inline%3DTrue%2C%0A%20%20%20%20)%0A%20%20%20%20spectrum_center_1310%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D1.26%2C%0A%20%20%20%20%20%20%20%20stop%3D1.36%2C%0A%20%20%20%20%20%20%20%20value%3D1.31%2C%0A%20%20%20%20%20%20%20%20step%3D0.001%2C%0A%20%20%20%20%20%20%20%20label%3D%22Spectrum%20center%20%CE%BB0%20(%C2%B5m%2C%201310%20band)%22%2C%0A%20%20%20%20)%0A%20%20%20%20spectrum_span_nm%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D10.0%2C%0A%20%20%20%20%20%20%20%20stop%3D200.0%2C%0A%20%20%20%20%20%20%20%20value%3D100.0%2C%0A%20%20%20%20%20%20%20%20step%3D5.0%2C%0A%20%20%20%20%20%20%20%20label%3D%22Spectrum%20span%20(nm)%22%2C%0A%20%20%20%20)%0A%20%20%20%20ng%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D2.0%2C%0A%20%20%20%20%20%20%20%20stop%3D5.0%2C%0A%20%20%20%20%20%20%20%20value%3D4.19%2C%0A%20%20%20%20%20%20%20%20step%3D0.01%2C%0A%20%20%20%20%20%20%20%20label%3D%22Group%20index%20ng%20(FSR%20estimate)%22%2C%0A%20%20%20%20)%0A%20%20%20%20n_eff%20%3D%20mo.ui.slider(%0A%20%20%20%20%20%20%20%20start%3D1.0%2C%0A%20%20%20%20%20%20%20%20stop%3D6.0%2C%0A%20%20%20%20%20%20%20%20value%3D2.40%2C%0A%20%20%20%20%20%20%20%20step%3D0.0001%2C%0A%20%20%20%20%20%20%20%20label%3D%22Phase%20effective%20index%20n_eff%20(toy%20model%3B%20tune%20fringes)%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20n_eff%2C%0A%20%20%20%20%20%20%20%20ng%2C%0A%20%20%20%20%20%20%20%20spectrum_center%2C%0A%20%20%20%20%20%20%20%20spectrum_center_1310%2C%0A%20%20%20%20%20%20%20%20spectrum_span_nm%2C%0A%20%20%20%20%20%20%20%20wl_band%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20view_mode%20%3D%20mo.ui.dropdown(%0A%20%20%20%20%20%20%20%20options%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Analytic%20only%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Simphony%20only%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Overlay%20(analytic%20%2B%20Simphony)%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20value%3D%22Analytic%20only%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22View%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(view_mode%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20simphony_io%20%3D%20mo.ui.radio(%0A%20%20%20%20%20%20%20%20options%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Direct%20waveguide%20I%2FO%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Include%20grating%20couplers%20(in%20%2B%20out)%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20value%3D%22Direct%20waveguide%20I%2FO%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Simphony%20I%2FO%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(simphony_io%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20run_simphony%20%3D%20mo.ui.checkbox(%0A%20%20%20%20%20%20%20%20label%3D%22Compute%20Simphony%20curve%22%2C%0A%20%20%20%20%20%20%20%20value%3DFalse%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(run_simphony%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20y_scale%20%3D%20mo.ui.radio(%0A%20%20%20%20%20%20%20%20options%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Linear%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Semilog%20(log%20y)%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20value%3D%22Linear%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Y%20scale%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(y_scale%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20show_plot_debug%20%3D%20mo.ui.checkbox(label%3D%22Show%20plot%20debug%20info%22%2C%20value%3DFalse)%0A%20%20%20%20return%20(show_plot_debug%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20show_advanced%20%3D%20mo.ui.checkbox(label%3D%22Show%20advanced%20controls%22%2C%20value%3DFalse)%0A%20%20%20%20return%20(show_advanced%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20playground_enabled%20%3D%20mo.ui.checkbox(%0A%20%20%20%20%20%20%20%20label%3D%22Enable%20expression%20playground%20(student%20editable)%22%2C%0A%20%20%20%20%20%20%20%20value%3DFalse%2C%0A%20%20%20%20)%0A%20%20%20%20playground_preset%20%3D%20mo.ui.radio(%0A%20%20%20%20%20%20%20%20options%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Ideal%20MZI%20(default)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Reduced%20visibility%20(V%3D0.8)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Add%20loss%20floor%20(2%25)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Custom%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20value%3D%22Ideal%20MZI%20(default)%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Playground%20preset%22%2C%0A%20%20%20%20)%0A%20%20%20%20playground_expr%20%3D%20mo.ui.text_area(%0A%20%20%20%20%20%20%20%20value%3D%220.5*(1%20%2B%20cos(2*pi*n_eff*delta_L%2Fwl_um))%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Custom%20transmission%20T(wl)%20(unitless)%22%2C%0A%20%20%20%20%20%20%20%20rows%3D2%2C%0A%20%20%20%20)%0A%20%20%20%20return%20playground_enabled%2C%20playground_expr%2C%20playground_preset%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20base_length%2C%0A%20%20%20%20delta_length%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20n_eff%2C%0A%20%20%20%20ng%2C%0A%20%20%20%20param_preset%2C%0A%20%20%20%20playground_enabled%2C%0A%20%20%20%20playground_expr%2C%0A%20%20%20%20playground_preset%2C%0A%20%20%20%20run_simphony%2C%0A%20%20%20%20show_advanced%2C%0A%20%20%20%20show_interactive%2C%0A%20%20%20%20show_plot_debug%2C%0A%20%20%20%20simphony_io%2C%0A%20%20%20%20spectrum_center%2C%0A%20%20%20%20spectrum_center_1310%2C%0A%20%20%20%20spectrum_span_nm%2C%0A%20%20%20%20view_mode%2C%0A%20%20%20%20wl_band%2C%0A%20%20%20%20y_scale%2C%0A)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20live_update%20%3D%20mo.ui.checkbox(label%3D%22Live%20update%22%2C%20value%3DTrue)%0A%20%20%20%20apply_update%20%3D%20mo.ui.button(%0A%20%20%20%20%20%20%20%20value%3D0%2C%0A%20%20%20%20%20%20%20%20label%3D%22Apply%22%2C%0A%20%20%20%20%20%20%20%20kind%3D%22neutral%22%2C%0A%20%20%20%20%20%20%20%20tooltip%3D%22When%20Live%20update%20is%20off%2C%20click%20Apply%20to%20recompute.%22%2C%0A%20%20%20%20%20%20%20%20on_click%3Dlambda%20v%3A%20(v%20or%200)%20%2B%201%2C%0A%20%20%20%20)%0A%0A%20%20%20%20basic_controls%20%3D%20mo.vstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.hstack(%5Bspectrum_center%2C%20spectrum_span_nm%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.hstack(%5By_scale%2C%20view_mode%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.hstack(%5Bbase_length%2C%20delta_length%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.hstack(%5Bparam_preset%2C%20ng%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20n_eff%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20advanced_controls%20%3D%20mo.vstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.hstack(%5Bshow_advanced%2C%20show_plot_debug%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20wl_band%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20spectrum_center_1310%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.hstack(%5Bplayground_enabled%2C%20playground_preset%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20playground_expr%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%0A%20%20%20%20controls_tabs%20%3D%20mo.ui.tabs(%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Basic%22%3A%20mo.vstack(%5Bbasic_controls%2C%20mo.hstack(%5Bsimphony_io%2C%20run_simphony%5D)%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Advanced%22%3A%20advanced_controls%2C%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20value%3D%22Basic%22%2C%0A%20%20%20%20%20%20%20%20lazy%3DTrue%2C%0A%20%20%20%20)%0A%0A%20%20%20%20controls_ui%20%3D%20mo.vstack(%5Bmo.hstack(%5Blive_update%2C%20apply_update%5D)%2C%20controls_tabs%5D)%0A%20%20%20%20return%20apply_update%2C%20controls_ui%2C%20live_update%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20apply_update%2C%0A%20%20%20%20base_length%2C%0A%20%20%20%20delta_length%2C%0A%20%20%20%20live_update%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20n_eff%2C%0A%20%20%20%20ng%2C%0A%20%20%20%20param_preset%2C%0A%20%20%20%20playground_enabled%2C%0A%20%20%20%20playground_expr%2C%0A%20%20%20%20playground_preset%2C%0A%20%20%20%20run_simphony%2C%0A%20%20%20%20show_advanced%2C%0A%20%20%20%20show_interactive%2C%0A%20%20%20%20show_plot_debug%2C%0A%20%20%20%20simphony_io%2C%0A%20%20%20%20spectrum_center%2C%0A%20%20%20%20spectrum_center_1310%2C%0A%20%20%20%20spectrum_span_nm%2C%0A%20%20%20%20view_mode%2C%0A%20%20%20%20wl_band%2C%0A%20%20%20%20y_scale%2C%0A)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%0A%20%20%20%20raw%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22base_length%22%3A%20float(base_length.value)%2C%0A%20%20%20%20%20%20%20%20%22delta_length%22%3A%20float(delta_length.value)%2C%0A%20%20%20%20%20%20%20%20%22param_preset%22%3A%20str(param_preset.value)%2C%0A%20%20%20%20%20%20%20%20%22spectrum_center%22%3A%20float(spectrum_center.value)%2C%0A%20%20%20%20%20%20%20%20%22spectrum_center_1310%22%3A%20float(spectrum_center_1310.value)%2C%0A%20%20%20%20%20%20%20%20%22wl_band%22%3A%20str(wl_band.value)%2C%0A%20%20%20%20%20%20%20%20%22spectrum_span_nm%22%3A%20float(spectrum_span_nm.value)%2C%0A%20%20%20%20%20%20%20%20%22y_scale%22%3A%20str(y_scale.value)%2C%0A%20%20%20%20%20%20%20%20%22ng%22%3A%20float(ng.value)%2C%0A%20%20%20%20%20%20%20%20%22n_eff%22%3A%20float(n_eff.value)%2C%0A%20%20%20%20%20%20%20%20%22view_mode%22%3A%20str(view_mode.value)%2C%0A%20%20%20%20%20%20%20%20%22simphony_io%22%3A%20str(simphony_io.value)%2C%0A%20%20%20%20%20%20%20%20%22run_simphony%22%3A%20bool(run_simphony.value)%2C%0A%20%20%20%20%20%20%20%20%22show_plot_debug%22%3A%20bool(show_plot_debug.value)%2C%0A%20%20%20%20%20%20%20%20%22show_advanced%22%3A%20bool(show_advanced.value)%2C%0A%20%20%20%20%20%20%20%20%22playground_enabled%22%3A%20bool(playground_enabled.value)%2C%0A%20%20%20%20%20%20%20%20%22playground_preset%22%3A%20str(playground_preset.value)%2C%0A%20%20%20%20%20%20%20%20%22playground_expr%22%3A%20str(playground_expr.value%20or%20%22%22)%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20applied_state%2C%20set_applied_state%20%3D%20mo.state(raw)%0A%20%20%20%20last_apply_click%2C%20set_last_apply_click%20%3D%20mo.state(0)%0A%0A%20%20%20%20if%20not%20bool(live_update.value)%20and%20int(apply_update.value)%20!%3D%20int(last_apply_click())%3A%0A%20%20%20%20%20%20%20%20set_applied_state(raw)%0A%20%20%20%20%20%20%20%20set_last_apply_click(int(apply_update.value))%0A%0A%20%20%20%20effective%20%3D%20raw%20if%20bool(live_update.value)%20else%20dict(applied_state())%0A%0A%20%20%20%20_band%20%3D%20str(effective.get(%22wl_band%22%2C%20%221550%20nm%20(default)%22))%0A%20%20%20%20if%20_band.startswith(%221310%22)%3A%0A%20%20%20%20%20%20%20%20wl0_um_effective%20%3D%20float(effective%5B%22spectrum_center_1310%22%5D)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20wl0_um_effective%20%3D%20float(effective%5B%22spectrum_center%22%5D)%0A%0A%20%20%20%20preset_deltaL_um%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22Reset%20to%20defaults%20(%CE%94L%3D10%20%C2%B5m)%22%3A%2010.0%2C%0A%20%20%20%20%20%20%20%20%22%CE%94L%20%3D%2025%20%C2%B5m%22%3A%2025.0%2C%0A%20%20%20%20%20%20%20%20%22%CE%94L%20%3D%2050%20%C2%B5m%22%3A%2050.0%2C%0A%20%20%20%20%20%20%20%20%22%CE%94L%20%3D%20100%20%C2%B5m%22%3A%20100.0%2C%0A%20%20%20%20%7D%0A%20%20%20%20preset_label%20%3D%20str(effective%5B%22param_preset%22%5D)%0A%20%20%20%20if%20preset_label%20in%20preset_deltaL_um%3A%0A%20%20%20%20%20%20%20%20delta_length_um_effective%20%3D%20float(preset_deltaL_um%5Bpreset_label%5D)%0A%20%20%20%20%20%20%20%20preset_active%20%3D%20True%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20delta_length_um_effective%20%3D%20float(effective%5B%22delta_length%22%5D)%0A%20%20%20%20%20%20%20%20preset_active%20%3D%20False%0A%0A%20%20%20%20w02_params%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22base_length_um%22%3A%20float(effective%5B%22base_length%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22delta_length_um_slider%22%3A%20float(effective%5B%22delta_length%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22delta_length_um_effective%22%3A%20delta_length_um_effective%2C%0A%20%20%20%20%20%20%20%20%22preset_active%22%3A%20preset_active%2C%0A%20%20%20%20%20%20%20%20%22param_preset%22%3A%20preset_label%2C%0A%20%20%20%20%20%20%20%20%22wl_band%22%3A%20_band%2C%0A%20%20%20%20%20%20%20%20%22wl0_um%22%3A%20wl0_um_effective%2C%0A%20%20%20%20%20%20%20%20%22spectrum_span_nm%22%3A%20float(effective%5B%22spectrum_span_nm%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22y_scale%22%3A%20str(effective%5B%22y_scale%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22semilog%22%3A%20str(effective%5B%22y_scale%22%5D)%20%3D%3D%20%22Semilog%20(log%20y)%22%2C%0A%20%20%20%20%20%20%20%20%22n_g%22%3A%20float(effective%5B%22ng%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22n_eff0%22%3A%20float(effective%5B%22n_eff%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22view_mode%22%3A%20str(effective%5B%22view_mode%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22simphony_io%22%3A%20str(effective%5B%22simphony_io%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22run_simphony%22%3A%20bool(effective%5B%22run_simphony%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22show_plot_debug%22%3A%20bool(effective%5B%22show_plot_debug%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22show_advanced%22%3A%20bool(effective%5B%22show_advanced%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22playground_enabled%22%3A%20bool(effective%5B%22playground_enabled%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22playground_preset%22%3A%20str(effective%5B%22playground_preset%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22playground_expr%22%3A%20str(effective%5B%22playground_expr%22%5D%20or%20%22%22)%2C%0A%20%20%20%20%20%20%20%20%22live_update%22%3A%20bool(live_update.value)%2C%0A%20%20%20%20%20%20%20%20%22applied%22%3A%20(not%20bool(live_update.value))%20and%20int(apply_update.value)%20%3E%200%2C%0A%20%20%20%20%7D%0A%20%20%20%20return%20delta_length_um_effective%2C%20w02_params%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20w02_params)%3A%0A%20%20%20%20jnp%20%3D%20np%20%20%23%20Fallback%20if%20JAX%20is%20not%20available.%0A%20%20%20%20mzi_circuit%20%3D%20None%0A%20%20%20%20mzi_circuit_with_gc%20%3D%20None%0A%20%20%20%20simphony_error%20%3D%20%22%22%0A%0A%20%20%20%20needs_simphony%20%3D%20w02_params%5B%22view_mode%22%5D%20in%20%5B%22Simphony%20only%22%2C%20%22Overlay%20(analytic%20%2B%20Simphony)%22%5D%0A%20%20%20%20if%20needs_simphony%3A%0A%20%20%20%20%20%20%20%20try%3A%20%20%23%20pragma%3A%20no%20cover%20-%20depends%20on%20environment%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20jax%20import%20config%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20config.update(%22jax_enable_x64%22%2C%20True)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20import%20jax.numpy%20as%20jnp_mod%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20jnp%20%3D%20jnp_mod%0A%20%20%20%20%20%20%20%20%20%20%20%20import%20sax%0A%20%20%20%20%20%20%20%20%20%20%20%20from%20simphony.libraries%20import%20siepic%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20try%3A%20%20%23%20pragma%3A%20no%20cover%20-%20depends%20on%20simphony%20%2F%20sax%20versions%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Y-branch%20MZI%3A%201x2%20splitter%20(forward)%20%2B%202x1%20combiner%20(reverse).%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20This%20provides%20a%20single%20output%20port%20at%20the%20combiner.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20hasattr(siepic%2C%20%22y_branch%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20AttributeError(%22simphony.libraries.siepic%20missing%20y_branch%20model%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20hasattr(siepic%2C%20%22waveguide%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20AttributeError(%22simphony.libraries.siepic%20missing%20waveguide%20model%22)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mzi_circuit%2C%20_%20%3D%20sax.circuit(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20netlist%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22instances%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22splitter%22%3A%20%22y_branch%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22short_wg%22%3A%20%22waveguide%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22long_wg%22%3A%20%22waveguide%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22combiner%22%3A%20%22y_branch%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22connections%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Splitter%20outputs%20to%20arms.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22splitter%2Cport_2%22%3A%20%22short_wg%2Co0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22splitter%2Cport_3%22%3A%20%22long_wg%2Co0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Arms%20into%20combiner%20(used%20in%20reverse%20as%20a%202x1%20combiner).%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22short_wg%2Co1%22%3A%20%22combiner%2Cport_2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22long_wg%2Co1%22%3A%20%22combiner%2Cport_3%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22ports%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22input%22%3A%20%22splitter%2Cport_1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22through%22%3A%20%22combiner%2Cport_1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20models%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22y_branch%22%3A%20siepic.y_branch%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22waveguide%22%3A%20siepic.waveguide%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20hasattr(siepic%2C%20%22grating_coupler%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mzi_circuit_with_gc%2C%20_%20%3D%20sax.circuit(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20netlist%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22instances%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22gc_in%22%3A%20%22grating_coupler%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22splitter%22%3A%20%22y_branch%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22short_wg%22%3A%20%22waveguide%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22long_wg%22%3A%20%22waveguide%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22combiner%22%3A%20%22y_branch%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22gc_out%22%3A%20%22grating_coupler%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22connections%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22gc_in%2Co1%22%3A%20%22splitter%2Cport_1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22combiner%2Cport_1%22%3A%20%22gc_out%2Co1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Splitter%20outputs%20to%20arms.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22splitter%2Cport_2%22%3A%20%22short_wg%2Co0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22splitter%2Cport_3%22%3A%20%22long_wg%2Co0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20Arms%20into%20combiner%20(used%20in%20reverse%20as%20a%202x1%20combiner).%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22short_wg%2Co1%22%3A%20%22combiner%2Cport_2%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22long_wg%2Co1%22%3A%20%22combiner%2Cport_3%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22ports%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22input%22%3A%20%22gc_in%2Co0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22through%22%3A%20%22gc_out%2Co0%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20models%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22grating_coupler%22%3A%20siepic.grating_coupler%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22y_branch%22%3A%20siepic.y_branch%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22waveguide%22%3A%20siepic.waveguide%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mzi_circuit%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mzi_circuit_with_gc%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20simphony_error%20%3D%20f%22Simphony%2FSAX%20circuit%20unavailable%3A%20%7Be%7D%22%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20mzi_circuit%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20mzi_circuit_with_gc%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20simphony_error%20%3D%20f%22Simphony%2FJAX%20imports%20unavailable%3A%20%7Be%7D%22%0A%20%20%20%20return%20jnp%2C%20mzi_circuit%2C%20mzi_circuit_with_gc%2C%20simphony_error%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20neff_linear_from_ng%2C%20np%2C%20pl%2C%20show_interactive%2C%20w02_params)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20_n_points%20%3D%20400%0A%20%20%20%20_wl_center_um%20%3D%20float(w02_params%5B%22wl0_um%22%5D)%0A%20%20%20%20_span_um%20%3D%20float(w02_params%5B%22spectrum_span_nm%22%5D)%20%2F%201e3%0A%20%20%20%20_wl_min_um%20%3D%20_wl_center_um%20-%20_span_um%20%2F%202%0A%20%20%20%20_wl_max_um%20%3D%20_wl_center_um%20%2B%20_span_um%20%2F%202%0A%0A%20%20%20%20_wl_um%20%3D%20np.linspace(_wl_min_um%2C%20_wl_max_um%2C%20_n_points)%0A%20%20%20%20_wl_nm%20%3D%20_wl_um%20*%201e3%0A%0A%20%20%20%20_semilog%20%3D%20bool(w02_params%5B%22semilog%22%5D)%0A%20%20%20%20_log_floor%20%3D%201e-6%0A%0A%20%20%20%20_n_index%20%3D%20float(w02_params%5B%22n_eff0%22%5D)%0A%20%20%20%20_ng_for_analytic%20%3D%20float(w02_params%5B%22n_g%22%5D)%0A%20%20%20%20_analytic_n_eff_lambda%2C%20_analytic_dn_eff_dlambda%20%3D%20neff_linear_from_ng(%0A%20%20%20%20%20%20%20%20wl_um%3D_wl_um%2C%0A%20%20%20%20%20%20%20%20wl0_um%3D_wl_center_um%2C%0A%20%20%20%20%20%20%20%20n_eff0%3D_n_index%2C%0A%20%20%20%20%20%20%20%20ng%3D_ng_for_analytic%2C%0A%20%20%20%20)%0A%20%20%20%20_delta_phi%20%3D%20(%0A%20%20%20%20%20%20%20%202%0A%20%20%20%20%20%20%20%20*%20np.pi%0A%20%20%20%20%20%20%20%20*%20_analytic_n_eff_lambda%0A%20%20%20%20%20%20%20%20*%20float(w02_params%5B%22delta_length_um_effective%22%5D)%0A%20%20%20%20%20%20%20%20%2F%20_wl_um%0A%20%20%20%20)%0A%20%20%20%20_T%20%3D%200.5%20*%20(1%20%2B%20np.cos(_delta_phi))%0A%20%20%20%20_analytic_value_plot%20%3D%20np.clip(_T%2C%20_log_floor%2C%20None)%20if%20_semilog%20else%20_T%0A%0A%20%20%20%20_analytic_df%20%3D%20pl.DataFrame(%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22wavelength_nm%22%3A%20_wl_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%20_T%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22value_plot%22%3A%20_analytic_value_plot%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22curve%22%3A%20%5B%22Analytic%20through%22%5D%20*%20len(_wl_nm)%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20)%0A%0A%20%20%20%20w02_spectrum%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22n_points%22%3A%20_n_points%2C%0A%20%20%20%20%20%20%20%20%22wl_center_um%22%3A%20_wl_center_um%2C%0A%20%20%20%20%20%20%20%20%22wl_min_um%22%3A%20_wl_min_um%2C%0A%20%20%20%20%20%20%20%20%22wl_max_um%22%3A%20_wl_max_um%2C%0A%20%20%20%20%20%20%20%20%22wl_um%22%3A%20_wl_um%2C%0A%20%20%20%20%20%20%20%20%22wl_nm%22%3A%20_wl_nm%2C%0A%20%20%20%20%20%20%20%20%22semilog%22%3A%20_semilog%2C%0A%20%20%20%20%20%20%20%20%22log_floor%22%3A%20_log_floor%2C%0A%20%20%20%20%7D%0A%20%20%20%20w02_analytic%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22n_eff0%22%3A%20_n_index%2C%0A%20%20%20%20%20%20%20%20%22n_g%22%3A%20_ng_for_analytic%2C%0A%20%20%20%20%20%20%20%20%22dn_eff_dlambda_um_inv%22%3A%20float(_analytic_dn_eff_dlambda)%2C%0A%20%20%20%20%20%20%20%20%22df%22%3A%20_analytic_df%2C%0A%20%20%20%20%7D%0A%20%20%20%20return%20w02_analytic%2C%20w02_spectrum%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20np%2C%20pl%2C%20safe_math_eval%2C%20show_interactive%2C%20w02_params%2C%20w02_spectrum)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20_wl_um%20%3D%20w02_spectrum%5B%22wl_um%22%5D%0A%20%20%20%20_wl_nm%20%3D%20w02_spectrum%5B%22wl_nm%22%5D%0A%20%20%20%20_semilog%20%3D%20w02_spectrum%5B%22semilog%22%5D%0A%20%20%20%20_log_floor%20%3D%20w02_spectrum%5B%22log_floor%22%5D%0A%0A%20%20%20%20_playground_error%20%3D%20%22%22%0A%20%20%20%20_playground_df%20%3D%20None%0A%0A%20%20%20%20if%20bool(w02_params%5B%22playground_enabled%22%5D)%3A%0A%20%20%20%20%20%20%20%20_preset%20%3D%20str(w02_params%5B%22playground_preset%22%5D)%0A%20%20%20%20%20%20%20%20_preset_exprs%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Ideal%20MZI%20(default)%22%3A%20%220.5*(1%20%2B%20cos(2*pi*n_eff*delta_L%2Fwl_um))%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Reduced%20visibility%20(V%3D0.8)%22%3A%20%220.5*(1%20%2B%200.8*cos(2*pi*n_eff*delta_L%2Fwl_um))%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Add%20loss%20floor%20(2%25)%22%3A%20%220.02%20%2B%200.98*0.5*(1%20%2B%20cos(2*pi*n_eff*delta_L%2Fwl_um))%22%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20_expr_str%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20_preset_exprs%5B_preset%5D.strip()%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20_preset%20in%20_preset_exprs%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20str(w02_params%5B%22playground_expr%22%5D%20or%20%22%22).strip()%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20if%20not%20_expr_str%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_playground_error%20%3D%20%22Enter%20an%20expression%20to%20plot.%22%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_env%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22wl_um%22%3A%20_wl_um%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22wl_nm%22%3A%20_wl_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pi%22%3A%20float(np.pi)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22delta_L%22%3A%20float(w02_params%5B%22delta_length_um_effective%22%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22n_eff%22%3A%20float(w02_params%5B%22n_eff0%22%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22n_g%22%3A%20float(w02_params%5B%22n_g%22%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_y%20%3D%20safe_math_eval(_expr_str%2C%20_env)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_y_arr%20%3D%20np.asarray(_y%2C%20dtype%3Dfloat)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20_y_arr.shape%20%3D%3D%20()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_y_arr%20%3D%20np.full_like(_wl_um%2C%20float(_y_arr))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_y_arr%20%3D%20_y_arr.reshape(-1)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20len(_y_arr)%20!%3D%20len(_wl_um)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Expression%20returned%20%7Blen(_y_arr)%7D%20values%3B%20expected%20%7Blen(_wl_um)%7D%20(or%20a%20scalar).%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_y_plot%20%3D%20np.clip(_y_arr%2C%20_log_floor%2C%20None)%20if%20_semilog%20else%20_y_arr%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_playground_df%20%3D%20pl.DataFrame(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22wavelength_nm%22%3A%20_wl_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%20_y_arr%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22value_plot%22%3A%20_y_plot%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22curve%22%3A%20%5B%22Student%20expression%22%5D%20*%20len(_wl_nm)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_playground_error%20%3D%20f%22%7Btype(e).__name__%7D%3A%20%7Be%7D%22%0A%0A%20%20%20%20w02_playground%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22enabled%22%3A%20bool(w02_params%5B%22playground_enabled%22%5D)%2C%0A%20%20%20%20%20%20%20%20%22error%22%3A%20_playground_error%2C%0A%20%20%20%20%20%20%20%20%22df%22%3A%20_playground_df%2C%0A%20%20%20%20%7D%0A%20%20%20%20return%20(w02_playground%2C)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20jnp%2C%0A%20%20%20%20mzi_circuit%2C%0A%20%20%20%20mzi_circuit_with_gc%2C%0A%20%20%20%20np%2C%0A%20%20%20%20pl%2C%0A%20%20%20%20simphony_error%2C%0A%20%20%20%20w02_params%2C%0A%20%20%20%20w02_spectrum%2C%0A)%3A%0A%20%20%20%20_simphony_selected%20%3D%20w02_params%5B%22view_mode%22%5D%20in%20%5B%0A%20%20%20%20%20%20%20%20%22Simphony%20only%22%2C%0A%20%20%20%20%20%20%20%20%22Overlay%20(analytic%20%2B%20Simphony)%22%2C%0A%20%20%20%20%5D%0A%20%20%20%20_use_gratings%20%3D%20w02_params%5B%22simphony_io%22%5D%20%3D%3D%20%22Include%20grating%20couplers%20(in%20%2B%20out)%22%0A%0A%20%20%20%20_sim_circuit%20%3D%20None%0A%20%20%20%20if%20_simphony_selected%3A%0A%20%20%20%20%20%20%20%20_sim_circuit%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20mzi_circuit_with_gc%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(_use_gratings%20and%20mzi_circuit_with_gc%20is%20not%20None)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20mzi_circuit%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20_wl_min_um%20%3D%20float(w02_spectrum%5B%22wl_min_um%22%5D)%0A%20%20%20%20_wl_max_um%20%3D%20float(w02_spectrum%5B%22wl_max_um%22%5D)%0A%20%20%20%20_n_points%20%3D%20int(w02_spectrum%5B%22n_points%22%5D)%0A%20%20%20%20_semilog%20%3D%20bool(w02_spectrum%5B%22semilog%22%5D)%0A%20%20%20%20_log_floor%20%3D%20float(w02_spectrum%5B%22log_floor%22%5D)%0A%0A%20%20%20%20_simphony_runtime_error%20%3D%20%22%22%0A%20%20%20%20_simphony_plotted%20%3D%20False%0A%20%20%20%20_sim_df%20%3D%20None%0A%0A%20%20%20%20_should_run%20%3D%20bool(w02_params%5B%22run_simphony%22%5D)%20and%20_simphony_selected%0A%0A%20%20%20%20if%20_should_run%20and%20_sim_circuit%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_wl_sim%20%3D%20jnp.linspace(_wl_min_um%2C%20_wl_max_um%2C%20_n_points)%0A%20%20%20%20%20%20%20%20%20%20%20%20_base_length_um%20%3D%20float(w02_params%5B%22base_length_um%22%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20_delta_length_um_effective%20%3D%20float(w02_params%5B%22delta_length_um_effective%22%5D)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20wg_pol%20%3D%20%22te%22%0A%20%20%20%20%20%20%20%20%20%20%20%20wg_width_nm%20%3D%20500.0%0A%20%20%20%20%20%20%20%20%20%20%20%20wg_height_nm%20%3D%20220.0%0A%20%20%20%20%20%20%20%20%20%20%20%20wg_loss%20%3D%200.0%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_pol%20%3D%20%22te%22%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_thickness_nm%20%3D%20220.0%0A%20%20%20%20%20%20%20%20%20%20%20%20gc_dwidth_nm%20%3D%200.0%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20sim_kwargs%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22wl%22%3A%20_wl_sim%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22short_wg%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22length%22%3A%20_base_length_um%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pol%22%3A%20wg_pol%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22width%22%3A%20wg_width_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22height%22%3A%20wg_height_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22loss%22%3A%20wg_loss%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22long_wg%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22length%22%3A%20(_base_length_um%20%2B%20_delta_length_um_effective)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pol%22%3A%20wg_pol%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22width%22%3A%20wg_width_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22height%22%3A%20wg_height_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22loss%22%3A%20wg_loss%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20_use_gratings%20and%20mzi_circuit_with_gc%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20sim_kwargs%5B%22gc_in%22%5D%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pol%22%3A%20gc_pol%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22thickness%22%3A%20gc_thickness_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22dwidth%22%3A%20gc_dwidth_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20sim_kwargs%5B%22gc_out%22%5D%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22pol%22%3A%20gc_pol%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22thickness%22%3A%20gc_thickness_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22dwidth%22%3A%20gc_dwidth_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20S%20%3D%20_sim_circuit(**sim_kwargs)%0A%20%20%20%20%20%20%20%20%20%20%20%20transmission_through%20%3D%20S%5B%22through%22%2C%20%22input%22%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20intensity_through%20%3D%20jnp.abs(transmission_through)%20**%202%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20_wl_nm%20%3D%20np.array(_wl_sim)%20*%201e3%0A%20%20%20%20%20%20%20%20%20%20%20%20intensity_through_np%20%3D%20np.array(intensity_through)%0A%20%20%20%20%20%20%20%20%20%20%20%20sim_value_plot%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20np.clip(intensity_through_np%2C%20_log_floor%2C%20None)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20_semilog%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%20intensity_through_np%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20curve_label%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Through%20(Simphony%2C%20with%20grating%20couplers)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20_use_gratings%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%20%22Through%20(Simphony)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20_sim_df%20%3D%20pl.DataFrame(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22wavelength_nm%22%3A%20_wl_nm%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%20intensity_through_np%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22value_plot%22%3A%20sim_value_plot%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22curve%22%3A%20%5Bcurve_label%5D%20*%20len(_wl_nm)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20_simphony_plotted%20%3D%20True%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20_simphony_runtime_error%20%3D%20f%22%7Btype(e).__name__%7D%3A%20%7Be%7D%22%0A%0A%20%20%20%20_simphony_status%20%3D%20%22%22%0A%20%20%20%20if%20_simphony_selected%3A%0A%20%20%20%20%20%20%20%20if%20not%20_should_run%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_simphony_status%20%3D%20%22Not%20computed%20(enable%20%E2%80%9CCompute%20Simphony%20curve%E2%80%9D)%22%0A%20%20%20%20%20%20%20%20elif%20_sim_circuit%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_simphony_status%20%3D%20f%22Unavailable%3A%20%60%7Bsimphony_error%7D%60%22%0A%20%20%20%20%20%20%20%20elif%20_simphony_runtime_error%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_simphony_status%20%3D%20f%22Runtime%20error%3A%20%60%7B_simphony_runtime_error%7D%60%22%0A%20%20%20%20%20%20%20%20elif%20_simphony_plotted%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_simphony_status%20%3D%20%22OK%20(Simphony%20curve%20computed)%22%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_simphony_status%20%3D%20%22No%20curve%20produced%20(unexpected)%22%0A%0A%20%20%20%20w02_simphony%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22selected%22%3A%20_simphony_selected%2C%0A%20%20%20%20%20%20%20%20%22should_run%22%3A%20_should_run%2C%0A%20%20%20%20%20%20%20%20%22use_gratings%22%3A%20_use_gratings%2C%0A%20%20%20%20%20%20%20%20%22circuit_available%22%3A%20_sim_circuit%20is%20not%20None%2C%0A%20%20%20%20%20%20%20%20%22plotted%22%3A%20_simphony_plotted%2C%0A%20%20%20%20%20%20%20%20%22status%22%3A%20_simphony_status%2C%0A%20%20%20%20%20%20%20%20%22runtime_error%22%3A%20_simphony_runtime_error%2C%0A%20%20%20%20%20%20%20%20%22df%22%3A%20_sim_df%2C%0A%20%20%20%20%20%20%20%20%22import_error%22%3A%20simphony_error%2C%0A%20%20%20%20%7D%0A%20%20%20%20return%20(w02_simphony%2C)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20alt%2C%0A%20%20%20%20controls_ui%2C%0A%20%20%20%20fsr_estimate_nm%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20phase_slope_rad_per_nm%2C%0A%20%20%20%20show_interactive%2C%0A%20%20%20%20w02_analytic%2C%0A%20%20%20%20w02_params%2C%0A%20%20%20%20w02_playground%2C%0A%20%20%20%20w02_simphony%2C%0A%20%20%20%20w02_spectrum%2C%0A)%3A%0A%20%20%20%20from%20_notebook_template%20import%20badge_row%2C%20download_csv_button%0A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%0A%20%20%20%20_wl_center_um%20%3D%20float(w02_spectrum%5B%22wl_center_um%22%5D)%0A%20%20%20%20_wl_min_um%20%3D%20float(w02_spectrum%5B%22wl_min_um%22%5D)%0A%20%20%20%20_wl_max_um%20%3D%20float(w02_spectrum%5B%22wl_max_um%22%5D)%0A%20%20%20%20_semilog%20%3D%20bool(w02_spectrum%5B%22semilog%22%5D)%0A%20%20%20%20_log_floor%20%3D%20float(w02_spectrum%5B%22log_floor%22%5D)%0A%0A%20%20%20%20_analytic_df%20%3D%20w02_analytic%5B%22df%22%5D%0A%0A%20%20%20%20_plot_rows%3A%20list%5Bdict%5D%20%3D%20%5B%5D%0A%20%20%20%20_view_mode%20%3D%20str(w02_params%5B%22view_mode%22%5D)%0A%20%20%20%20if%20_view_mode%20in%20%5B%22Analytic%20only%22%2C%20%22Overlay%20(analytic%20%2B%20Simphony)%22%5D%3A%0A%20%20%20%20%20%20%20%20_plot_rows.extend(_analytic_df.to_dicts())%0A%0A%20%20%20%20if%20w02_playground.get(%22df%22)%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20_plot_rows.extend(w02_playground%5B%22df%22%5D.to_dicts())%0A%0A%20%20%20%20if%20_view_mode%20in%20%5B%22Simphony%20only%22%2C%20%22Overlay%20(analytic%20%2B%20Simphony)%22%5D%3A%0A%20%20%20%20%20%20%20%20if%20w02_simphony.get(%22df%22)%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_plot_rows.extend(w02_simphony%5B%22df%22%5D.to_dicts())%0A%0A%20%20%20%20_base_length_um%20%3D%20float(w02_params%5B%22base_length_um%22%5D)%0A%20%20%20%20_delta_length_um%20%3D%20float(w02_params%5B%22delta_length_um_effective%22%5D)%0A%20%20%20%20_short_length_mm%20%3D%20_base_length_um%20%2F%201e3%0A%20%20%20%20_long_length_mm%20%3D%20(_base_length_um%20%2B%20_delta_length_um)%20%2F%201e3%0A%0A%20%20%20%20fsr_nm%20%3D%20fsr_estimate_nm(%0A%20%20%20%20%20%20%20%20wl0_um%3D_wl_center_um%2C%20ng%3Dfloat(w02_params%5B%22n_g%22%5D)%2C%20delta_length_um%3D_delta_length_um%0A%20%20%20%20)%0A%20%20%20%20phase_slope_est_rad_per_nm%20%3D%20phase_slope_rad_per_nm(%0A%20%20%20%20%20%20%20%20wl0_um%3D_wl_center_um%2C%20ng%3Dfloat(w02_params%5B%22n_g%22%5D)%2C%20delta_length_um%3D_delta_length_um%0A%20%20%20%20)%0A%0A%20%20%20%20fringes_est%20%3D%20None%0A%20%20%20%20if%20fsr_nm%20is%20not%20None%20and%20fsr_nm%20%3E%200%3A%0A%20%20%20%20%20%20%20%20fringes_est%20%3D%20float(w02_params%5B%22spectrum_span_nm%22%5D)%20%2F%20fsr_nm%0A%0A%20%20%20%20download_button%20%3D%20mo.md(%22%22)%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20download_button%20%3D%20download_csv_button(%0A%20%20%20%20%20%20%20%20%20%20%20%20mo%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20_plot_rows%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20filename%3D%22mzi_spectrum.csv%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20label%3D%22Download%20CSV%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20preferred_fields%3D%5B%22wavelength_nm%22%2C%20%22value%22%2C%20%22value_plot%22%2C%20%22curve%22%5D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20except%20Exception%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20download_button%20%3D%20mo.md(%22%22)%0A%0A%20%20%20%20_sim_requested%20%3D%20_view_mode%20in%20%5B%22Simphony%20only%22%2C%20%22Overlay%20(analytic%20%2B%20Simphony)%22%5D%0A%0A%20%20%20%20status_badges_list%20%3D%20%5B%0A%20%20%20%20%20%20%20%20f%22%CE%94L%20%3D%20%3Cstrong%3E%7B_delta_length_um%3A.1f%7D%20%C2%B5m%3C%2Fstrong%3E%22%2C%0A%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22FSR%20%E2%89%88%20%3Cstrong%3E%7Bfsr_nm%3A.2f%7D%20nm%3C%2Fstrong%3E%22%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20fsr_nm%20is%20not%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20%22FSR%3A%20%3Cstrong%3E(%CE%94L%20%3D%200)%3C%2Fstrong%3E%22%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%5D%0A%20%20%20%20if%20phase_slope_est_rad_per_nm%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20status_badges_list.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22%7Cd%CE%94%CF%86%2Fd%CE%BB%7C%40%CE%BB0%20%E2%89%88%20%3Cstrong%3E%7Bphase_slope_est_rad_per_nm%3A.2f%7D%20rad%2Fnm%3C%2Fstrong%3E%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20status_badges_list.append(%0A%20%20%20%20%20%20%20%20f%22span%20%3D%20%3Cstrong%3E%7Bfloat(w02_params%5B'spectrum_span_nm'%5D)%3A.0f%7D%20nm%3C%2Fstrong%3E%22%0A%20%20%20%20)%0A%20%20%20%20if%20fringes_est%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20status_badges_list.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22~%20fringes%20in%20view%20%E2%89%88%20%3Cstrong%3E%7Bfringes_est%3A.1f%7D%3C%2Fstrong%3E%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20status_badges_list.extend(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22View%3A%20%3Cstrong%3E%7B_view_mode%7D%3C%2Fstrong%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22Update%3A%20%3Cstrong%3E%7B'Live'%20if%20w02_params%5B'live_update'%5D%20else%20'Apply'%7D%3C%2Fstrong%3E%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Simphony%3A%20%3Cstrong%3E%7Bw02_simphony.get('status'%2C'')%7D%3C%2Fstrong%3E%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20_sim_requested%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%20%22Simphony%3A%20%3Cstrong%3E(not%20requested)%3C%2Fstrong%3E%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20status_badges%20%3D%20badge_row(%0A%20%20%20%20%20%20%20%20mo%2C%20status_badges_list%2C%20style%3D%22margin%3A%200.35rem%200%200.25rem%200%3B%22%0A%20%20%20%20)%0A%0A%20%20%20%20if%20_view_mode%20%3D%3D%20%22Simphony%20only%22%20and%20not%20w02_simphony.get(%22plotted%22%2C%20False)%3A%0A%20%20%20%20%20%20%20%20_reason_lines%3A%20list%5Bstr%5D%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20if%20not%20w02_simphony.get(%22should_run%22%2C%20False)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_reason_lines.append(%22Status%3A%20**Not%20computed**%20(Compute%20Simphony%20curve%20is%20off).%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20_reason_lines.append(%22Fix%3A%20enable%20**Compute%20Simphony%20curve**%20under%20Controls.%22)%0A%20%20%20%20%20%20%20%20elif%20not%20w02_simphony.get(%22circuit_available%22%2C%20False)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_reason_lines.append(%22Status%3A%20**Unavailable**%20(Simphony%2FSAX%20circuit%20not%20available%20here).%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20_reason_lines.append(f%22Details%3A%20%60%7Bw02_simphony.get('import_error'%2C'')%7D%60%22)%0A%20%20%20%20%20%20%20%20elif%20w02_simphony.get(%22runtime_error%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_reason_lines.append(%22Status%3A%20**Runtime%20error**%20during%20circuit%20evaluation.%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20_reason_lines.append(f%22Details%3A%20%60%7Bw02_simphony.get('runtime_error'%2C'')%7D%60%22)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_reason_lines.append(%22Status%3A%20**No%20curve%20produced**%20(unexpected).%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20_reason_lines.append(%22Fix%3A%20try%20toggling%20**Compute%20Simphony%20curve**%20off%2Fon%20and%20re-run.%22)%0A%0A%20%20%20%20%20%20%20%20chart_out%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22**Simphony-only%20view%3A**%20no%20Simphony%20curve%20to%20display.%5Cn%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%5Cn%22.join(f%22-%20%7Bline%7D%22%20for%20line%20in%20_reason_lines)%0A%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%5Cn%5CnTip%3A%20switch%20to%20**Overlay**%20to%20compare%20with%20the%20analytic%20curve.%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20if%20not%20_plot_rows%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_plot_rows.extend(_analytic_df.to_dicts())%0A%0A%20%20%20%20%20%20%20%20y_scale_obj%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20alt.Scale(type%3D%22log%22%2C%20domain%3D%5B_log_floor%2C%201%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20_semilog%0A%20%20%20%20%20%20%20%20%20%20%20%20else%20alt.Scale(domain%3D%5B0%2C%201%5D)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20y_field%20%3D%20%22value_plot%22%20if%20_semilog%20else%20%22value%22%0A%20%20%20%20%20%20%20%20chart%20%3D%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20alt.Chart(alt.Data(values%3D_plot_rows))%0A%20%20%20%20%20%20%20%20%20%20%20%20.mark_line(point%3DTrue)%0A%20%20%20%20%20%20%20%20%20%20%20%20.encode(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3Dalt.X(%22wavelength_nm%22%2C%20type%3D%22quantitative%22%2C%20title%3D%22Wavelength%20(nm)%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3Dalt.Y(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y_field%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20type%3D%22quantitative%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22Through%20power%20(log%20scale)%22%20if%20_semilog%20else%20%22Through%20power%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20scale%3Dy_scale_obj%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20color%3Dalt.Color(%22curve%22%2C%20type%3D%22nominal%22%2C%20title%3D%22Curve%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tooltip%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alt.Tooltip(%22wavelength_nm%22%2C%20type%3D%22quantitative%22%2C%20title%3D%22Wavelength%20(nm)%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alt.Tooltip(%22value%22%2C%20type%3D%22quantitative%22%2C%20title%3D%22Through%20power%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20alt.Tooltip(%22curve%22%2C%20type%3D%22nominal%22%2C%20title%3D%22Curve%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20).properties(title%3D%22MZI%20transfer%20function%22%2C%20width%3D500%2C%20height%3D250).interactive()%0A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20chart_out%20%3D%20mo.ui.altair_chart(chart)%20if%20hasattr(mo.ui%2C%20%22altair_chart%22)%20else%20chart%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20chart_out%20%3D%20mo.md(f%22**Plot%20render%20error%3A**%20%60%7Btype(e).__name__%7D%3A%20%7Be%7D%60%22)%0A%0A%20%20%20%20simphony_help%20%3D%20mo.md(%22%22)%0A%0A%20%20%20%20if%20w02_params.get(%22preset_active%22)%20and%20abs(%0A%20%20%20%20%20%20%20%20float(w02_params%5B%22delta_length_um_slider%22%5D)%20-%20float(w02_params%5B%22delta_length_um_effective%22%5D)%0A%20%20%20%20)%20%3E%201e-9%3A%0A%20%20%20%20%20%20%20%20preset_note%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22**%CE%94L%20preset%20active%3A**%20using%20**%CE%94L%20%3D%20%7Bfloat(w02_params%5B'delta_length_um_effective'%5D)%3A.1f%7D%20%C2%B5m**%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22(slider%20shows%20%7Bfloat(w02_params%5B'delta_length_um_slider'%5D)%3A.1f%7D%20%C2%B5m).%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20preset_note%20%3D%20mo.md(%22%22)%0A%0A%20%20%20%20playground_error%20%3D%20(%0A%20%20%20%20%20%20%20%20mo.md(f%22**Playground%20error%3A**%20%60%7Bw02_playground%5B'error'%5D%7D%60%22)%0A%20%20%20%20%20%20%20%20if%20w02_playground.get(%22error%22)%0A%20%20%20%20%20%20%20%20else%20mo.md(%22%22)%0A%20%20%20%20)%0A%0A%20%20%20%20mo.vstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20chart_out%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20status_badges%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20download_button%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20preset_note%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20playground_error%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20controls_ui%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22**Next%3A**%20scroll%20down%20for%20the%20**FSR%20measurement%20tool**.%22)%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_interactive)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20from%20_notebook_template%20import%20make_fsr_tool_widgets%0A%0A%20%20%20%20auto_source%2C%20lam1_nm%2C%20lam2_nm%2C%20lam1_state%2C%20lam2_state%2C%20set_lam1%2C%20set_lam2%20%3D%20(%0A%20%20%20%20%20%20%20%20make_fsr_tool_widgets(mo)%0A%20%20%20%20)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20auto_source%2C%0A%20%20%20%20%20%20%20%20lam1_nm%2C%0A%20%20%20%20%20%20%20%20lam1_state%2C%0A%20%20%20%20%20%20%20%20lam2_nm%2C%0A%20%20%20%20%20%20%20%20lam2_state%2C%0A%20%20%20%20%20%20%20%20set_lam1%2C%0A%20%20%20%20%20%20%20%20set_lam2%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20auto_fsr_from_curve%2C%0A%20%20%20%20auto_source%2C%0A%20%20%20%20doc_callout_html%2C%0A%20%20%20%20fsr_estimate_nm%2C%0A%20%20%20%20lam1_nm%2C%0A%20%20%20%20lam1_state%2C%0A%20%20%20%20lam2_nm%2C%0A%20%20%20%20lam2_state%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20phase_slope_rad_per_nm%2C%0A%20%20%20%20set_lam1%2C%0A%20%20%20%20set_lam2%2C%0A%20%20%20%20show_interactive%2C%0A%20%20%20%20w02_analytic%2C%0A%20%20%20%20w02_params%2C%0A%20%20%20%20w02_playground%2C%0A%20%20%20%20w02_simphony%2C%0A)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20wl0_um%20%3D%20float(w02_params%5B%22wl0_um%22%5D)%0A%20%20%20%20ng_for_fsr_tool%20%3D%20float(w02_params%5B%22n_g%22%5D)%0A%20%20%20%20dL_um%20%3D%20float(w02_params%5B%22delta_length_um_effective%22%5D)%0A%20%20%20%20dL_slider_um%20%3D%20float(w02_params%5B%22delta_length_um_slider%22%5D)%0A%20%20%20%20_preset_active%20%3D%20bool(w02_params%5B%22preset_active%22%5D)%0A%0A%20%20%20%20fsr_est_nm%20%3D%20fsr_estimate_nm(wl0_um%3Dwl0_um%2C%20ng%3Dng_for_fsr_tool%2C%20delta_length_um%3DdL_um)%0A%0A%20%20%20%20measured%20%3D%20None%0A%20%20%20%20error_pct%20%3D%20None%0A%20%20%20%20delta_phi_est_rad%20%3D%20None%0A%20%20%20%20delta_phi_est_cycles%20%3D%20None%0A%20%20%20%20parse_error%20%3D%20%22%22%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20if%20lam1_state().strip()%20and%20lam2_state().strip()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20l1%20%3D%20float(lam1_state())%0A%20%20%20%20%20%20%20%20%20%20%20%20l2%20%3D%20float(lam2_state())%0A%20%20%20%20%20%20%20%20%20%20%20%20measured%20%3D%20abs(l2%20-%20l1)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20dL_um%20%3E%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fsr_tool_phase_slope%20%3D%20phase_slope_rad_per_nm(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20wl0_um%3Dwl0_um%2C%20ng%3Dng_for_fsr_tool%2C%20delta_length_um%3DdL_um%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20fsr_tool_phase_slope%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fsr_tool_two_pi%20%3D%206.283185307179586%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20delta_phi_est_rad%20%3D%20float(fsr_tool_phase_slope%20*%20measured)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20delta_phi_est_cycles%20%3D%20float(delta_phi_est_rad%20%2F%20fsr_tool_two_pi)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20fsr_est_nm%20is%20not%20None%20and%20fsr_est_nm%20%3E%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20error_pct%20%3D%20100.0%20*%20(measured%20-%20fsr_est_nm)%20%2F%20fsr_est_nm%0A%20%20%20%20except%20Exception%20as%20e%3A%0A%20%20%20%20%20%20%20%20parse_error%20%3D%20f%22%7Btype(e).__name__%7D%3A%20%7Be%7D%22%0A%0A%20%20%20%20def%20_curve_df(source%3A%20str)%3A%0A%20%20%20%20%20%20%20%20if%20source%20%3D%3D%20%22Analytic%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20w02_analytic.get(%22df%22)%2C%20%22%22%0A%20%20%20%20%20%20%20%20if%20source%20%3D%3D%20%22Simphony%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20bool(w02_simphony.get(%22plotted%22%2C%20False))%20or%20w02_simphony.get(%22df%22)%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20None%2C%20%22Simphony%20curve%20not%20available%20(compute%20it%20first%2C%20or%20switch%20view).%22%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20w02_simphony%5B%22df%22%5D%2C%20%22%22%0A%20%20%20%20%20%20%20%20if%20source%20%3D%3D%20%22Student%20expression%22%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20not%20bool(w02_playground.get(%22enabled%22%2C%20False))%20or%20w02_playground.get(%22df%22)%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20None%2C%20%22Student%20expression%20curve%20not%20available%20(enable%20the%20playground).%22%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20w02_playground%5B%22df%22%5D%2C%20%22%22%0A%20%20%20%20%20%20%20%20return%20None%2C%20%22Unknown%20source.%22%0A%0A%20%20%20%20auto_choice%20%3D%20str(auto_source.value)%0A%20%20%20%20if%20auto_choice%20%3D%3D%20%22Best%20available%22%3A%0A%20%20%20%20%20%20%20%20if%20bool(w02_simphony.get(%22plotted%22%2C%20False))%20and%20w02_simphony.get(%22df%22)%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20auto_choice%20%3D%20%22Simphony%22%0A%20%20%20%20%20%20%20%20elif%20bool(w02_playground.get(%22enabled%22%2C%20False))%20and%20w02_playground.get(%22df%22)%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20auto_choice%20%3D%20%22Student%20expression%22%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20auto_choice%20%3D%20%22Analytic%22%0A%0A%20%20%20%20auto_df%2C%20auto_df_error%20%3D%20_curve_df(auto_choice)%0A%20%20%20%20auto_result%20%3D%20None%0A%20%20%20%20if%20auto_df%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20wl_nm%20%3D%20auto_df.get_column(%22wavelength_nm%22).to_numpy()%0A%20%20%20%20%20%20%20%20%20%20%20%20y%20%3D%20auto_df.get_column(%22value%22).to_numpy()%0A%20%20%20%20%20%20%20%20%20%20%20%20auto_result%20%3D%20auto_fsr_from_curve(wl_nm%3Dwl_nm%2C%20y%3Dy%2C%20wl0_nm%3Dfloat(wl0_um%20*%201e3))%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20auto_df_error%20%3D%20f%22%7Btype(e).__name__%7D%3A%20%7Be%7D%22%0A%0A%20%20%20%20fsr_tool_blocks%20%3D%20%5B%0A%20%20%20%20%20%20%20%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22exercise%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20tag%3D%22Tool%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3D%22Measure%20the%20FSR%20from%20the%20plot%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20html%3Dr%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20Hover%20a%20curve%20to%20read%20wavelengths%20from%20the%20tooltip.%20Enter%20two%20%3Cem%3Eadjacent%20maxima%3C%2Fem%3E%20wavelengths%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20(in%20nm)%20below%3B%20the%20tool%20computes%20the%20measured%20FSR%20and%20compares%20it%20to%20the%20rule-of-thumb%20estimate%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20shown%20below.%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20mo.md(r%22Rule-of-thumb%3A%20%24%5Cmathrm%7BFSR%7D%20%5Capprox%20%5Clambda_0%5E2%2F(n_g%5C%2C%5CDelta%20L)%24.%22)%2C%0A%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Derivation%20link%3A%20an%20FSR%20is%20the%20%CE%94%CE%BB%20that%20makes%20the%20relative%20phase%20change%20by%20**2%CF%80**%20near%20%CE%BB0.%22%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22Using%3A%20**%CE%94L%20%3D%20%7BdL_um%3A.2f%7D%20%C2%B5m**%20(effective)%2C%20**%CE%BB0%20%3D%20%7Bwl0_um*1e3%3A.1f%7D%20nm**%2C%20**ng%20%3D%20%7Bng_for_fsr_tool%3A.2f%7D**.%22%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20mo.hstack(%5Bauto_source%5D)%2C%0A%20%20%20%20%5D%0A%20%20%20%20if%20_preset_active%20and%20abs(dL_slider_um%20-%20dL_um)%20%3E%201e-9%3A%0A%20%20%20%20%20%20%20%20fsr_tool_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22**Note%3A**%20a%20%CE%94L%20preset%20is%20active%2C%20so%20the%20%CE%94L%20slider%20is%20ignored%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22(slider%20shows%20%7BdL_slider_um%3A.2f%7D%20%C2%B5m).%20Set%20*Parameter%20preset*%20to%20**Custom**%20to%20use%20the%20slider.%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20if%20auto_df_error%3A%0A%20%20%20%20%20%20%20%20fsr_tool_blocks.append(mo.md(f%22**Auto-measure%20(%7Bauto_choice%7D)%3A**%20%7Bauto_df_error%7D%22))%0A%20%20%20%20elif%20isinstance(auto_result%2C%20dict)%20and%20bool(auto_result.get(%22ok%22%2C%20False))%3A%0A%20%20%20%20%20%20%20%20_a1%20%3D%20float(auto_result%5B%22lam1_nm%22%5D)%0A%20%20%20%20%20%20%20%20_a2%20%3D%20float(auto_result%5B%22lam2_nm%22%5D)%0A%20%20%20%20%20%20%20%20_afsr%20%3D%20float(auto_result%5B%22fsr_nm%22%5D)%0A%20%20%20%20%20%20%20%20use_auto%20%3D%20mo.ui.button(%0A%20%20%20%20%20%20%20%20%20%20%20%20value%3D0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20kind%3D%22neutral%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20label%3Df%22Use%20auto%20peaks%20(%CE%BB1%3D%7B_a1%3A.2f%7D%20nm%2C%20%CE%BB2%3D%7B_a2%3A.2f%7D%20nm)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20on_click%3Dlambda%20v%3A%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20set_lam1(f%22%7B_a1%3A.2f%7D%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20set_lam2(f%22%7B_a2%3A.2f%7D%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(v%20or%200)%20%2B%201%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%5B-1%5D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20fsr_tool_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22**Auto-measured%20FSR%20(%7Bauto_choice%7D%2C%20%7Bint(auto_result.get('n_peaks'%2C0))%7D%20peaks%20found)%3A**%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22**%7B_afsr%3A.2f%7D%20nm**%22%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20fsr_tool_blocks.append(use_auto)%0A%20%20%20%20elif%20isinstance(auto_result%2C%20dict)%3A%0A%20%20%20%20%20%20%20%20fsr_tool_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(f%22**Auto-measure%20(%7Bauto_choice%7D)%3A**%20%7Bauto_result.get('message'%2C'Could%20not%20measure.')%7D%22)%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20fsr_tool_blocks.append(mo.hstack(%5Blam1_nm%2C%20lam2_nm%5D))%0A%0A%20%20%20%20if%20parse_error%3A%0A%20%20%20%20%20%20%20%20fsr_tool_blocks.append(mo.md(f%22**Parse%20error%3A**%20%60%7Bparse_error%7D%60%22))%0A%20%20%20%20elif%20fsr_est_nm%20is%20None%3A%0A%20%20%20%20%20%20%20%20fsr_tool_blocks.append(mo.md(%22Estimated%20FSR%3A%20**(%CE%94L%20%3D%200%20%E2%86%92%20no%20fringes)**%22))%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20fsr_tool_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.md(f%22Estimated%20ideal%20FSR%20(using%20ng)%3A%20**%7Bfsr_est_nm%3A.2f%7D%20nm**%22)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20if%20measured%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20fsr_tool_blocks.append(mo.md(f%22Measured%20FSR%3A%20**%7Bmeasured%3A.2f%7D%20nm**%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20delta_phi_est_rad%20is%20not%20None%20and%20delta_phi_est_cycles%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fsr_tool_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Phase%20change%20estimate%20near%20%CE%BB0%3A%20**%CE%94%CF%86%20%E2%89%88%20%7Bdelta_phi_est_rad%3A.2f%7D%20rad**%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22(%E2%89%88%20**%7Bdelta_phi_est_cycles%3A.2f%7D%C3%972%CF%80**)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20error_pct%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fsr_tool_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(f%22Percent%20difference%20vs%20estimate%3A%20**%7Berror_pct%3A%2B.1f%7D%25**%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20abs(error_pct)%20%3E%2025%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20fsr_tool_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22**Tip%3A**%20if%20you%20changed%20%CE%94L%20or%20the%20view%20mode%2C%20re-pick%20%CE%BB1%20and%20%CE%BB2%20from%20the%20*current*%20plot%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22(old%20values%20often%20produce%20a%20mismatch).%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20fsr_tool_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22Enter%20%60%CE%BB1%60%20and%20%60%CE%BB2%60%20to%20compute%20the%20measured%20FSR.%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20fsr_tool_view%20%3D%20mo.vstack(%5Bmo.md(%22%23%23%23%20FSR%20measurement%20tool%22)%5D%20%2B%20fsr_tool_blocks)%0A%20%20%20%20fsr_tool_view%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_interactive)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20task_fsr%20%3D%20mo.ui.checkbox(label%3D%22Measured%20FSR%20for%20two%20%CE%94L%20values%22%2C%20value%3DFalse)%0A%20%20%20%20task_compare%20%3D%20mo.ui.checkbox(label%3D%22Compared%20Analytic%20vs%20Simphony%20(Overlay)%22%2C%20value%3DFalse)%0A%20%20%20%20task_export%20%3D%20mo.ui.checkbox(label%3D%22Downloaded%20CSV%20(and%2For%20exported%20GDS)%22%2C%20value%3DFalse)%0A%20%20%20%20return%20task_compare%2C%20task_export%2C%20task_fsr%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20doc_callout_html%2C%0A%20%20%20%20doc_callout_list%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20show_interactive%2C%0A%20%20%20%20task_compare%2C%0A%20%20%20%20task_export%2C%0A%20%20%20%20task_fsr%2C%0A)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22info%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Key%20ideas%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22What%20you%20should%20learn%20from%20the%20plot%22%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3EInterference%3A%3C%2Fstrong%3E%20the%20output%20power%20oscillates%20because%20the%20two%20arms%20recombine%20with%20a%20phase%20difference%20%CE%94%CF%86.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3E%CE%94L%20sets%20the%20fringe%20spacing%3A%3C%2Fstrong%3E%20increasing%20%CE%94L%20makes%20fringes%20get%20closer%20together%20(smaller%20FSR).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3En%3Csub%3Eeff%3C%2Fsub%3E%20vs%20n%3Csub%3Eg%3C%2Fsub%3E%3A%3C%2Fstrong%3E%20phase%20uses%20an%20effective%20index%2C%20but%20FSR%20depends%20on%20group%20index%20(dispersion%20matters).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3EWhy%20two%20curves%3A%3C%2Fstrong%3E%20analytic%20is%20an%20idealized%20model%3B%20Simphony%2FSAX%20assembles%20wavelength-dependent%20compact%20models.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%20%20%20%20mo.md(%22%23%23%23%20Checklist%20(before%20moving%20on)%22)%0A%20%20%20%20mo.vstack(%5Btask_fsr%2C%20task_compare%2C%20task_export%5D)%0A%0A%20%20%20%20doc_callout_html(%0A%20%20%20%20%20%20%20%20%22exercise%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Checkpoint%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Record%20your%20results%22%2C%0A%20%20%20%20%20%20%20%20html%3D%22%22%22%0A%20%20%20%20%20%20%20%20%3Cp%3EFill%20in%20the%20table%20below%20(copy%20into%20your%20lab%20notes).%20Use%20the%20tool%20above%20to%20measure%20FSR%20from%20two%20adjacent%20maxima.%3C%2Fp%3E%0A%20%20%20%20%20%20%20%20%22%22%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20%7C%20Case%20%7C%20%CE%94L%20(%C2%B5m)%20%7C%20ng%20%7C%20%CE%BB0%20(nm)%20%7C%20Estimated%20FSR%20(nm)%20%7C%20Measured%20FSR%20(nm)%20%7C%20%25%20difference%20%7C%0A%20%20%20%20%20%20%20%20%7C---%7C---%3A%7C---%3A%7C---%3A%7C---%3A%7C---%3A%7C---%3A%7C%0A%20%20%20%20%20%20%20%20%7C%20A%20(default)%20%7C%2010%20%7C%204.19%20%7C%201550%20%7C%20%20%7C%20%20%7C%20%20%7C%0A%20%20%20%20%20%20%20%20%7C%20B%20(your%20choice)%20%7C%20%20%7C%20%20%7C%20%20%7C%20%20%7C%20%20%7C%20%20%7C%0A%0A%20%20%20%20%20%20%20%20%3Csmall%3ETip%3A%20if%20a%20%CE%94L%20preset%20is%20active%2C%20the%20notebook%20uses%20the%20**effective%20%CE%94L**%20shown%20in%20the%20tool%20readout%20(not%20the%20slider%20value).%3C%2Fsmall%3E%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%0A%20%20%20%20doc_callout_list(%0A%20%20%20%20%20%20%20%20%22warning%22%2C%0A%20%20%20%20%20%20%20%20tag%3D%22Common%20mistakes%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Debugging%20%E2%80%9Cmy%20FSR%20doesn%E2%80%99t%20match%E2%80%9D%22%2C%0A%20%20%20%20%20%20%20%20items%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3EPreset%20override%3A%3C%2Fstrong%3E%20if%20a%20%CE%94L%20preset%20is%20active%2C%20moving%20the%20%CE%94L%20slider%20won%E2%80%99t%20change%20the%20plot%E2%80%94set%20%3Cem%3EParameter%20preset%20%E2%86%92%20Custom%3C%2Fem%3E.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3EStale%20%CE%BB1%2F%CE%BB2%3A%3C%2Fstrong%3E%20if%20you%20change%20%CE%94L%2C%20%CE%BB0%2C%20ng%2C%20or%20View%20mode%2C%20re-pick%20new%20adjacent%20maxima%3B%20old%20values%20won%E2%80%99t%20match.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3Eng%20vs%20neff%3A%3C%2Fstrong%3E%20%3Ccode%3En_g%3C%2Fcode%3E%20sets%20fringe%20spacing%20(FSR)%3B%20%3Ccode%3En_eff(%CE%BB0)%3C%2Fcode%3E%20sets%20phase%20offset.%20Don%E2%80%99t%20expect%20them%20to%20do%20the%20same%20thing.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cstrong%3ESimphony%20availability%3A%3C%2Fstrong%3E%20if%20Simphony%20is%20unavailable%20or%20errors%2C%20Overlay%20won%E2%80%99t%20show%20a%20second%20curve%E2%80%94check%20the%20%3Cem%3ESimphony%3A%3C%2Fem%3E%20status%20in%20the%20Model%20panel.%22%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_interactive)%3A%0A%20%20%20%20mo.stop(not%20show_interactive)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Guided%20exploration%0A%0A%20%20%20%20Try%20adjusting%20the%20sliders%20above%20and%20observe%20how%20the%20spectrum%20changes%3A%0A%0A%20%20%20%20-%20**Increase%20%CE%94L**%3A%20what%20happens%20to%20the%20fringe%20spacing%20(FSR)%3F%0A%20%20%20%20-%20**Change%20base%20arm%20length**%3A%20does%20this%20change%20the%20fringe%20spacing%20in%20a%20lossless%20model%3F%0A%0A%20%20%20%20You%20can%20think%20ahead%20to%20fabrication%3A%20base%20arm%20length%20affects%20footprint%20(and%20later%2C%20loss).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_layout_section%2C%20w02_params)%3A%0A%20%20%20%20mo.stop(not%20show_layout_section)%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20r%22%22%22%0A%20%20%20%20%20%20%20%20%23%23%23%20Connecting%20model%20and%20layout%0A%0A%20%20%20%20%20%20%20%20In%20the%20analytic%20model%2C%20the%20key%20parameter%20is%20the%20**path%20length%20difference**%20%CE%94L%20between%20the%20two%20arms.%0A%20%20%20%20%20%20%20%20In%20layout%2C%20%CE%94L%20corresponds%20to%20the%20extra%20physical%20length%20you%20route%20into%20one%20arm%20of%20the%20interferometer.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20_delta_length_um_effective%20%3D%20float(w02_params%5B%22delta_length_um_effective%22%5D)%0A%20%20%20%20if%20bool(w02_params%5B%22preset_active%22%5D)%3A%0A%20%20%20%20%20%20%20%20_deltaL_note%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22Analytic%20model%20currently%20uses%20%CE%94L%20%3D%20**%7B_delta_length_um_effective%3A.1f%7D%20%C2%B5m**%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22(preset%20overrides%20slider%3A%20%7Bfloat(w02_params%5B'delta_length_um_slider'%5D)%3A.1f%7D%20%C2%B5m).%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20_deltaL_note%20%3D%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22Analytic%20model%20currently%20uses%20%CE%94L%20%3D%20**%7B_delta_length_um_effective%3A.1f%7D%20%C2%B5m**.%22%0A%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20_deltaL_note%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_layout_section)%3A%0A%20%20%20%20mo.stop(not%20show_layout_section)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%3Ca%20id%3D%22layout%22%3E%3C%2Fa%3E%0A%20%20%20%20%23%23%20From%20model%20to%20layout%3A%20gdsfactory%0A%0A%20%20%20%20The%20interactive%20plot%20above%20can%20show%20**two%20different%20curves**%20(choose%20*View%20%E2%86%92%20Overlay*)%3A%0A%0A%20%20%20%20-%20**Analytic%20curve%3A**%20our%20%E2%80%9Cby-hand%E2%80%9D%20ideal%20model%2C%20derived%20from%20interference%20and%20a%20simple%20phase%20term.%0A%20%20%20%20-%20**Simphony%20curve%3A**%20a%20**circuit%20simulation**%20assembled%20from%20**component%20models**%20(compact%20models)%20using%20SAX.%0A%0A%20%20%20%20In%20the%20Simphony%20view%2C%20the%20MZI%20isn%E2%80%99t%20%E2%80%9Cdrawn%E2%80%9D%20%E2%80%94%20it%E2%80%99s%20built%20from%20*building%20blocks*%20(splitter%2C%20waveguides%2C%20combiner)%2C%0A%20%20%20%20where%20each%20block%20has%20a%20wavelength-dependent%20response%20(often%20represented%20as%20an%20**S-matrix**).%20SAX%20connects%20these%0A%20%20%20%20blocks%20according%20to%20a%20netlist%20and%20computes%20the%20overall%20response.%0A%0A%20%20%20%20**So%20where%20does%20gdsfactory%20fit%3F**%0A%0A%20%20%20%20gdsfactory%20is%20our%20layout%20engine%3A%20it%20builds%20**geometry**%20(Components%20with%20ports%20and%20waveguides)%20and%20exports%20**GDS**.%0A%20%20%20%20In%20this%20notebook%2C%20gdsfactory%20appears%20here%20as%20a%20transition%3A%20you%E2%80%99ve%20modelled%20an%20MZI%E2%80%99s%20behavior%2C%20and%20next%20you%E2%80%99ll%0A%20%20%20%20learn%20how%20to%20*realize*%20an%20MZI%20in%20layout%20with%20the%20right%20ports%2C%20routing%2C%20and%20parameter%20control.%0A%0A%20%20%20%20This%20section%20builds%20a%20simple%20example%20MZI%20layout%20using%20%60gf.components.mzi(...)%60%20and%20shows%20an%20SVG%20preview%20inside%20marimo%20when%20possible.%20You%20can%20also%20export%20a%20GDS%20file%20for%20inspection%20in%20KLayout.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_layout_section)%3A%0A%20%20%20%20mo.stop(not%20show_layout_section)%0A%20%20%20%20show_layout%20%3D%20mo.ui.checkbox(label%3D%22Show%20layout%20preview%22%2C%20value%3DTrue)%0A%20%20%20%20gds_out%20%3D%20mo.ui.text(%0A%20%20%20%20%20%20%20%20value%3D%22marimo_course%2Fbuild%2Fweek2_mzi_example.gds%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22GDS%20output%20path%22%2C%0A%20%20%20%20)%0A%20%20%20%20export_gds%20%3D%20mo.ui.button(%0A%20%20%20%20%20%20%20%20value%3D0%2C%0A%20%20%20%20%20%20%20%20on_click%3Dlambda%20v%3A%20(v%20or%200)%20%2B%201%2C%0A%20%20%20%20%20%20%20%20kind%3D%22success%22%2C%0A%20%20%20%20%20%20%20%20label%3D%22Write%20GDS%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20export_gds%2C%20gds_out%2C%20show_layout%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Path%2C%0A%20%20%20%20b64%2C%0A%20%20%20%20delta_length_um_effective%2C%0A%20%20%20%20export_gds%2C%0A%20%20%20%20gds_out%2C%0A%20%20%20%20gf%2C%0A%20%20%20%20gf_import_error%2C%0A%20%20%20%20mo%2C%0A%20%20%20%20show_layout%2C%0A%20%20%20%20show_layout_section%2C%0A)%3A%0A%20%20%20%20mo.stop(not%20show_layout_section)%0A%20%20%20%20layout_blocks%20%3D%20%5B%5D%0A%0A%20%20%20%20c%20%3D%20None%0A%20%20%20%20build_error%20%3D%20%22%22%0A%20%20%20%20if%20gf%20is%20None%3A%0A%20%20%20%20%20%20%20%20layout_blocks.append(mo.md(%22%60gdsfactory%60%20is%20not%20available%20in%20this%20environment.%22))%0A%20%20%20%20%20%20%20%20if%20gf_import_error%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20layout_blocks.append(mo.md(f%22Details%3A%20%60%7Bgf_import_error%7D%60%22))%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20c%20%3D%20gf.components.mzi(delta_length%3Dfloat(delta_length_um_effective))%0A%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20build_error%20%3D%20f%22%7Btype(e).__name__%7D%3A%20%7Be%7D%22%0A%0A%20%20%20%20%20%20%20%20if%20c%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20layout_blocks.append(mo.md(f%22(Could%20not%20build%20%60gf.components.mzi%60%3A%20%60%7Bbuild_error%7D%60)%22))%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20show_layout.value%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20svg%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20hasattr(gf%2C%20%22export%22)%20and%20hasattr(gf.export%2C%20%22to_svg%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20svg%20%3D%20gf.export.to_svg(c)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20except%20Exception%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20svg%20%3D%20None%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20isinstance(svg%2C%20str)%20and%20%22%3Csvg%22%20in%20svg%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20svg_b64%20%3D%20b64.b64encode(svg.encode(%22utf-8%22)).decode(%22ascii%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layout_blocks.extend(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22%23%23%23%20Layout%20preview%22)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cdiv%20style%3D'max-width%3A100%25%3B%20overflow%3Aauto%3B'%3E%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22%3Cimg%20src%3D'data%3Aimage%2Fsvg%2Bxml%3Bbase64%2C%7Bsvg_b64%7D'%20style%3D'max-width%3A100%25%3B%20height%3Aauto%3B'%2F%3E%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3C%2Fdiv%3E%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layout_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22(Preview%20unavailable%20in%20this%20environment%3B%20SVG%20export%20was%20not%20available.)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20export_gds.value%20and%20export_gds.value%20%3E%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20out_path%20%3D%20Path(gds_out.value).expanduser()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20out_path.parent.mkdir(parents%3DTrue%2C%20exist_ok%3DTrue)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20written%20%3D%20c.write_gds(gdspath%3Dout_path)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layout_blocks.append(mo.md(f%22Wrote%3A%20%60%7Bwritten%7D%60%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20except%20Exception%20as%20e%3A%20%20%23%20pragma%3A%20no%20cover%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layout_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(f%22(GDS%20write%20failed%3A%20%60%7Btype(e).__name__%7D%3A%20%7Be%7D%60)%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20layout_blocks.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%22Click%20**Write%20GDS**%20to%20export%20the%20example%20layout.%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20if%20not%20layout_blocks%3A%0A%20%20%20%20%20%20%20%20layout_blocks.append(mo.md(%22%22))%0A%20%20%20%20mo.vstack(layout_blocks)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20show_overview)%3A%0A%20%20%20%20mo.stop(not%20show_overview)%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20What%E2%80%99s%20next%0A%0A%20%20%20%20In%20%60marimo_course%2Flessons%2Fw02_pdk_mzi_layout.py%60%2C%20you%E2%80%99ll%20shift%20from%20modelling%20to%20implementation%3A%0A%0A%20%20%20%20-%20Build%20an%20MZI%20layout%20from%20PDK%20building%20blocks%20with%20correct%20ports%20and%20routing.%0A%20%20%20%20-%20Control%20%CE%94L%20in%20geometry%20and%20verify%20it%20matches%20the%20modelling%20intuition%20from%20this%20notebook.%0A%20%20%20%20-%20Export%20GDS%20and%20inspect%20it%20(KLayout)%2C%20preparing%20for%20more%20realistic%20PDK-accurate%20circuits.%0A%0A%20%20%20%20In%20upcoming%20modelling%20lessons%2C%20we%E2%80%99ll%20add%20realism%20step-by-step%3A%0A%0A%20%20%20%20-%20**Dispersion%3A**%20use%20a%20wavelength-dependent%20%60n_eff(%CE%BB)%60%20so%20%60n_g%60%20emerges%20naturally%20(and%20FSR%20becomes%20a%20local%20approximation).%0A%20%20%20%20-%20**Loss%20%2B%20visibility%3A**%20include%20propagation%20loss%20(and%20later%2C%20imbalance)%20so%20fringes%20aren%E2%80%99t%20perfectly%200%E2%80%931.%0A%20%20%20%20-%20**Non-ideal%20couplers%3A**%20explore%20splitter%20imbalance%20and%20phase%20conventions%2C%20and%20how%20they%20affect%20%E2%80%9Cthrough%20vs%20cross%E2%80%9D.%0A%20%20%20%20-%20**Tuning%2Fmodulation%3A**%20connect%20phase%20tuning%20(thermal%2Felectrical)%20to%20a%20shift%20in%20the%20interference%20pattern.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
ee3f5ee6ac6eed658975d4ac80164482