current state

This commit is contained in:
gac-alvra
2023-03-10 20:48:58 +01:00
parent 8883cc8855
commit 9b44063753

271
panel.py
View File

@ -1,7 +1,12 @@
from collections import deque from collections import deque
from random import random import random
import wx import wx
import numpy as np import numpy as np
import epics
from datetime import datetime
#from epics.wx import MotorPanel
from slic.gui.widgets import LabeledMathEntry from slic.gui.widgets import LabeledMathEntry
from slic.gui.widgets import make_filled_hbox, make_filled_vbox, EXPANDING from slic.gui.widgets import make_filled_hbox, make_filled_vbox, EXPANDING
@ -9,149 +14,211 @@ from slic.gui.widgets.plotting import PlotPanel
from bstrd import BS, bsstream from bstrd import BS, bsstream
# config # config
#STAGEpv = epics.PV('SLAAR11-LMOT-M452:MOTOR_1.VAL') # global globi nshots = 1000
mm2fs = 6671.2 # light speed and delay stages
ttThreshold = 5
iZeroThreshold = 0.5
# spectrometer axis in time
timeAx = -1.91*(np.arange(0,2048)-1024)
# channels
STAGEpv = epics.PV('SLAAR11-LMOT-M452:MOTOR_1.VAL') # global globi
chname_amplitude = "SARES11-SPEC125-M1.edge_amplitude" chname_amplitude = "SARES11-SPEC125-M1.edge_amplitude"
chname_jitter = "SARES11-SPEC125-M1.edge_position" chname_jitter = "SARES11-SPEC125-M1.edge_position"
chname_deriv = "SARES11-SPEC125-M1.edge_derivative" chname_deriv = "SARES11-SPEC125-M1.edge_derivative"
chname_events = "SAR-CVME-TIFALL4:EvtSet" chname_events = "SAR-CVME-TIFALL4:EvtSet"
chname_iZero = "SAROP11-PBPS110:INTENSITY" chname_iZero = "SAROP11-PBPS110:INTENSITY"
length = 500
mm2fs = 6671.2 # lightspeed and delay stages
threshold = 7
# create channel # create channels
ch_amp = BS(chname_amplitude) ch_amp = BS(chname_amplitude)
ch_jitter = BS(chname_jitter) ch_jitter = BS(chname_jitter)
ch_events = BS(chname_events) ch_events = BS(chname_events)
ch_iZero = BS(chname_iZero) ch_iZero = BS(chname_iZero)
ch_deriv = BS(chname_deriv) ch_deriv = BS(chname_deriv)
iso_format = "%Y-%m-%d %H:%M:%S"
def goodshots(events, iZero, amps, *arrays):
fel = events[:, 13]
laser = events[:, 18]
darkShot = events[:, 21]
pulsePicking = events[:,200]
iZero = iZero
amplitudes = amps
pumped_shots = np.logical_and.reduce((fel, laser, np.logical_not(darkShot), pulsePicking, iZero > iZeroThreshold, amps > ttThreshold))
# pumped_shots = np.logical_and.reduce((fel, laser, np.logical_not(darkShot)))
return [a[pumped_shots] for a in arrays]
class MainPanel(wx.Panel): class MainPanel(wx.Panel):
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent) super().__init__(parent)
self.evts = np.empty((1000,256)) self.evts = np.empty((nshots,256))
self.jitter = np.empty(1000) self.jitter = np.empty(nshots)
self.amp = np.empty(1000) self.amp = np.empty(nshots)
self.iZero = np.empty(1000) self.iZero = np.empty(nshots)
self.deriv = np.empty((1000,2048)) self.deriv = np.empty((nshots,2048))
self.edge = np.empty((nshots,2048))
self.beans = deque(maxlen=10) self.stagePos = deque(maxlen=1000)
self.spilled = deque(maxlen=10) self.jitters = deque(maxlen=1000)
self.jstds = deque(maxlen=1000)
self.amps = deque(maxlen=1000)
self.astds = deque(maxlen=1000)
btn_minus = wx.Button(self, label="-") self.plot_jitters = plot_jitters = PlotPanel(self, figsize=(2,3))
btn_plus = wx.Button(self, label="+") self.plot_amps = plot_amps = PlotPanel(self, figsize=(2,3))
btn_check = wx.Button(self, label="?") self.plot_edges = plot_edges = PlotPanel(self, figsize=(6,5))
btns = (btn_minus, btn_plus, btn_check) plots1 = (plot_edges,)
hb_plot1 = make_filled_hbox(plots1)
plots2 = (plot_jitters, plot_amps)
hb_plot2 = make_filled_hbox(plots2)
btn_clearQ = wx.Button(self, label="Clear plots")
btns = (btn_clearQ,)
hb_btns = make_filled_hbox(btns) hb_btns = make_filled_hbox(btns)
self.le_beans = le_beans = LabeledMathEntry(self, label="How many beans?", value=0) self.chkbx_feedback = chkbx_feedback = wx.CheckBox(self, label="feedback")
self.le_spilled = le_spilled = LabeledMathEntry(self, label="Spilled beans:", value=0) chkbxs = (btn_clearQ, chkbx_feedback)
le_spilled.Disable() hb_chkbx = make_filled_hbox(chkbxs)
self.plot_beans = plot_beans = PlotPanel(self) self.plot_stage = plot_stage = PlotPanel(self, figsize=(6,2))
self.plot_spilled = plot_spilled = PlotPanel(self) self.plot_timeseries_jitters = plot_timeseries_jitters = PlotPanel(self, figsize=(6,2))
self.plot_timeseries_amps = plot_timeseries_amps = PlotPanel(self, figsize=(6,2))
plots3 = (plot_timeseries_jitters,)
plots4 = (plot_timeseries_amps,)
plots5 = (plot_stage,)
hb_plot3 = make_filled_hbox(plots3)
hb_plot4 = make_filled_hbox(plots4)
hb_plot5 = make_filled_hbox(plots5)
plots = (plot_beans, plot_spilled) widgets = (hb_plot1, hb_plot2, hb_plot3, hb_plot4, hb_plot5, hb_chkbx)
hb_plots = make_filled_hbox(plots) box = make_filled_vbox(widgets, border=1)
widgets = (hb_btns, le_beans, le_spilled, EXPANDING, hb_plots)
box = make_filled_vbox(widgets, border=10)
self.SetSizerAndFit(box) self.SetSizerAndFit(box)
btn_minus.Bind(wx.EVT_BUTTON, self.on_click_minus) btn_clearQ.Bind(wx.EVT_BUTTON, self.on_click_clearQ)
btn_plus.Bind(wx.EVT_BUTTON, self.on_click_plus)
btn_check.Bind(wx.EVT_BUTTON, self.on_click_check) self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_update, self.timer)
self.timer.Start(100)
def on_click_minus(self, _event): def on_update(self, _event):
le = self.le_beans
current = le.GetValue()
le.SetValue(current - 1)
self.update_plot()
self.time = datetime.now().strftime(iso_format)
def on_click_plus(self, _event): self.evts = np.empty((nshots,256))
if random() < 0.9: self.jitter = np.empty(nshots)
le = self.le_beans self.amp = np.empty(nshots)
else: self.iZero = np.empty(nshots)
le = self.le_spilled self.deriv = np.empty((nshots,2048))
current = le.GetValue() or 0
le.SetValue(current + 1)
self.update_plot()
for i in range(nshots):
def on_click_check(self, _event): tempa = ch_events.get()
self.evts[i] = tempa
self.evts = np.empty((1000,256)) tempb = ch_jitter.get()
self.jitter = np.empty(1000) self.jitter[i] = tempb
self.amp = np.empty(1000) tempc = ch_amp.get()
self.iZero = np.empty(1000) self.amp[i] = tempc
self.deriv = np.empty((1000,2048)) tempd = ch_iZero.get()
self.iZero[i] = tempd
tempe = ch_deriv.get()
def goodshots(events, *arrays): self.deriv[i] = tempe
fel = events[:, 13]
laser = events[:, 18]
darkShot = events[:, 21]
pumped_shots = np.logical_and.reduce((fel, laser, np.logical_not(darkShot)))
return [a[pumped_shots] for a in arrays]
# percent = self.get_percentage()
# msg = f"You spilled {percent:.2}% of the beans."
# self.le_beans.SetValue(0)
# self.le_spilled.SetValue(0)
# wx.MessageBox(msg, "Spillage Stats", wx.OK|wx.ICON_WARNING)
for i in range(1000):
self.evts[i] = ch_events.get()
self.jitter[i] = ch_jitter.get()
self.amp[i] = ch_amp.get()
self.iZero[i] = ch_iZero.get()
self.deriv[i] = ch_deriv.get()
next(bsstream) next(bsstream)
wx.GetApp().Yield()
self.deriv, self.amp, self.jitter, self.iZero = goodshots(self.evts, self.deriv, self.amp, self.jitter, self.iZero) self.deriv, self.amp, self.jitter = goodshots(self.evts, self.iZero, self.amp, self.deriv, self.amp, self.jitter)
self.update_plot()
if (len(np.asarray(self.jitter)) > 1):
self.jitters.append(np.mean(self.jitter))
self.jstds.append(np.std(self.jitter))
self.amps.append(np.mean(self.amp))
self.astds.append(np.std(self.amp))
def get_percentage(self): if (self.chkbx_feedback.IsChecked()) & (np.abs(np.mean(self.jitter)) > 50) & (np.abs(np.mean(self.jitter)) < 1000):
b = self.le_beans.GetValue() or 0 moveTo = STAGEpv.get()*mm2fs - np.mean(self.jitter)
s = self.le_spilled.GetValue() or 0 STAGEpv.put(moveTo/mm2fs)
return s / b * 100
self.stagePos.append(STAGEpv.get())
else:
print("{} Where are my X-rays?".format(self.time))
self.jitters.append(np.nan)
self.jstds.append(np.nan)
self.amps.append(np.nan)
self.astds.append(np.nan)
self.stagePos.append(np.nan)
def update_plot(self):
self.store_values()
self.draw_plot() self.draw_plot()
def store_values(self):
b = self.le_beans.GetValue() or 0
s = self.le_spilled.GetValue() or 0
self.beans.append(b)
self.spilled.append(s)
def draw_plot(self): def draw_plot(self):
self.plot_beans.clear() self.plot_jitters.clear()
self.plot_spilled.clear() self.plot_amps.clear()
self.plot_beans.plot(self.deriv[0], color='grey') self.plot_edges.clear()
self.plot_beans.plot(self.deriv[-1], color='grey') self.plot_timeseries_jitters.clear()
self.plot_beans.plot(self.deriv[10], color='grey') self.plot_timeseries_amps.clear()
self.plot_beans.plot(self.deriv[-10], color='grey') self.plot_stage.clear()
self.plot_beans.plot(np.mean(self.deriv, axis=0), color='orangered')
self.plot_spilled.plot(self.jitter) self.plot_edges.set_xlabel('relative arrival time, fs')
self.plot_beans.draw() self.plot_edges.set_xlim(-1500,1500)
self.plot_spilled.draw() self.plot_edges.set_ylabel('transmission change, %')
self.plot_timeseries_jitters.set_xlabel('time ago, a.u.')
self.plot_timeseries_jitters.set_ylabel('arrival time, fs')
self.plot_timeseries_amps.set_xlabel('time ago, a.u.')
self.plot_timeseries_amps.set_ylabel('edge amplitude, %')
self.plot_stage.set_xlabel('time ago, a.u.')
self.plot_stage.set_ylabel('m452 position, mm')
self.plot_edges.set_xlabel('relative arrival time, fs')
self.plot_edges.set_xlim(-1500,1500)
self.plot_edges.set_ylabel('transmission change, %')
self.plot_jitters.set_xlabel('relative arrival time, fs')
self.plot_jitters.set_ylabel('counts')
self.plot_amps.set_xlabel('edge amplitudes, %')
self.plot_amps.set_ylabel('counts')
if (len(self.deriv) > 0):
self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey')
self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey')
self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey')
self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey')
self.plot_edges.plot(timeAx, self.deriv[random.randrange(0, len(self.deriv))], color='grey')
self.plot_edges.plot(timeAx, np.mean(self.deriv, axis=0), color='orangered')
self.plot_edges.set_title("{}, offset of {}$\,$fs, jitter of {}$\,$fs rms".format(self.time,np.round(np.mean(self.jitter),1), np.round((np.std(self.jitter)),1)))
self.plot_edges.axvline(x=np.mean(self.jitter), color='k', linestyle="--")
self.plot_jitters.hist(self.jitter, facecolor='orangered', edgecolor='black')
self.plot_amps.hist(self.amp, facecolor='orangered', edgecolor='black')
self.plot_stage.plot(self.stagePos, 'o-')
self.plot_timeseries_jitters.fill_between(np.arange(0, len(self.jitters)), np.asarray(self.jstds)+np.asarray(self.jitters), -np.asarray(self.jstds)+np.asarray(self.jitters), color='gold')
self.plot_timeseries_jitters.plot(np.arange(0, len(self.jitters)), self.jitters, 'o-', color='orangered')
self.plot_timeseries_amps.plot(np.arange(0, len(self.amps)), self.amps, 'o-', color='orangered')
self.plot_timeseries_amps.fill_between(np.arange(0, len(self.amps)), np.asarray(self.astds)+np.asarray(self.amps), -np.asarray(self.astds)+np.asarray(self.amps), color='gold')
self.plot_edges.draw()
self.plot_jitters.draw()
self.plot_amps.draw()
self.plot_timeseries_jitters.draw()
self.plot_timeseries_amps.draw()
self.plot_stage.draw()
def goodshots(events, *arrays): def on_click_clearQ(self, _event):
fel = events[:, 13] self.jitters.clear()
laser = events[:, 18] self.jstds.clear()
darkShot = events[:, 21] self.amps.clear()
pumped_shots = np.logical_and.reduce((fel, laser, np.logical_not(darkShot))) self.astds.clear()
return [a[pumped_shots] for a in arrays] self.stagePos.clear()