Quickstart sample

Build a small ring circuit with grating couplers. Export the layout + run a circuit simulation to verify circuit operation.

Importing the technology file

We start with importing the silicon_photonics technology, which is a basic technology shipped with IPKISS. You can replace this technology by another technology (custom made, or from our list of supported PDKs). and the layers will automatically adjust to reflect this technology.

from technologies import silicon_photonics
from ipkiss3 import all as i3

# Import other python libraries.
import numpy as np
import pylab as plt

Creating the ring resonator

Here we use a ring resonator from the picazzo component library (the Picazzo Library is a generic component library with a wide range of photonic components).

from picazzo3.filters.ring import RingRect180DropFilter
my_ring = RingRect180DropFilter()

# Setting the layout properties of the ring.
my_ring_layout = my_ring.Layout(bend_radius=10.0) # We set the bend radius of the ring to 10.
my_ring_layout.visualize() # We visualize the layout of the ring

Running a circuit simulation

Here we set some simple model parameters for the directional coupler of the ring, and then we run a circuit simulation. Note that the waveguide lengths are automatically extracted from the layout.

cp = dict(cross_coupling1=1j*0.3**0.5,
          straight_coupling1=0.7**0.5) #The coupling from bus to ring and back

my_ring_cm = my_ring.CircuitModel(coupler_parameters=[cp, cp]) # 2 couplers

# Simulating the ring.
wavelengths = np.linspace(1.50, 1.6, 2001)
S = my_ring_cm.get_smatrix(wavelengths=wavelengths)

plt.plot(wavelengths, np.abs(S['in1', 'out1'])**2, 'b', label="pass")
plt.plot(wavelengths, np.abs(S['in1', 'out2'])**2, 'r', label="drop")
plt.plot(wavelengths, np.abs(S['in1', 'in2'])**2, 'g', label="add")

plt.xlabel("Wavelength ($\mu m$)")
plt.ylabel("Power transmission")

Creating the grating coupler

The picazzo component library also contains parametrized curved grating couplers. We will pick one to use in our circuit.

from picazzo3.fibcoup.curved import FiberCouplerCurvedGrating
my_grating = FiberCouplerCurvedGrating()

# Setting the layout properties of the grating layout.
my_grating_layout = my_grating.Layout(n_o_lines=24, period_x=0.65, box_width=15.5)

# Setting the properties of the circuit model and simulate.
my_grating_cm = my_grating.CircuitModel(center_wavelength=1.55,

S = my_grating_cm.get_smatrix(wavelengths=wavelengths)
plt.plot(wavelengths, np.abs(S['vertical_in', 'out'])**2, 'b', label="pass")
  • ../_images/sphx_glr_plot_quickstart_003.png
  • ../_images/sphx_glr_plot_quickstart_004.png

Creating a small circuit with the ring and grating coupler

Next, we can use some high-level routing functionality from IPKISS to place the grating couplers and the ring, and route waveguides between them. This is done using PlaceAndAutoRoute component

# Create the place and auto-route.
from picazzo3.routing.place_route import PlaceAndAutoRoute
my_circuit = PlaceAndAutoRoute(child_cells={"in_grating": my_grating,
                                            "pass_grating": my_grating,
                                            "add_grating" : my_grating,
                                            "drop_grating" : my_grating,
                                            "ring" : my_ring},

                                   links=[("in_grating:out", "ring:in1"),
                                          ("pass_grating:out", "ring:out1"),
                                          ("add_grating:out", "ring:in2"),
                                          ("drop_grating:out", "ring:out2")]

# Setting the transformations of the childcells in the layoutview.
distance_x = 100.0
distance_y = 30.0
my_circuit_layout = my_circuit.Layout(child_transformations={"ring": (0, 0),
                                                             "in_grating": i3.Rotation(rotation=0) + i3.Translation((-distance_x, -distance_y)),
                                                             "pass_grating": i3.Rotation(rotation=180) + i3.Translation((distance_x, -distance_y)),
                                                             "add_grating": i3.Rotation(rotation=180) + i3.Translation((distance_x, distance_y)),
                                                             "drop_grating": i3.Rotation(rotation=0) + i3.Translation((-distance_x, distance_y)),


# Simulate the circuit.
my_circuit_cm = my_circuit.CircuitModel()
S = my_circuit_cm.get_smatrix(wavelengths=wavelengths)

plt.plot(wavelengths, np.abs(S['in_grating_vertical_in', 'pass_grating_vertical_in'])**2, 'b', label="pass")
plt.plot(wavelengths, np.abs(S['in_grating_vertical_in', 'drop_grating_vertical_in'])**2, 'r', label="drop")
plt.plot(wavelengths, np.abs(S['in_grating_vertical_in', 'add_grating_vertical_in'])**2, 'g', label="add")
plt.plot(wavelengths, np.abs(S['in_grating_vertical_in', 'in_grating_vertical_in'])**2, 'k', label="reflection")
  • ../_images/sphx_glr_plot_quickstart_005.png
  • ../_images/sphx_glr_plot_quickstart_006.png

You can clearly see the following features in this response:

  • the grating response: the grating was designed for 1550 nm, and has a gaussian-like profile,
  • the ring resonances
  • there are some ripples on the circuit response, this is due to reflections on the grating couplers.

Caphe is a bidirectional-aware circuit solver (each optical port has a forward and backward propagating wave), and this is how we can capture these important parasitic effects.