655 lines
34 KiB
Python
655 lines
34 KiB
Python
from PyQt6.QtGui import *
|
|
from PyQt6.QtWidgets import *
|
|
from PyQt6.QtCore import *
|
|
|
|
import multiprocessing
|
|
import multiprocessing.managers
|
|
|
|
import time
|
|
import traceback,sys,os
|
|
import numpy as np
|
|
import pyqtgraph as pg
|
|
from scripts import import_txt
|
|
import random
|
|
|
|
from scipy.optimize import curve_fit
|
|
|
|
from timeit import default_timer as timer
|
|
|
|
# Get the current script's directory
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
# Get the parent directory by going one level up
|
|
parent_dir = os.path.dirname(current_dir)
|
|
# Add the parent directory to sys.path
|
|
sys.path.append(parent_dir)
|
|
|
|
from design_files.imc_Cernox_calibr_design import Ui_MainWindow
|
|
|
|
|
|
class WorkerSignals(QObject):
|
|
'''
|
|
Defines the signals available from a running worker thread.
|
|
Supported signals are:
|
|
finished: No data
|
|
error: tuple (exctype, value, traceback.format_exc() )
|
|
result: object data returned from processing, anything
|
|
progress: int indicating % progress
|
|
'''
|
|
finished = pyqtSignal()
|
|
error = pyqtSignal(tuple)
|
|
result = pyqtSignal(object)
|
|
progress = pyqtSignal(list)
|
|
|
|
|
|
class Worker(QRunnable):
|
|
'''
|
|
Worker thread
|
|
Inherits from QRunnable to handler worker thread setup, signals and wrap-up.
|
|
:param callback: The function callback to run on this worker thread. Supplied args and
|
|
kwargs will be passed through to the runner.
|
|
:type callback: function
|
|
:param args: Arguments to pass to the callback function
|
|
:param kwargs: Keywords to pass to the callback function
|
|
'''
|
|
|
|
def __init__(self, fn, *args, **kwargs):
|
|
super(Worker, self).__init__()
|
|
|
|
# Store constructor arguments (re-used for processing)
|
|
self.fn = fn
|
|
self.args = args
|
|
self.kwargs = kwargs
|
|
self.signals = WorkerSignals()
|
|
|
|
# Add the callback to our kwargs
|
|
self.kwargs['progress_callback'] = self.signals.progress
|
|
|
|
@pyqtSlot()
|
|
def run(self):
|
|
'''
|
|
Initialise the runner function with passed args, kwargs.
|
|
'''
|
|
|
|
# Retrieve args/kwargs here; and fire processing using them
|
|
try:
|
|
result = self.fn(*self.args, **self.kwargs)
|
|
except:
|
|
traceback.print_exc()
|
|
exctype, value = sys.exc_info()[:2]
|
|
self.signals.error.emit((exctype, value, traceback.format_exc()))
|
|
else:
|
|
self.signals.result.emit(result) # Return the result of the processing
|
|
finally:
|
|
self.signals.finished.emit() # Done
|
|
|
|
def get_float(Qline,default = 0): #gets value from QLineEdit and converts it to float. If text is empty or cannot be converted, it returns "default" which is 0, if not specified
|
|
try:
|
|
out = float(Qline.text())
|
|
except:
|
|
out = default
|
|
return(out)
|
|
|
|
def update_single_entry(dict,name,ind,val): #updates a single value in global vars. To do so it gets the current value of "dict('name')", replaces "val" at indec "ind" and sends this back
|
|
data = dict.get(f"{name}") #get data
|
|
data[ind] = val #replace entry
|
|
dict.update({f"{name}":data}) #send data back
|
|
|
|
def calibration_function(x,a,b,c):
|
|
# return 1/(a + b*np.log(x)+c*np.log(x)**2 + d*np.log(x)**3 + e*np.log(x)**4 + g*np.log(x)**5)
|
|
# return 1/(a + b*np.log(x)+c*np.log(x)**2 + d*np.log(x)**3)
|
|
return 1/(a + b*np.log(x)+c*np.log(x)**2)
|
|
|
|
|
|
class MainWindow(QMainWindow, Ui_MainWindow):
|
|
def __init__(self, *args, **kwargs):
|
|
# Get the current script's directory
|
|
self.current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
# Get the parent directory by going one level up
|
|
self.parent_dir = os.path.dirname(current_dir)
|
|
|
|
#establish connection to global variables
|
|
# try: #try to connect to global variables
|
|
# manager = multiprocessing.managers.BaseManager(address=('localhost',5001), authkey=b'')
|
|
# manager.connect()
|
|
# manager.register('sync_BK_9132B')
|
|
# self.sync_BK_9132B = manager.sync_BK_9132B()
|
|
# except: #open global variables, if no connection can be made (i.e. it is not running). Then connect to it
|
|
# # subprocess.call(['D:\\Python instrument drivers\\env\\Scripts\\python.exe', 'D:\\Python instrument drivers\\StandAlones\\global_variables.py'])
|
|
# self.global_vars = QProcess()
|
|
# self.global_vars.start(self.parent_dir+"\\env\\Scripts\\python.exe", [self.current_dir+'\\global_variables.py'])
|
|
# manager.connect()
|
|
# manager.register('sync_BK_9132B')
|
|
# self.sync_BK_9132B = manager.sync_BK_9132B()
|
|
# print('!!!\nI opened global variables myself. If you close me, global variables will shut down too. Consider starting global variables in own instance for more security\n!!!')
|
|
|
|
#fill in variables, if they are not defined in global variables
|
|
# self.sync_BK_9132B.update({'setU':[0,0,0], 'setI':[0,0,0], 'OutputOn':[False, False, False], 'U':[0,0,0], 'I':[0,0,0], 'P':[0,0,0]})
|
|
|
|
#import Gui from QT designer file
|
|
super(MainWindow, self).__init__(*args, **kwargs)
|
|
self.setupUi(self)
|
|
|
|
#setup plot
|
|
self.graphWidget.setBackground('w')
|
|
self.graphWidget.setTitle("Calibration curve")
|
|
self.graphWidget.setLabel('bottom', 'Resistance (Ohm)')
|
|
self.graphWidget.setLabel('left', 'Temperature (K)')
|
|
# axis = pg.DateAxisItem()
|
|
# self.graphWidget.setAxisItems({'bottom':axis})
|
|
|
|
temp = [time.time(),time.time()-1]
|
|
pen1 = pg.mkPen(color=(255, 0, 0), width=2)
|
|
pen2 = pg.mkPen(color=(0, 0, 255), width=1)
|
|
self.plot_1 = self.graphWidget.plot(temp,[1,0],pen = pen1, name = 'Cernox', symbol ='x', symbolPen ='r', symbolBrush = 0.2)
|
|
self.plot_2 = self.graphWidget.plot(temp,[1,0],pen = pen2, name = 'Calibration fit')
|
|
self.graphWidget.addLegend()
|
|
|
|
self.plot_2.hide()
|
|
|
|
#set up pyQT threadpool
|
|
self.threadpool = QThreadPool()
|
|
|
|
|
|
#define signals and slots
|
|
self.actionSet_default.triggered.connect(self.set_default)
|
|
self.actionReset_default.triggered.connect(self.read_default)
|
|
self.button_connect.clicked.connect(self.start_meas)
|
|
self.line_Tsteps.editingFinished.connect(self.set_Tsteps)
|
|
self.button_start_measurement.clicked.connect(self.set_PerformMeasurement)
|
|
self.button_perform_calibration.clicked.connect(self.set_PerformCalibration)
|
|
self.Slider_select_cernox.valueChanged.connect(self.set_select_cernox)
|
|
self.comboBox_Fit_Interpolation.currentIndexChanged.connect(self.set_select_fit_interpolation)
|
|
self.line_Interpolation_res.editingFinished.connect(self.set_Interpolation_res)
|
|
self.checkBox_default_file_path.stateChanged.connect(self.set_use_default_file_path)
|
|
self.button_load_data.clicked.connect(self.load_calibration)
|
|
self.line_filePath.editingFinished.connect(self.set_file_path)
|
|
self.button_load_rawdata.clicked.connect(self.load_rawdata)
|
|
self.line_Equilibr_time_imc_to_LS.editingFinished.connect(self.set_Equilibr_time)
|
|
self.line_Equilibr_time_LS_to_imc.editingFinished.connect(self.set_Equilibr_time)
|
|
self.comboBox_LS_imc.currentIndexChanged.connect(self.set_select_LS218_imc)
|
|
|
|
|
|
|
|
#define constants
|
|
self.Npoints = 200 #number of point to plot
|
|
self.NextTpoint = 0 #Temperature value at which next measurement of T_cernox & R_cernox should be performed, depends on T_steps
|
|
self.T_steps = 0.1 #Temperature step size in Kelvin for calibration curve, relevant for self.NextTpoints
|
|
self.timedelta = 10 #measured time in seconds between last measurement and now. It has to be greater than self.Equilibr_time_LS_to_imc in order to measure new temperature with LS218
|
|
self.PerformMeasurement = False #Boolean. If True: Measurement will be performed
|
|
self.PerformCalibration = False #Boolean. If True: Calibration fit wil be performed
|
|
self.T_array = np.empty(shape=(0,8)) #Array with all T measurements for calibration fit
|
|
self.U_array = np.empty(shape=(0,8)) #Array with all U measurements for calibration fit
|
|
self.selected_cernox = 0 #Selected cernox for data / calibration fit plotting
|
|
self.Calibration_finished = False #Boolean. If True: Calibration fit finished and fit can be plotted
|
|
self.select_fit_interpolation = 0 #Select between fit (0) or interpolation (1)
|
|
self.Interpolation_res = 100 #Amount of interpolated points per Kelvin
|
|
self.use_default_file_path = True #If True: Use default file path for loading calibration (\\calibration_data)
|
|
self.file_path = 0 #File path for loading calibration
|
|
self.select_LS218_imc = 0 #Decide between LS218 or calibrated imc data for forward data (0: LS218, 1: imc)
|
|
self.Equilibr_time_imc_to_LS = 3 #Equilibrium time for imc -> t -> LS218 (seconds)
|
|
self.Equilibr_time_LS_to_imc = 1 #Equilibrium time for LS -> t -> imc (seconds)
|
|
self.T_imc_old = False #Boolean which will be compared to T_imc in global variables to check if global_variable has been changed
|
|
self.running = True #true while app is running
|
|
self.disable_plot = False #constant to disable plot to improve performance. Is changed by checkbox checkBox_disableplots
|
|
self.lines_config_float = [self.line_Tsteps, self.line_Equilibr_time_imc_to_LS, self.Equilibr_time_LS_to_imc, self.line_Interpolation_res]#is used for config file
|
|
self.lines_config_strings = [self.line_filePath]#is used for config file
|
|
self.checkboxes_config = [self.checkBox_default_file_path]#is used for config file
|
|
self.combobox_config = [self.comboBox_Fit_Interpolation]#is used for config file
|
|
|
|
#read default values from config and set them in gui
|
|
self.read_default()
|
|
|
|
|
|
def start_meas(self):
|
|
|
|
#establish connection to global variables
|
|
try: #try to connect to global variables
|
|
manager = multiprocessing.managers.BaseManager(address=('localhost',5001), authkey=b'')
|
|
manager.connect()
|
|
manager.register('syncdict')
|
|
manager.register('sync_BK_9132B')
|
|
manager.register('sync_LS_218')
|
|
manager.register('sync_LS_218')
|
|
manager.register('sync_imc')
|
|
manager.register('sync_converted')
|
|
self.syncdict = manager.syncdict()
|
|
self.sync_BK_9132B = manager.sync_BK_9132B()
|
|
self.sync_LS_218 = manager.sync_LS_218()
|
|
self.sync_imc = manager.sync_imc()
|
|
self.sync_converted = manager.sync_converted()
|
|
except: #open global variables, if no connection can be made (i.e. it is not running). Then connect to it
|
|
# subprocess.call(['D:\\Python instrument drivers\\env\\Scripts\\python.exe', 'D:\\Python instrument drivers\\StandAlones\\global_variables.py'])
|
|
self.global_vars = QProcess()
|
|
self.global_vars.start(self.current_dir+"\\.venv\\Scripts\\python.exe", [self.current_dir+'\\global_variables_TF.py'])
|
|
manager.connect()
|
|
manager.register('syncdict')
|
|
manager.register('sync_BK_9132B')
|
|
manager.register('sync_LS_218')
|
|
manager.register('sync_imc')
|
|
manager.register('sync_converted')
|
|
self.syncdict = manager.syncdict()
|
|
self.sync_BK_9132B = manager.sync_BK_9132B()
|
|
self.sync_LS_218 = manager.sync_LS_218()
|
|
self.sync_imc = manager.sync_imc()
|
|
self.sync_converted = manager.sync_converted()
|
|
print('!!!\nI opened global variables myself. If you close me, global variables will shut down too. Consider starting global variables in own instance for more security\n!!!')
|
|
|
|
#fill in variables, in case they are not defined in global variables
|
|
self.sync_LS_218.update({'T':[0,0,0,0,0,0,0,0]})
|
|
|
|
if self.syncdict.get('T_imc') == None:
|
|
self.syncdict.update({'T_imc':self.T_imc_old})
|
|
|
|
#set proper U and I values for LS<>imc relais
|
|
update_single_entry(self.sync_BK_9132B, "setU", 2, 5)
|
|
update_single_entry(self.sync_BK_9132B, "setI", 2, 1)
|
|
|
|
#Start timer. Not important now, but its needed to calculate a beginning self.timedelta
|
|
self.time_start = timer()
|
|
|
|
|
|
self.worker = Worker(self.update_all)
|
|
self.worker.signals.progress.connect(self.update_gui)
|
|
self.threadpool.start(self.worker)
|
|
self.bla = 4
|
|
|
|
def update_all(self, progress_callback):
|
|
#get values from device and write them to global variables. Checks if global variables changed from last iteration. Also pass it to upddate_gui with emit(T)
|
|
while self.running == True:
|
|
|
|
#Check if T_imc has changed in global variables. If so: Execute self.set_select_LS218_imc function
|
|
T_imc_new = self.syncdict.get('T_imc')
|
|
if T_imc_new != self.T_imc_old:
|
|
if T_imc_new == True: #Convert from T_imc boolean (True -> imc) to select_LS218_imc (0 -> LS218, 1 -> imc)
|
|
status = 1
|
|
else:
|
|
status = 0
|
|
self.set_select_LS218_imc(status)
|
|
self.comboBox_LS_imc.setCurrentIndex(status)
|
|
|
|
self.T_imc_old = T_imc_new
|
|
|
|
|
|
|
|
#update_single_entry(dict,name,ind,val)
|
|
|
|
#GENERATE DUMMY MEASUREMENT VALUES
|
|
# Uparams = [ 1.27319446e-03, 1.18559736e-03, 2.22734335e-04, 2.62920119e-05, -2.70008105e-05, 6.36768397e-06] #Params for dummy measurement values
|
|
|
|
# T = [self.bla + 0.1*random.random() for i in range(0,8)] #read Temperature of LS218 (8 Cernox sensors)
|
|
# U = calibration_function(T, *Uparams) #read Voltage of all imc Cernox channels
|
|
# for i,value in enumerate(U):
|
|
# U[i] = U[i] + 1*random.random()
|
|
|
|
#Measure temperature with LS218
|
|
T = self.sync_LS_218.get('T')
|
|
|
|
#Print measured data
|
|
# print("Values = " +str(np.round(U[0],2)) +" " +str(np.round(T[0],2)))
|
|
|
|
|
|
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
#Select file_path for saving
|
|
if self.use_default_file_path == True: #use default file path: Folder \calibration_data
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
path = current_dir+'\\calibration_data' #To make sure the config file is at the right place, independent from where the program is started the location of the file is retrieved
|
|
else: #use specific file path
|
|
if self.file_path == 0:
|
|
print("No file path entered.")
|
|
else:
|
|
path = self.file_path
|
|
|
|
if self.PerformCalibration == False: #Be able to perform Measurement if Boolean is False
|
|
if self.PerformMeasurement == True: #Perform Measurement if Boolean is True
|
|
self.time_now = timer()
|
|
self.timedelta = self.time_now - self.time_start
|
|
if T[0] >= self.NextTpoint and self.timedelta > self.Equilibr_time_imc_to_LS: #Take measurement point if temperature of Cernox 1 is higher than self.NextTpoint
|
|
|
|
self.T_array = np.append(self.T_array, [T], axis=0) #Append current T value to self.T_array for calibration
|
|
|
|
#Measure Cernox voltage with imc. Therefore, turn on relais and wait a short time
|
|
update_single_entry(self.sync_BK_9132B, "OutputOn", 2, True)
|
|
time.sleep(self.Equilibr_time_LS_to_imc)
|
|
U = self.sync_imc.get('T')
|
|
update_single_entry(self.sync_BK_9132B, "OutputOn", 2, False)
|
|
# time.sleep(2.5)
|
|
|
|
self.U_array = np.append(self.U_array, [U], axis=0) #Append current U value to self.U_array for calibration
|
|
|
|
#Save measured data in file
|
|
path_T = path + '\\Cernox_calibration_rawdata_T.txt' #Rawdata: T_array
|
|
path_U = path + '\\Cernox_calibration_rawdata_U.txt' #Rawdata: U_array
|
|
with open(path_T,'a') as file_T:
|
|
np.savetxt(file_T, [T])
|
|
with open(path_U,'a') as file_U:
|
|
np.savetxt(file_U, [U])
|
|
print("Saved measurement in rawdata.")
|
|
|
|
self.NextTpoint = self.NextTpoint + self.T_steps #Increase NextTpoint by one T_step for next measurement
|
|
self.time_start = timer()
|
|
else: #Dont measure anything
|
|
self.NextTpoint = T[0] #Reset NextTpoint to current temperature of Cernox 1
|
|
else:
|
|
#Perform Calibration fit/interpolation with saved measurements in T_array & U_array
|
|
|
|
#Create two arrays for params and param stds for fitting functionality
|
|
self.Params_array = np.empty(shape=(0,3)) #Array with all fitting parameters for all 1-8 Cernoxs (6 because of 6 fit parameters)
|
|
self.Std_array = np.empty(shape=(0,3)) #Array with all fitting parameter stds for all 1-8 Cernox (6 because of 6 fit parameters)
|
|
|
|
#In case of curve-fitting, set array size to fixed value of 1000. This value is arbitrary and is just importan for plotting.
|
|
if self.select_fit_interpolation == 0:
|
|
self.T_calibr_array = np.empty(shape=(1000,8))
|
|
self.U_calibr_array = np.empty(shape=(1000,8))
|
|
|
|
#In case interpolation will be performed, increase size of T_calibr_array and U_calibr_array dependent on interpolation_res
|
|
if self.select_fit_interpolation == 1:
|
|
Tmin_global = np.min(self.T_array)
|
|
Tmax_global = np.max(self.T_array)
|
|
number_of_points = int(self.Interpolation_res*(Tmax_global-Tmin_global)) #number of temperature points for interpolation
|
|
self.T_calibr_array = np.empty(shape=(number_of_points,8))
|
|
self.U_calibr_array = np.empty(shape=(number_of_points,8))
|
|
|
|
for i in range(0,8): #Perform curve fit / interpolation for all 8 Cernox sensors
|
|
|
|
#Minimum and maximum voltage of Cernox i, measured during measurement interval
|
|
Umin = np.min(self.U_array[:,i])
|
|
Umax = np.max(self.U_array[:,i])
|
|
|
|
#Minimum and maximum temperature of Cernox i, measured during measurement interval
|
|
Tmin = np.min(self.T_array[:,i])
|
|
Tmax = np.max(self.T_array[:,i])
|
|
|
|
if self.select_fit_interpolation == 0: #Perform fit
|
|
|
|
Params, Cov = curve_fit(calibration_function, self.U_array[:,i], self.T_array[:,i], maxfev = 1000000)
|
|
Std = np.diag(Cov)
|
|
#
|
|
#, p0=(-6.82560246e+01, 4.35751772e+01, -8.53436023e+00, 1.26904343e-01, 1.24338400e-01, -9.53073013e-03)
|
|
#
|
|
|
|
#Append Params and Std values to self.xxx_arrays
|
|
self.Params_array = np.append(self.Params_array, [Params], axis=0)
|
|
self.Std_array = np.append(self.Std_array, [Std], axis=0)
|
|
|
|
self.U_calibr_array[:,i] = np.linspace(Umin, Umax, 1000) #Voltage data points. #points = 1000 is chosen arbitrarily, just important for plotting
|
|
self.T_calibr_array[:,i] = calibration_function(self.U_calibr_array[:,i], *Params)
|
|
print("Fitted cernox " +str(i) +" successfully.")
|
|
|
|
path2 = path +'\\Cernox'+str(i)+'_fit.txt' #To make sure the config file is at the right place, independent from where the program is started the location of the file is retrieved
|
|
#Add Umin and Umax to file. Relevant information when loading this calibration file.
|
|
Params_and_Limits = np.append(Params, [Umin])
|
|
Params_and_Limits = np.append(Params_and_Limits, [Umax])
|
|
np.savetxt(path2, Params_and_Limits)
|
|
print("Fit parameters saved.")
|
|
|
|
if self.select_fit_interpolation == 1: #Perform interpolation
|
|
#(Perform interpolation with T on x-axis and U on y-axis since we want to define interpolation_res as #points per KELVIN)
|
|
self.T_calibr_array[:,i] = np.linspace(Tmin, Tmax, number_of_points)
|
|
self.U_calibr_array[:,i] = np.interp(self.T_calibr_array[:,i], self.T_array[:,i], self.U_array[:,i])
|
|
print("Interpolated cernox " +str(i) +" successfully.")
|
|
|
|
#Save interpolation array (combination of U_calibr_array and T_calibr_array)
|
|
interpolation_array = np.vstack((self.U_calibr_array[:,i], self.T_calibr_array[:,i])).T
|
|
path2 = path +'\\Cernox'+str(i)+'_interpolation.txt' #To make sure the config file is at the right place, independent from where the program is started the location of the file is retrieved
|
|
np.savetxt(path2, interpolation_array)
|
|
print("Interpolation list saved.")
|
|
|
|
self.PerformCalibration = False
|
|
self.Calibration_finished = True
|
|
|
|
|
|
if self.Calibration_finished == True and self.select_LS218_imc == 1:
|
|
update_single_entry(self.sync_BK_9132B, "OutputOn", 2, True) #Turn on imc<>LS218 relais
|
|
U = self.sync_imc.get('T')
|
|
else:
|
|
update_single_entry(self.sync_BK_9132B, "OutputOn", 2, False) #Turn off imc<>LS218 relais
|
|
U = [1,1,1,1,1,1,1,1]
|
|
|
|
|
|
progress_callback.emit([U,T]) #Emits list of Voltage U and Temperature T
|
|
|
|
self.bla = self.bla + 0.05 #self.bla increased for dummy measurement values
|
|
time.sleep(0.1)
|
|
|
|
# del(self.BK) #disconnect device when self.running is set to False
|
|
|
|
def update_gui(self, List):
|
|
#Convert List into original format
|
|
U = List[0]
|
|
T = List[1]
|
|
|
|
#Plot live data while measuring
|
|
self.plot_1.setData(self.U_array[:,self.selected_cernox],self.T_array[:,self.selected_cernox])
|
|
|
|
if self.Calibration_finished == True: #Plot fitting curve
|
|
|
|
self.plot_2.show()
|
|
self.plot_2.setData(self.U_calibr_array[:,self.selected_cernox],self.T_calibr_array[:,self.selected_cernox])
|
|
|
|
#Converting all current U measurements to temperature measurements:
|
|
T_calculated = []
|
|
|
|
if self.select_fit_interpolation == 0: #Perform conversion by calculating T with fitting curve
|
|
for i in range(0,8):
|
|
T_calc_single = calibration_function(U[i], *self.Params_array[i])
|
|
T_calculated.append(T_calc_single)
|
|
|
|
if self.select_fit_interpolation == 1: #Perform conversion by searching for the best entry in interpolation array
|
|
for i in range(0,8):
|
|
Nearest_index = self.nearest_value_in_array(self.U_calibr_array[:,i], U[i])
|
|
T_calc_single = self.T_calibr_array[Nearest_index, i]
|
|
T_calculated.append(T_calc_single)
|
|
|
|
if self.select_LS218_imc == 0: #LS218 data should be forwarded
|
|
T_output = T
|
|
|
|
|
|
else: #Forward calibrated imc data
|
|
T_output = T_calculated
|
|
|
|
|
|
else: #Forward LS218 data
|
|
T_output = T
|
|
|
|
self.sync_converted.update({'T':T_output})
|
|
print(T_output)
|
|
|
|
|
|
def set_Tsteps(self):
|
|
#updates T_steps (temperature step size for cernox calibration)
|
|
self.T_steps = get_float(self.line_Tsteps)
|
|
|
|
def set_PerformMeasurement(self):
|
|
#updates status for cernox calibration measurement to True -> Measurement will be performed
|
|
if self.PerformMeasurement == True:
|
|
self.PerformMeasurement = False
|
|
else:
|
|
self.PerformMeasurement = True
|
|
|
|
def set_PerformCalibration(self):
|
|
#updates status for cernox calibration fit. If True -> Perform fit with measurement data in T_array & U_array
|
|
if self.PerformCalibration == True:
|
|
self.PerformCalibration = False
|
|
else:
|
|
self.PerformCalibration = True
|
|
|
|
def set_select_cernox(self, value):
|
|
self.selected_cernox = value -1 # -1 because we want to have same declaration in python and #Cernox
|
|
self.line_Cernox.setText(str(self.selected_cernox))
|
|
|
|
def set_select_fit_interpolation(self, value):
|
|
self.select_fit_interpolation = value
|
|
|
|
if value == 0:
|
|
self.button_perform_calibration.setText("Perform Fit")
|
|
self.button_load_data.setText("Load fit data from file path")
|
|
self.line_Interpolation_res.setEnabled(False)
|
|
if value == 1:
|
|
self.button_perform_calibration.setText("Perform Interpolation")
|
|
self.button_load_data.setText("Load interpolation data from file path")
|
|
self.line_Interpolation_res.setEnabled(True)
|
|
|
|
self.Calibration_finished = False #Set boolean to False in order to stop conversion of U-values to T-values in update_gui
|
|
|
|
def set_Interpolation_res(self):
|
|
self.Interpolation_res = get_float(self.line_Interpolation_res)
|
|
|
|
def set_use_default_file_path(self):
|
|
self.use_default_file_path = self.checkBox_default_file_path.isChecked()
|
|
|
|
if self.use_default_file_path == True:
|
|
self.line_filePath.setEnabled(False)
|
|
else:
|
|
self.line_filePath.setEnabled(True)
|
|
|
|
def load_calibration(self):
|
|
if self.use_default_file_path == True: #use default file path: Folder \calibration_data
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
path = current_dir+'\\calibration_data' #To make sure the config file is at the right place, independent from where the program is started the location of the file is retrieved
|
|
else: #use specific file path
|
|
if self.file_path == 0:
|
|
print("No file path entered.")
|
|
else:
|
|
path = self.file_path
|
|
#Loading rawdata (measured U & T points) before loading calibration data
|
|
self.load_rawdata()
|
|
|
|
if self.select_fit_interpolation == 0:
|
|
#Create arrays with shape (1000,8) where 1000 is the amount of points to be plotted
|
|
self.T_calibr_array = np.empty(shape=(1000,8))
|
|
self.U_calibr_array = np.empty(shape=(1000,8))
|
|
|
|
#Create new Params_array and Std_array
|
|
self.Params_array = np.empty(shape=(0,6)) #Array with all fitting parameters for all 1-8 Cernoxs (6 because of 6 fit parameters)
|
|
self.Std_array = np.empty(shape=(0,6)) #Array with all fitting parameter stds for all 1-8 Cernox (6 because of 6 fit parameters)
|
|
|
|
if self.select_fit_interpolation == 1:
|
|
#Create arrays with size dependent on arrays to be loaded. Measure size for the first Cernox
|
|
pathCernoxInterpolation = path +'\\Cernox0_interpolation.txt'
|
|
preview = np.loadtxt(pathCernoxInterpolation)
|
|
preview_length = len(preview[:,0])
|
|
self.T_calibr_array = np.empty(shape=(preview_length,8))
|
|
self.U_calibr_array = np.empty(shape=(preview_length,8))
|
|
|
|
for i in range(0,8):
|
|
|
|
if self.select_fit_interpolation == 0: #Load fitting parameters
|
|
|
|
pathCernoxFit = path +'\\Cernox'+str(i)+'_fit.txt'
|
|
LoadedData = np.loadtxt(pathCernoxFit)
|
|
Params = LoadedData[0:-2]
|
|
Umin = LoadedData[-2]
|
|
Umax = LoadedData[-1]
|
|
|
|
#Append Params to Params_array
|
|
self.Params_array = np.append(self.Params_array, [Params], axis=0)
|
|
|
|
#Crate dataset for curve-fit plotting
|
|
self.U_calibr_array[:,i] = np.linspace(Umin, Umax, 1000) #Voltage data points. #points = 1000 is chosen arbitrarily, just important for plotting
|
|
self.T_calibr_array[:,i] = calibration_function(self.U_calibr_array[:,i], *Params)
|
|
|
|
print("Loaded cernox " +str(i) +" fitting parameters successfully.")
|
|
|
|
else: #Load interpolation parameters
|
|
pathCernoxInterpolation = path +'\\Cernox'+str(i)+'_interpolation.txt'
|
|
self.U_calibr_array[:,i] = np.loadtxt(pathCernoxInterpolation)[:,0]
|
|
self.T_calibr_array[:,i] = np.loadtxt(pathCernoxInterpolation)[:,1]
|
|
|
|
|
|
self.Calibration_finished = True
|
|
|
|
def load_rawdata(self):
|
|
#Just load rawdata from measurement without calibration (fit / interpolation) data
|
|
if self.use_default_file_path == True: #use default file path: Folder \calibration_data
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
path = current_dir+'\\calibration_data' #To make sure the config file is at the right place, independent from where the program is started the location of the file is retrieved
|
|
else: #use specific file path
|
|
if self.file_path == 0:
|
|
print("No file path entered.")
|
|
else:
|
|
path = self.file_path
|
|
|
|
#Loading rawdata (measured U & T points) before loading calibration data
|
|
pathRawData_T = path + '\\Cernox_calibration_rawdata_T.txt'
|
|
self.T_array = np.loadtxt(pathRawData_T)
|
|
pathRawData_U = path + '\\Cernox_calibration_rawdata_U.txt'
|
|
self.U_array = np.loadtxt(pathRawData_U)
|
|
|
|
|
|
def set_file_path(self):
|
|
self.file_path = self.line_filePath.text()
|
|
|
|
def nearest_value_in_array(self, array, value): #Returns index of closest entry in array compared to value
|
|
index = (np.abs(array - value)).argmin()
|
|
return(index)
|
|
|
|
def set_Equilibr_time(self):
|
|
self.Equilibr_time_LS_to_imc = get_float(self.line_Equilibr_time_LS_to_imc)
|
|
self.Equilibr_time_imc_to_LS = get_float(self.line_Equilibr_time_imc_to_LS)
|
|
|
|
def set_select_LS218_imc(self, value):
|
|
self.select_LS218_imc = value
|
|
if value == 0:
|
|
time.sleep(1.5) #time for LS218 to settle
|
|
|
|
|
|
def set_default(self):
|
|
#saves current set values to txt file in subdirectory configs. All entries that are saved are defined in self.lines_config
|
|
#Overwrites old values in config file.
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
path = current_dir+'\\configs\\imc_Cernox_calibr_config.txt' #To make shure the config file is at the right place, independent from where the program is started the location of the file is retrieved
|
|
file = open(path,'w')
|
|
for l in self.lines_config_float:
|
|
temp = f"{get_float(l)}"
|
|
file.write(temp+'\t')
|
|
for l in self.lines_config_strings:
|
|
file.write(l.text()+'\t')
|
|
for c in self.checkboxes_config:
|
|
file.write(str(c.isChecked())+'\t')
|
|
for c in self.combobox_config:
|
|
file.write(str(c.currentIndex())+'\t')
|
|
file.write('\n')
|
|
file.close
|
|
|
|
def read_default(self):
|
|
#reads default values from config file in subdirectory config and sets the values in gui. Then self.change is set to true so values are send
|
|
#to device. (If no config file exists, it does nothing.)
|
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
path = current_dir+'\\configs\\imc_Cernox_calibr_config.txt' #To make shure the config file is read from the right place, independent from where the program is started the location of the file is retrieved
|
|
try: #exit function if config file does not exist
|
|
vals = import_txt.read_raw(path)
|
|
except:
|
|
print('no config file found on')
|
|
print(path)
|
|
return
|
|
formats = ['.2f', '.2f', '.2f','.2f','.2f','.0f']
|
|
|
|
for l,v,f in zip(self.lines_config_float,vals[0],formats):
|
|
v = float(v) #convert string in txt to float, so number can be formatted according to "formats" when it's set
|
|
l.setText(format(v,f))
|
|
|
|
for l,v in zip(self.lines_config_strings,vals[0][len(self.lines_config_float):]):
|
|
l.setText(v)
|
|
|
|
for c,v in zip(self.checkboxes_config,vals[0][len(self.lines_config_float)+len(self.lines_config_strings):]):
|
|
c.setChecked(v == 'True')
|
|
|
|
for c,v in zip(self.combobox_config,vals[0][len(self.lines_config_float)+len(self.lines_config_strings)+len(self.checkboxes_config):]):
|
|
c.setCurrentIndex(int(v))
|
|
|
|
self.change = True
|
|
|
|
def closeEvent(self,event): #when window is closed self.running is set to False, so all threads stop
|
|
self.running = False
|
|
time.sleep(1)
|
|
event.accept()
|
|
|
|
|
|
|
|
app = QApplication(sys.argv)
|
|
|
|
window = MainWindow()
|
|
window.show()
|
|
app.exec() |