From 31ab136e7eff3c7693204d606aa7183ad6163c4a Mon Sep 17 00:00:00 2001 From: Roger Kalt Date: Mon, 7 Nov 2016 07:44:31 +0100 Subject: [PATCH] Startup --- script/jitter_vs_avggatelength_scan.py | 384 +++++++++++++++++++++++++ 1 file changed, 384 insertions(+) create mode 100644 script/jitter_vs_avggatelength_scan.py diff --git a/script/jitter_vs_avggatelength_scan.py b/script/jitter_vs_avggatelength_scan.py new file mode 100644 index 0000000..3dfeb3e --- /dev/null +++ b/script/jitter_vs_avggatelength_scan.py @@ -0,0 +1,384 @@ +""" +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 = 5 +################################################################# + + + + + +# some other parameters + +# 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 + + + + +# 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_satpower = PV("SAT_POWER" ,SECTION + "-RKLY-DCP10:FOR-POWER-AVG") +#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() +mva_satpower.initialize() + + + +################################################################################# +# scan + +hvps = mva_hvps.read() +rfrate = mva_rfrate.read() +satpower = mva_satpower.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 = lscan(cv_rf_ampl, (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", after_read=after, 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() +mva_satpower.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)) + + + +#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) +set_attribute(path, "RF Rate", rfrate) +set_attribute(path, "Saturation Power", satpower) + + +################################################################################# +# New overview plot of the results + +[pyp,pya]=plot([None,None],["summary_phase_jit","summary_amplt_jit"], title="Results Overview Jitter") + +#Y error plot +pya.setStyle(pya.Style.ErrorY) +pya.setLegendVisible(True) + +sy1s = LinePlotErrorSeries("saturated") +pya.addSeries(sy1s) +sy1s.setLinesVisible(False) +sy1s.appendData(1.0, ref_jit_amplt.sat.mean, ref_jit_amplt.sat.min, ref_jit_amplt.sat.max) +sy1s.appendData(2.0, iqm_jit_amplt.sat.mean, iqm_jit_amplt.sat.min, iqm_jit_amplt.sat.max) +sy1s.appendData(3.0, pre_jit_amplt.sat.mean, pre_jit_amplt.sat.min, pre_jit_amplt.sat.max) +sy1s.appendData(4.0, kly_jit_amplt.sat.mean, kly_jit_amplt.sat.min, kly_jit_amplt.sat.max) +sy1s.appendData(5.0, vsum_jit_amplt.sat.mean, vsum_jit_amplt.sat.min, vsum_jit_amplt.sat.max) + +sy1m5 = LinePlotErrorSeries("drive 5% below") +pya.addSeries(sy1m5) +sy1m5.setLinesVisible(False) +sy1m5.appendData(1.1, ref_jit_amplt.m5.mean, ref_jit_amplt.m5.min, ref_jit_amplt.m5.max) +sy1m5.appendData(2.1, iqm_jit_amplt.m5.mean, iqm_jit_amplt.m5.min, iqm_jit_amplt.m5.max) +sy1m5.appendData(3.1, pre_jit_amplt.m5.mean, pre_jit_amplt.m5.min, pre_jit_amplt.m5.max) +sy1m5.appendData(4.1, kly_jit_amplt.m5.mean, kly_jit_amplt.m5.min, kly_jit_amplt.m5.max) +sy1m5.appendData(5.1, vsum_jit_amplt.m5.mean, vsum_jit_amplt.m5.min, vsum_jit_amplt.m5.max) + +sy1m10 = LinePlotErrorSeries("drive 10% below") +pya.addSeries(sy1m10) +sy1m10.setLinesVisible(False) +sy1m10.appendData(1.2, ref_jit_amplt.m10.mean, ref_jit_amplt.m10.min, ref_jit_amplt.m10.max) +sy1m10.appendData(2.2, iqm_jit_amplt.m10.mean, iqm_jit_amplt.m10.min, iqm_jit_amplt.m10.max) +sy1m10.appendData(3.2, pre_jit_amplt.m10.mean, pre_jit_amplt.m10.min, pre_jit_amplt.m10.max) +sy1m10.appendData(4.2, kly_jit_amplt.m10.mean, kly_jit_amplt.m10.min, kly_jit_amplt.m10.max) +sy1m10.appendData(5.2, vsum_jit_amplt.m10.mean, vsum_jit_amplt.m10.min, vsum_jit_amplt.m10.max) + + +m=pya.addMarker(1.0, pya.AxisId.X, "REF",pya.background) +m.setLabelPaint(Color.BLACK) +m=pya.addMarker(2.0, pya.AxisId.X, "IQM",pya.background) +m.setLabelPaint(Color.BLACK) +m=pya.addMarker(3.0, pya.AxisId.X, "PRE",pya.background) +m.setLabelPaint(Color.BLACK) +m=pya.addMarker(4.0, pya.AxisId.X, "KLY",pya.background) +m.setLabelPaint(Color.BLACK) +m=pya.addMarker(5.0, pya.AxisId.X, "VSUM",pya.background) +m.setLabelPaint(Color.BLACK) + + +#Y error plot +pyp.setStyle(pyp.Style.ErrorY) +pyp.setLegendVisible(True) + +sy2s = LinePlotErrorSeries("saturated") +pyp.addSeries(sy2s) +sy2s.setLinesVisible(False) +sy2s.appendData(1.0, ref_jit_phase.sat.mean, ref_jit_phase.sat.min, ref_jit_phase.sat.max) +sy2s.appendData(2.0, iqm_jit_phase.sat.mean, iqm_jit_phase.sat.min, iqm_jit_phase.sat.max) +sy2s.appendData(3.0, pre_jit_phase.sat.mean, pre_jit_phase.sat.min, pre_jit_phase.sat.max) +sy2s.appendData(4.0, kly_jit_phase.sat.mean, kly_jit_phase.sat.min, kly_jit_phase.sat.max) +sy2s.appendData(5.0, vsum_jit_phase.sat.mean, vsum_jit_phase.sat.min, vsum_jit_phase.sat.max) + +sy2m5 = LinePlotErrorSeries("drive 5% below") +pyp.addSeries(sy2m5) +sy2m5.setLinesVisible(False) +sy2m5.appendData(1.1, ref_jit_phase.m5.mean, ref_jit_phase.m5.min, ref_jit_phase.m5.max) +sy2m5.appendData(2.1, iqm_jit_phase.m5.mean, iqm_jit_phase.m5.min, iqm_jit_phase.m5.max) +sy2m5.appendData(3.1, pre_jit_phase.m5.mean, pre_jit_phase.m5.min, pre_jit_phase.m5.max) +sy2m5.appendData(4.1, kly_jit_phase.m5.mean, kly_jit_phase.m5.min, kly_jit_phase.m5.max) +sy2m5.appendData(5.1, vsum_jit_phase.m5.mean, vsum_jit_phase.m5.min, vsum_jit_phase.m5.max) + +sy2m10 = LinePlotErrorSeries("drive 10% below") +pyp.addSeries(sy2m10) +sy2m10.setLinesVisible(False) +sy2m10.appendData(1.2, ref_jit_phase.m10.mean, ref_jit_phase.m10.min, ref_jit_phase.m10.max) +sy2m10.appendData(2.2, iqm_jit_phase.m10.mean, iqm_jit_phase.m10.min, iqm_jit_phase.m10.max) +sy2m10.appendData(3.2, pre_jit_phase.m10.mean, pre_jit_phase.m10.min, pre_jit_phase.m10.max) +sy2m10.appendData(4.2, kly_jit_phase.m10.mean, kly_jit_phase.m10.min, kly_jit_phase.m10.max) +sy2m10.appendData(5.2, vsum_jit_phase.m10.mean, vsum_jit_phase.m10.min, vsum_jit_phase.m10.max) + +m=pyp.addMarker(1.0, pyp.AxisId.X, "REF",pyp.background) +m.setLabelPaint(Color.BLACK) +m=pyp.addMarker(2.0, pyp.AxisId.X, "IQM",pyp.background) +m.setLabelPaint(Color.BLACK) +m=pyp.addMarker(3.0, pyp.AxisId.X, "PRE",pyp.background) +m.setLabelPaint(Color.BLACK) +m=pyp.addMarker(4.0, pyp.AxisId.X, "KLY",pyp.background) +m.setLabelPaint(Color.BLACK) +m=pyp.addMarker(5.0, pyp.AxisId.X, "VSUM",pyp.background) +m.setLabelPaint(Color.BLACK) + + + + +################################################################################# +# ELOG + +msg = "HVPS command = " + str(hvps)[:6] + "V)" +msg = msg + "\nsaturation power = " + str(satpower)[:6] + "MW)" +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 +# need some sleep before and after to allow plots to be updated and to be stored to disk +time.sleep(1.0) +plot_files1 = get_plot_snapshots("Jitter Scan","png") +plot_files2 = get_plot_snapshots("Results Overview Jitter","png") +plot_files = plot_files2 + plot_files1 +time.sleep(1.0) +elogllrf("Jitter Scan (HVPS="+str(hvps)[:6]+"V / "+str(rfrate)[:6]+" Hz)", msg,"Measurement", "RF Stability", SECTION, plot_files) + + +