# 1.2. Electro-optic phase shifter¶

An electro-optic phase shifter works by varying the voltage over a p-n diode in reverse bias. The waveguide is placed in correspondence of the junction. Varying the reverse bias moves the position of the junction, modulating the carrier density in the waveguide. As a result, the refractive index of the waveguide material is modulated through the plasma-dispersion effect. This, in turn, modulates the effective index and the phase of the light at the end of the waveguide.

## 1.2.1. Layout¶

The layout of a phase shifter is composed of an optical part and an electrical part.

### 1.2.1.1. Optical Waveguide¶

The optical part controls the layers to etch in the silicon in order to create a waveguide where a mode can propagate. The waveguide is a SiRibWaveguideTemplate and is controlled by the core_width and rib_width properties.

from si_fab import all as pdk
from ipkiss3 import all as i3

ps = pdk.PhaseShifterWaveguide(core_width=0.45, rib_width=8.0, length=2.0)
ps_lv = ps.Layout()
ps_lv.visualize(annotate=True)
xs = ps_lv.cross_section(cross_section_path=i3.Shape([(1.0, -8.0), (1.0, 8.0)]))
xs.visualize()


### 1.2.1.2. Electrical contact¶

The modulation happens because of the plasma dispersion effect at the junction. The electrical characteristics of the junction are controlled by the doping profile as a function of position in the waveguide cross section. SiFab has four possible doping levels: NPLUS, N, P and PPLUS. Each of these has its equivalent layer: i3.TECH.PPLAYER.NPLUS, i3.TECH.i3.PPLAYER.N, i3.TECH.i3.PPLAYER.P and i3.TECH.PPLAYER.PPLUS.

By default, the junction is exactly in the middle of the waveguide. If asymmetric doping profiles are used, the junction can be offset by using the junction_offset property. The width of the p-doped and n-doped layers are set by p_width and n_width. The offset of the highly doped regions are set by pplus_offset and nplus_offset for p-type and n-type doping, respectively. The highly doped regions are contacted with contact vias with pitch offset p_contact_offset and n_contact_offset, while using n_contact_rows and p_contact_rows. Finally, a connection is made to the metal layer M2 through M1 and contact vias, using the parameters m1_width, m1_offset, m2_width, m2_offset, n_o_via_row, via_pitch, via_offset.

from si_fab import all as pdk
from ipkiss3 import all as i3

ps = pdk.PhaseShifterWaveguide(
core_width=0.8,
rib_width=7.8,
length=2.0,
junction_offset=0.1,
p_width=6.0,
n_width=6.0,
pplus_offset=2.0,
nplus_offset=2.0,
p_contact_offset=3.0,
n_contact_offset=3.0,
p_contact_rows=3,
n_contact_rows=3,
m1_width=3.6,
m1_offset=2.0,
m2_width=4.8,
m2_offset=3.2,
n_via_rows=6,
via_pitch=0.6,
via_offset=3.8,
)

ps_lv = ps.Layout()
ps_lv.visualize(annotate=True)
xs = ps_lv.cross_section(cross_section_path=i3.Shape([(1.0, -10.0), (1.0, 10.0)]))
xs.visualize()


## 1.2.2. Model¶

The phase shifter is modeled using a $$V_{\pi}L_{\pi}$$ model that is associated with a time constant $$\tau$$. Usually, $$V_{\pi}L_{\pi}$$ is determined by the reverse bias and the doping profile of the junction, as well as by the temperature. Its value can be obtained through device level simulations or measurements. $$\tau$$ is usually dominated by the $$RC$$ constant associated with the capacitance of the phase shifter and the driver output resistance. Both $$\tau$$ and $$V_{\pi}L_{\pi}$$ need to be obtained through measurements or simulations and are not calculated by IPKISS.

SiFab also contains a simulation recipe simulate_phaseshifter that allows us to experiment with the dynamics of the phase shiter.

from si_fab import all as pdk
from si_fab.components.phase_shifter.simulation.simulate import simulate_phaseshifter
import pylab as plt
import numpy as np
import os

# Phase Shifter
name = "simple_step"
results_array = []
length = 1e4
ps = pdk.PhaseShifterWaveguide(length=length,
core_width=0.45,
rib_width=8.0,
junction_offset=-0.1)
vpi_lpi = 1.2
capacitance = 1.1e-15  # F/um
resistance = 50
tau = ps.length * capacitance * resistance
ps.CircuitModel(vpi_lpi=vpi_lpi)

results = simulate_phaseshifter(
cell=ps,
nsteps=1000,
dt=5e-12,
step_amplitude=vpi_lpi,
center_wavelength=1.5,
debug=False,
)

def phase_unwrap_normalize(results):
unwrapped = np.unwrap(np.angle(results))
return (unwrapped-unwrapped[1] * np.ones(unwrapped.shape))/np.pi

outputs = ["optical_in", "gnd", "vsrc_mod", "optical_out"]
titles = ["Source input", "Source ground", "Source modulation", "Output"]
process = [np.real, np.real, np.real, phase_unwrap_normalize]
ylabels = ["V/m", "V", "V", "rad"]
fig, axs = plt.subplots(nrows=len(outputs), ncols=1, figsize=(6, 8))

for ax, pr, out, ylabel, title in zip(axs, process, outputs, ylabels, titles):
data = pr(results[out][1:])
ax.set_title(title)
ax.plot(results.timesteps[1:], data, label="length: {}".format(length))
ax.set_ylabel(ylabel)

plt.tight_layout()
fig.savefig(os.path.join("{}.png".format(name)), bbox_inches='tight')
plt.show()


Exercise 1

1. Copy topical_training/mzm/explore_phaseshifter/explore_electrical.py.
2. Try to replicate the following cross-section.

Solution

Exercise 2

1. Copy topical_training/mzm/explore_phaseshifter/explore_electrical.py.
2. Sweep the length of the phase shifter and explore the compromise between speed and modulation amplitude of the phase.

Solution