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()