Code owners
Assign users and groups as approvers for specific file changes. Learn more.
current_amplifiers.py 11.20 KiB
import numpy as np
from time import sleep
from epics import caget, caput
from .userCalcs import userStringSeq_pvs, userStringSeq_clear
from .VLS_PGM import mono_energy_get
def ca_detector_list(branch):
"""
returns the list of keithley current amplifiers based on key
key: 'ARPES' / 'Staff'
"""
ca_list = list(ca_dictionary()[branch].keys())
return ca_list
def ca_dictionary():
"""
dictionary of connected Kiethlys and thier names
Previously: CA_Name
"""
ca={}
ca["b"] = {
1: 'W-mesh',
2: 'H-wire',
3: 'V-wire',
4: 'Slit1A',
5: 'Slit1A',
9: 'D2B',
10: 'B-branch',
12: '',
13: 'Slit3C',
14: 'MeshD',
15: 'DiodeC',
}
ca["c"] = {
1:'TEY',
}
return ca
##############################################################################################################
################################ Keithley ##############################
##############################################################################################################
def Keithley_pv(ca_ioc, ca_num):
return "29id"+ca_ioc+":ca"+str(ca_num)+":"
class Keithley:
"""
class for Keithley current amplifiers
"""
def __init__(self,ca_ioc, ca_num):
self._pv = Keithley_pv(ca_ioc, ca_num)
try:
self.name = ca_dictionary()[ca_ioc][ca_num]
except:
self.name = 'CA'+ca_ioc+str(ca_num)
self.current
self.rate
self.filter_num
self.range
def get(self):
"""
reads the current SRS and corresponding scaler values
"""
self.current = caget(self.pv+"read")
self.range = 'Autoscale' if caget(self.pv+"rangeAuto",as_string=True)=='On' else caget(self.pv+"range",as_string=True)
self.rate = caget(self.pv+"rate")
digital_filter = (self.pv+'digitalFilter')
self.filter_num = 1 if digital_filter == 'On' else (self.pv+'digitalFilterCount')
def reset(self,rate="Slow"):
"""
Previously: Reset_CA
"""
pv = self.pv
caput(pv+":reset.PROC",1)
caput(pv+":digitalFilterSet","Off")
caput(pv+":medianFilterSet","Off")
caput(pv+":zeroCheckSet",0)
caput(pv+":rangeAuto",1)
caput(pv+":rateSet",rate)
caput(pv+":rangeAutoUlimit","20mA")
caput(pv+":read.SCAN",".5 second")
def autoscale(self,On_Off='On',gain=7):
"""
ca_ioc = 'b' / 'c'
ca_num = 2
On_Off= 'On' => Turns On the Autoscale; gain is irrelevant.
On_Off= 'Off' => Turns Off the Autoscale with gain below:
0 = 2nA
1 = 20nA
2 = 200nA
3 = 2uA
4 = 20uA
5 = 200uA
6 = 2mA
7 = 20mA
Previously: CA_Autoscale
"""
pv = self.pv
caput(pv+":rangeAutoSet",On_Off)
sleep(0.5)
caput(pv+":rangeSet",gain)
print(pv,"Autoscale",On_Off)
if On_Off == 'Off':
sleep(1)
print("Gain set to:",caget(pv+":range",as_string=True))
def avg(self,num_averages,rate='Slow',verbose=True):
"""
Turns on the filtering for the Keithlys for average during a scan
rate: Keithley sampling rate
'Slow' / 'Medium' / 'Fast'
num_averages: number of points to average
returns the settling_time
Previously: CA_Filter
"""
pv = self.pv
name=self.name
t=0.1
if rate == "Slow":
t=6/60.0
elif rate == "Medium":
t=1/60.0
elif rate == "Fast":
t=0.1/60.0
settling_time=round(max(0.15,num_averages*t+0.1),2)
if num_averages <= 1: # no averaging
self.reset(rate)
settling_time = None
if verbose:
print("Average disabled: "+name+" - "+pv)
else:
caput(pv+"read.SCAN","Passive",wait=True,timeout=500)
caput(pv+"rateSet",rate)
sleep(1)
caput(pv+"digitalFilterCountSet",num_averages,wait=True,timeout=500)
caput(pv+"digitalFilterControlSet","Repeat",wait=True,timeout=500)
caput(pv+"digitalFilterSet","On",wait=True,timeout=500)
if verbose:
print("Average enabled: "+name+" - "+pv)
print("Detector settling time: "+str(settling_time)+"s")
return settling_time
def ca_reset_all(rate="Slow"):
""""
Previously: Reset_CA_all
"""
ca_dict = ca_dictionary()
for ca_ioc in ca_dict.keys():
for ca_num in ca_dict[ca_ioc].keys():
CA = Keithley(ca_ioc,ca_num)
CA.reset()
caput("29idb:ca5:read.SCAN","Passive") # CA5 in passive
print("\nAll the current amplifiers have been reset; ca5 set to passive.")
def ca_live_sequence(ioc,seq_num,detector_list):
"""
creates a string sequence to put keithleys back in live mode
ca_list = list of ca to go in live
Previously: CA_Live_StrSeq
"""
userStringSeq_pv, userStringSeq_proc = userStringSeq_pvs(ioc, seq_num) # do we need to add 29idb:ca5 ???
userStringSeq_clear(ioc,seq_num)
caput(userStringSeq_pv+".DESC","CA Live "+ioc)
for (i,ca) in enumerate(detector_list):
pv = "29id"+ca[0]+":ca"+str(ca[1])+":"
ca_read_pv = pv+'read.SCAN CA NMS'
ca_avg_pv = pv+'digitalFilterSet PP NMS'
caput(userStringSeq_pv+".LNK"+str(i+1),ca_avg_pv)
caput(userStringSeq_pv+".STR" +str(i+1),"Off")
n=len(detector_list)
if n+1+i < 10:
caput(userStringSeq_pv+".LNK" +str(n+1+i),ca_read_pv)
caput(userStringSeq_pv+".STR" +str(n+1+i),".5 second")
caput(userStringSeq_pv+".WAIT"+str(n+1+i),"After"+str(n))
elif n+1+i == 10:
caput(userStringSeq_pv+".LNKA",ca_read_pv)
caput(userStringSeq_pv+".STRA",".5 second")
caput(userStringSeq_pv+".WAITA","After"+str(n))
return userStringSeq_proc
def ca_average(avg_pts,ca_list,rate="Slow",verbose=True):
"""
Average reading of the relevant current amplifiers for the current scanIOC/branch.
Previously: CA_average
"""
print("\nAverage set to: "+str(max(avg_pts,1)))
for i in range(0,len(ca_list)):
ca = Keithley(ca_list[i][0],ca_list[i][1])
ca.avg(avg_pts,rate=rate,verbose=verbose)
def load_responsivity_curve():
"""
Loads the responsivity curve for the AUX100 photo diode, used to convert
current to flux at a given photon energy
Previously: loadResponsivityCurve
"""
FilePath='/home/beams/29IDUSER/Documents/User_Macros/Macros_29id/IEX_Dictionaries/'
FileName="DiodeResponsivityCurve"
data = np.loadtxt(FilePath+FileName, delimiter=' ', skiprows=1)
return data
def current2flux(current,hv=None,verbose=True):
"""
Converts the current to flux for of an AUX 100 diode using the responisity curves
hv = None; gets the current mono energy; otherwise you will need to specify
Previously CA2flux
"""
try:
curve=load_responsivity_curve()
except:
print('responsivity curve not loaded')
return
responsivity=curve[:,0]
energy=curve[:,1]
charge = 1.602e-19
if hv is None:
try:
hv = mono_energy_get()
except:
print('specify hv')
return
eff=np.interp(hv,energy,responsivity)
flux = current/(eff*hv*charge)
if verbose:
print("\nCalculating flux for:")
print(" hv = %.1f eV" % hv)
print(" current = %.3e Amp" % current)
print("Flux = %.3e ph/s\n" % flux)
return flux
def flux2current(flux,hv=None,verbose=True):
"""
Converts the specified flux to a current for of an AUX 100 diode using the responisity curves
hv = None; gets the current mono energy; otherwise you will need to specify
"""
try:
curve=load_responsivity_curve()
except:
print('responsivity curve not loaded')
return
responsivity=curve[:,0]
energy=curve[:,1]
charge = 1.602e-19
if hv is None:
try:
hv = mono_energy_get()
except:
print('specify hv')
return
eff=np.interp(hv,energy,responsivity)
current = flux*(eff*hv*charge)
if verbose:
print("\nCalculating current for:")
print(" hv = %.1f eV" % hv)
print(" flux = %.3e ph/s" % flux)
print("Current = %.3e Amp/n" % current)
return current
##############################################################################################################
################################ SRS ##############################
##############################################################################################################
class SRS:
"""
SRS current amplifier and corresponding scalers
"""
def __init__(self,scaler_pv,srs_pv):
self._scaler_pv = scaler_pv
self._srs_pv = srs_pv
self.scaler_value
self.gain
self.unit
self.current
self.get()
def get(self):
"""
reads the current SRS and corresponding scaler values
"""
self.scaler_value = caget(self._scaler_pv)
self.gain = float(caget(self._scaler_pv+'sens_num.VAL',as_string=True))
self.unit = caget(self._scaler_pv+'sens_unit.VAL',as_string=True)
CA = {'pA':1e-12, 'nA':1e-9, 'uA':1e-6, 'mA':1e-3}
self.current = self.scaler_value * self.gain * CA[self.unit]
def setgain(self,gain,unit):
"""
gain = 1,2,5,10,20,50,100,200,500
unit = 'pA, 'nA', 'uA', 'mA'
"""
caput(self._srs_pv+'sens_num.VAL',str(gain))
caput(self._srs_pv+'sens_unit.VAL',str(unit))
def srs_print_all(self, long=False):
"""
prints SRS setting
"""
invert=caget(self._srs_pv+'invert_on.VAL',as_string=True)
currentUnit=caget(self._srs_pv+'sens_unit.VAL',as_string=True)
currentValue=caget(self._srs_pv+'sens_num.VAL',as_string=True)
offsetValue=caget(self._srs_pv+"offset_num.VAL",as_string=True)
offsetUnit=caget(self._srs_pv+"offset_unit.VAL",as_string=True)
offsetSign=caget(self._srs_pv+"offset_sign.VAL",as_string=True)
offsetFactor=caget(self._srs_pv+"off_u_put.VAL",as_string=True)
print('Gain: '+currentValue+' '+currentUnit+' (invert '+invert+')')
print('Baseline: '+offsetSign+' '+offsetFactor+' x '+offsetValue+" "+offsetUnit)
if long:
filterType=caget(self._srs_pv+'filter_type.VAL',as_string=True)
filterLow=caget(self._srs_pv+'low_freq.VAL',as_string=True)
filterHigh=caget(self._srs_pv+'high_freq.VAL',as_string=True)
blank=caget(self._srs_pv+'blank_on.VAL',as_string=True)
biasOnOff=caget(self._srs_pv+'bias_on.VAL',as_string=True)
biasValue=caget(self._srs_pv+'bias_put.VAL',as_string=True)
print('Filter: '+filterType+' - Low/High: '+filterLow+' -'+filterHigh)
print('Bias: '+biasOnOff+'- '+biasValue)
print('Blank: '+blank)