Introduction

Welcome to the first notebook! This notebook is broken down into two sections. The first section aims to get you started with Finesse. It contains some basic tasks how to use two of the most important components in an interferometer, a mirror and a laser. The second section involves building up a Fabry-Perot cavity.

In [1]:
%run pykat_notebook_defaults.py
pykat.init_pykat_plotting()
                                              ..-
    PyKat 1.0.19          _                  '(
                          \`.|\.__...-""""-_." )
       ..+-----.._        /  ' `            .-'
   . '            `:      7/* _/._\    \   (
  (        '::;;+;;:      `-"' =" /,`"" `) /
  L.        \`:::a:f            c_/     n_'
  ..`--...___`.  .    ,  
   `^-....____:   +.      www.gwoptics.org/pykat

Imported matplotlib.pyplot as plt
Imported numpy as np
You can now use 'print(kat)' to display the Finesse code of a 'kat' object

Beams and mirrors

These first tasks are designed to get you accquainted with some of the basic features of how Finesse works. Here we will look just purely at a laser and mirror component and how the optical field behaves. These tasks will expand on what you already learned about theoretically in the lectures previous to this.

Tasks

These tasks will involve several steps each. This will usually be looking up how to write Finesse commands, forming a Finesse model, running the simulation with Pykat, and then relating the results you see back to the theory from the lectures.

Remember, these tasks are meant to get you thinking and comparing to the theory you learned in the lectures. Talk to your fellow students and ask lots of questions!

Task 1: Laser and a mirror

Write the Finesse code to model a laser outputting 10W of power that is incident on a mirror 1m away. The mirror should reflect 80% of the light and transmit 20%. You'll find the following references useful:

You should write your Finesse code in a multi-line string variable, for example:

code = """
This
is a
multi-line
string
"""

Each line should contain one Finesse command.

In [2]:
code = """
l l1 10 0 n0
s s1 1 n0 n1
m m1 0.8 0.2 0 n1 n2
"""

Task 2: Laser and a mirror kat object

(a) Create a kat object and add the Finesse code you created in Task 1 to it using the kat.parseCommands function.

(b) Add two photo diodes to measure the optical power reflected and transmitted at the mirror.

In [3]:
kat = finesse.kat()
kat.parseCommands(code)
kat.parseCommands("""
pd Prefl n1
pd Ptran n2
""")

Task 3: Power conservation

Using the kat object above, set kat.noxaxis = True. This tells Finesse to compute just one data point for our model and not change any parameters. You can also set kat.verbose = False to stop it from printing information when the simulation is running.

(a) Run this kat object to get the simulation output.

(b) Does the reflected and transmitted power match up with the input power?

In [4]:
kat.noxaxis = True
kat.verbose = False

out = kat.run()

print("Calculated powers")
print(out['Prefl'], out['Ptran'])

# Total power adds up to 10W
Calculated powers
8.0 2.0

Task 4: Complex fields

The optical field has both an amplitude and a phase. We can output this in Finesse using the amplitude detector (ad).

(a) For this task you should look up the syntax for the ad detector. Hint: the frequency given in the ad detector is relative to the default optical frequency $f = c/1064$nm. You can see what the default wavelength is using kat.lambda0.

(b) Add three amplitude detectors: one looking at the beam going into the mirror, one looking at the reflected field, and another looking at the transmitted field. Add the command yaxis abs:deg to output a complex number from Finesse so we can get the magnitude and phase of the field.

(c) Run the kat object and print the magnitude and phases of the optical fields. What is the difference in phase from the incident field to the reflected field and incident field to tranmitted field? Why is the phase different on transmission?

(d) What units do the pd and ad detector outputs in Finesse have?

In [5]:
# ad detector syntax
# ad name frequency node

kat = finesse.kat()
kat.parseCommands(code)
kat.parseCommands("""
ad aI 0 n1*
ad aR 0 n1
ad aT 0 n2
yaxis abs:deg
""")

kat.noxaxis = True
kat.verbose = False

out = kat.run()

out.info()

# We can see from the output that the reflected and incident field have the same phase
# but on transmission it is 90 degrees extra. This is due to the phase relationship at
# a surface to conserve energy.
--- Output info ---

Run date and time: 2017-07-11 10:03:25.421229
Detectors used: aI, aR, aT

No xaxis used
aI Abs         : min = 3.162277660168380e+00 max = 3.162277660168380e+00
aI Phase [Deg] : min = 0.000000000000000e+00 max = 0.000000000000000e+00
aR Abs         : min = 2.828427124746190e+00 max = 2.828427124746190e+00
aR Phase [Deg] : min = 0.000000000000000e+00 max = 0.000000000000000e+00
aT Abs         : min = 1.414213562373090e+00 max = 1.414213562373090e+00
aT Phase [Deg] : min = 9.000000000000000e+01 max = 9.000000000000000e+01
In [6]:
# The units of the pd detectors are Watts, the ad detectors is
# sqrt{Watt}, as Finesse scales the electric field so that |E|^2 = Power

Task 5: Mirror positions, or tunings

One of the most crucial aspects in optical interferometery is accurately positioning mirrors. The optical wavelengths we use in gravitational wave detectors is $\lambda=1064nm$. Typically we are interested in either macroscopic positioning, such as a mirror is 1m, 1cm, 1mm, etc. away, or in microscopic positions which are fractions of $\lambda$. The resonance condition of a Fabry-Perot cavity requires its length to be an integer number of half-wavelengths. For the light of an Nd:YAG laser, length differences $\ll \lambda=1064$nm are of interest. Some orders of magnitude:

  • LIGO peak senitivity in meters: $\sim 10^{-20}$ m
  • LIGO cavity mirror postion control accuracy: $< 10^{-12}$ m
  • LIGO arm cavity length: $\sim 10^3$ m
  • Relative numerical accuracy of floating point numbers: $10^{-15}$

As we can see there are many orders of magnitude difference between the lengths of cavities and the types of signal we might measure. With such a large dynamic range typical floating point variables used in computers cannot represent this. Thus we break lengths up into macroscopic and microscopic lengths. The length given by the space component are macroscopic and are always rounded to the nearest interger number of $\lambda$.

We change the microscopic length differences in Finesse by changing the mirrors tuning value. Tuning is usually refered to in units of degrees, 360 degrees $= \lambda$. So a tuning of 180 degrees means we have moved the mirror by half a wavelength. You can read more about this in the Living Review, section 2.5, "Lengths and tunings: numerical accuracy of distances".

The aim of this tasks is to think about the phase relationships Finesse uses, as this is important to grasp for later tasks.

(a) Using your kat object from before, change the mirror tuning by 90 degrees. How did the phase of the reflected and transmitted fields change relative to the incident field?

(b) If you change the tuning by 360 degrees, do the amplitudes of the optical fields change?

(c) If you change the length of the space between the mirror and laser, does it affect the phase?

In [7]:
kat = finesse.kat()
kat.parseCommands(code)
kat.parseCommands("""
ad aI 0 n1*
ad aR 0 n1
ad aT 0 n2
yaxis abs:deg
""")

kat.m1.phi += 90

kat.noxaxis = True
kat.verbose = False

out = kat.run()

out.info()

# The phase relationship on transmission has stayed the same, just 90 degrees, as the shifting position does not affect
# the phase accumulated on propagation. On reflection though the beam had to take a longer path than before, so it is now
# 180 degrees out of phase with the incident.
--- Output info ---

Run date and time: 2017-07-11 10:03:26.414553
Detectors used: aI, aR, aT

No xaxis used
aI Abs         : min = 3.162277660168380e+00 max = 3.162277660168380e+00
aI Phase [Deg] : min = 0.000000000000000e+00 max = 0.000000000000000e+00
aR Abs         : min = 2.828427124746190e+00 max = 2.828427124746190e+00
aR Phase [Deg] : min = 1.800000000000000e+02 max = 1.800000000000000e+02
aT Abs         : min = 1.414213562373090e+00 max = 1.414213562373090e+00
aT Phase [Deg] : min = 9.000000000000000e+01 max = 9.000000000000000e+01
In [8]:
kat.s1.L += 10

kat.run().info()

# The phases don't change when the length changes as Finesse defines that a space always has an integer number
# of wavelengths for the default frequency.
--- Output info ---

Run date and time: 2017-07-11 10:03:27.176711
Detectors used: aI, aR, aT

No xaxis used
aI Abs         : min = 3.162277660168380e+00 max = 3.162277660168380e+00
aI Phase [Deg] : min = 0.000000000000000e+00 max = 0.000000000000000e+00
aR Abs         : min = 2.828427124746190e+00 max = 2.828427124746190e+00
aR Phase [Deg] : min = 1.800000000000000e+02 max = 1.800000000000000e+02
aT Abs         : min = 1.414213562373090e+00 max = 1.414213562373090e+00
aT Phase [Deg] : min = 9.000000000000000e+01 max = 9.000000000000000e+01

Task 6: Scanning parameters

So far we have just run a single data point in our simulations. Usually we want to change some thing and see how the outputs vary, and we will be doing this a lot in the coming notebooks. In Finesse we vary parameters in a simulation using the xaxis command, this changes some parameter from one value to another and computes it for $N$ steps between them.

(a) Look up the syntax for the xaxis command.

(b) Add an xaxis command to change the input laser power from 1W to 10W in 20 steps.

(c) Plot the reflected and transmitted powers.

(d) Does the sum of reflected and transmitted power always equal the input power?

In [9]:
# xaxis command
# xaxis component parameter lin/log upper lower steps

kat = finesse.kat()
kat.parseCommands(code)
kat.parseCommands("""
pd Prefl n1
pd Ptran n2
yaxis abs:deg
xaxis l1 P lin 1 10 20
""")

kat.verbose = False

out = kat.run()

plt.plot(out.x, out['Prefl'], label="Refl")
plt.plot(out.x, out['Ptran'], label="Tran")
plt.plot(out.x, out['Prefl'] + out['Ptran'], label="Total")
plt.xlabel(out.xlabel)
plt.ylabel("Power [W]")
plt.legend()
plt.tight_layout()

Fabry-Perot Cavity

Optical cavities are based on the the original idea for a spectroscopy standard published by Fabry and Perot in 1899. Cavities are a fundamental building block of current gravitational wave detectors and an important instrument in laser optics. In this session we will model a simple optical cavity to demonstrate how numerical models can be used to design and understand the performance of a cavity for a given task.

At the end of this section you will be able to:

  • Create your own model of a cavity using Finesse and Pykat
  • Know the different types of Fabry-Perot cavities
  • Understand that due to limitations of numerical models, we must break down length changes into macro and microscopic changes.

The Optical Layout

Here we have a sketch of the setup that we want to model. It consists of a two mirror cavity m1 and m2 $L$ meters apart. On the input side we have a laser and a beamsplitter. The beamsplitter is separates the incident and reflected light in practise to allow us to measure the power. There is also then a photodiode on transmission to see any light leaving the cavity.

The above layout can be represented with Finesse commands as shown below:

In [10]:
cavity = """
l laser 2 0 n0  
s s1 1 n0 n1 
bs bs1 0.5 0.5 0 0 n1 n2 n3 n4
s s2 1 n3 nc1

m m1 0.8 0.2 0 nc1 nc2
s sL 3000 nc2 nc3
m m2 0.9 0.1 0 nc3 nc4
"""

Above we have defined each optical component with its own command. Each component has a one or more nodes. Each node is given a unique name, the node represents where a laser will enter or exit the component. For example, the line:

m m1 0.8 0.2 0 nc1 nc2

is a mirror called m1 which has two nodes called nc1 and nc2 which represent beams incident and reflected from either side, if the mirror is transmissive light will transmit through either way through the mirror too.

We then join different optical components together with space components, this describe how the laser propagates from each component to another.

Before proceeding you should familiarise yourself with code used and the parameters that have been set. For this the Finesse online syntax reference will be helpful. For example, from the above code can you extract what:

  • The reflectivities of the input and output mirrors?
  • The length of the cavity?
  • The power of the laser beam?

Tasks

In these tasks we shall build upon the knowledge taught in the lectures. We will do this by performing numerical experiments using Finesse. We want you to explore the behaviour of Fabry-Perot cavities for different parameter ranges. These tasks will give you an aim, but will not necessarily walk you through each step required. We will expect you to think about the problem and experiment to try and understand and solve it.

Task 1: Adding in power detectors

(a) Taking the Fabry-Perot Finesse model shown above add in the commands for three photodiodes to measure the DC power of light:

  • one to show the reflected power
  • one to show the transmitted power
  • and one to show the circulating power
In [11]:
kat = finesse.kat()
kat.parseCommands(cavity)
kat.parseCommands("""
pd circ nc2
pd refl nc1
pd tran nc4
""")

Task 2: Cavity scans

Run two simulations to show how the three cavity powers vary over these two variables:

  • (a) The microscopic position of the end mirror
  • (b) The laser frequency

Your plots should show a few resonances of the cavity.

(c) Extract the Free Spectral Range of this cavity from the modelled data. Tip: The Scipy package has a function for detecting multiple peaks called scipy.signal.find_peaks_cwt, which you might find useful

(d) How does this compare to the analytic result?

In [12]:
kat = finesse.kat()
kat.parseCommands(cavity)
kat.parseCommands("""
pd circ nc2
pd refl nc1
pd tran nc4
""")

_kat = kat.deepcopy()
_kat.parseCommands("xaxis m2 phi lin -90 450 1000")
fig = _kat.run().plot(ylabel="Power [W]")
--------------------------------------------------------------
Running kat - Started at 2017-07-11 10:03:37.646072
100% | ETA:  0:00:00 | Calculating                                             
Finished in 0.0773518 seconds
In [13]:
_kat = kat.deepcopy()
_kat.parseCommands("xaxis laser f lin 0 200k 1000")
out = _kat.run()
fig = out.plot(ylabel="Power [W]")
--------------------------------------------------------------
Running kat - Started at 2017-07-11 10:03:38.559943
 96% | ETA:  0:00:00 | Calculating                                             
Finished in 0.0736098 seconds
100% | ETA:  0:00:00 | Calculating                                             
In [14]:
from scipy.signal import find_peaks_cwt

indexes = find_peaks_cwt(out['circ'], np.ones_like(out['circ']))

print("Modelled FSR: ", out.x[indexes][2]-out.x[indexes][1])
print("Calculated FSR: ", 3e8/6000)
Modelled FSR:  50000.0
Calculated FSR:  50000.0

Task 3: Cavity types

Run three simulations to show how the reflected, transmitted, and circulating cavity powers vary over microscopic tuning for:

  • (a) impedance matched cavity
  • (b) overcoupled cavity
  • (c) undercoupled cavity

Hint: You might find the kat.m2.setRTL(R, T, L) method for changing the mirror parameters useful.

Your plots should show a few resonances of the cavity.

  • (d) What interesting feature does an impedance matched cavity have?
  • (e) In gravitational wave detectors we typically want very high optical powers, Is an over and under coupled cavity better for getting a higher circulating power in the cavity?
In [15]:
kat = finesse.kat()
kat.verbose = False
kat.parseCommands(cavity)
kat.parseCommands("""
pd circ nc2
pd refl nc1
pd tran nc4
""")

for R, title in zip([kat.m1.R.value-0.2, kat.m1.R.value, 1],
             ["Under", "Impedance", "Over"]):
    _kat = kat.deepcopy()
    _kat.m2.setRTL(R,1-R,0)
    _kat.parseCommands("xaxis m2 phi lin -90 450 1000")
    fig = _kat.run().plot(ylabel="Power [W]", title=title)
In [16]:
# We see some interesting features here:
# Impendance matched allows all the light to be transmitted through the cavity.
# Over coupled reflects all the light
# Over coupled has a much larger circulating power compared to under coupled.

Task 4: Frequency response, FWHM, and finesse

This taks is about used modelled data to extract some cavity parameters. You should experiment with ways to achieve this task.

Using your overcoupled Fabry-Perot cavity Finesse model with R=0.9 and T=0.1 for the input mirror:

(a) Plot the power circulating in the cavity as a function of the input laser frequency. You should change the laser frequency by at least two Free Spectral Ranges of the cavity.

(b) Using this data, compute the cavity's full-width-half-maximum and finesse. Compare these results to analytic solutions. There isn't one specific way to do this task, you should experiment and problem solve!

In [17]:
kat = finesse.kat()
kat.verbose = False
kat.parseCommands(cavity)
kat.m1.setRTL(0.9,0.1,0)
kat.m2.setRTL(1,0,0)
kat.parseCommands("""
pd circ nc2
xaxis laser f lin 20k 120k 1000
""")
out = kat.run()
In [18]:
from scipy.signal import find_peaks_cwt

indexes = find_peaks_cwt(out['circ'], np.ones_like(out['circ']))
FSR = out.x[indexes][2] - out.x[indexes][1]
FSR
Out[18]:
50000.0
In [23]:
# To find the FWHM we'll make a zoomed in plot around the 50kHz resonance
kat = finesse.kat()
kat.verbose = False
kat.parseCommands(cavity)
kat.m1.setRTL(0.9,0.1,0)
kat.m2.setRTL(1,0,0)
kat.parseCommands("""
pd circ nc2
xaxis laser f lin 49.5k 50.5k 1000
""")
out = kat.run()

plt.plot(out.x, out['circ']/out['circ'].max())
Out[23]:
[<matplotlib.lines.Line2D at 0x112094c50>]
In [24]:
# Reading from this plot we can roughly see the FWHM is 800Hz
In [25]:
print("Modelled finesse =", FSR/800)
Calculated finesse = 62.5
In [29]:
print("Calculated finesse =", 2*np.pi/0.1) 
Calculated finesse = 62.83185307179586
In [ ]: