Skip to content
Snippets Groups Projects
Commit 82344541 authored by Andreas Freise's avatar Andreas Freise
Browse files

cleaning up code, moving more code here, small change to finesse file

parent ae7cc3c7
No related branches found
No related tags found
No related merge requests found
Pipeline #
...@@ -39,11 +39,13 @@ ...@@ -39,11 +39,13 @@
# should have losses but no reflectivity. Alternatively beamsplitter components # should have losses but no reflectivity. Alternatively beamsplitter components
# with non-zero reflectivity can be used to detect the AR reflections # with non-zero reflectivity can be used to detect the AR reflections
# - Same as above for PRM and SRM AR coatings # - Same as above for PRM and SRM AR coatings
# - change order of `cav' commands, arm cavities need to come first
# #
# Change of parameter values # Change of parameter values
# - BS substrate length were assymetric and did not match substrate thickness, # - BS substrate length were assymetric and did not match substrate thickness,
# changed to symmetric 0.0687m, using pykat.GWdetectors.aLIGO.BSpath(0.06) # changed to symmetric 0.0687m, using pykat.GWdetectors.aLIGO.BSpath(0.06)
# - changed SRM transmission from 35% to 20%, matching the aLIGO 2015 paper # - changed SRM transmission from 35% to 20%, matching the aLIGO 2015 paper
# - changed arm length to L=3994.4692, see [4], Table 10.2
# #
# Changes in file structure # Changes in file structure
# - removed length calculation fucntions for PRC and SRC sub-length # - removed length calculation fucntions for PRC and SRC sub-length
...@@ -54,24 +56,8 @@ ...@@ -54,24 +56,8 @@
# - changed naming for thermal lens components # - changed naming for thermal lens components
# - changed naming of PRMHR to PRM and node names in PRM substrate # - changed naming of PRMHR to PRM and node names in PRM substrate
# - changed naming of SRMHR to SRM and node names in SRM substrate # - changed naming of SRMHR to SRM and node names in SRM substrate
# - chnaged name of ITMHR to ITM and ETMHR to ETM # - changed name of ITMHR to ITM and ETMHR to ETM
# - # - changed names of arm spaces from LXarm, LYarm to LX, LY
# Laser
#
# Modulation
#
# IMC
#
# PRC
#
# BS
#
# Arms
# - changed arm length to L=3994.4692, see [4], Table 10.2
#
# SRC
#
# OMC
# #
# #
...@@ -174,7 +160,7 @@ m1 ITMY 0.014 $Mloss $phi_ITMY nITMYs2 nITMY2 ...@@ -174,7 +160,7 @@ m1 ITMY 0.014 $Mloss $phi_ITMY nITMYs2 nITMY2
attr ITMY Rc -1934 attr ITMY Rc -1934
# Y arm length # Y arm length
s LYarm $Larm nITMY2 nETMY1 s LY $Larm nITMY2 nETMY1
# Y arm end mirror # Y arm end mirror
m1 ETMY 5u $Mloss $phi_ETMY nETMY1 nETMYs1 m1 ETMY 5u $Mloss $phi_ETMY nETMY1 nETMYs1
...@@ -208,7 +194,7 @@ m1 ITMX 0.014 $Mloss $phi_ITMX nITMXs2 nITMX2 ...@@ -208,7 +194,7 @@ m1 ITMX 0.014 $Mloss $phi_ITMX nITMXs2 nITMX2
attr ITMX Rc -1934 attr ITMX Rc -1934
# X arm length # X arm length
s LXarm $Larm nITMX2 nETMX1 s LX $Larm nITMX2 nETMX1
# X arm end mirror # X arm end mirror
m1 ETMX 5u $Mloss $phi_ETMX nETMX1 nETMXs1 m1 ETMX 5u $Mloss $phi_ETMX nETMX1 nETMXs1
...@@ -250,12 +236,12 @@ attr SRM Rc -5.6938 ...@@ -250,12 +236,12 @@ attr SRM Rc -5.6938
########################################################################### ###########################################################################
maxtem 4 maxtem 4
#cav cavIMC MC2 nMC2in MC2 nMC2refl #cav cavIMC MC2 nMC2in MC2 nMC2refl
cav cavXARM ITMX nITMX2 ETMX nETMX1
cav cavYARM ITMY nITMY2 ETMY nETMY1
cav cavPRX PRM nPRM2 ITMX nITMXs2 cav cavPRX PRM nPRM2 ITMX nITMXs2
cav cavPRY PRM nPRM2 ITMY nITMYs2 cav cavPRY PRM nPRM2 ITMY nITMYs2
cav cavSRX SRM nSRM1 ITMX nITMXs2 cav cavSRX SRM nSRM1 ITMX nITMXs2
cav cavSRY SRM nSRM1 ITMY nITMYs2 cav cavSRY SRM nSRM1 ITMY nITMYs2
cav cavXARM ITMX nITMX2 ETMX nETMX1
cav cavYARM ITMY nITMY2 ETMY nETMY1
# removed OMC # removed OMC
########################################################################### ###########################################################################
...@@ -334,7 +320,6 @@ pd1 AS_f2_Q $f2 103 nSRM2 ...@@ -334,7 +320,6 @@ pd1 AS_f2_Q $f2 103 nSRM2
%%% FTblock locks %%% FTblock locks
########################################################################### ###########################################################################
set PRCL_err POP_f1_I re set PRCL_err POP_f1_I re
set MICH_err POP_f2_Q re set MICH_err POP_f2_Q re
set CARM_err REFL_f1_I re set CARM_err REFL_f1_I re
......
...@@ -75,15 +75,15 @@ class aLIGO(object): ...@@ -75,15 +75,15 @@ class aLIGO(object):
if "f3" in self.kat.constants.keys(): if "f3" in self.kat.constants.keys():
self.f3 = float(self.kat.constants["f3"].value) self.f3 = float(self.kat.constants["f3"].value)
# TODO add else here! # TODO add else here!
# check modultion frequencies
if (5 * self.f1 != self.f2):
print(" ** Warning: modulation frequencies do not match: 5*f1!=f2")
# defining a dicotionary for the main mirror positions (tunings) # defining a dicotionary for the main mirror positions (tunings)
self.tunings = {} self.tunings = {}
self.tunings = self.get_tunings(self.kat) self.tunings = self.get_tunings(self.kat)
# compute lengths such as PRC lentgth from individual lengths
self.compute_derived_lengths(self.kat) self.compute_derived_lengths(self.kat)
# check modultion frequencies
if (5 * self.f1 != self.f2):
print(" ** Warning: modulation frequencies do not match: 5*f1!=f2")
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# define ports and signals # define ports and signals
...@@ -114,16 +114,16 @@ class aLIGO(object): ...@@ -114,16 +114,16 @@ class aLIGO(object):
def adjust_PRC_length(self, kat): def adjust_PRC_length(self, kat, verbose=False):
""" """
Adjust PRC length so that it fulfils the requirement Adjust PRC length so that it fulfils the requirement
lPRC = (N+1/2) * c/(2*f1), see [1] equation C.1 lPRC = (N+1/2) * c/(2*f1), see [1] equation C.1
In the current design N=3 In the current design N=3
""" """
print("-- adjusting PRC length") vprint(verbose, "-- adjusting PRC length")
ltmp = 0.5 * clight / self.f1 ltmp = 0.5 * clight / self.f1
delta_l = 3.5 * ltmp - self.lPRC delta_l = 3.5 * ltmp - self.lPRC
print(" adusting kat.lp1.L by {}m".format(delta_l)) vprint(verbose, " adusting kat.lp1.L by {:.4g}m".format(delta_l))
kat.lp1.L += delta_l kat.lp1.L += delta_l
self.compute_derived_lengths(kat) self.compute_derived_lengths(kat)
...@@ -136,15 +136,19 @@ class aLIGO(object): ...@@ -136,15 +136,19 @@ class aLIGO(object):
kat = _kat.deepcopy() kat = _kat.deepcopy()
fig = plt.figure() fig = plt.figure()
ax = fig.add_subplot(1,1,1) ax = fig.add_subplot(1,1,1)
startf = self.f1-400.0 startf = self.f1-4000.0
stopf = self.f1+400.0 stopf = self.f1+4000.0
if _kat.maxtem == "off":
nmStr = None
else:
nmStr = "0 0"
code = """ code = """
ad f1p {0} nPRM2 ad f1p {0} {1} nPRM2
ad f1m -{0} nPRM2 ad f1m {0} -{1} nPRM2
xaxis mod1 f lin {1} {2} 200 xaxis mod1 f lin {2} {3} 200
put f1p f $x1 put f1p f $x1
put f1m f $mx1 put f1m f $mx1
""".format(self.f1, startf, stopf) """.format(nmStr, self.f1, startf, stopf)
kat.parseCommands(code) kat.parseCommands(code)
out = kat.run() out = kat.run()
ax.plot(out.x-self.f1,np.abs(out["f1p"]), label=" f1") ax.plot(out.x-self.f1,np.abs(out["f1p"]), label=" f1")
...@@ -177,13 +181,31 @@ class aLIGO(object): ...@@ -177,13 +181,31 @@ class aLIGO(object):
self.lPRC = self.lpr + self.lMI self.lPRC = self.lpr + self.lMI
self.lSRC = self.lsr + self.lMI self.lSRC = self.lsr + self.lMI
self.lSchnupp = self.lx - self.ly self.lSchnupp = self.lx - self.ly
if verbose: self.compute_derived_resonances(kat)
print("-- small MI lengths")
print(" lx = {}m, ly = {}m".format(np.round(self.lx, 4), np.round(self.ly, 4))) def compute_derived_resonances(self, kat):
#print(" lpr = {}m, lsr = {}m".format(np.round(self.lpr, 4), np.round(self.lsr),4)) self.fsrX = 0.5 * clight / float(kat.LX.L)
#print(" lMI = {}m, lSchnupp = {}m".format(np.round(self.lMI, 4) , self.lSchnupp)) self.fsrY = 0.5 * clight / float(kat.LY.L)
print(" lSchnupp = {}m".format(np.round(self.lSchnupp,4))) self.fsrPRC = 0.5 * clight / self.lPRC
print(" lPRC = {}m, lSRC= {}m".format(self.lPRC, self.lSRC)) self.fsrSRC = 0.5 * clight / self.lSRC
self.f1_PRC = 3.5 * self.fsrPRC
def lengths_status(self, kat):
print(" .--------------------------------------------------.")
print("| - arm length: |")
print("| Lx = {:11.7}m, Ly = {:11.7}m |".format(float(kat.LX.L), float(kat.LY.L)))
print("| - small MI and recycling lengths: | ")
print("| lx = {:11.7}m, ly = {:11.7}m |".format(self.lx, self.ly))
print("| lpr = {:11.7}m, lsr = {:11.7}m |".format(self.lpr, self.lsr))
print("| lMI = {:11.7}m, lSchnupp = {:11.5}m |".format(self.lMI, self.lSchnupp))
print("| lPRC = {:11.7}m, lSRC = {:11.7}m |".format(self.lPRC, self.lSRC))
print("+---------------------------------------------------+")
print("| - associated cavity frequencies [Hz]: |")
print("| fsrx = {:11.8}, fsry = {:11.8} |".format(self.fsrX, self.fsrY))
print("| fsrPRC = {:11.8}, fsrSRC = {:11.8} |".format(self.fsrPRC, self.fsrSRC))
print("| f1_PRC = {:11.8} |".format(self.f1_PRC))
print("| f1 = {:11.8}, f2 = {:11.9} |".format(self.f1, self.f2))
print(" `--------------------------------------------------'")
def get_tunings(self, kat): def get_tunings(self, kat):
self.tunings["maxtem"] = kat.maxtem self.tunings["maxtem"] = kat.maxtem
...@@ -208,36 +230,36 @@ class aLIGO(object): ...@@ -208,36 +230,36 @@ class aLIGO(object):
def apply_lock_feedback(self, kat, out): def apply_lock_feedback(self, kat, out):
tuning = self.get_tunings(kat) tuning = self.get_tunings(kat)
if "ETMX_lock" in out.keys(): if "ETMX_lock" in out.ylabels:
tuning["ETMX"] += float(out["ETMX_lock"]) tuning["ETMX"] += float(out["ETMX_lock"])
else: else:
print(" ** Warning: could not find ETMX lock") print(" ** Warning: could not find ETMX lock")
if "ETMY_lock" in out.keys(): if "ETMY_lock" in out.ylabels:
tuning["ETMY"] += float(out["ETMY_lock"]) tuning["ETMY"] += float(out["ETMY_lock"])
else: else:
print(" ** Warning: could not find ETMY lock") print(" ** Warning: could not find ETMY lock")
if "PRCL_lock" in out.keys(): if "PRCL_lock" in out.ylabels:
tuning["PRM"] += float(out["PRCL_lock"]) tuning["PRM"] += float(out["PRCL_lock"])
else: else:
print(" ** Warning: could not find PRCL lock") print(" ** Warning: could not find PRCL lock")
if ("MICH_lock" in out.keys()) and ("ITMY_lock" in out.keys()): if ("MICH_lock" in out.ylabels) and ("ITMY_lock" in out.ylabels):
tuning["ITMX"] += float(out["MICH_lock"]) tuning["ITMX"] += float(out["MICH_lock"])
tuning["ITMY"] += float(out["ITMY_lock"]) tuning["ITMY"] += float(out["ITMY_lock"])
else: else:
print(" ** Warning: could not find MICH (ITMY) lock") print(" ** Warning: could not find MICH (ITMY) lock")
if "SRCL_lock" in out.keys(): if "SRCL_lock" in out.ylabels:
tuning["SRM"] += float(out["SRCL_lock"]) tuning["SRM"] += float(out["SRCL_lock"])
else: else:
print(" ** Warning: could not find SRCL lock") print(" ** Warning: could not find SRCL lock")
self.set_tunings(kat, tuning) self.set_tunings(kat, tuning)
def pretune(self, _kat, pretune_precision=1.0e-4): def pretune(self, _kat, pretune_precision=1.0e-4, verbose=False):
print("-- pretuning interferometer to precision {0:2g} deg = {1:2g} m".format(pretune_precision, pretune_precision*_kat.lambda0/360.0)) print("-- pretuning interferometer to precision {0:2g} deg = {1:2g} m".format(pretune_precision, pretune_precision*_kat.lambda0/360.0))
kat=_kat.deepcopy() kat=_kat.deepcopy()
#_kat.ITMX.phi=0.0 #_kat.ITMX.phi=0.0
#_kat.ITMY.phi=0.0 #_kat.ITMY.phi=0.0
print(" scanning X arm (maximising power)") vprint(verbose, " scanning X arm (maximising power)")
kat1 = kat.deepcopy() kat1 = kat.deepcopy()
make_transparent(kat1,["PRM","SRM"]) make_transparent(kat1,["PRM","SRM"])
make_transparent(kat1,["ITMY", "ETMY"]) make_transparent(kat1,["ITMY", "ETMY"])
...@@ -245,10 +267,10 @@ class aLIGO(object): ...@@ -245,10 +267,10 @@ class aLIGO(object):
phi, precision = self.scan_to_precision(kat1, self.preARMX, pretune_precision) phi, precision = self.scan_to_precision(kat1, self.preARMX, pretune_precision)
phi=round(phi/pretune_precision)*pretune_precision phi=round(phi/pretune_precision)*pretune_precision
phi=round_to_n(phi,5) phi=round_to_n(phi,5)
print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision))
self.preARMX.apply_tuning(_kat,phi) self.preARMX.apply_tuning(_kat,phi)
print(" scanning Y arm (maximising power)") vprint(verbose, " scanning Y arm (maximising power)")
kat = _kat.deepcopy() kat = _kat.deepcopy()
make_transparent(kat,["PRM","SRM"]) make_transparent(kat,["PRM","SRM"])
make_transparent(kat,["ITMX", "ETMX"]) make_transparent(kat,["ITMX", "ETMX"])
...@@ -256,34 +278,35 @@ class aLIGO(object): ...@@ -256,34 +278,35 @@ class aLIGO(object):
phi, precision = self.scan_to_precision(kat, self.preARMY, pretune_precision) phi, precision = self.scan_to_precision(kat, self.preARMY, pretune_precision)
phi=round(phi/pretune_precision)*pretune_precision phi=round(phi/pretune_precision)*pretune_precision
phi=round_to_n(phi,5) phi=round_to_n(phi,5)
print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision))
self.preARMY.apply_tuning(_kat,phi) self.preARMY.apply_tuning(_kat,phi)
print(" scanning MICH (minimising power)") vprint(verbose, " scanning MICH (minimising power)")
kat = _kat.deepcopy() kat = _kat.deepcopy()
make_transparent(kat,["PRM","SRM"]) make_transparent(kat,["PRM","SRM"])
phi, precision = self.scan_to_precision(kat, self.preMICH, pretune_precision, minmax="min", precision=30.0) phi, precision = self.scan_to_precision(kat, self.preMICH, pretune_precision, minmax="min", precision=30.0)
phi=round(phi/pretune_precision)*pretune_precision phi=round(phi/pretune_precision)*pretune_precision
phi=round_to_n(phi,5) phi=round_to_n(phi,5)
print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision))
self.preMICH.apply_tuning(_kat,phi, add=True) self.preMICH.apply_tuning(_kat,phi, add=True)
print(" scanning PRCL (maximising power)") vprint(verbose, " scanning PRCL (maximising power)")
kat = _kat.deepcopy() kat = _kat.deepcopy()
make_transparent(kat,["SRM"]) make_transparent(kat,["SRM"])
phi, precision = self.scan_to_precision(kat, self.prePRCL, pretune_precision) phi, precision = self.scan_to_precision(kat, self.prePRCL, pretune_precision)
phi=round(phi/pretune_precision)*pretune_precision phi=round(phi/pretune_precision)*pretune_precision
phi=round_to_n(phi,5) phi=round_to_n(phi,5)
print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision))
self.prePRCL.apply_tuning(_kat,phi) self.prePRCL.apply_tuning(_kat,phi)
print(" scanning SRCL (maximising carrier power, then adding 90 deg)") vprint(verbose, " scanning SRCL (maximising carrier power, then adding 90 deg)")
kat = _kat.deepcopy() kat = _kat.deepcopy()
phi, precision = self.scan_to_precision(kat, self.preSRCL, pretune_precision, phi=0) phi, precision = self.scan_to_precision(kat, self.preSRCL, pretune_precision, phi=0)
phi=round(phi/pretune_precision)*pretune_precision phi=round(phi/pretune_precision)*pretune_precision
phi=round_to_n(phi,4)-90.0 phi=round_to_n(phi,4)-90.0
print(" found max/min at: {} (precision = {:2g})".format(phi, precision)) vprint(verbose, " found max/min at: {} (precision = {:2g})".format(phi, precision))
self.preSRCL.apply_tuning(_kat,phi) self.preSRCL.apply_tuning(_kat,phi)
print(" ... done")
def scan_to_precision(self, kat, DOF, pretune_precision, minmax="max", phi=0.0, precision=60.0): def scan_to_precision(self, kat, DOF, pretune_precision, minmax="max", phi=0.0, precision=60.0):
while precision>pretune_precision*DOF.scale: while precision>pretune_precision*DOF.scale:
...@@ -306,34 +329,34 @@ class aLIGO(object): ...@@ -306,34 +329,34 @@ class aLIGO(object):
Pin = float(kat.L0.P) Pin = float(kat.L0.P)
tunings = self.get_tunings(kat) tunings = self.get_tunings(kat)
print(" .------------------------------------------------------.") _maxtemStr = "{:3}".format(tunings["maxtem"])
print(" | pretuned for maxtem = {:4} (-1 = 'off') |".format(tunings["maxtem"])) if tunings["maxtem"] == -1:
_maxtemStr="off"
print(" .--------------------------------------------------.")
print(" | pretuned for maxtem = {}, phase = {:2} |".format(_maxtemStr, int(kat.phase)))
keys_t = list(tunings.keys()) keys_t = list(tunings.keys())
keys_t.remove("maxtem") keys_t.remove("maxtem")
print(" .------------------------------------------------------.") print(" .--------------------------------------------------.")
print(" | port power[W] pow. ratio | optics tunings |") print(" | port power[W] pow. ratio | optics tunings |")
print(" +----------------------------|-------------------------+") print(" +----------------------------|---------------------+")
idx_p = 0 idx_p = 0
idx_t = 0 idx_t = 0
run_p = True while (idx_p < len(pretune_DOFs) or idx_t < len(keys_t)):
run_t = True
while (run_p or run_t):
if idx_p < len(pretune_DOFs): if idx_p < len(pretune_DOFs):
p = pretune_DOFs[idx_p] p = pretune_DOFs[idx_p]
print(" | {:5}: {:8.3g} {:8.3g} |".format(p.name, float(out[p.port.name]), float(out[p.port.name])/Pin),end="") print(" | {:5}: {:9.4g} {:9.4g} |".format(p.name, float(out[p.port.name]), float(out[p.port.name])/Pin),end="")
idx_p +=1 idx_p +=1
else: else:
print(" | |", end="") print(" | |", end="")
run_p = False
if idx_t < len(keys_t): if idx_t < len(keys_t):
t=keys_t[idx_t] t=keys_t[idx_t]
print(" {:5}: {:9.3g} |".format(t, float(self.tunings[t]))) print(" {:5}: {:9.3g} |".format(t, float(self.tunings[t])))
idx_t +=1 idx_t +=1
else: else:
print(" |") print(" |")
run_t = False print(" `--------------------------------------------------'")
print(" `------------------------------------------------------'")
# probably extra and can be removed
def power_ratios(self, _kat): def power_ratios(self, _kat):
kat = _kat.deepcopy() kat = _kat.deepcopy()
kat.verbose = False kat.verbose = False
...@@ -392,12 +415,49 @@ class aLIGO(object): ...@@ -392,12 +415,49 @@ class aLIGO(object):
plt.tight_layout() plt.tight_layout()
plt.show(block=0) plt.show(block=0)
def find_DC_offset(self, _kat, AS_power, precision=1e-4): def set_DC_offset(self, _kat, DCoffset=None, verbose=False):
if DCoffset:
self.DCoffset=DCoffset
print("-- applying user-defined DC offset:")
pretuning = self.get_tunings(_kat)
pretuning["ETMY"] += self.DCoffset
pretuning["ETMX"] -= self.DCoffset
self.set_tunings(_kat, pretuning)
kat = _kat.deepcopy()
sigStr = self.AS_DC.signal(kat)
signame = self.AS_DC.signal_name(kat)
kat.parseCommands(sigStr)
kat.noxaxis=True
out = kat.run()
self.DCoffsetW=float(out[signame])
else:
# Finding light power in AS port (mostly due to RF sidebands now
kat = _kat.deepcopy()
sigStr = self.AS_DC.signal(kat)
signame = self.AS_DC.signal_name(kat)
kat.parseCommands(sigStr)
kat.noxaxis=True
out = kat.run()
print("-- adjusting DCoffset based on light in dark port:")
waste_light = round(float(out[signame]),1)
print(" waste light in AS port of {:2} W".format(waste_light))
kat_lock = _kat.deepcopy()
self.find_DC_offset(kat_lock, 2*waste_light)
pretuning = self.get_tunings(kat_lock)
pretuning["ETMY"] += self.DC_offset
pretuning["ETMX"] -= self.DC_offset
self.set_tunings(_kat, pretuning)
self.DCoffset_meter = self.DCoffset / 360.0 * _kat.lambda0
vprint(verbose, " DCoffset = {:6.4} deg ({:6.4}m)".format(self.DCoffset, self.DCoffset_meter))
vprint(verbose, " at dark port power: {:6.4}W".format(self.DCoffsetW))
def find_DC_offset(self, _kat, AS_power, precision=1e-4, verbose=False):
""" """
Returns the DC offset of DARM that corrponds to the Returns the DC offset of DARM that corrponds to the
specified power in the AS power. specified power in the AS power.
""" """
print("-- finding DC offset for AS power of {:3g} W".format(AS_power)) vprint(verbose, " finding DC offset for AS power of {:3g} W".format(AS_power))
kat = _kat.deepcopy() kat = _kat.deepcopy()
kat.verbose = False kat.verbose = False
kat.noxaxis = True kat.noxaxis = True
...@@ -413,8 +473,10 @@ class aLIGO(object): ...@@ -413,8 +473,10 @@ class aLIGO(object):
#print(out[self.AS_DC.name]-AS_power) #print(out[self.AS_DC.name]-AS_power)
return np.abs(out[self.AS_DC.name]-AS_power) return np.abs(out[self.AS_DC.name]-AS_power)
out=fmin(powerDiff,0,xtol=precision,ftol=1e-3,args=(kat, Xphi, Yphi, AS_power)) vprint(verbose, " starting peak search...")
print(" DC offset for AS_DC={} W is: {}".format(AS_power, out[0])) out=fmin(powerDiff,0,xtol=precision,ftol=1e-3,args=(kat, Xphi, Yphi, AS_power), disp=verbose)
vprint(verbose, " ... done")
vprint(verbose, " DC offset for AS_DC={} W is: {}".format(AS_power, out[0]))
self.DCoffset = round(out[0],6) self.DCoffset = round(out[0],6)
self.DCoffsetW = AS_power self.DCoffsetW = AS_power
return self.DCoffset return self.DCoffset
...@@ -445,42 +507,47 @@ class aLIGO(object): ...@@ -445,42 +507,47 @@ class aLIGO(object):
return code1 return code1
def generate_lock_block(self, _kat, _gains=None, _accuracies=None, verbose=False): def generate_lock_block(self, _kat, _gains=None, _accuracies=None, verbose=True):
""" """
gains: optical gain is in W per rad gains: optical gain is in W per deg
accuracies: error signal threshold in W accuracies: error signal threshold in W
rms, estimated loop noise rms m
to compute accuracies from rms, we convert
rms to radians as rms_rad = rms * 2 pi/lambda
and then multiply by the optical gain.
""" """
kat = _kat.deepcopy() kat = _kat.deepcopy()
if _gains == None: # optical gains in W/rad
ogDARM = optical_gain(kat, self.DARM, self.DARM) ogDARM = optical_gain(kat, self.DARM, self.DARM)
ogCARM = optical_gain(kat, self.CARM, self.CARM) ogCARM = optical_gain(kat, self.CARM, self.CARM)
ogPRCL = optical_gain(kat, self.PRCL, self.PRCL) ogPRCL = optical_gain(kat, self.PRCL, self.PRCL)
ogMICH = optical_gain(kat, self.MICH, self.MICH) ogMICH = optical_gain(kat, self.MICH, self.MICH)
ogSRCL = optical_gain(kat, self.SRCL, self.SRCL) ogSRCL = optical_gain(kat, self.SRCL, self.SRCL)
if verbose:
print("-- optical gains:") if _gains == None:
print(" DARM: {}".format(ogDARM)) # manually tuning relative gains
print(" CARM: {}".format(ogCARM)) gainExtra = [0.5, 0.005, 1.0, 0.5, 0.025]
print(" PRCL: {}".format(ogPRCL)) factor = -1.0 * 180 / math.pi # convert from rad/W to -1 * deg/W
print(" MICH: {}".format(ogMICH)) gainDARM = round_to_n(gainExtra[0] * factor / ogDARM, 2) # manually tuned
print(" SRCL: {}".format(ogSRCL)) gainCARM = round_to_n(gainExtra[1] * factor / ogCARM, 2) # factor 0.005 for better gain hirarchy with DARM
gains = [ ogDARM, ogCARM, ogPRCL, ogMICH, ogSRCL] gainPRCL = round_to_n(gainExtra[2] * factor / ogPRCL, 2) # manually tuned
gainMICH = round_to_n(gainExtra[3] * factor / ogMICH, 2) # manually tuned
gainSRCL = round_to_n(gainExtra[4] * factor / ogSRCL, 2) # gain hirarchy with MICH
gains = [ gainDARM, gainCARM, gainPRCL, gainMICH, gainSRCL]
else: else:
gains = _gains.copy() gains = _gains.copy()
rms = [1e-13, 1e-12, 1e-11, 1e-11, 1e-11] # rms: loop accuracies in meters (manually tuned for the loops to work
factor = 2.0 * math.pi / kat.lambda0 # with the default file)
# to compute accuracies from rms, we convert
# rms to radians as rms_rad = rms * 2 pi/lambda
# and then multiply by the optical gain.
rms = [1e-13, 1e-13, 1e-12, 1e-11, 50e-11] # default accuracies in meters
factor = 2.0 * math.pi / kat.lambda0 # convert from m to radians
if _accuracies == None: if _accuracies == None:
accDARM = round_to_n(np.abs(factor * rms[0] * gains[0]),2) accDARM = round_to_n(np.abs(factor * rms[0] * ogDARM),2)
accCARM = round_to_n(np.abs(factor * rms[1] * gains[1]),2) * 0.1 # manually tuned accCARM = round_to_n(np.abs(factor * rms[1] * ogCARM),2)
accPRCL = round_to_n(np.abs(factor * rms[2] * gains[2]),2) * 0.1 # manually tuned accPRCL = round_to_n(np.abs(factor * rms[2] * ogPRCL),2)
accMICH = round_to_n(np.abs(factor * rms[3] * gains[3]),2) accMICH = round_to_n(np.abs(factor * rms[3] * ogMICH),2)
accSRCL = round_to_n(np.abs(factor * rms[4] * gains[4]),2) * 50.0 # manually tuned accSRCL = round_to_n(np.abs(factor * rms[4] * ogSRCL),2)
acc = [accDARM, accCARM, accPRCL, accMICH, accSRCL] acc = [accDARM, accCARM, accPRCL, accMICH, accSRCL]
else: else:
acc = _accuracies.copy() acc = _accuracies.copy()
...@@ -501,20 +568,11 @@ class aLIGO(object): ...@@ -501,20 +568,11 @@ class aLIGO(object):
func DARM_err = $AS_f2_I_re - {} func DARM_err = $AS_f2_I_re - {}
""".format(nameDARM, nameCARM, namePRCL, nameMICH, nameSRCL, self.DCoffsetW) """.format(nameDARM, nameCARM, namePRCL, nameMICH, nameSRCL, self.DCoffsetW)
factor = 0.4 * -1.0 * 180 / math.pi # 0.2 because of multiple locks cross talk code2 = """lock DARM_lock $DARM_err {:8.2} {:8.2}
gainDARM = round_to_n(factor / ogDARM, 2) lock CARM_lock $CARM_err {:8.2g} {:8.2g}
gainCARM = round_to_n(0.01 * factor / ogCARM, 2) # factor 0.01 for better gain hirarchy lock PRCL_lock $PRCL_err {:8.2g} {:8.2g}
gainPRCL = round_to_n(2.0 * factor / ogPRCL, 2) # manually tuned lock MICH_lock $MICH_err {:8.2g} {:8.2g}
gainMICH = round_to_n(1.0 * factor / ogMICH, 2) # manually tuned lock SRCL_lock $SRCL_err {:8.2g} {:8.2g}""".format(gains[0], acc[0], gains[1], acc[1], gains[2], acc[2], gains[3], acc[3], gains[4], acc[4])
gainSRCL = round_to_n(0.05 * factor / ogSRCL, 2) # gain hirrchy with MICH
code2 = """
lock DARM_lock $DARM_err {} {}
lock CARM_lock $CARM_err {} {}
lock PRCL_lock $PRCL_err {} {}
lock MICH_lock $MICH_err {} {}
lock SRCL_lock $SRCL_err {} {}
""".format(gainDARM, acc[0], gainCARM, acc[1], gainPRCL, acc[2], gainMICH, acc[3], gainSRCL, acc[4])
code3 = """ code3 = """
noplot ITMY_lock noplot ITMY_lock
...@@ -540,6 +598,41 @@ class aLIGO(object): ...@@ -540,6 +598,41 @@ class aLIGO(object):
########################################################################### ###########################################################################
%%% FTend locks %%% FTend locks
""" """
factor1 = 2.0 * math.pi / 360.0
factor2 = 2.0 * math.pi / kat.lambda0
factor3 = 360.0 / kat.lambda0
factor4 = -1.0 * 180 / math.pi
if verbose:
print(" .--------------------------------------------------.")
print(" | Parameters for locks: |")
print(" +--------------------------------------------------+")
print(" | -- optical gains [W/rad], [W/deg] and [W/m]: |")
print(" | DARM: {:12.5}, {:12.5}, {:12.5} |".format(ogDARM, ogDARM*factor1, ogDARM*factor2))
print(" | CARM: {:12.5}, {:12.5}, {:12.5} |".format(ogCARM, ogCARM*factor1, ogCARM*factor2))
print(" | PRCL: {:12.5}, {:12.5}, {:12.5} |".format(ogPRCL, ogPRCL*factor1, ogPRCL*factor2))
print(" | MICH: {:12.5}, {:12.5}, {:12.5} |".format(ogMICH, ogMICH*factor1, ogMICH*factor2))
print(" | SRCL: {:12.5}, {:12.5}, {:12.5} |".format(ogSRCL, ogSRCL*factor1, ogSRCL*factor2))
print(" +--------------------------------------------------+")
print(" | -- defult loop accuracies [deg], [m] and [W]: |")
print(" | DARM: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[0], rms[0], np.abs(rms[0]*ogDARM*factor2)))
print(" | CARM: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[1], rms[1], np.abs(rms[1]*ogCARM*factor2)))
print(" | PRCL: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[2], rms[2], np.abs(rms[2]*ogPRCL*factor2)))
print(" | MICH: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[3], rms[3], np.abs(rms[3]*ogMICH*factor2)))
print(" | SRCL: {:12.6}, {:12.6}, {:12.6} |".format(factor3*rms[4], rms[4], np.abs(rms[4]*ogSRCL*factor2)))
print(" +--------------------------------------------------+")
print(" | -- extra gain factors (factor * 1/optical_gain): |")
print(" | DARM: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[0],factor4/ogDARM, gainExtra[0]*factor4/ogDARM))
print(" | CARM: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[1],factor4/ogCARM, gainExtra[1]*factor4/ogCARM))
print(" | PRCL: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[2],factor4/ogPRCL, gainExtra[2]*factor4/ogPRCL))
print(" | MICH: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[3],factor4/ogMICH, gainExtra[3]*factor4/ogMICH))
print(" | SRCL: {:5.4} * {:12.6} = {:12.6} |".format(gainExtra[4],factor4/ogSRCL, gainExtra[4]*factor4/ogSRCL))
print(" +--------------------------------------------------+")
print(" | -- lock commands used: |")
for l in code2.splitlines():
print (" | {:49}|".format(l))
print(" `--------------------------------------------------'")
return "".join([code1, code2, code3]) return "".join([code1, code2, code3])
# --------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------
...@@ -737,7 +830,7 @@ def make_transparent(kat, _components): ...@@ -737,7 +830,7 @@ def make_transparent(kat, _components):
raise pkex.BasePyKatException("Cannot find component {}".format(components)) raise pkex.BasePyKatException("Cannot find component {}".format(components))
return kat return kat
def reconnect_nodes(kat, component1, idx1, node_name): def reconnect_nodes(kat, component1, idx1, node_name, verbose=False):
c_string = component1.getFinesseText() c_string = component1.getFinesseText()
c = c_string[0].split() c = c_string[0].split()
new_string = " ".join(c[:-2]) new_string = " ".join(c[:-2])
...@@ -746,22 +839,22 @@ def reconnect_nodes(kat, component1, idx1, node_name): ...@@ -746,22 +839,22 @@ def reconnect_nodes(kat, component1, idx1, node_name):
nodes[1] = c[-1] nodes[1] = c[-1]
nodes[idx1]=node_name nodes[idx1]=node_name
new_string = new_string + " " + nodes[0] + " " + nodes[1] new_string = new_string + " " + nodes[0] + " " + nodes[1]
#print(" new string ='{}'".format(new_string)) vprint(verbose, " new string ='{}'".format(new_string))
kat.parseCommands(new_string) kat.parseCommands(new_string)
def remove_commands(kat, _commands): def remove_commands(kat, _commands, verbose=False):
commands=make_list_copy(_commands) commands=make_list_copy(_commands)
# removing commands # removing commands
for o in kat.commands.values(): for o in kat.commands.values():
if o.name in commands: if o.name in commands:
o.remove() o.remove()
commands = [c for c in commands if c != o.name] commands = [c for c in commands if c != o.name]
#print(' {} removed'.format(o)) vprint(verbose, ' {} removed'.format(o))
if len(commands) != 0: if len(commands) != 0:
raise pkex.BasePyKatException("Cannot find command(s) {}".format(commands)) raise pkex.BasePyKatException("Cannot find command(s) {}".format(commands))
return kat return kat
def remove_components(kat, _components, component_in=None, component_out=None): def remove_components(kat, _components, component_in=None, component_out=None, verbose=False):
components=make_list_copy(_components) components=make_list_copy(_components)
if kat.components[components[-1]].nodes[1]: if kat.components[components[-1]].nodes[1]:
node_in = kat.components[components[-1]].nodes[1].name node_in = kat.components[components[-1]].nodes[1].name
...@@ -773,7 +866,7 @@ def remove_components(kat, _components, component_in=None, component_out=None): ...@@ -773,7 +866,7 @@ def remove_components(kat, _components, component_in=None, component_out=None):
if o.name in components: if o.name in components:
o.remove() o.remove()
components = [c for c in components if c != o.name] components = [c for c in components if c != o.name]
#print(' {} removed'.format(o)) vprint(verbose, ' {} removed'.format(o))
if len(components) != 0: if len(components) != 0:
raise pkex.BasePyKatException("Cannot find component(s) {}".format(components)) raise pkex.BasePyKatException("Cannot find component(s) {}".format(components))
# reconnecting nodes if requested # reconnecting nodes if requested
...@@ -837,7 +930,7 @@ def optical_gain(_kat, DOF_sig, DOF_det, f=10.0): ...@@ -837,7 +930,7 @@ def optical_gain(_kat, DOF_sig, DOF_det, f=10.0):
kat.noxaxis = True kat.noxaxis = True
kat.parseCommands("yaxis lin abs:deg") kat.parseCommands("yaxis lin abs:deg")
out = kat.run() out = kat.run()
return np.real(out[_detName]) return float(np.real(out[_detName]))
def find_peak(out, detector, minmax='max', debug=False): def find_peak(out, detector, minmax='max', debug=False):
""" """
...@@ -852,11 +945,12 @@ def find_peak(out, detector, minmax='max', debug=False): ...@@ -852,11 +945,12 @@ def find_peak(out, detector, minmax='max', debug=False):
find_peak(out, "pdout", minmax='min') find_peak(out, "pdout", minmax='min')
""" """
stepsize = out.x[1]-out.x[0] stepsize = out.x[1]-out.x[0]
if debug:
print(" stepsize (precision) of scan: {0:g}".format(stepsize)) print(" stepsize (precision) of scan: {0:g}".format(stepsize))
_max, _min = peak.peakdetect( out[detector],out.x, 1) _max, _min = peak.peakdetect( out[detector],out.x, 1)
if debug==True: if debug:
plt.figure() plt.figure()
plt.plot(out.x,out[detector]) plt.plot(out.x,out[detector])
print("max: ") print("max: ")
...@@ -877,7 +971,7 @@ def find_peak(out, detector, minmax='max', debug=False): ...@@ -877,7 +971,7 @@ def find_peak(out, detector, minmax='max', debug=False):
else: else:
raise pkex.BasePyKatException("maxmin must be 'max' or 'min'") raise pkex.BasePyKatException("maxmin must be 'max' or 'min'")
if debug==True: if debug:
plt.plot(X_out,Y_out,'o') plt.plot(X_out,Y_out,'o')
plt.xlabel('tuning [deg]') plt.xlabel('tuning [deg]')
plt.ylabel('{0} output'.format(detector)) plt.ylabel('{0} output'.format(detector))
...@@ -900,3 +994,8 @@ def round_to_n(x, n): ...@@ -900,3 +994,8 @@ def round_to_n(x, n):
power = -int(math.floor(math.log10(abs(x)))) + (n - 1) power = -int(math.floor(math.log10(abs(x)))) + (n - 1)
factor = (10 ** power) factor = (10 ** power)
return round(x * factor) / factor return round(x * factor) / factor
def vprint(verbose, printstr):
if verbose:
print(printstr)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment