**2.Plane Waves > 1.Fabry Perot Cavity**

**4. Linewidth**

Author: Daniel TÃ¶yrÃ¤

*linewidth* of a cavity is commonly defined as the *Full Width at Half Maximum* (FWHM) of the resonance peak, which we use here. But other definitions are also used, for example the *Half Width at Half Maximum* (HWHM) and the *pole frequency* $f_p$, which both are equal to half the FWHM. The linewidth tells us how large the frequency band is that is resonant inside the cavity, thus, how well the cavity filters out other frequencies. The linewidth is related to the Free Spectral range (see previous notebook) through the cavity finesse, which will be handled in the next notebook.

** Recommended notebooks before you start:**

We recommend that you have looked through the notebook **03_Resonance.ipynb** that you find in the folder 01_Fabry_Perot_cavity before you start this one, or that you have basic experience of IPython/Jupyter Notebooks, PyKat, Finesse, and resonance in a Fabry-Perot cavity. The link above only works if you started IPython/Jupyter Notebook in the top directory of this course.

**Reading material and references:**

[1] A. Freise, K. Strain, D. Brown, and C. Bond, "Interferometer Techniques for Gravitational-Wave Detection", *Living Reviews in Relativity* **13**, 1 (2010). - Living review article (more like a book) on laser interferometry in the frequency domain for detecting gravitational waves, and FINESSE.

[2] A. Freise, D. Brown, and C. Bond, "Finesse, Frequency domain INterferomEter Simulation SoftwarE". - FINESSE-manual

[3] FINESSE syntax reference - Useful online syntax reference for FINESSE. Also available in the Finesse manual [2], but this online version is updated more often.

**After this session you will... **

- be able to tell which cavity properties that affect the cavity linewidth
- have computed the linewidth of a cavity
- have seen how to use
`scipy.optimize.scalar()`

and`scipy.optimize.bisect()`

for finding a local maximum/minimum, and zero crossing.

First we import the PyKat and other Python packages that we need:

In [2]:

```
import numpy as np # Importing numpy
import matplotlib # For plotting
import matplotlib.pyplot as plt
from pykat import finesse # Importing the pykat.finesse package
from pykat.commands import * # Importing all packages in pykat.commands.
from IPython.display import display, HTML # Allows us to display HTML.
# Telling the notebook to make plots inline.
%matplotlib inline
# Initialises the PyKat plotting tool. Change dpi value
# to change figure sizes on your screen.
pykat.init_pykat_plotting(dpi=90)
```

Now we crate our FINESSE model of the optical setup:

In [3]:

```
basekat=finesse.kat() # initialising Finesse
basekat.verbose = False
basecode = """
l laser 1 0 n0 # Laser (Power = 1 W, wavelength offset = 0)
s s1 1 n0 nc1 # Space (Length = 1 m)
## The cavity ##
m m1 0.7 0.3 0 nc1 nc2 # Mirror (R = 0.7, T = 0.3, phi = 0)
s sL 4000 nc2 nc3 # Space (Length = 4 km)
m m2 0.8 0.2 0 nc3 nc4 # Mirror (R = 0.8, T = 0.2, phi = 0)
"""
basekat.parseKatCode(basecode) # Parsing the FINESSE-code
```

In the example in the previous notebook on free spectral range, we can clearly see that the peaks become narrower the longer the cavity is, so we know that the linewidth depends on the cavity length. In this example we will show that linewidth also depends on the reflectance of the mirrors. We will do three runs, each with a different set of mirror reflectances.

First we add detectors and simulation instructions:

In [4]:

```
kat1 = basekat.deepcopy()
code = '''
## Detectors ##
# Photo diodes measuring DC-power
pd refl nc1 # Reflected
pd circ nc2 # Circulating
pd tran nc4 # Transmitted
## Simulation instructions ##
xaxis laser f lin -15k 15k 1000 # Sweeping the laser frequency
yaxis abs # Returns magnitude of detector outputs
'''
# Parsing the FINESSE code
kat1.parseCommands(code)
```

`out1a`

, `out1b`

, and `out1c`

.

In [5]:

```
# 1st run, original, R1 = 0.7, R2 = 0.8
out1a = kat1.run()
# 2nd run, R1 = 0.9, R2 = 0.8
kat1.m1.R = 0.9
kat1.m1.T = 0.1
out1b = kat1.run()
# 3rd run, R1 = 0.9, R2 = 0.95
kat1.m2.R = 0.95
kat1.m2.T = 0.05
out1c = kat1.run()
```

Finally, we plot the results:

In [6]:

```
# Run 1
fig1a = out1a.plot(xlabel='Frequency [Hz]',
ylabel='Power [W]',
title='Run 1: $R_1 = 0.7$, $R_2 = 0.8$')
# Run 2
fig1b = out1b.plot(xlabel='Frequency [Hz]',
ylabel='Power [W]',
title='Run 2: $R_1 = 0.9$, $R_2 = 0.8$')
# Run 3
fig1c = out1c.plot(xlabel='Frequency [Hz]',
ylabel='Power [W]',
title='Run 3: $R_1 = 0.9$, $R_2 = 0.95$')
```

Investigate how the FSR depends on the macroscopic cavity length by testing a couple of different lengths. Find the FSR of each run either manually by "zooming" in the peaks with the FINESSE command `xaxis`

, or by making use of the `scipy.optimize`

library, where I would suggest `scipy.optimize.minimize_scalar()`

(see hint below). Try to also work out an analytical expression for the FSR of a cavity, and compare with your simulated result.

**Hint on using scipy.optimize.minimize_scalar() : **

`scipy.optimize.minimize_scalar()`

requires as its first argument a name of a function to be minimised, so first define a function. For example like this (not exactly in this form, you need to do a small change for your task):

```
def my_function(x):
kat.laser.f = x
out = kat.run()
return out['tran']
```

In the Finesse code you can replace the `xaxis`

command with `noxaxis`

so that a call to `kat.run()`

returns only one value, which is necessary for `minimize_scalar()`

to work.

Then you can call the scipy function to find the minimum of `my_function()`

as:

```
import scipy.optimize as opt
opt.minimize_scalar(my_function, ...)
```

**Answer:**

In [ ]:

```
```

Compute the linewidth of the example cavity, either manually by "zooming" in the peaks with the FINESSE command `xaxis`

, or by making use of the `scipy.optimize`

library, where I would suggest `scipy.optimize.minimize_scalar()`

in combination with `scipy.optimize.bisect()`

(see hint below). Try to also work out an analytical expression for the FSR of a cavity, and compare with your simulated results.

**Hint on using scipy.optimize.minimize_scalar() and scipy.optimize.bisect(): **

Both `scipy.optimize.minimize_scalar()`

and `scipy.optimize.bisect()`

require as their first argument a name of a function, so you first need to define a function. For example like this (not exactly in this form, you need to do a small change for your task):

```
def my_function(x):
kat.laser.f = x
out = kat.run()
return out['tran']
```

In the Finesse code you can replace the `xaxis`

command with `noxaxis`

so that a call to `kat.run()`

returns only one value, which is necessary for `minimize_scalar()`

and `bisect()`

to work.

Then you can call the scipy functions to perform the wanted optimisation on `my_function()`

as:

```
import scipy.optimize as opt
opt.minimize_scalar(my_function, ...)
```

**Answer:**

`basekat`

, adding a photo diode detecting circulating power, and adding simulation instructions. Note that we use the command `noxaxis`

, which means that we just runs the current setup, i.e., only one data point.

In [7]:

```
kat2 = basekat.deepcopy() # Copying basekat
# Adding detectors and simulation instructions
code = '''
## Detectors ##
pd circ nc2 # Measuringn circulating power
## Simulation instructions ##
noxaxis # Changing nothing, just running current setup.
yaxis abs # Returns absolute value of the detector output
'''
# Parsing the FINESSE code
kat2.parseCommands(code)
```

Now we write the function `find_fwhm()`

that requires a `kat`

-object as the only input, and it returns the FWHM of the cavity as long as we have a detector measuring the circulating or transmitted power, and no other detectors. As you see below, the function `find_fwhm()`

has two inner functions as well: one that finds maximums, and one that finds zero crossings. `find_fwhm`

operates in two steps:

- Finds the maximum by using
`minimize_scalar()`

, and stores it. - Uses half the maximum to offset the function that is used to find the zero crossing such that it crossers zero when the resonance peak has dropped half its power.

