290 lines
10 KiB
Python
290 lines
10 KiB
Python
"""
|
|
File: jitter_scan.py
|
|
Author: KR84
|
|
Copyright PSI LLRF, 2016
|
|
|
|
Purpose Record RF system jitters and store / archive data
|
|
Preconditions - RF station is running
|
|
- AVG gates are set-up for correct length for particular station, P2P count is set to 100 for all channels + vsum
|
|
- AMPLT-REFERENCE is set to the klystron saturation point
|
|
- feedbacks are in closed loop (both)
|
|
- you know the settling time of the feedback + 100 P2P-count + 100 Hz, if required, change it below
|
|
-
|
|
|
|
"""
|
|
|
|
#################################################################
|
|
# Parameter SECTION, change it to your RF station before run
|
|
SECTION = "SINSB01"
|
|
|
|
# for 100 Hz and P2P-count = 100 this can be at least 1.1 seconds
|
|
latency = 1
|
|
#################################################################
|
|
|
|
|
|
|
|
|
|
|
|
# some other parameters
|
|
|
|
|
|
|
|
|
|
|
|
# re-define filename, such that the SECTION is also in the filename
|
|
set_context(path = "{data}/{year}_{month}/{date}/{date}_{time}_" + str(SECTION) + "_{name}")
|
|
|
|
|
|
#################################################################################
|
|
# define all PVs
|
|
#import ch.psi.pshell.epics.ProcessVariable as PV
|
|
import ch.psi.pshell.epics.ChannelDouble as PV
|
|
|
|
# controlled variabales
|
|
cv_rf_phase = PV("phase_ref", SECTION + "-RSYS:SET-VSUM-PHASE")
|
|
cv_rf_amplt = PV("amplt_ref", SECTION + "-RSYS:SET-ACC-VOLT")
|
|
|
|
# measured variables
|
|
mv_ref_jit_amplt = PV("REF_amplt_jit" ,SECTION + "-RLLE-REF10:SIG-AMPLT-JIT-P2P-REL")
|
|
mv_ref_jit_phase = PV("REF_phase_jit" ,SECTION + "-RLLE-REF10:SIG-PHASE-JIT-P2P")
|
|
|
|
mv_iqm_jit_amplt = PV("IQM_amplt_jit" ,SECTION + "-RIQM-DCP10:FOR-AMPLT-JIT-P2P-REL")
|
|
mv_iqm_jit_phase = PV("IQM_phase_jit" ,SECTION + "-RIQM-DCP10:FOR-PHASE-JIT-P2P")
|
|
|
|
mv_pre_jit_amplt = PV("PRE_amplt_jit" ,SECTION + "-RPRE-DCP10:FOR-AMPLT-JIT-P2P-REL")
|
|
mv_pre_jit_phase = PV("PRE_phase_jit" ,SECTION + "-RPRE-DCP10:FOR-PHASE-JIT-P2P")
|
|
|
|
mv_kly_jit_amplt = PV("KLY_amplt_jit" ,SECTION + "-RKLY-DCP10:FOR-AMPLT-JIT-P2P-REL")
|
|
mv_kly_jit_phase = PV("KLY_phase_jit" ,SECTION + "-RKLY-DCP10:FOR-PHASE-JIT-P2P")
|
|
|
|
mv_vsum_jit_amplt = PV("VSUM_amplt_jit" ,SECTION + "-RLLE-DSP:VSUM-AMPLT-JIT-P2P")
|
|
mv_vsum_jit_phase = PV("VSUM_phase_jit" ,SECTION + "-RLLE-DSP:VSUM-PHASE-JIT-P2P")
|
|
|
|
# auxiliary measured variables, but not scanned
|
|
mva_hvps = PV("HVPS" ,SECTION + "-RMOD:V-SET")
|
|
mva_rfrate = PV("RF_RATE" ,SECTION + "-RLLE-EVR:CHCK-EVNT")
|
|
#mva_hvps = PV("HVPS" ,"SINEG01-RMOD:V-SET")
|
|
|
|
# initialize all PVs
|
|
cv_rf_phase.initialize()
|
|
cv_rf_amplt.initialize()
|
|
mv_ref_jit_amplt.initialize()
|
|
mv_ref_jit_phase.initialize()
|
|
mv_iqm_jit_amplt.initialize()
|
|
mv_iqm_jit_phase.initialize()
|
|
mv_pre_jit_amplt.initialize()
|
|
mv_pre_jit_phase.initialize()
|
|
mv_kly_jit_amplt.initialize()
|
|
mv_kly_jit_phase.initialize()
|
|
mv_vsum_jit_amplt.initialize()
|
|
mv_vsum_jit_phase.initialize()
|
|
|
|
mva_hvps.initialize()
|
|
mva_rfrate.initialize()
|
|
|
|
|
|
|
|
#################################################################################
|
|
# scan
|
|
|
|
hvps = mva_hvps.read()
|
|
rfrate = mva_rfrate.read()
|
|
|
|
# define current amplitude as saturation amplitude, then define three scans
|
|
amplt_sat = cv_rf_amplt.read()
|
|
amplt_m5 = 0.95 * amplt_sat
|
|
amplt_m10 = 0.9 * amplt_sat
|
|
amplt_step = 0.049999 * amplt_sat
|
|
|
|
scan_result = ascan((cv_rf_amplt, cv_rf_phase), (mv_ref_jit_amplt,mv_ref_jit_phase,mv_iqm_jit_amplt,mv_iqm_jit_phase,mv_pre_jit_amplt,mv_pre_jit_phase,mv_kly_jit_amplt,mv_kly_jit_phase,mv_vsum_jit_amplt,mv_vsum_jit_phase), ( amplt_m10, -170.0), (amplt_sat, 180.0), (amplt_step, 10.0) , latency=latency, title="Jitter Scan", zigzag=False)
|
|
|
|
|
|
|
|
#################################################################################
|
|
# close all PVs
|
|
cv_rf_phase.close()
|
|
cv_rf_amplt.close()
|
|
mv_ref_jit_amplt.close()
|
|
mv_ref_jit_phase.close()
|
|
mv_iqm_jit_amplt.close()
|
|
mv_iqm_jit_phase.close()
|
|
mv_pre_jit_amplt.close()
|
|
mv_pre_jit_phase.close()
|
|
mv_kly_jit_amplt.close()
|
|
mv_kly_jit_phase.close()
|
|
mv_vsum_jit_amplt.close()
|
|
mv_vsum_jit_phase.close()
|
|
|
|
mva_hvps.close()
|
|
mva_rfrate.close()
|
|
|
|
|
|
#################################################################################
|
|
# analyze
|
|
|
|
# struct definition to hold all relevant statistics data
|
|
class statistics_data (object):
|
|
min = 0.0
|
|
mean = 0.0
|
|
max = 0.0
|
|
sigma = 0.0
|
|
|
|
# struct definition for statistics dat aof all three amplitude levels
|
|
class all_statistics_data (object):
|
|
sat = statistics_data()
|
|
m5 = statistics_data()
|
|
m10 = statistics_data()
|
|
|
|
def return_string_amplt(self):
|
|
# give results back as formatted string for amplt
|
|
ret_str = "Statistics:\tmin\t\tmean\t\tmax\t\tstdev"
|
|
ret_str = ret_str + "\nSaturation :\t" + "%.3e" % (self.sat.min) + "\t" + "%.3e" % (self.sat.mean) + "\t" + "%.3e" % (self.sat.max) + "\t" + "%.3e" % (self.sat.stdev)
|
|
ret_str = ret_str + "\n5% out of sat :\t" + "%.3e" % (self.m5.min) + "\t" + "%.3e" % (self.m5.mean) + "\t" + "%.3e" % (self.m5.max) + "\t" + "%.3e" % (self.m5.stdev)
|
|
ret_str = ret_str + "\n10% out of sat:\t" + "%.3e" % (self.m10.min) + "\t" + "%.3e" % (self.m10.mean) + "\t" + "%.3e" % (self.m10.max) + "\t" + "%.3e" % (self.m10.stdev)
|
|
return ret_str
|
|
|
|
def return_string_phase(self):
|
|
# give results back as formatted string for phase
|
|
ret_str = "Statistics:\tmin\tmean\tmax\tstdev"
|
|
ret_str = ret_str + "\nSaturation :\t" + "%.3f" % (self.sat.min) + "\t" + "%.3f" % (self.sat.mean) + "\t" + "%.3f" % (self.sat.max) + "\t" + "%.3f" % (self.sat.stdev)
|
|
ret_str = ret_str + "\n5% out of sat :\t" + "%.3f" % (self.m5.min) + "\t" + "%.3f" % (self.m5.mean) + "\t" + "%.3f" % (self.m5.max) + "\t" + "%.3f" % (self.m5.stdev)
|
|
ret_str = ret_str + "\n10% out of sat:\t" + "%.3f" % (self.m10.min) + "\t" + "%.3f" % (self.m10.mean) + "\t" + "%.3f" % (self.m10.max) + "\t" + "%.3f" % (self.m10.stdev)
|
|
return ret_str
|
|
|
|
|
|
|
|
def statistics_calc(data_in):
|
|
"function calculates the min/max/mean/stdev of an array"
|
|
temp = statistics_data();
|
|
temp.mean = mean (data_in)
|
|
temp.min = min (data_in)
|
|
temp.max = max (data_in)
|
|
temp.stdev = stdev(data_in)
|
|
return temp
|
|
|
|
|
|
def all_statistics_calc(data_in):
|
|
"function calculates for all three amplitudes the statistics data."
|
|
temp = all_statistics_data();
|
|
temp.m10 = statistics_calc (data_in[0:35])
|
|
temp.m5 = statistics_calc (data_in[36:71])
|
|
temp.sat = statistics_calc (data_in[72:107])
|
|
return temp
|
|
|
|
|
|
|
|
# create emtpy structs
|
|
ref_jit_amplt = all_statistics_data()
|
|
ref_jit_phase = all_statistics_data()
|
|
|
|
iqm_jit_amplt = all_statistics_data()
|
|
iqm_jit_phase = all_statistics_data()
|
|
|
|
pre_jit_amplt = all_statistics_data()
|
|
pre_jit_phase = all_statistics_data()
|
|
|
|
kly_jit_amplt = all_statistics_data()
|
|
kly_jit_phase = all_statistics_data()
|
|
|
|
vsum_jit_amplt = all_statistics_data()
|
|
vsum_jit_phase = all_statistics_data()
|
|
|
|
# calculate statistics
|
|
ref_jit_amplt = all_statistics_calc(scan_result.getReadable(0))
|
|
ref_jit_phase = all_statistics_calc(scan_result.getReadable(1))
|
|
|
|
iqm_jit_amplt = all_statistics_calc(scan_result.getReadable(2))
|
|
iqm_jit_phase = all_statistics_calc(scan_result.getReadable(3))
|
|
|
|
pre_jit_amplt = all_statistics_calc(scan_result.getReadable(4))
|
|
pre_jit_phase = all_statistics_calc(scan_result.getReadable(5))
|
|
|
|
kly_jit_amplt = all_statistics_calc(scan_result.getReadable(6))
|
|
kly_jit_phase = all_statistics_calc(scan_result.getReadable(7))
|
|
|
|
vsum_jit_amplt = all_statistics_calc(scan_result.getReadable(8))
|
|
vsum_jit_phase = all_statistics_calc(scan_result.getReadable(9))
|
|
|
|
# define plot range limits dependant on the staation type
|
|
if SECTION[1] == 'I':
|
|
if SECTION[3] == 'S':
|
|
# S-band
|
|
a_lim = 1.8e-4
|
|
p_lim = 0.018
|
|
else:
|
|
# X-Band
|
|
a_lim = 1.8e-4
|
|
p_lim = 0.072
|
|
else:
|
|
# C-band
|
|
a_lim = 1.8e-4
|
|
p_lim = 0.036
|
|
|
|
#a_lim = 5.0e-4
|
|
#p_lim = 0.04
|
|
|
|
# adjust plot ranges for the color bar to be always the same
|
|
i=0
|
|
for p in get_plots("Jitter Scan"):
|
|
if i % 2 == 0:
|
|
p.setScale(0.0, a_lim)
|
|
else :
|
|
p.setScale(0.0, p_lim)
|
|
i += 1
|
|
|
|
|
|
#Setting attributes to the scan group
|
|
path = get_context().group
|
|
set_attribute(path, "SECTION", SECTION)
|
|
"""
|
|
set_attribute(path, "ref_jit_amplt", ref_jit_amplt)
|
|
set_attribute(path, "ref_jit_phase", ref_jit_phase)
|
|
|
|
set_attribute(path, "iqm_jit_amplt", iqm_jit_amplt)
|
|
set_attribute(path, "iqm_jit_phase", iqm_jit_phase)
|
|
|
|
set_attribute(path, "pre_jit_amplt", pre_jit_amplt)
|
|
set_attribute(path, "pre_jit_phase", pre_jit_phase)
|
|
|
|
set_attribute(path, "kly_jit_amplt", kly_jit_amplt)
|
|
set_attribute(path, "kly_jit_phase", kly_jit_phase)
|
|
"""
|
|
|
|
set_attribute(path, "HVPS", hvps)
|
|
|
|
|
|
|
|
#################################################################################
|
|
# ELOG
|
|
|
|
msg = "HVPS command = " + str(hvps)[:6] + "V)"
|
|
msg = msg + "\n---------------------------------------------------------"
|
|
msg = msg + "\nREF amplt\n" + ref_jit_amplt.return_string_amplt()
|
|
msg = msg + "\n\nREF phase\n" + ref_jit_phase.return_string_phase()
|
|
msg = msg + "\n---------------------------------------------------------"
|
|
msg = msg + "\nIQM amplt\n" + iqm_jit_amplt.return_string_amplt()
|
|
msg = msg + "\n\nIQM phase\n" + iqm_jit_phase.return_string_phase()
|
|
msg = msg + "\n---------------------------------------------------------"
|
|
msg = msg + "\nPRE amplt\n" + pre_jit_amplt.return_string_amplt()
|
|
msg = msg + "\n\nPRE phase\n" + pre_jit_phase.return_string_phase()
|
|
msg = msg + "\n---------------------------------------------------------"
|
|
msg = msg + "\nKLY amplt\n" + kly_jit_amplt.return_string_amplt()
|
|
msg = msg + "\n\nKLY phase\n" + kly_jit_phase.return_string_phase()
|
|
msg = msg + "\n---------------------------------------------------------"
|
|
msg = msg + "\nVSUM amplt\n" + vsum_jit_amplt.return_string_amplt()
|
|
msg = msg + "\n\nVSUM phase\n" + vsum_jit_phase.return_string_phase()
|
|
msg = msg + "\n---------------------------------------------------------"
|
|
msg = msg + "\n\nPlots axis: X-axis = Three amplitude setpoints from left to right: 10% below sat / 5% below sat / sat"
|
|
msg = msg + "\nY-axis = Readback phase (with feedback closed = setpoint phase)"
|
|
msg = msg + "\n\nData file: " + get_context().path
|
|
|
|
print msg
|
|
|
|
# save the entry in the logbook
|
|
plot_files = get_plot_snapshots("Jitter Scan")
|
|
time.sleep(1.0)
|
|
elogllrf("Jitter Scan (HVPS="+str(hvps)[:6]+"V / "+str(rfrate)[:6]+" Hz)", msg,"Measurement", "RF Stability", SECTION, plot_files)
|
|
|
|
|
|
|