5. Tyndall ADK: Four-lanes Mach-Zehnder Modulator (MZM)

In this tutorial, we provide an example of the design of a high-speed four-lane Mach-Zehnder modulator (MZM) packaged using the components illustrated in the figure below.

../../_images/full_circuit_zoom_regions.png

The design is based on elements from a foundry photonics design kit, combined with custom components designed in a photonics team on top of this PDK and the packaging frame from a packaging assembly design kit. The code used to create this design and referenced in this tutorial can be found in your Luceda Academy project in luceda_academy/designs/four_lane_mzm.

5.1. Fully assembled design

The GDSII of the finalised design is generated by running the regenerate.py file. Let’s go through it step by step.

5.2. Step 1: Importing the dependencies

In Luceda IPKISS, dependencies of your design are imported at the top of your code, just like you would do for any other Python module. In our case, we import the following dependencies:

  • SiFab PDK: SiFab is a demonstration PDK emulating the technology of a traditional SOI foundry. Grating couplers, splitters and bondpads will be directly imported from here.

  • Tyndall ADK: The Assembly Design Kit (ADK) for Tyndall is a design kit for packaging silicon photonics IC. By using the ADK, it is a lot easier to adhere to the design rules that will enable you to package and measure your chip afterwards.

  • P-Team Library for SiFab: Local component library containing components that are shared across different designs made by your photonics team.

  • Four-lane MZM design: This design is defined in a separate file and uses ingredients from the dependencies above to create the four-lane MZM.

luceda_academy/designs/four_lane_mzm/regenerate.py
from si_fab import all as pdk
from tyndall_packaging.all import UniformPackagingArray
from pteam_library_si_fab.components.mzm.pcell.cell import MZModulator
from four_lane_mzm import PackagedFourLaneMZM, FourLaneMZM

5.3. Step 2: Instantiating the phase shifter and the splitter

After the import statements, we instantiate the phase shifter from the SiFab PDK with the desired length. For more information about this PCell and the parameters that can be set, check out the SiFab documentation: PhaseShifterWaveguide.

luceda_academy/designs/four_lane_mzm/regenerate.py
# Phase Shifter
ps = pdk.PhaseShifterWaveguide(
    name="phaseshifter",
    length=phase_shifter_length,
)

../../_images/splitter.png

Next, we instantiate the heater that we are going to use for the MZM later.

luceda_academy/designs/four_lane_mzm/regenerate.py
# Heater
heater = pdk.HeatedWaveguide(name="heater")
heater.Layout(shape=[(0.0, 0.0), (100.0, 0.0)])

Similarly, we instantiate the splitter that we will need later in the final 4-lane MZM circuit. We use the MMI1x2Optimized1550 from the SiFab PDK, which has been optimized for maximum transmission at 1550.

luceda_academy/designs/four_lane_mzm/regenerate.py
# Splitter
splitter = pdk.MMI1x2Optimized1550()

../../_images/phase_shifter_top.jpg

5.4. Step 3: Instantiating the MZM

The Mach-Zehnder modulator we will use in this tutorial is made of two arms, each with an electro-optic phase modulator and heater. The design of the MZM is explained in details in the Mach-Zehnder modulator tutorial. In step 1, we imported the MZM from the P-Team library for SiFab. Now we instantiate the MZM and we pass to the MZM PCell the phase shifter we have instantiated above, together with parameters to adjust the metal pads size and position.

luceda_academy/designs/four_lane_mzm/regenerate.py
# Modulator
mzm = MZModulator(
    name="mzm",
    phaseshifter=ps,
    heater=heater,
    splitter=splitter,
    rf_pitch_in=2 * rf_interposer_gap,
    rf_pitch_out=2 * rf_interposer_gap,
    rf_pad_length=rf_interposer_gap,
    rf_pad_width=rf_interposer_gap,
    rf_signal_width=rf_signal_width,
    rf_ground_width=20.0,
)

../../_images/mzm.png

5.5. Step 4: Instantiating the four-lane MZM

The last missing ingredient to create the 4-lane MZM is the splitter. We can pass the previously instantiated splitter to the 4-lane MZM PCell, which we have defined separately in the file four_lane_mzm.py and imported at the top.

luceda_academy/designs/four_lane_mzm/regenerate.py
# Splitter
splitter = pdk.MMI1x2Optimized1550()

# Modulator
mzm = MZModulator(
    name="mzm",
    phaseshifter=ps,
    heater=heater,
    splitter=splitter,
    rf_pitch_in=2 * rf_interposer_gap,
    rf_pitch_out=2 * rf_interposer_gap,
    rf_pad_length=rf_interposer_gap,
    rf_pad_width=rf_interposer_gap,
    rf_signal_width=rf_signal_width,
    rf_ground_width=20.0,
)

# 4-lane MZM
four_lane_mzm = FourLaneMZM(
    name="FourLaneMZM",
    mzm=mzm,
    splitter=splitter,
    interposer_pitch=rf_interposer_gap,
    bend_radius=10.0,
)

../../_images/four_lane_mzm.png

5.6. Step 5: Instantiating the Tyndall ADK packaging frame

From the Luceda ADK for Tyndall, we have imported UniformPackagingArray which consists of fiber arrays on the west and/or east side of the PIC, and bondpads on the north and south sides. Here we instantiate it by using the fiber grating coupler and bondpad PCells from SiFab (FC_TE_1550 and BondPad) and by specifying the desired number of gratings and pads in the arrays.

luceda_academy/designs/four_lane_mzm/regenerate.py
# Frame
tyndall_frame = UniformPackagingArray(
    name="TyndallFrame",
    bondpad=pdk.BondPad(metal1_size=(50, 70), metal2_size=(50, 70)),
    grating=pdk.FC_TE_1550(),
    n_o_user_west_gratings=8,
    n_o_user_east_gratings=0,
    n_o_north_bondpads=0,
    n_o_south_bondpads=8,
)

../../_images/tyndall_frame.png

5.7. Step 6: Routing to the packaging frame and exporting the design

Finally, we can instantiate the packaged four-lane MZM, by combining the four-lane MZM with the packaging frame. The PackagedFourLaneMZM PCell takes care of automatically routing the inputs and outputs of the four-lane MZM circuit to the inputs and outputs of the packaging frame. This PCell is defined in the file four_lane_mzm.py.

luceda_academy/designs/four_lane_mzm/regenerate.py
# Routing to Frame
top = PackagedFourLaneMZM(
    name="MZM4_PACKAGED",
    spacing_rfpad2edge=10,
    packaging_frame=tyndall_frame,
    wire_spacing=10.0,
    bend_radius=10,
    dut=four_lane_mzm,
)
lv = top.Layout()
lv.write_gdsii("mzm4_packaged.gds")
../../_images/full_circuit.png