Segmented photodiodes

Segemented photodiodes are multi-element photodiodes that can resolve both frequency and spatial beats in an optical beam. The most common segmented photodiode is a quadrant photodiode, known as a QPD. This splits a photodiode into four segments, the signal generated by each segments can then be summed or subtracted from one another to measure if a beam is offset horizontally or vertically from the photodiodes central point.

Two types of measurements are possible a DC measurement and an RF measurement. The DC does as above and just simply measures the total optical power incident on each segment. The RF measurement demodulates each segment at some RF frequency and then performs the subtraction/summation. The DC scheme is used for pointing and steady state alignment of a beam, whereas the RF measurement allows us to perform differential wavefront sensing. Essentially measuring the relative tilt and alignment differences between two sidebands.

In Finesse a segmented photodiode is represented by a matrix \(\mathbf{K}\) that describes how each higher order mode beats at the photodiode. A QPD for example will cause a HG00 and HG10 to now generate a signal, whereas on a single element photodiode these two modes would be orthongal. Therefore we can understand the segmentation as breaking modal degeneracies to ensure certain modes generate a signal. A more detailed description of this process and how to mathematically generate the matrix is given in [28].

Given that we have a discrete vector of modal amplitudes, \(\hat{E}\), we can compute two inner products to generate a single value output,

\[S = \hat{E}^{\ast} \cdot (\mathbf{K} \cdot \hat{E}). \]

Photodiode types - pdtype

The pdtype module has some common segemented photodiode types you can use.

  • pdtypes.XSPLIT : splits the photoiode into left and right segments for measuring horizontal displacements.

  • pdtypes.YSPLIT : splits the photoiode into up and down segments for measuring vertical displacements.

Each of the pdtype objects are a dictionary which contain a general statement about how different modes should beat and what scaling factor should be applied.

Printing the first few entries to XSPLIT

>>> pdtypes.XSPLIT

{ (0, 'x', 1, 'x'): 0.797884560802865,
(0, 'x', 3, 'x'): -0.32573500793528,
(0, 'x', 5, 'x'): 0.218509686118416,

The key of the dictionary is a tuple (0, ‘x’, 1, ‘x’) where the first two indicies are the n-th and m-th input mode and the latter two the output mode indices. The ‘x’ is a wildcard. The value of this entry is scaling factor to use for mode beats that match this condition. There we can read the first entry as saying the 0th order mode beats with the 1st order with an extra scaling factor of 0.797. Due to the wildcard the the m index must be the same, e.g. HG01 beats with HG11, HG04 and HG14, etc. all with the same scaling factor.

These beats are often limited to order 40 or so as it becomes computational expensive to compute larger beats but also the practicality of using this many orders in a simulation is questionable.

Photodiode type example

Using KatScript we can specify the pdtype directly. Here we just vary the pointing of a beam by misaligning a component and seeing the output on a a horizontal and vertical split photoiode.

import finesse
model = finesse.Model()
l l1
bs bs1 R=1 T=0
nothing n1
pd qpdx n1.p1.i pdtype=xsplit
pd qpdy n1.p1.i pdtype=ysplit
link(l1, bs1, 10, n1)

gauss g1 bs1.p2.o w0=1m z=0
xaxis(bs1.xbeta, lin, -10u, 10u, 10)

out =

Higher order mode convergence

For large displacements of a beam relative to its spot size size, or misalignments relative to its divergence angle, case must be taken to use enough modes to describe the effect.

Consider a steering mirror directing some beam onto a QPD. The signal outputted from an infinitely sized QPD in the x-direction is proportional to the spot size, \(w\) and the displacement \(\Delta x\)

\[S = \mathrm{erf} \left (\frac{2 \sqrt{2} \Delta x}{w} \right) \]

We can use a similar model to above to compute how accurately Finesse matches this with different number of mode orders used.

import finesse
import matplotlib.pyplot as plt
import numpy as np
from scipy.special import erf

model = finesse.Model()
D = 10 # Distance from optic to QPD [m]

l l1
bs bs1 R=1 T=0 # Steering mirror
nothing n1
pd qpdx n1.p1.i pdtype=xsplit
pd qpdy n1.p1.i pdtype=ysplit
link(l1, bs1, {D}, n1)

gauss g1 bs1.p2.o w0=1m z=0
xaxis(bs1.xbeta, lin, -0.5m, 0.5m, 100)

Lastly, we run and plot the outputs:

maxtems = range(1, 12, 2)
    'color', [ for i in np.linspace(0, 0.9, len(maxtems))]
# loop over each maximum order and run the simulation
for maxtem in maxtems:
    out =
    delta_x = out.x1*D
    plt.plot(delta_x/model.n1.p1.i.qx.w, out['qpdx'], label=f'maxtem = {maxtem}')

w_ = model.n1.p1.i.qx.w/np.sqrt(2)
plt.plot(delta_x / model.n1.p1.i.qx.w, -erf(2*delta_x/w_), c='k', ls='--', label='Analytic')
plt.xlabel(r"Displacement on QPD [$\Delta \mathrm{x}/\mathrm{w}$]")
plt.ylabel("QPD output [W/m]")
<matplotlib.legend.Legend at 0x7fdb49c20e30>

The x-axis is plotted in units of displacement per spot-size - this is the important ratio to always consider when deciding how many orders are required in such scenarios. For large displacements an ever increasing number of modes are required to describe a displaced HG00, eventually this becomes too computationally expensive. However, we do see that for small displacements the first order adequately describes the system.


An extra minus sign is included in the analytic formula which is due to coordinate system definitions in Finesse. See Coordinate systems.