In [8]:

```
import scipy.optimize as opt
def find_fwhm(kat):
# Function for finding FSR of a cavity
# Finding the laser component of the kat-object
laser = kat.getAll(pykat.components.laser)[0]
def find_max(f):
# Function that is minimised at the frequency f
# that gives maximum transmitted power.
laser.f = f # Setting new laser frequency
out_max = kat.run() # Running
return -out_max.y[0,0] # Output
def find_pole(f, P1):
# Function that crosses zero when the measured power
# equals P1.
laser.f = f
out_pole = kat.run()
return out_pole.y[0,0]-P1
# Step 1: Finding the peak power
# -------------------------------
opts = {'xtol': 1.0e-6, 'maxiter': 500}
# Calling minimize_scalar with Brent's method to
# find minimum of find_max().
sol_1 = opt.minimize_scalar(find_max,
method='brent',
options=opts)
P_half = -sol_1.fun/2
f0 = sol_1.x
print('Maximum found: P = {0:.3f} W, f0 = {1:.2e} Hz'
.format(2*P_half,f0))
# Step 2: Finding the Pole frequency
# -----------------------------------
# Calling bisect() to find where the power is equal to half the
# the peak power, thus P_half.
fp = opt.bisect(find_pole, 0, 1.0e4, args=(P_half), xtol=1e-6)
fwhm = 2*(fp-f0) # Computing FWHM
print('Pole found: f_p = {0:.2e} Hz'.format(fp))
print('FWHM = {0:.2e} Hz'.format(fwhm))
print()
return fwhm
```

Now we test our function for 3 different mirror reflectance configurations.

In [9]:

```
fwhm = [] # List for storing simulated fwhm
FWHM = [] # List for storing analytical fwhm
c = 299792458.0 # Speed of light
L = kat2.sL.L.value # Length of cavity
# 1st run, original, R1 = 0.7, R2 = 0.8
# --------------------------------------
R1 = 0.7
R2 = 0.8
# Simulated
fwhm.append(find_fwhm(kat2))
# Analytical
FWHM.append( (c/(L*np.pi))*
np.arcsin( (1-np.sqrt(R1*R2))/(2*(R1*R2)**(1/4) ) ) )
# 2nd run, R1 = 0.9, R2 = 0.8
# ---------------------------------------
R1 = 0.9
kat2.m1.R = R1
kat2.m1.T = 1-R1
# Simulated
fwhm.append(find_fwhm(kat2))
# Analytical
FWHM.append( (c/(L*np.pi))*
np.arcsin( (1-np.sqrt(R1*R2))/(2*(R1*R2)**(1/4) ) ) )
# 3rd run, R1 = 0.9, R2 = 0.95
R2 = 0.95
kat2.m2.R = R2
kat2.m2.T = 1-R2
# Simulated
fwhm.append(find_fwhm(kat2))
# Analytical
FWHM.append( (c/(L*np.pi))*
np.arcsin( (1-np.sqrt(R1*R2))/(2*(R1*R2)**(1/4) ) ) )
```

Printing the results to screen:

In [25]:

```
print('Cavity Linewidth in FWHM [Hz]')
print('--------------------------------------------------------------')
print('Run: \t\t1 \t\t2 \t\t3')
print('[R1, R2]: \t[{0}, {1}] \t[{2}, {1}] \t[{2}, {3}]'
.format(0.7,0.8,0.9,0.95))
print('Computed: \t{0[0]:.4e} Hz\t{0[1]:.4e} Hz\t{0[2]:.4e} Hz'
.format(fwhm))
print('Analytical: \t{0[0]:.4e} Hz\t{0[1]:.4e} Hz\t{0[2]:.4e} Hz'
.format(FWHM))
print('--------------------------------------------------------------')
```

\begin{align}
\mathrm{FWHM} = \frac{c}{\pi L}\arcsin \left[ \frac{1-r_1 r_2}{2\sqrt{r_1 r_2}} \right],
\end{align}

where $r_x = \sqrt{R_x}$.

In this session we have ...

- seen that the cavity linewidth depends on the cavity length and the reflectance of the mirrors.
- computed the linewidth of a cavity
- seen the analytical expression for the linewidth

In the next session we will go through what is meant by *Finesse* of a cavity.