The ‘frequency_response’ action for modelling transfer functions

As seen in the previous section we can manually compute single input to multiple output (SIMO) transfer functions with a few lines of KatScript. If we wanted to inject multiple signals separately from one another to compute a full multiple input multiple output (MIMO) it can get awkward with the manual method. This would require adding and removing signal generators in some for-loop then concatenating all the results together.

In Finesse 3 we have introduced the Readout component. This is a mix of a detector and a component. it has one optical port for light to be incident on, then it can have one or several output electrical ports. This means instead of taking transfer functions from some signal generator to a detector, we can simple take specify electrical or mechanical nodes to inject a signal at, then simply read the result out at another node.

Consider a similar example to what we discussed in the previous section: a laser beam reflected from a mirror far away then back on to a photodiode. Instead of specifying a power detector pd1 we now use a readout_dc component which we’ll call REFL. This models a photodiode which measures signal fluctuations and converts it into an electrical output at the port REFL.DC. You’ll notice in this we do not need to specify the signal frequency like we did previously with pd1

import finesse
finesse.init_plotting()

model = finesse.Model()
model.parse("""
l l1 P=1
s s1 l1.p1 m1.p1 L=10k
m m1 R=1 T=0
readout_dc REFL l1.p1.i

butter current_drive 1 lowpass 5k
link(current_drive, l1.amp)

fsig(1)
""")

Now we introduce a new analysis that can be performed on a model, the frequency_response action. This single action allows you to inject multiple signals and read them out at multiple outputs over a generic frequency vector. Above we use the geomspace(start, stop, steps) (:seealso: numpy.geomspace) to create a logarithmic vector (linspace is also available as well as specify arbitrary ones, e.g. [1, 10, 11.5, 18]). Next we provide an array of inputs nodes, followed by an array (or singular in this case) output node.

model.parse("""
frequency_response(
    geomspace(100, 100k, 100),       # frequency vector
    [current_drive.p1.i, l1.amp.i],  # injection nodes
    REFL.DC.o                        # output nodes
)
""")
sol = model.run()
sol.plot();
<Figure size 576x355.968 with 0 Axes>
../../_images/readouts_1_1.svg
sol.plot_readouts(); # alternate plot method
../../_images/readouts_2_0.svg

Note

In cases where a port only has a single node you can just write the port for shorthand REFL.DC.o is equivalent to REFL.DC when some element or command expects a node.