craft-software/Legacy/TF_Control/imc_Cernox_calibr_CRAFT.py
2025-07-04 15:52:40 +02:00

742 lines
38 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_CRAFT_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)
def linear_func(x,a,b):
return a*x+b
def CRAFT_Heater_Power_function(T): #Calculates the heater power needed for specific temperature for calibration ramping
Top_params = [1.3017, -5.5796]
Bottom_params = [1.286, -3.477]
Power_top = linear_func(T, *Top_params)
Power_bottom = linear_func(T, *Bottom_params)
return [Power_top, Power_bottom]
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)
self.line_Wait_time.editingFinished.connect(self.set_wait_time)
self.line_Tstart.editingFinished.connect(self.set_Tstart)
self.line_Tstop.editingFinished.connect(self.set_Tstop)
#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_Tstart, self.line_Tstop, self.line_Tsteps, self.line_Wait_time, self.line_Equilibr_time_imc_to_LS, self.line_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
self.wait_time = 60 #Waiting time for setup to get stable temperature to perform measurement for calibration.
self.T_start = 5 #T_start for Calibration. This is just a rough estimation of temperature, since the heater power is NOT driven by a PID controller
self.T_stop = 15 #T_stop for Calibration. This is just a rough estimation of temperature, since the heater power is NOT driven by a PID controller
self.setT = 0 #set temperature for heater. This is just a random value. It is set later according to edit_line in GUI
#read default values from config and set them in gui
self.read_default()
self.set_file_path()
self.set_Tsteps()
self.set_Interpolation_res()
self.set_use_default_file_path()
self.set_Equilibr_time()
self.set_Tstart()
self.set_Tstop()
self.set_wait_time()
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_BK_9132B_2')
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_BK_9132B_2 = manager.sync_BK_9132B_2()
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_BK_9132B_2')
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_BK_9132B_2 = manager.sync_BK_9132B_2()
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()
#Set power supply for heater in correct state:
update_single_entry(self.sync_BK_9132B_2,'OutputOn',0,True)
update_single_entry(self.sync_BK_9132B_2,'OutputOn',1,True)
update_single_entry(self.sync_BK_9132B_2,'setI',0,1.5)
update_single_entry(self.sync_BK_9132B_2,'setI',1,1.5)
update_single_entry(self.sync_BK_9132B_2,'setU',0,0)
update_single_entry(self.sync_BK_9132B_2,'setU',1,0)
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
# Set heater to power needed to reach self.setT:
R_Heater = 75 #Resistance of heaters (Ohm)
setP = CRAFT_Heater_Power_function(self.setT)
if setP[0] <0:
setP[0] = 0
if setP[1] <0:
setP[1] = 0
U_top = np.sqrt(setP[0]*R_Heater)
U_bottom = np.sqrt(setP[1]*R_Heater)
update_single_entry(self.sync_BK_9132B_2,'setU',0,U_top)
update_single_entry(self.sync_BK_9132B_2,'setU',1,U_bottom)
# print(setP)
self.time_now = timer()
self.timedelta = self.time_now - self.time_start
self.set_wait_time() #update wait time
if self.timedelta > self.wait_time and self.timedelta > self.Equilibr_time_imc_to_LS and self.setT <= self.T_stop: #Take measurement point if temperature of Cernox 1 is higher than self.NextTpoint
#Measure multiple temperature values for mean:
T_array_mean = np.empty(shape=(0,8))
for i in range(0,10):
T_value = self.sync_LS_218.get('T')
T_array_mean = np.append(T_array_mean, [T_value], axis=0)
time.sleep(0.2)
T = np.mean(T_array_mean, axis=0)
T = T.tolist()
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)
#Measure multiple voltages
U_array = np.empty(shape=(0,8))
for i in range(0,10):
U_meas = self.sync_imc.get('T')
U_array = np.append(U_array, [U_meas], axis=0)
time.sleep(0.2)
U = np.mean(U_array, axis=0)
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 #NICHT MEHR GEBRAUCHT, ALTER CODE
self.setT = self.setT + self.T_steps
self.time_start = timer()
else: #Dont measure anything
self.NextTpoint = T[0] #Reset NextTpoint to current temperature of Cernox 1
self.setT = self.T_start #set set-Temperature to T_start
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_wait_time(self):
self.wait_time = get_float(self.line_Wait_time)
def set_Tstart(self):
self.T_start = get_float(self.line_Tstart)
def set_Tstop(self):
self.T_stop = get_float(self.line_Tstop)
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_CRAFT_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_CRAFT_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','.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()