235 lines
5.2 KiB
Plaintext
235 lines
5.2 KiB
Plaintext
#!/usr/bin/python
|
|
# Reference only: the beamline scientist's laser-delay script, attached to request 2.
|
|
# Kept verbatim (Python 2 era, CaChannel/epicsPV) as the behavioural spec for the BEC
|
|
# LaserDelay device. Do not import or run it from BEC code.
|
|
|
|
from CaChannel import ca, CaChannel
|
|
from epicsPV import epicsPV
|
|
from math import *
|
|
from numpy import *
|
|
import time
|
|
|
|
#Possible values of Laser: Duetto, KML, XITON, PI
|
|
Laser="Duetto"
|
|
Beamline="SuperXAS"
|
|
#LaserTriggerMode: "internal" or "external" External means from Event receiver.
|
|
|
|
|
|
LaserTriggerMode="external"
|
|
|
|
# Units of time are nanoseconds
|
|
|
|
#If internal triggering is used, set LaserPeriod (time between two laser pulses) as it is set at the laser
|
|
LaserPeriod=0
|
|
if (LaserTriggerMode=="internal"): LaserPeriod=2000.2
|
|
|
|
|
|
#Timing mode "DelayAndPhase" - use both Delay card and phase shifter, "Delay" - use only delay card, "Phase" - use only phase shifter
|
|
if (Laser=="Duetto"):
|
|
TimingMode="DelayAndPhase"
|
|
|
|
#Index Of delay channel (as in EPICS name) used for laser
|
|
DelayChIndex=1
|
|
EVRChIndex=2
|
|
|
|
#For SuperXAS 1 corresponds to the old (KML) phase shifter
|
|
#For SuperXAS 2 corresponds to ES4 phase shifter
|
|
PhaseShifterIndex=2
|
|
|
|
|
|
|
|
#change only for another synchrotron
|
|
RFPeriod=2.0
|
|
|
|
DelayCh=CaChannel()
|
|
DelayChFine=CaChannel()
|
|
EVRCh=CaChannel()
|
|
PhaseV1=CaChannel()
|
|
PhaseV2=CaChannel()
|
|
|
|
|
|
def ConnectEpics():
|
|
|
|
global CavityPeriod, Laser, Beamline
|
|
global DelayCh, DelayChFine, EVRCh, PhaseV1, PhaseV2
|
|
|
|
if (Laser=="Duetto"):
|
|
CavityPeriod=12.01
|
|
|
|
if (Beamline=="SuperXAS"):
|
|
DN="X10DA-ES2-TIM:SET"+str(DelayChIndex)
|
|
EVRChName="X10DA-ES2-TIM:EVR-FPS"+str(EVRChIndex)
|
|
if (PhaseShifterIndex==1):
|
|
PhaseV1Name="X10DA-LAS-PHSH:V1"
|
|
PhaseV2Name="X10DA-LAS-PHSH:V2"
|
|
if (PhaseShifterIndex==2):
|
|
PhaseV1Name="X10DA-ES4:AO-02"
|
|
PhaseV2Name="X10DA-ES4:AO-01"
|
|
|
|
if (Beamline=="Phoenix"):
|
|
DN="X07MB-ES-TIM:SET"+str(DelayChIndex)
|
|
EVRChName="X07MB-ES-TIM:EVR-FPS"+str(EVRChIndex)
|
|
PhaseV1Name="X07MB-ES1-PP2:VO2"
|
|
PhaseV2Name="X07MB-ES1-PP2:VO1"
|
|
|
|
DelayChName=DN+"-DELAY"
|
|
DelayChFineName=DN+"-FINE"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((TimingMode=="Delay") or (TimingMode=="DelayAndPhase")):
|
|
DelayCh.searchw(DelayChName)
|
|
DelayChFine.searchw(DelayChFineName)
|
|
|
|
if ((TimingMode=="Phase") or (TimingMode=="DelayAndPhase")):
|
|
PhaseV1.searchw(PhaseV1Name)
|
|
PhaseV2.searchw(PhaseV2Name)
|
|
|
|
if (LaserTriggerMode=="external"):
|
|
EVRCh.searchw(EVRChName)
|
|
|
|
#Maybe will be useful to automatically set pulse width for different lasers
|
|
#def SetPulseWidth():
|
|
|
|
|
|
def CurrentSituation(FromScopeXrayMinusLaser):
|
|
|
|
global LaserPeriod, OffsetT
|
|
if (TimingMode=="Delay"):
|
|
PhaseT=0
|
|
if (TimingMode=="Phase"):
|
|
DelayCardT=0
|
|
|
|
if (LaserTriggerMode=="external"):
|
|
LaserPeriod=1000*EVRCh.getw()
|
|
print ("LaserPeriod=", LaserPeriod)
|
|
|
|
if ((TimingMode=="Delay") or (TimingMode=="DelayAndPhase")):
|
|
dt1=DelayCh.getw()
|
|
dt2=DelayChFine.getw()
|
|
DelayCardT=2.0*dt1+0.01*dt2
|
|
|
|
|
|
|
|
if ((TimingMode=="Phase") or (TimingMode=="DelayAndPhase")):
|
|
PhaseT=GetPhaseT()
|
|
Ph=FromScopeXrayMinusLaser%CavityPeriod
|
|
OffsetPhaseT=-PhaseT-Ph
|
|
OffsetT=-DelayCardT-FromScopeXrayMinusLaser
|
|
|
|
print ("LaserPeriod=", LaserPeriod)
|
|
print ("OffsetT=", OffsetT)
|
|
print ("Current PhaseT", PhaseT)
|
|
print ("Offset Phse shifter T", OffsetPhaseT)
|
|
qwe=(LaserPeriod, OffsetT, OffsetPhaseT, PhaseT)
|
|
# print ("qwe=",qwe)
|
|
savetxt("Timing.offset", qwe)
|
|
|
|
|
|
|
|
def GetPhaseT():
|
|
v1=PhaseV1.getw()
|
|
v2=PhaseV2.getw()
|
|
phi=atan2(v2,v1)
|
|
T=RFPeriod*phi/(2*pi)
|
|
return T
|
|
|
|
|
|
|
|
def SetVoltages(phi):
|
|
|
|
#Vmax may be different for different lasers or phase shifters
|
|
#if (PhaseShifterIndex==1):
|
|
Vmax=1.0
|
|
|
|
V1=Vmax*cos(phi)
|
|
V2=Vmax*sin(phi)
|
|
PhaseV1.putw(V1)
|
|
PhaseV2.putw(V2)
|
|
#set values via epics
|
|
print (V1, V2)
|
|
time.sleep(0.1)
|
|
|
|
|
|
|
|
|
|
def MovePhaseShifter(RelativeDelay):
|
|
|
|
|
|
|
|
NumStepsPerPeriod=36
|
|
DelayStep=sign(RelativeDelay)*RFPeriod/NumStepsPerPeriod
|
|
|
|
#read current values of
|
|
|
|
CurT=GetPhaseT()
|
|
for t1 in arange(0,RelativeDelay, DelayStep):
|
|
phi1=2*pi*(CurT+t1)/RFPeriod
|
|
SetVoltages(phi1)
|
|
|
|
phi1=2*pi*(CurT+RelativeDelay)/RFPeriod
|
|
SetVoltages(phi1)
|
|
|
|
|
|
|
|
|
|
def MoveDelayCard(NewDelayTime):
|
|
print ("ndt,lp", NewDelayTime, LaserPeriod)
|
|
t1=NewDelayTime%LaserPeriod
|
|
t2=int(t1/2.0)
|
|
t3=int((t1%2.0)/0.009999)
|
|
print ("t1 t2 t3 ",t1,t2,t3)
|
|
DelayCh.putw(t2)
|
|
DelayChFine.putw(t3)
|
|
|
|
|
|
|
|
def SetDelay(t=0):
|
|
global LaserPeriod, OffsetT
|
|
a=loadtxt("Timing.offset")
|
|
LaserPeriod=a[0]
|
|
OffsetT=a[1]
|
|
print ("a1=",a[1])
|
|
OffsetPhaseT=a[2]
|
|
print ("OffsetPhaseT from File", OffsetPhaseT)
|
|
CurrentPhaseT=a[3]
|
|
print ("Current value of PhaseT", CurrentPhaseT)
|
|
|
|
TotalT=-OffsetT-t
|
|
ForPhaseShifter=-t%CavityPeriod-OffsetPhaseT
|
|
print ("-t/Cavity", -t%CavityPeriod, "-OffsetPhaseT", OffsetPhaseT, "-CurrentPhaseT", CurrentPhaseT)
|
|
MoveDelayCard(TotalT)
|
|
print ("Relative Phase shifter delay", ForPhaseShifter-CurrentPhaseT)
|
|
MovePhaseShifter(ForPhaseShifter-CurrentPhaseT)
|
|
print ("OffsetT before save=", OffsetT)
|
|
savetxt("Timing.offset",(LaserPeriod,OffsetT,OffsetPhaseT,ForPhaseShifter))
|
|
|
|
|
|
def main():
|
|
|
|
|
|
ConnectEpics()
|
|
# CurSit=-20.015+15.46
|
|
# #CurSit=-14.58+15.46
|
|
# CurSit=546.04-546.92
|
|
#CurSit=0.1
|
|
#CurrentSituation(FromScopeXrayMinusLaser=CurSit)
|
|
|
|
print ("------------------")
|
|
|
|
SetDelay(-4.9)
|
|
|
|
# SetDelay(0.5)
|
|
# time.sleep(5)
|
|
# SetDelay(.5)
|
|
if __name__=="__main__":
|
|
main()
|
|
#MovePhaseShifter(2.0)
|
|
#MoveDelayCard(25.)
|
|
#time.sleep(10)
|