current state
This commit is contained in:
271
panel.py
271
panel.py
@ -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()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user