411 lines
18 KiB
Python
411 lines
18 KiB
Python
from collections import deque
|
|
import random
|
|
import wx
|
|
import numpy as np
|
|
import epics
|
|
|
|
import datetime
|
|
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.dates
|
|
|
|
#from epics.wx import MotorPanel
|
|
|
|
from slic.gui.widgets import LabeledMathEntry
|
|
from slic.gui.widgets import make_filled_hbox, make_filled_vbox, EXPANDING
|
|
from slic.gui.widgets.plotting import PlotPanel
|
|
|
|
from bstrd import BS, bsstream
|
|
from epics import caget, caput, cainfo
|
|
|
|
from scipy.signal import savgol_filter
|
|
from decimal import Decimal
|
|
|
|
import time
|
|
|
|
|
|
def gauss(axis, amp, center, sigma):
|
|
return amp*np.exp( -1*(axis - center)**2/(2*sigma**2))
|
|
#nshots = 100
|
|
|
|
#channel_tof = "SATES21-GES1:A1_VALUES"
|
|
|
|
|
|
#ch_tof = BS(channel_tof)
|
|
|
|
#temp_tof = ch_tof.get()
|
|
#print(temp_tof)
|
|
#next(bsstream)
|
|
|
|
|
|
|
|
temp1_channel = 'SATES20-CWAG-GEP01:TEMP07'
|
|
temp2_channel = 'SATES20-CWAG-GEP01:TEMP08'
|
|
|
|
voltage1_channel = 'SATES20-CWAG-GEP01:DAC07_VOLTS'
|
|
voltage2_channel = 'SATES20-CWAG-GEP01:DAC08_VOLTS'
|
|
|
|
pressure_channel = 'SATES21-VM-VT2010:PRESSURE'
|
|
|
|
temp1_PV = epics.PV(temp1_channel)
|
|
temp2_PV = epics.PV(temp2_channel)
|
|
voltage1_PV = epics.PV(voltage1_channel)
|
|
voltage2_PV = epics.PV(voltage2_channel)
|
|
pressure_PV = epics.PV(pressure_channel)
|
|
|
|
iso_format = "%Y-%m-%d %H:%M:%S"
|
|
|
|
|
|
|
|
def create_text_entry(parent,text = "", maxlength = 5, hint = 0, setvalue = 0):
|
|
text = wx.StaticText(parent, -1, text)
|
|
textentry = wx.TextCtrl(parent)
|
|
textentry.SetMaxLength(maxlength)
|
|
textentry.SetHint('%s'%str(hint))
|
|
textentry.SetValue('%s'%str(setvalue))
|
|
return textentry, text
|
|
|
|
|
|
|
|
|
|
class MainPanel(wx.Panel):
|
|
|
|
|
|
def __init__(self, parent):
|
|
super().__init__(parent)
|
|
self.quelength = 6000000
|
|
self.temp1deque = deque(maxlen=self.quelength)
|
|
self.temp2deque = deque(maxlen=self.quelength)
|
|
self.pressuredeque = deque(maxlen=self.quelength)
|
|
# self.simple_ctl = True
|
|
# self.set_temp1 = 20
|
|
# self.set_temp2 = 20
|
|
self.temp_min = 0
|
|
self.temp_max = 250
|
|
|
|
self.set_name1 = 'Sample'
|
|
self.set_name2 = 'Tip'
|
|
|
|
self.currenttemp1 = temp1_PV.get()
|
|
self.currenttemp2 = temp2_PV.get()
|
|
self.pressure = pressure_PV.get()
|
|
|
|
# self.prev_error1 = self.set_temp1 - self.currenttemp1
|
|
# self.sum_error1 = 0
|
|
# self.ctl1 = 0
|
|
# self.prev_error2 = self.set_temp2 - self.currenttemp2
|
|
# self.sum_error2 = 0
|
|
# self.ctl2 = 0
|
|
|
|
self.plottemp = plottemp = PlotPanel(self, figsize=(4,4))
|
|
plots1 = (plottemp,)
|
|
hb_plot1 = make_filled_hbox(plots1)
|
|
|
|
self.t0 = time.time()
|
|
self.last_update_time = time.time()
|
|
self.tList = deque(maxlen=self.quelength)
|
|
|
|
self.set_twindow = 60 #Minutes
|
|
|
|
self.update_interval = 1 #Seconds
|
|
self.twindow_listlength = int((float(self.set_twindow*60)) / self.update_interval)
|
|
|
|
|
|
|
|
###### ROI box ######
|
|
# self.temp1, self.tempt1 = create_text_entry(self, text = self.set_name1 + " Set", maxlength = 5, setvalue = self.set_temp1)
|
|
# temp1box = make_filled_vbox((self.tempt1, self.temp1), border=1)
|
|
|
|
self.temp_min_ctrl, self.tempwt1 = create_text_entry(self, text = "Temperature Y Minimum", maxlength = 5, setvalue = self.temp_min)
|
|
temp_minbox = make_filled_vbox((self.tempwt1, self.temp_min_ctrl), border=1)
|
|
|
|
# self.temp2, self.tempt2 = create_text_entry(self, text = self.set_name2 + " Set", maxlength = 5, setvalue = self.set_temp2)
|
|
# temp2box = make_filled_vbox((self.tempt2, self.temp2), border=1)
|
|
|
|
self.temp_max_ctrl, self.tempwt2 = create_text_entry(self, text = "Temperature Y Maximum", maxlength = 5, setvalue = self.temp_max)
|
|
temp_maxbox = make_filled_vbox((self.tempwt2, self.temp_max_ctrl), border=1)
|
|
|
|
self.temp1_indicator = wx.Button(self, label = self.set_name1 + " Heat")
|
|
self.temp1_indicator.Disable()
|
|
self.temp1_indicator.SetBackgroundColour(wx.NullColour)
|
|
self.temp2_indicator = wx.Button(self, label = self.set_name2 + " Heat")
|
|
self.temp2_indicator.Disable()
|
|
self.temp2_indicator.SetBackgroundColour(wx.NullColour)
|
|
indicatorbox = make_filled_vbox((self.temp1_indicator, self.temp2_indicator), border=1)
|
|
|
|
# self.btn_on = wx.Button(self, label="TC ON")
|
|
# self.btn_off = wx.Button(self, label="TC OFF")
|
|
# self.btn_on.SetBackgroundColour(wx.NullColour)
|
|
# self.btn_off.SetBackgroundColour(wx.Colour(0,200,0))
|
|
|
|
# self.btn_PID = wx.Button(self, label="PID Control")
|
|
# self.btn_PID.SetBackgroundColour(wx.NullColour)
|
|
|
|
# self.btn_simple = wx.Button(self, label="Binary Control")
|
|
# self.btn_simple.SetBackgroundColour(wx.Colour(0,200,200))
|
|
|
|
btn_updatesettemp = wx.Button(self, label="Update Temp Y Axis")
|
|
btn_clearplots = wx.Button(self, label="Clear Plots")
|
|
# ctlbox = make_filled_vbox((self.btn_PID, self.btn_simple), border=1)
|
|
# tempbox = make_filled_hbox(( self.btn_on, self.btn_off, ctlbox, temp1box, temp_minbox, temp2box, temp_maxbox, btn_updatesettemp), border=1)
|
|
tempbox = make_filled_hbox((indicatorbox, temp_minbox, temp_maxbox, btn_updatesettemp), border=1)
|
|
|
|
temp_box = make_filled_vbox((tempbox, hb_plot1))
|
|
|
|
|
|
self.plotpressure = plotpressure = PlotPanel(self, figsize=(4,4))
|
|
plots2 = (plotpressure,)
|
|
hb_plot2 = make_filled_hbox(plots2)
|
|
|
|
self.twindow, self.twindowt = create_text_entry(self, text = "Time Window [Minutes]", maxlength = 5, setvalue = self.set_twindow)
|
|
set_twindow_btn = wx.Button(self, label="Update Time Window")
|
|
self.pressure_min_ctrl, self.pressure_min_text = create_text_entry(self, text = "Pressure Y Minimum", maxlength = 15, setvalue = "1e-9")
|
|
self.pressure_max_ctrl, self.pressure_max_text = create_text_entry(self, text = "Pressure Y Maximum", maxlength = 15, setvalue = "1e-2")
|
|
set_pressure_btn = wx.Button(self, label="Update Pressure Y Axis")
|
|
self.pressure_min = Decimal('1e-9')
|
|
self.pressure_max = Decimal('1e-2')
|
|
|
|
twindow_box = make_filled_vbox((self.twindowt, self.twindow))
|
|
press_min_box = make_filled_vbox((self.pressure_min_text, self.pressure_min_ctrl))
|
|
press_max_box = make_filled_vbox((self.pressure_max_text, self.pressure_max_ctrl))
|
|
|
|
self.name1, self.namew1 = create_text_entry(self, text = "Temp 1 Label", maxlength = 20, setvalue = self.set_name1)
|
|
self.name2, self.namew2 = create_text_entry(self, text = "Temp 2 Label", maxlength = 20, setvalue = self.set_name2)
|
|
btn_updatename = wx.Button(self, label = "Update Labels")
|
|
name_box_1 = make_filled_vbox((self.namew1, self.name1), border=1)
|
|
name_box_2 = make_filled_vbox((self.namew2, self.name2), border=1)
|
|
name_box = make_filled_hbox((name_box_1, name_box_2, btn_updatename, btn_clearplots), border=1)
|
|
|
|
pressure_entries_box = make_filled_hbox(( twindow_box, press_min_box, press_max_box, set_twindow_btn, set_pressure_btn), border=1)
|
|
pressure_box = make_filled_vbox((hb_plot2, pressure_entries_box))
|
|
box = make_filled_vbox((temp_box, pressure_box, name_box))
|
|
self.SetSizerAndFit(box)
|
|
|
|
|
|
|
|
# self.btn_on.Bind(wx.EVT_BUTTON, self.on_click_on)
|
|
# self.btn_off.Bind(wx.EVT_BUTTON, self.on_click_off)
|
|
# self.btn_PID.Bind(wx.EVT_BUTTON, self.on_click_PID)
|
|
# self.btn_simple.Bind(wx.EVT_BUTTON, self.on_click_simple)
|
|
btn_updatesettemp.Bind(wx.EVT_BUTTON, self.on_click_updateTemp) # change function later
|
|
btn_clearplots.Bind(wx.EVT_BUTTON, self.on_click_clearPlots)
|
|
btn_updatename.Bind(wx.EVT_BUTTON, self.on_click_updateNames)
|
|
set_twindow_btn.Bind(wx.EVT_BUTTON, self.on_click_twindow)
|
|
|
|
set_pressure_btn.Bind(wx.EVT_BUTTON, self.on_click_updatePressure)
|
|
|
|
|
|
self.timer = wx.Timer(self)
|
|
self.Bind(wx.EVT_TIMER, self.on_update, self.timer)
|
|
self.timer.Start(100)
|
|
|
|
|
|
def on_update(self, _event):
|
|
|
|
self.time = time.time()
|
|
self.currentvolt1 = voltage1_PV.get()
|
|
self.currentvolt2 = voltage2_PV.get()
|
|
self.currenttemp1 = temp1_PV.get()
|
|
self.currenttemp2 = temp2_PV.get()
|
|
self.pressure = pressure_PV.get()
|
|
|
|
if self.time - self.last_update_time > self.update_interval: ### Update voltage settings and append to queue every 2 seconds
|
|
self.tList = np.append(self.tList, matplotlib.dates.date2num(datetime.datetime.now()))
|
|
self.temp1deque.append(self.currenttemp1)
|
|
self.temp2deque.append(self.currenttemp2)
|
|
self.pressuredeque.append(self.pressure)
|
|
self.last_update_time = time.time()
|
|
if voltage1_PV.get() > 0.1:
|
|
self.temp1_indicator.SetBackgroundColour(wx.Colour(200,0,0))
|
|
else:
|
|
self.temp1_indicator.SetBackgroundColour(wx.NullColour)
|
|
if voltage2_PV.get() > 0.1:
|
|
self.temp2_indicator.SetBackgroundColour(wx.Colour(200,0,0))
|
|
else:
|
|
self.temp2_indicator.SetBackgroundColour(wx.NullColour)
|
|
# if self.PID_ctl == True:
|
|
# self.change_temp_PID()
|
|
# self.tempt1.SetForegroundColour(wx.NullColour)
|
|
# self.tempt2.SetForegroundColour(wx.NullColour)
|
|
|
|
# if self.simple_ctl == True:
|
|
# self.change_temp()
|
|
|
|
self.draw_plot()
|
|
|
|
wx.GetApp().Yield()
|
|
|
|
|
|
# def ctlToVolts(self, ctl):
|
|
# a = 2.03787295
|
|
# v0 = 1.90207996
|
|
# value = ctl/a + v0
|
|
# if value == -np.inf or ctl <= 0:
|
|
# return 0.0
|
|
# if ctl >= 1:
|
|
# return 5.0
|
|
# else:
|
|
# return value
|
|
|
|
# def change_temp(self):
|
|
# ## currently open or close transistor, future, implement PID
|
|
# self.last_update_time = time.time()
|
|
# if self.currenttemp1 - self.set_temp1 > self.temp_min or self.onOff == False:
|
|
# voltage1_PV.put(0)
|
|
# print('Current temp: %0.1f // Set temp %0.1f // Turn OFF voltage'%(self.currenttemp1,self.set_temp1 ))
|
|
# self.tempt1.SetForegroundColour(wx.Colour(255,0,0))
|
|
|
|
# else:
|
|
# voltage1_PV.put(5)
|
|
# print('Current temp: %0.1f // Set temp %0.1f // Turn ON voltage'%(self.currenttemp1,self.set_temp1 ))
|
|
# self.tempt1.SetForegroundColour(wx.Colour(0,255,0))
|
|
|
|
# if self.currenttemp2 - self.set_temp2 > self.temp_max or self.onOff == False:
|
|
# voltage2_PV.put(0)
|
|
# print('Current temp: %0.1f // Set temp %0.1f // Turn OFF voltage'%(self.currenttemp2,self.set_temp2 ))
|
|
# self.tempt2.SetForegroundColour(wx.Colour(255,0,0))
|
|
|
|
# else:
|
|
# voltage2_PV.put(5)
|
|
# print('Current temp: %0.1f // Set temp %0.1f // Turn ON voltage'%(self.currenttemp2,self.set_temp2 ))
|
|
# self.tempt2.SetForegroundColour(wx.Colour(0,255,0))
|
|
# print('_____________________________________________________________')
|
|
|
|
|
|
# def change_temp_PID(self):
|
|
# ## currently open or close transistor, future, implement PID
|
|
# self.last_update_time = time.time()
|
|
# self.T = self.update_interval
|
|
# self.ctl_error1 = self.set_temp1 - self.currenttemp1
|
|
# self.ctl_error2 = self.set_temp2 - self.currenttemp2
|
|
# self.deriv_error1 = self.ctl_error1 - self.prev_error1
|
|
# self.deriv_error2 = self.ctl_error2 - self.prev_error2
|
|
|
|
# self.kScale = 1
|
|
# self.kp = 0.4 / self.kScale
|
|
# self.ki = (0.02 * self.T) / self.kScale
|
|
# self.kd = (1.0 / self.T) / self.kScale
|
|
|
|
# self.ctl1 = (self.kp * self.ctl_error1) + (self.ki * self.sum_error1) + (self.kd * self.deriv_error1)
|
|
# self.ctl2 = (self.kp * self.ctl_error2) + (self.ki * self.sum_error2) + (self.kd * self.deriv_error2)
|
|
|
|
# if abs(self.ctl_error1) < 5:
|
|
# self.sum_error1 += self.ctl_error1
|
|
# if abs(self.ctl_error1) < 5:
|
|
# self.sum_error2 += self.ctl_error2
|
|
# self.prev_error1 = self.ctl_error1
|
|
# self.prev_error2 = self.ctl_error2
|
|
|
|
# if self.onOff == False:
|
|
# voltage1_PV.put(0)
|
|
# voltage2_PV.put(0)
|
|
# print('Temperature Control Off')
|
|
# else:
|
|
# voltage1_PV.put(self.ctlToVolts(self.ctl1))
|
|
# voltage2_PV.put(self.ctlToVolts(self.ctl2))
|
|
# print('PID Control 1 = ' + str(round(self.ctl1, 3)) + ' // Voltage 1 = ' + str(round(self.ctlToVolts(self.ctl1), 3)) + ' V')
|
|
# print('PID Control 2 = ' + str(round(self.ctl2, 3)) + ' // Voltage 2 = ' + str(round(self.ctlToVolts(self.ctl2), 3)) + ' V')
|
|
# print('_____________________________________________________________')
|
|
|
|
|
|
def draw_plot(self):
|
|
self.plottemp.clear()
|
|
self.plottemp.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%H:%M.%S'))
|
|
self.plottemp.set_xlabel("Time [H:M.S]")
|
|
self.plottemp.set_ylabel("Temperature [C]")
|
|
self.plottemp.set_ylim([self.temp_min, self.temp_max])
|
|
if (len(self.tList) < self.twindow_listlength):
|
|
self.plottemp.plot(np.squeeze(self.tList).flatten(), np.squeeze(self.temp1deque).flatten(), '.-', label = self.set_name1)
|
|
self.plottemp.plot(np.squeeze(self.tList).flatten(), np.squeeze(self.temp2deque).flatten(), '.-', label = self.set_name2)
|
|
# if self.onOff == True:
|
|
# self.plottemp.axhline(y = self.set_temp1, color = 'b', alpha = 0.2)
|
|
# self.plottemp.axhline(y = self.set_temp2, color = 'r', alpha = 0.2)
|
|
else:
|
|
self.plottemp.plot(np.squeeze(self.tList).flatten()[len(self.tList) - self.twindow_listlength:], np.squeeze(self.temp1deque).flatten()[len(self.tList) - self.twindow_listlength:], '.-', label = self.set_name1)
|
|
self.plottemp.plot(np.squeeze(self.tList).flatten()[len(self.tList) - self.twindow_listlength:], np.squeeze(self.temp2deque).flatten()[len(self.tList) - self.twindow_listlength:], '.-', label = self.set_name2)
|
|
# if self.onOff == True:
|
|
# self.plottemp.axhline(y = self.set_temp1, color = 'b', alpha = 0.2)
|
|
# self.plottemp.axhline(y = self.set_temp2, color = 'r', alpha = 0.2)
|
|
self.plottemp.legend([self.set_name1 + ": " + str(round(self.currenttemp1, 2)) + " C", self.set_name2 + ": " + str(round(self.currenttemp2, 2)) + " C"], loc='upper left')
|
|
self.plottemp.draw()
|
|
|
|
self.plotpressure.clear()
|
|
self.plotpressure.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%H:%M.%S'))
|
|
self.plotpressure.set_xlabel("Time [H:M.S]")
|
|
self.plotpressure.set_ylabel("Pressure [mBar]")
|
|
if (len(self.tList) < self.twindow_listlength):
|
|
self.plotpressure.plot(np.squeeze(self.tList).flatten(), np.squeeze(self.pressuredeque).flatten(), '.-', label = 'Pressure')
|
|
else:
|
|
self.plotpressure.plot(np.squeeze(self.tList).flatten()[len(self.tList) - self.twindow_listlength:], np.squeeze(self.pressuredeque).flatten()[len(self.tList) - self.twindow_listlength:], '.-', label = 'Pressure')
|
|
self.plotpressure.set_ylim([self.pressure_min, self.pressure_max])
|
|
self.plotpressure.set_yscale('log')
|
|
# self.plotpressure.legend(loc='upper left')
|
|
self.plotpressure.draw()
|
|
|
|
|
|
def on_click_updateTemp(self, _event):
|
|
# self.set_temp1 = np.double(self.temp1.GetValue())
|
|
# self.set_temp2 = np.double(self.temp2.GetValue())
|
|
self.temp_min = np.double(self.temp_min_ctrl.GetValue())
|
|
self.temp_max = np.double(self.temp_max_ctrl.GetValue())
|
|
# self.prev_error1 = self.set_temp1 - self.currenttemp1
|
|
# self.sum_error1 = 0
|
|
# self.ctl1 = 0
|
|
# self.prev_error2 = self.set_temp2 - self.currenttemp2
|
|
# self.sum_error2 = 0
|
|
# self.ctl2 = 0
|
|
|
|
# print('Updated temperature setpoints')
|
|
|
|
# def on_click_on(self, _event):
|
|
# self.prev_error1 = self.set_temp1 - self.currenttemp1
|
|
# self.sum_error1 = 0
|
|
# self.ctl1 = 0
|
|
# self.prev_error2 = self.set_temp2 - self.currenttemp2
|
|
# self.sum_error2 = 0
|
|
# self.ctl2 = 0
|
|
# self.onOff = True
|
|
# self.btn_on.SetBackgroundColour(wx.Colour(0,200,0))
|
|
# self.btn_off.SetBackgroundColour(wx.NullColour)
|
|
|
|
# def on_click_off(self, _event):
|
|
# self.onOff = False
|
|
# self.btn_on.SetBackgroundColour(wx.NullColour)
|
|
# self.btn_off.SetBackgroundColour(wx.Colour(0,200,0))
|
|
|
|
# def on_click_PID(self, _event):
|
|
# self.PID_ctl = True
|
|
# self.simple_ctl = False
|
|
# self.btn_PID.SetBackgroundColour(wx.Colour(0,200,200))
|
|
# self.btn_simple.SetBackgroundColour(wx.NullColour)
|
|
|
|
# def on_click_simple(self, _event):
|
|
# self.simple_ctl = True
|
|
# self.PID_ctl = False
|
|
# self.btn_simple.SetBackgroundColour(wx.Colour(0,200,200))
|
|
# self.btn_PID.SetBackgroundColour(wx.NullColour)
|
|
|
|
def on_click_clearPlots(self, _event):
|
|
self.tList = deque(maxlen=self.quelength)
|
|
self.temp1deque = deque(maxlen=self.quelength)
|
|
self.temp2deque = deque(maxlen=self.quelength)
|
|
self.pressuredeque = deque(maxlen=self.quelength)
|
|
|
|
def on_click_updatePressure(self, _event):
|
|
self.pressure_min = Decimal(self.pressure_min_ctrl.GetValue())
|
|
self.pressure_max = Decimal(self.pressure_max_ctrl.GetValue())
|
|
|
|
def on_click_updateNames(self, _event):
|
|
n1 = self.name1.GetValue()
|
|
n2 = self.name2.GetValue()
|
|
self.tempt1.SetLabel(n1)
|
|
self.tempt2.SetLabel(n2)
|
|
self.tempwt1.SetLabel(n1 + " Threshold")
|
|
self.tempwt2.SetLabel(n2 + " Threshold")
|
|
self.set_name1 = n1
|
|
self.set_name2 = n2
|
|
|
|
def on_click_twindow(self, _event):
|
|
self.set_twindow = self.twindow.GetValue()
|
|
self.twindow_listlength = int((float(self.set_twindow)*60) / self.update_interval)
|