From 4d1730297f07871bff09fc8e97a49c62b89da4c5 Mon Sep 17 00:00:00 2001 From: Daniel Brown <ddb@star.sr.bham.ac.uk> Date: Fri, 31 Jan 2014 01:21:22 +0000 Subject: [PATCH] adding in fsig command (not parsing yet). See example test_fsig.py in bin folder. Also made component variable an optional argument for xaxis and x2axis which will break previous scripts. Did this as when setting the parameter to tune, the Param object contains whatever component owns that parameter so no need to pass it twice. Also stops someone passing a parameter not for the component stated. --- bin/test_fsig.py | 50 +++++++++++++++++++ pykat/commands.py | 24 +++++---- pykat/components.py | 12 ++--- pykat/finesse.py | 116 ++++++++++++++++++++++++++++++++++++++++++-- pykat/param.py | 19 +++++++- 5 files changed, 195 insertions(+), 26 deletions(-) create mode 100644 bin/test_fsig.py diff --git a/bin/test_fsig.py b/bin/test_fsig.py new file mode 100644 index 0000000..2e5b318 --- /dev/null +++ b/bin/test_fsig.py @@ -0,0 +1,50 @@ +from pykat import finesse +from pykat.detectors import * +from pykat.components import * +from pykat.commands import * +from pykat.structs import * + +import numpy as np +import pylab as pl + +code = """ +l l1 2 0 n1 +m m1 0.99 0.01 0 n1 n2 +s cav1 1200 n2 n3 +m m2 0.99 0.01 -0.1 n3 n4 + +attr m2 m 1 # mech sus1 + +ad up_refl 0 n1 +ad low_refl 0 n1 + +qd refl_A 0 0 n1 +qd refl_Q 0 90 n1 +qd tran_A 0 0 n4 +qd tran_Q 0 90 n4 + +put up_refl f $x1 +put low_refl f $mx1 + +yaxis log re:im +""" + +kat = finesse.kat(kat_code=code) + +kat.signals.apply(kat.l1.power, 1, 0) +kat.signals.apply(kat.m1.phi, 1, 90) + +kat.add(xaxis('log', [1, 1000], kat.signals.f, 100)) + +out = kat.run(printout=0, printerr=0) + +# using real and imag part compute the complex value of the upper and lower sidebands +a_up = out.y[:,0] + out.y[:,1]*1j +a_lo = out.y[:,2] + out.y[:,3]*-1j + +pl.figure(1) +pl.loglog(out.x, np.abs(a_up + a_lo), out.x, np.abs((a_up - a_lo) / (1j))) +pl.xlabel(out.xlabel) +pl.title("Reflection quadratures with no relative carrier phase") +pl.legend(["Amplitude","Phase"]) +pl.show() \ No newline at end of file diff --git a/pykat/commands.py b/pykat/commands.py index 27a3bda..a47b0dd 100644 --- a/pykat/commands.py +++ b/pykat/commands.py @@ -10,6 +10,7 @@ import exceptions from components import * from structs import * from pykat.param import Param, putter +import pykat.exceptions as pkex class Command(object): def __init__(self): @@ -50,7 +51,7 @@ class gauss(object): class xaxis(Command): - def __init__(self, scale, limits, comp, param, steps, axis_type="xaxis"): + def __init__(self, scale, limits, param, steps, comp=None, axis_type="xaxis"): self._axis_type = axis_type self.x = putter("x1") @@ -79,20 +80,17 @@ class xaxis(Command): self.steps = int(steps) - # if entered component is a string then just store and use that - if isinstance(comp, str): - self.__comp = comp - elif not isinstance(comp, Component): - raise exceptions.ValueError("{0} has not been added".format(comp)) - else: - self.__comp = comp - if isinstance(param, str): self.__param = param + if comp == None: + raise pkex.BasePyKatException("If parameter is set with a string, the comp argument must set the component name") + + self.__comp = comp elif not isinstance(param, Param) : - raise exceptions.ValueError("param argument is not of type Param") + raise pkex.BasePyKatException("param argument is not of type Param") else: self.__param = param + self.__comp = param._owner.name @staticmethod def parseFinesseText(text): @@ -108,7 +106,7 @@ class xaxis(Command): if len(values) != 6: raise exceptions.RuntimeError("xaxis Finesse code format incorrect '{0}'".format(text)) - return xaxis(values[2], [values[3], values[4]], values[0], values[1], values[5], axis_type=axis_type) + return xaxis(values[2], [values[3], values[4]], values[1], values[5], comp=values[0], axis_type=axis_type) def getFinesseText(self): # store either the component name of the string provided @@ -120,8 +118,8 @@ class xaxis(Command): min(self.limits), max(self.limits), self.steps, axis_type=self._axis_type); class x2axis(xaxis): - def __init__(self, scale, limits, comp, param, steps): - xaxis.__init__(self, scale, limits, comp, param, steps, axis_type="x2axis") + def __init__(self, scale, limits, param, steps, comp=None): + xaxis.__init__(self, scale, limits, param, steps, comp=comp, axis_type="x2axis") self.x = putter("x2") self.mx = putter("mx2") diff --git a/pykat/components.py b/pykat/components.py index 8a37f6f..696c42e 100644 --- a/pykat/components.py +++ b/pykat/components.py @@ -158,11 +158,11 @@ class AbstractMirrorComponent(Component): self.__R = Param("R", self, SIfloat(R)) self.__T = Param("T", self, SIfloat(T)) - self.__phi = Param("phi", self, SIfloat(phi)) + self.__phi = Param("phi", self, SIfloat(phi), canFsig=True, fsig_name="phs") self.__Rcx = AttrParam("Rcx", self, SIfloat(Rcx)) self.__Rcy = AttrParam("Rcy", self, SIfloat(Rcy)) - self.__xbeta = AttrParam("xbeta", self, SIfloat(xbeta)) - self.__ybeta = AttrParam("ybeta", self, SIfloat(ybeta)) + self.__xbeta = AttrParam("xbeta", self, SIfloat(xbeta), canFsig=True, fsig_name="x") + self.__ybeta = AttrParam("ybeta", self, SIfloat(ybeta), canFsig=True, fsig_name="y") self.__mass = AttrParam("mass", self, SIfloat(mass)) self.__r_ap = AttrParam("r_ap", self, SIfloat(r_ap)) @@ -682,9 +682,9 @@ class laser(Component): self._requested_node_names.append(node) - self.__power = Param("P", self, SIfloat(P)) - self.__f_offset = Param("f", self, SIfloat(f_offset)) - self.__phase = Param("phase", self, SIfloat(phase)) + self.__power = Param("P", self, SIfloat(P), canFsig=True, fsig_name="amp") + self.__f_offset = Param("f", self, SIfloat(f_offset), canFsig=True, fsig_name="f") + self.__phase = Param("phase", self, SIfloat(phase), canFsig=True, fsig_name="phs") self.__noise = AttrParam("noise", self, 0) @property diff --git a/pykat/finesse.py b/pykat/finesse.py index a40f858..c94ef79 100644 --- a/pykat/finesse.py +++ b/pykat/finesse.py @@ -40,6 +40,7 @@ from pykat.components import Component from pykat.commands import Command, xaxis from pykat.gui.gui import pyKatGUI from pykat.SIfloat import * +from pykat.param import Param, AttrParam import pykat.exceptions as pkex @@ -127,7 +128,98 @@ class katRun2D(object): return self.z[idx].squeeze() else: raise pkex.BasePyKatException("No output by the name {0} found".format(str(value))) - + +class Signals: + class fsig: + def __init__(self, param, name, amplitude, phase): + self._params = [] + self.__target = param + self.__name = name + self.__amplitude = Param("amp", self, SIfloat(amplitude)) + self.__phase = Param("phase", self, SIfloat(phase)) + + # unfortunatenly the target names for fsig are not the same as the + # various parameter names of the components, e.g. mirror xbeta is x + # for fsig. So we need to check here what type of component we are targetting + # and then based on the parameter specfied get the name + if not param.canFsig: + raise pkex.BasePyKatException("Cannot fsig parameter {1} on component {0}".format(str(param._owner), param.name)) + + + def _register_param(self, param): + self._params.append(param) + + @property + def name(self): return self.__name + + @property + def amplitude(self): return self.__amplitude + + @property + def phase(self): return self.__phase + + @property + def target(self): return self.__target.fsig_name + + @property + def owner(self): return self.__target._owner.name + + def getFinesseText(self): + rtn = [] + + for p in self._params: + rtn.extend(p.getFinesseText()) + + return rtn + + @property + def name(self): + # if we don't have any signals yet then use a dummy name + # however we need to always tune a real fsig command + # so need to get the name of at least one of them + # as if you tune one you tune them all + if len(self.targets) == 0: + return "signal" + else: + return self.targets[0].name + + @property + def f(self): return self.__f + + def __init__(self): + + self.targets = [] + self._params = [] + + self.__f = Param("f", self, 1) + + def _register_param(self, param): + self._params.append(param) + + def apply(self, target, amplitude, phase, name=None): + + if target == None: + raise pkex.BasePyKatException("No target was specified for signal to be applied") + + if name == None: + name = "sig_" +target._owner.name + "_" + target.name + + self.targets.append(Signals.fsig(target, name, amplitude, phase)) + + + def getFinesseText(self): + rtn = [] + + for t in self.targets: + rtn.extend(t.getFinesseText()) + rtn.append("fsig {name} {comp} {target} {frequency} {phase} {amplitude}".format(name = t.name, comp=t.owner, target=t.target, frequency=str(self.f), phase=str(t.phase), amplitude=str(t.amplitude))) + + for p in self._params: + rtn.extend(p.getFinesseText()) + + return rtn + + class Block: def __init__(self, name): self.__name = name @@ -154,10 +246,11 @@ class kat(object): self.__tempdir = tempdir self.__tempname = tempname self.pykatgui = None - - # initialise default block - self.__currentTag= NO_BLOCK - self.__blocks[NO_BLOCK] = Block(NO_BLOCK) + self.__signals = Signals() + + # initialise default block + self.__currentTag= NO_BLOCK + self.__blocks[NO_BLOCK] = Block(NO_BLOCK) # Various options for running finesse, typicaly the commands with just 1 input # and have no name attached to them. @@ -181,6 +274,9 @@ class kat(object): cls = type(self) self.__class__ = type(cls.__name__, (cls,), {}) + @property + def signals(self): return self.__signals + @property def maxtem(self): return self.__maxtem @maxtem.setter @@ -689,6 +785,16 @@ class kat(object): out.append(txt + "\n") + # now get any signal commands + txt = self.signals.getFinesseText() + + if txt != None: + if isinstance(txt,list): + for t in txt: out.append(t+ "\n") + else: + out.append(txt + "\n") + + if self.scale != None and self.scale !='': out.append("scale {0}\n".format(self.scale)) if self.phase != None: out.append("phase {0}\n".format(self.phase)) if self.maxtem != None: out.append("maxtem {0}\n".format(self.maxtem)) diff --git a/pykat/param.py b/pykat/param.py index e47d378..52a5fc8 100644 --- a/pykat/param.py +++ b/pykat/param.py @@ -57,13 +57,22 @@ class putter(object): class Param(putable, putter): - def __init__(self, name, owner, value, isPutable=True, isPutter=True, isTunable=True, var_name=None): + def __init__(self, name, owner, value, canFsig=False, fsig_name=None, isPutable=True, isPutter=True, isTunable=True, var_name=None): self._name = name self._owner = owner self._value = value self._isPutter = isPutter self._isTunable = isTunable self._owner._register_param(self) + self._canFsig = False + + if canFsig: + self._canFsig = True + + if fsig_name == None: + raise pkex.BasePyKatException("If parameter is a possible fsig target the fsig_name argument must be set") + + self.__fsig_name = fsig_name if isPutter: if var_name == None: @@ -73,7 +82,13 @@ class Param(putable, putter): if isPutable: putable.__init__(self, owner.name, name, isPutable) - + + @property + def canFsig(self): return self._canFsig + + @property + def fsig_name(self): return self.__fsig_name + @property def name(self): return self._name -- GitLab