Closing control loops¶
Discuss the difference in Finesse between DC and AC closed loop control.
DC control loops - ‘lock’¶
DC control loops are used to manually adjust the degrees of freedom (DOFs) in an
optical system based on error signal measurements, until the error signals are
within a specified tolerance. Several Finesse Actions
have been developed
to facilitate such locking. In particular, the Action
RunLocks
can
be used to move a system to lock. Below we describe how this Action
works and
show an example of its use.
Methods Used for DC Locking
RunLocks
provides two methods that the user may choose from to attempt
to achieve lock in a Finesse model. Such a model must include user-defined locks
specified using the lock
command. These locks specify the error signals that will
be used in locking, the unique DOF associated with each error signal, and the gain
relating each error signal/DOF pair. To describe how RunLocks
works, let us
denote the set of values of the error signals as the vector \(\vec{E}\), the set
of values of the DOFs as the vector \(\vec{F}\), and the set of gains as \(\vec{G}\).
In the first method that a user may call when running RunLocks
, henceforth
named the ‘proportional’ method, each DOF responds proportionally to the error signal with which it
was paired in the model. That is, it is assumed that each error signal \(E_i\) depends
only on the DOF \(F_i\):
\(\Delta E_i = G_i \Delta F_i.\)
Therefore, to attempt to lock the model with this method, the value the DOFs are iteratively updated according to the following equation, where \(j\) is the iteration step:
\(F_{i, j+1} = F_{i,j} - \frac{E_{i,j}}{G_i}.\)
The iteration continues until all error signals are within tolerances or until
a user-defined maximum number of iterations is reached. This method may be called within
RunLocks
by using the option method="proportional"
.
However, this method has its limitations because, in general, DOFs tend to affect multiple
error signals. This can be observed by constructing a ‘gain matrix,’ which shows the
derivatives of all error signals with respect to all DOFs. This gain matrix should be
diagonal if the proportional method is to be used. For a real system, however, some off-diagonal
elements may be even larger than the diagonal elements. Note that when using
RunLocks
, we assume that the model is close enough to lock that a change
in any DOF induces either a linear or a negligible change in the error signals;
i.e., all gains are constant or near zero throughout the locking process. The Action
CheckLinearity
may be used to check this assumption. If this assumption holds,
we can write the sensing matrix as shown below:
In this way, the sensing matrix can be thought as a constant Jacobian matrix. Based on this
intuition, the second method that RunLocks
may use applies Newton’s method for
multidimensional root-finding. This method may be used with the
option method="newton"
. At each iteration step, the DOFs are changed all together
according to the following equation:
\(\vec{F}_{j+1} = \vec{F}_{j} - \textbf{G}^{-1} \vec{E}_{j}.\)
Theoretically, this method should achieve lock much faster and for a wider range of initial conditions than the proportional method. Below, we show this to be true in practice.
Example: Locking a Dual-Recycled Interferometer
Here, we present a simplified example for the locking of a dual-recycled interferometer,
similar to Advanced Virgo. We compare the performance of the two locking methods of
RunLocks
by attempting to lock this interferometer to the dark fringe.
We’ll first set up the optical geometry. This geometry uses the same three
modulation frequencies as used in Advanced Virgo for the construction of error
signals.
import numpy as np
import matplotlib.pyplot as plt
import finesse
from finesse.analysis.actions import RunLocks
finesse.configure(plotting=True)
kat = finesse.Model()
kat.parse(
"""
###########################################################################
### Variables
###########################################################################
var Larm 2999.8
var Lprc 12
var Lsrc 12
var Mtm 40
var prmT 0.04835
var itmT 0.01377
var srmT 0.4
var lmichx 5.3662
var lmichy 5.244
var f1 6270777
var f2 9*f1
var f3 4/3*f1
###########################################################################
### Input optics
###########################################################################
l L0 125
s l_mod1 L0.p1 eo1.p1
mod eo1 f1 0.1 order=3
s l_mod2 eo1.p2 eo2.p1
mod eo2 f2 0.1 order=3
s l_mod3 eo2.p2 eo3.p1
mod eo3 f3 0.1 order=3
s l_in eo3.p2 prm.p1 L=53
#Power recycling mirror
m prm T=prmT L=30u Rc=-1430
s l_prc prm.p2 bs.p1 L=Lprc
# Central beamsplitter
bs bs T=0.5 L=0 alpha=45
###########################################################################
### X arm
###########################################################################
s lx bs.p3 itmx.p1 L=lmichx
m itmx T=itmT L=37.5u phi=90 Rc=-1424.6
s LX itmx.p2 etmx.p1 L=Larm
m etmx T=5u L=37.5u phi=90 Rc=1695.0
###########################################################################
### Y arm
###########################################################################
s ly bs.p2 itmy.p1 L=lmichy
m itmy T=itmT L=37.5u phi=0 Rc=-1424.5
s LY itmy.p2 etmy.p1 L=Larm
m etmy T=5u L=37.5u phi=0.0 Rc=1696.0
###########################################################################
### Signal Recyling Cavity
###########################################################################
s l_src bs.p4 srm.p1 L=Lsrc
m srm T=srmT L=30u Rc=1430.0
###########################################################################
### Cavities
###########################################################################
# Arms
cav cavX itmx.p2.o priority=3
cav cavY itmy.p2.o priority=3
# PRC
cav cavPRW prm.p2.o via=itmx.p1.i priority=2
cav cavPRN prm.p2.o via=itmy.p1.i priority=2
# SRC
cav cavSRW srm.p1.o via=itmx.p1.i priority=1
cav cavSRN srm.p1.o via=itmy.p1.i priority=1
"""
)
Now we introduce the degrees of freedom (DOFs) that can be adjusted to
reach lock, the error signals (measured via demodulation at the signal
recycling and power recycling mirrors), and the locks relating the DOFs
to the error signals. Gains are initially set at unity, but get set to
appropriate values calculated with finite differences during RunLocks
(in the case of Newton’s method, the entire sensing matrix will be calculated).
kat.parse(
"""
###########################################################################
### Degrees of Freedom, Readouts, and Locks
###########################################################################
dof DARM etmx.dofs.z -1 etmy.dofs.z +1
dof CARM etmx.dofs.z +1 etmy.dofs.z +1
dof MICH itmx.dofs.z -1 etmx.dofs.z -1 itmy.dofs.z +1 etmy.dofs.z +1
dof PRCL prm.dofs.z +1
dof SRCL srm.dofs.z -1
readout_rf rd_sr_f1 srm.p2.o f=eo1.f phase=0 output_detectors=True
readout_rf rd_pr_f1 prm.p1.o f=eo1.f phase=0
readout_rf rd_pr_f2 prm.p1.o f=eo2.f phase=0
readout_rf rd_pr_f3 prm.p1.o f=eo3.f phase=0
lock DARM_lock rd_sr_f1.outputs.I DARM.DC 1 1e-9
lock CARM_lock rd_pr_f1.outputs.I CARM.DC 1 1e-9
lock MICH_lock rd_pr_f2.outputs.Q MICH.DC 1 1e-9
lock PRCL_lock rd_pr_f3.outputs.I PRCL.DC 1 1e-9
lock SRCL_lock rd_pr_f2.outputs.I SRCL.DC 1 1e-9
"""
)
At this point, it would typically be necessary to perform ‘pre-tuning’ steps to
move the model close enough to lock for the DC control loops to succeed. Here,
however, because the geometry is relatively simple and higher-order modes are not
considered, the model is very close to lock as defined. We can therefore kick the model
away from lock by changing one or more DOFs and then observe whether the control loops
succeed in bringing the model back to lock. Below, we explore simultaneous deviations
in the common arm length CARM and the differential arm length DARM, varying each from
their set points over the ranges \((-0.08^\circ, 0.08^\circ)\). Here, the units of
degrees mean that we are deviating the microscopic path lengths of the optical components
to reach a desired phase shift: e.g., a change of \(0.01^\circ\) for a laser wavelength
of 1064 nm corresponds to a length change of 29.6 pm. For each deviation, we store the
number of iterations of the locking procedure required to reach lock. If the locking does
not converge within the maximum number of iterations specified (100), we return None
.
For more complex models, it is often required to set max_iterations
to 1,000 or even
10,000. But for this simple model, if convergence is not achieved within 100 iterations,
it will not be achieved within 10,000.
num_points = 21
DARM_limit, CARM_limit = 0.08, 0.08
DARM_values = np.linspace(-1*DARM_limit, DARM_limit, num_points)
CARM_values = np.linspace(-1*CARM_limit, CARM_limit, num_points)
# Array to store results.
iter_list = np.zeros((2,num_points,num_points))
for ind_D, val_D in enumerate(DARM_values):
for ind_C, val_C in enumerate(CARM_values):
# Reset parameters to their set points
kat_paired = kat.deepcopy()
kat_newton = kat.deepcopy()
# Deviate DARM and CARM from their setpoints
kat_paired.DARM.DC = val_D
kat_paired.CARM.DC = val_C
kat_newton.DARM.DC = val_D
kat_newton.CARM.DC = val_C
# Try to lock with the paired method
sol_paired = kat_paired.run(
RunLocks(
method="proportional", exception_on_fail=False,
no_warning=True, max_iterations=100,
display_progress=False, optimize_phase=True
)
)
if sol_paired.iters > 99:
iter_list[0, ind_D, ind_C] = None
else:
iter_list[0, ind_D, ind_C] = sol_paired.iters
# Try to lock with Newton's method
sol_newton = kat_newton.run(
RunLocks(
method="newton", exception_on_fail=False,
no_warning=True, max_iterations=100,
display_progress=False, optimize_phase=True
)
)
if sol_newton.iters > 99:
iter_list[1, ind_D, ind_C] = None
else:
iter_list[1, ind_D, ind_C] = sol_newton.iters
We then display the number of iterations required for each deviation. A white pixel indicates that the locking exceeded the maximum number of iterations.
fig, axs = plt.subplots(1,2)
im1 = axs[0].imshow(np.log10(iter_list[0]), extent=[-1*CARM_limit,CARM_limit,-1*DARM_limit,DARM_limit],
aspect=CARM_limit/DARM_limit, vmin=0, vmax=2)
im1 = axs[1].imshow(np.log10(iter_list[1]), extent=[-1*CARM_limit,CARM_limit,-1*DARM_limit,DARM_limit],
aspect=CARM_limit/DARM_limit, vmin=0, vmax=2)
axs[0].set_xlabel("CARM Deviation (deg)", fontsize=10)
axs[1].set_xlabel("CARM Deviation (deg)", fontsize=10)
axs[0].set_ylabel("DARM Deviation (deg)", fontsize=10)
axs[1].set_ylabel("DARM Deviation (deg)", fontsize=10)
axs[0].set_title("Paired Method",fontsize=12)
axs[1].set_title("Newton's Method")
fig.subplots_adjust(right=0.8, wspace=0.75)
cbar_ax = fig.add_axes([0.1, 0.1, 0.7, 0.4])
cbar_ax.axis('off')
cbar = fig.colorbar(im1,ax=cbar_ax, location="bottom",
label=r"$\log_{10}$(Number of Iterations)")
We observe that Newton’s method converges for a much larger fraction of this parameter space than the paired method. Moreover, for pixels in which the paired method converges, Newton’s method requires far fewer iterations.
AC control loops¶
AC control loops are about shaping feedback and looking and control loop stability, etc.