Mach-Zehnder Interferometer (MZI)

We use SiEPIC EBeam library in this tutorial.

This notebook walks through the process of setting up and simulating a mach-zehnder interferometer device using the OPICS package.

A mach-zehnder interferometer is a basic waveguide interference device. It consists of two couplers (or Y branches) connected by two waveguides of different length (see below). The difference between the two waveguide lengths causes differential delay, which contributes to the frequency dependent interference pattern.

7b13d3edea1e4917b5c00d366b433c93

[1]:
import time
import warnings
import numpy as np
from opics.globals import c
from opics import Network
import opics

freq = np.linspace(c * 1e6 / 1.5, c * 1e6 / 1.6, 2000)

OPICS version 0.1.6

Import component library

Import ebeam library from libs module.

[2]:
ebeam = opics.libraries.ebeam

Define network

Create an instance of Network class, which is used to add, connect, and simulate circuit components.

[4]:
circuit_name = "mzi"
circuit = opics.Network()

Add circuit components

Add grating couplers, 3dB power splitters (e.g. Y-splitter or Y-branch), and waveguides to circuit. You can define custom frequency data points for a component as well (see the example for output_GC).

[5]:
#define component instances
input_gc  = circuit.add_component(ebeam.GC(freq))
y1 =   circuit.add_component(ebeam.Y(freq))
wg1 =  circuit.add_component(ebeam.Waveguide(freq,50e-6))
wg2 =  circuit.add_component(ebeam.Waveguide(freq,150e-6))
y2 =  circuit.add_component(ebeam.Y(freq))
output_gc = circuit.add_component(ebeam.GC(freq))

Define circuit connectivity

In this section, we define the component connections. The connections are defined using Network.connect, e.g.

Network.connect(component1, component1_port, component2, component2_port)

[6]:
#define circuit connectivity
circuit.connect(input_gc, 1, y1, 0)
circuit.connect(y1, 1, wg1, 0)
circuit.connect(y1, 2, wg2, 0)
circuit.connect(y2, 0, output_gc, 1)
circuit.connect(wg1, 1, y2, 1)
circuit.connect(wg2, 1, y2, 2)

Simuate the circuit

[7]:
warnings.filterwarnings('ignore') #ignore all/complex number warnings from numpy or scipy
sim_start = time.time()

#simulate network
circuit.simulate_network()

print("simulation finished in %ss"%(str(round(time.time()-sim_start,2))))
simulation finished in 0.06s

Visualize the simulation result

[8]:
circuit.sim_result.plot_sparameters(show_freq = False, scale="log")
../_images/notebooks_01-Mach-Zehnder_Interferometer_13_0.svg