""" 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 = "SINSB02" # for 100 Hz and P2P-count = 100 this can be at least 1.1 seconds latency = 2 ################################################################# # 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 # 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_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() ################################################################################# # scan hvps = mva_hvps.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 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), ( 0.2, -170.0), (0.3, 180.0), (0.05, 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() ################################################################################# # 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)) # adjust plot ranges for the color bar to be always the same a_lim = 5.0e-4 p_lim = 0.04 i=0 for p in get_plots("Jitter Scan"): if i % 2 == 0: p.setColorScale(0.0, a_lim) else : p.setColorScale(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", msg,"Measurement", "RF Stability", SECTION, plot_files)