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 collections import json # 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.Automation_Measurement_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 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 self.manager = multiprocessing.managers.BaseManager(address=('localhost',5001), authkey=b'') self.manager.connect() self.manager.register('syncdict') self.manager.register('sync_main') self.manager.register('sync_BK_9174B') self.manager.register('sync_BK_9174B_2') self.manager.register('sync_BK_9131B') self.syncdict = self.manager.syncdict() self.sync_main = self.manager.sync_main() self.sync_BK_9174B = self.manager.sync_BK_9174B() self.sync_BK_9174B_2 = self.manager.sync_BK_9174B_2() self.sync_BK_9131B = self.manager.sync_BK_9131B() 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']) self.manager.connect() self.manager.register('syncdict') self.manager.register('sync_main') self.manager.register('sync_BK_9174B') self.manager.register('sync_BK_9174B_2') self.manager.register('sync_BK_9131B') self.syncdict = self.manager.syncdict() self.sync_main = self.manager.sync_main() self.sync_BK_9174B = self.manager.sync_BK_9174B() self.sync_BK_9174B_2 = self.manager.sync_BK_9174B_2() self.sync_BK_9131B = self.manager.sync_BK_9131B() 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 #import Gui from QT designer file super(MainWindow, self).__init__(*args, **kwargs) self.setupUi(self) #setup of pens for Plots pen1 = pg.mkPen(color=(255, 180, 180), width=2) #pen for T pen1_avg = pg.mkPen(color=(200, 0, 0), width=2) #pen for T average pen2 = pg.mkPen(color=(0, 0, 255), width=2) #pen for Tset pen3 = pg.mkPen(color=(0,0,255), width=2, style=Qt.PenStyle.DashLine) #pen for Tset range #setup PID Monitoring Plot self.graphWidget_Temp_Top.setBackground('w') self.graphWidget_Temp_Top.setTitle("PID Temperature Top") self.graphWidget_Temp_Top.setLabel('left', 'Temperature (K)') self.graphWidget_Temp_Top.setLabel('bottom', 'Time (s)') self.graphWidget_Temp_Bottom.setBackground('w') self.graphWidget_Temp_Bottom.setTitle("PID Temperature Bottom") self.graphWidget_Temp_Bottom.setLabel('left', 'Temperature (K)') self.graphWidget_Temp_Bottom.setLabel('bottom', 'Time (s)') self.plot_top_T = self.graphWidget_Temp_Top.plot([0,1],[1,0],pen = pen1, name = 'T') self.plot_top_T_average = self.graphWidget_Temp_Top.plot([0,1],[1,0],pen = pen1_avg, name = 'T avg') self.plot_top_Tset = self.graphWidget_Temp_Top.plot([0,1],[1,0],pen = pen2, name = 'Tset') self.plot_top_Tset_range_lower = self.graphWidget_Temp_Top.plot([0,1],[1,0],pen = pen3, name = 'Tset Range') self.plot_top_Tset_range_upper = self.graphWidget_Temp_Top.plot([0,1],[1,0],pen = pen3, name = 'Tset Range') self.plot_top_Tset_cooldown_finished = self.graphWidget_Temp_Top.plot([0,1],[1,0],pen = pen3, name = 'Cooldown fin.') self.plot_bottom_T = self.graphWidget_Temp_Bottom.plot([0,1],[1,0],pen = pen1, name = 'T') self.plot_bottom_T_average = self.graphWidget_Temp_Bottom.plot([0,1],[1,0],pen = pen1_avg, name = 'T avg') self.plot_bottom_Tset = self.graphWidget_Temp_Bottom.plot([0,1],[1,0],pen = pen2, name = 'Tset') self.plot_bottom_Tset_range_lower = self.graphWidget_Temp_Bottom.plot([0,1],[1,0],pen = pen3, name = 'Tset Range') self.plot_bottom_Tset_range_upper = self.graphWidget_Temp_Bottom.plot([0,1],[1,0],pen = pen3, name = 'Tset Range') self.plot_bottom_Tset_cooldown_finished = self.graphWidget_Temp_Bottom.plot([0,1],[1,0],pen = pen3, name = 'Cooldown fin.') self.plot_top_Tset.hide() self.plot_bottom_Tset.hide() self.graphWidget_Temp_Top.addLegend() self.graphWidget_Temp_Bottom.addLegend() #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.comboBox_Current_Mode.currentIndexChanged.connect(self.set_Current_Mode) self.line_Gradient.editingFinished.connect(self.set_Additional_Params) self.line_Bext.editingFinished.connect(self.set_Additional_Params) self.line_Speed.editingFinished.connect(self.set_Additional_Params) self.pushButton_Start_Measurement.clicked.connect(self.Start_Measurement) self.pushButton_Stop_Measurement.clicked.connect(self.Stop_Measurement) self.lineEdit_Gradient_List.editingFinished.connect(self.set_Bext_Gradient_List) self.pushButton_Stop_Waiting.clicked.connect(self.set_stop_wait_process) self.pushButton_Calculate_Parameters.clicked.connect(self.Calculate_Parameters) self.pushButton_Perform_Compensation.clicked.connect(self.Run_Perform_all_Bext_Compensations) self.pushButton_Abort_Compensation.clicked.connect(self.Abort_Perform_all_Bext_Compensations) self.pushButton_Compensation_Take_It.clicked.connect(self.Set_Take_It_Current) self.pushButton_load_Bext_Compensation.clicked.connect(self.load_Bext_Compensation_parameters) self.pushButton_Pause_Measurement.clicked.connect(self.set_Pause) #define constants self.running = True self.set_old = [0,0,1] #variable to save the 'old' set values to compare them to the global variables. It differs from set_new in the first iteration. This ensures that new parameters are send to the device self.set_new = [0,0,0] #variable to save the new set values to compare them to the old ones self.lines_config_float = [self.line_Min_Gradient, self.line_Max_Gradient, self.line_Gradient_Stepwidth, self.line_Min_Bext, self.line_Max_Bext, self.line_Stepwidth_Bext, self.line_Base_Temperature, self.line_Cooldown_Finished_Temperature, self.line_Sensor_Distance, self.line_Gradient, self.line_Bext, self.line_Speed, self.line_time_per_cooldown, self.line_PID_Temperature_Average_Time, self.line_PID_Temperature_Tolerance, self.line_PID_Temperature_Time, self.line_Buffer_Length, self.line_Plot_Seconds]#is used for config file self.lines_config_strings = [self.lineEdit_Gradient_List, self.line_Points_Folder_Path, self.line_Bext_Compensation_Path]#is used for config file self.checkboxes_config = [self.checkBox_Unlimited_Measurements]#is used for config file self.combobox_config = [self.comboBox_Current_Mode]#is used for config file self.Params_Lines = [self.line_Min_Gradient, self.line_Max_Gradient, self.line_Gradient_Stepwidth, self.line_Min_Bext, self.line_Max_Bext, self.line_Stepwidth_Bext, self.lineEdit_Gradient_List, self.checkBox_Unlimited_Measurements] self.Additional_Params = [0,0,0] self.Bext_Gradient_List = [] #List of Gradients for TF vs. Bext Measurement self.Status_Perform_Measurement = False self.Current_Mode = 0 self.Temp_Buffer = collections.deque([]) self.Temp_Average_Buffer = collections.deque([]) self.stop_wait_process = False #used to stop the waiting process for reaching Tset or Cooldown_Finished_Temperature self.PID_Temperature_Checker_On = False # Variable to check if PID_Temperature_Checker is running self.Cooldown_Finished_Checker_On = False # Variable to check if Cooldown_Finished_Checker is running self.Perform_all_Bext_Compensations_Boolean = False #Variable to check if self.Perform_all_Bext_Compensations should be running self.Bext_Compensations_Current_List = [] # List with all Compensation parameters self.Bext_Compensation_List = [] # List with all Bext values to be compensated self.Take_It_Current = False #Boolean which will be set to True if Compensated failed but currents should be stored self.pause = False #Pause measurement series if True #read default values from config and set them in gui self.read_default() self.set_Bext_Gradient_List() self.set_Additional_Params() # Standard things self.line_Status.setText("Ready for measurements.") # Start standard thread self.worker = Worker(self.update_all) self.worker.signals.progress.connect(self.Update_PID_Monitor) self.threadpool.start(self.worker) # # Start temperature monitoring thread # worker_temperature = Worker(self.temperature_thread) # self.threadpool.start(worker_temperature) def update_all(self, progress_callback): #Checks if global variables changed from last iteration. while self.running == True: #Checking for changes in global variables (e.g. temperatures) for i,n in enumerate(['T']): #get new set values from global variables and compare to old ones. self.set_new[i] = self.sync_main.get(n) if self.set_new != self.set_old: #if a button is clicked or global variables are changed the program checks which setting has been changed. if self.set_new[0] != self.set_old[0]: #if T changed, write T in local variable self.T = self.set_new[0] # if self.T is a list with two values: if self.T is not None and isinstance(self.T, list) and len(self.T) == 2: # self.Temperature_Monitor() #Write Temps in Dqueue, etc. progress_callback.emit(self.T) if self.set_new[1] != self.set_old[1]: #if Start_Compensation is changed new Start_Compensation is saved locally self.Start_Compensation = self.set_new[1] # self.update_setValues(self.set_new) #Change GUI text lines self.set_old = self.set_new[:] #List needs to be sliced so that only values are taken and not just a pointer is created print("Closed") def Calculate_Parameters(self): #Collect Measurement parameters: Current_Mode = self.Current_Mode self.Gradient_List = [] self.Bext_List = [] Number_of_Measurements = 0 if Current_Mode == 0: #Collect params for TF vs. DT Measurement Series Min_Gradient = get_float(self.line_Min_Gradient) Max_Gradient = get_float(self.line_Max_Gradient) Stepwidth_Gradient = get_float(self.line_Gradient_Stepwidth) Unlimited_Measurements = self.checkBox_Unlimited_Measurements.isChecked() # Create list with Gradients from Min to Max (incl. Max) with Stepwidth_Gradient stepwidth try: self.Gradient_List = list(np.arange(Min_Gradient, Max_Gradient + Stepwidth_Gradient, Stepwidth_Gradient)) except: self.line_Status.setText("Error in Gradient params.") return self.Gradient_List = [np.round(self.Gradient_List[i],3) for i in range(len(self.Gradient_List))] self.Number_of_Measurements = len(self.Gradient_List) # Fill Bext + Zero-Bext into listWidget_Bext Bext = self.Additional_Params[1] self.Bext_Compensation_List = [[0,0,0], [0,Bext,0]] #Bext List and Zero-Bext in the beginning self.listWidget_Bext.clear() # Clear old entries self.listWidget_Bext_Progress.clear() # Clear old entries for i, Bext in enumerate(self.Bext_Compensation_List): self.listWidget_Bext.addItem(str(Bext)) self.listWidget_Bext_Progress.addItem(QListWidgetItem("Pending")) if Current_Mode == 1: #Collect params for TF vs. Bext Measurement Series Min_Bext = get_float(self.line_Min_Bext) Max_Bext = get_float(self.line_Max_Bext) Stepwidth_Bext = get_float(self.line_Stepwidth_Bext) # Create list with Bext from Min to Max (incl. Max) with Stepwidth_Bext stepwidth try: if Max_Bext >= Min_Bext: self.Bext_List = list(np.arange(Min_Bext, Max_Bext + Stepwidth_Bext, Stepwidth_Bext)) else: # in case Max_Bext < Min_Bext calculate np.arange in other direction and reverse self.Bext_List = list(np.arange(Max_Bext, Min_Bext + Stepwidth_Bext, Stepwidth_Bext)) self.Bext_List.reverse() except: self.line_Status.setText("Error in Bext params.") return self.Bext_List = [np.round(self.Bext_List[i],3) for i in range(len(self.Bext_List))] if len(self.Bext_Gradient_List) == 0: # If Bext_List is empty, return self.line_Status.setText("Error in Bext params. Gradient List is empty.") return else: self.Number_of_Measurements = len(self.Bext_List)* len(self.Bext_Gradient_List) # Number of measurements is the product of the number of Bext and the number of Gradients # Fill Bext + Zero-Bext into listWidget_Bext Bext_List_with_ZeroBext = self.Bext_List.copy() Bext_List_with_ZeroBext.insert(0,0) self.Bext_Compensation_List = [[0, x, 0] for x in Bext_List_with_ZeroBext] #Bext List and Zero-Bext in the beginning self.listWidget_Bext.clear() # Clear old entries self.listWidget_Bext_Progress.clear() # Clear old entries for i, Bext in enumerate(self.Bext_Compensation_List): self.listWidget_Bext.addItem(str(Bext)) self.listWidget_Bext_Progress.addItem(QListWidgetItem("Pending")) # Write number of measurements in lineEdit self.line_Number_Cooldowns.setText(str(self.Number_of_Measurements)) # If line_time_per_cooldown is float, calculate the total time for the measurement try: Time_per_Cooldown = get_float(self.line_time_per_cooldown) except: Time_per_Cooldown = 0 # Decide for the unit of time. for > 120 seconds, use minutes, for > 120 minutes, use hours, otherwise use seconds Time_total = Time_per_Cooldown * self.Number_of_Measurements if Time_total > 120*60: # If total time is greater than 120 minutes, use hours Time_total = Time_total / 3600 # Convert to hours Time_unit = "h" elif Time_total > 120: # If total time is greater than 120 seconds, use minutes Time_total = Time_total / 60 # Convert to minutes Time_unit = "min" else: # If total time is greater than 0 seconds, use seconds Time_unit = "s" # Write total time in lineEdit self.line_total_time_needed.setText(f"{Time_total:.2f} {Time_unit}") def Perform_Measurement(self, progress_callback): # Calculate Measurement parameters self.Calculate_Parameters() Current_Mode = self.Current_Mode # Get Points Folder Path Points_Folder_Path = self.line_Points_Folder_Path.text() # if Points_Folder_Path is empty, return if Points_Folder_Path == "": self.line_Status.setText("Please specify a Points Folder Path.") return Points_Fileend_Gradient = "points_TF_vs_DT" Points_Fileend_Bext = "points_TF_vs_Bext" #Set GUI properties self.line_Status.setText("Measurement started.") self.enable_line_edits(self.Params_Lines, False) self.comboBox_Current_Mode.setEnabled(False) self.pushButton_Calculate_Parameters.setEnabled(False) # self.progressBar.setEnabled(True) # Update Cooldown number in GUI self.line_Number_Cooldowns.setText(f"0 / {self.Number_of_Measurements}") # PERFORM MEASUREMENT if Current_Mode == 0: #Perform TF vs. Gradient Measurement # If Points_Folder already has a file with the same name, append a number to the filename if os.path.exists(os.path.join(Points_Folder_Path, Points_Fileend_Gradient + ".txt")): i = 1 while os.path.exists(os.path.join(Points_Folder_Path, Points_Fileend_Gradient + f"_{i}.txt")): i += 1 Points_Fileend_Gradient += f"_{i}" Points_Path = Points_Folder_Path + "\\" + Points_Fileend_Gradient + ".txt" # Full path to the points file # Put the points_path and filename in the sync_main dictionary self.sync_main.update({'Points_Path': Points_Path}) # Get additional parameters Bext = self.Additional_Params[1] Speed = self.Additional_Params[2] # Perform Cooldowns according to the Gradient_List: for Cooldown_index, Gradient in enumerate(self.Gradient_List): if self.Status_Perform_Measurement == False: # If self.Status_Perform_Measurement is False, break the loop break # Update gradient in line_gradient self.line_Gradient.setText(str(Gradient)) # Perform Cooldown with Gradient, Bext and Speed self.Perform_Cooldown(Gradient, Bext, Speed) # Perform Cooldown with Gradient, Bext and Speed # Update Cooldown number in GUI self.line_Number_Cooldowns.setText(f"{Cooldown_index + 1} / {self.Number_of_Measurements}") if self.pause == True: #Pause measurement series if True #turn off coils self.sync_BK_9174B.update({'OutputOn':[False,False]}) self.sync_BK_9174B_2.update({'OutputOn':[False,False]}) #turn off relais self.sync_BK_9131B.update({'OutputOn':[False,False,False]}) #Set PID to T=0 self.sync_main.update({'T_set':[0, 0]}) self.sync_main.update({'T_reset':True}) while self.pause == True: time.sleep(0.1) if Current_Mode == 1: #Perform TF vs. Bext Measurement # If Points_Folder already has a file with the same name, append a number to the filename if os.path.exists(os.path.join(Points_Folder_Path, Points_Fileend_Bext + ".txt")): i = 1 while os.path.exists(os.path.join(Points_Folder_Path, Points_Fileend_Bext + f"_{i}.txt")): i += 1 Points_Fileend_Bext += f"_{i}" Points_Path = Points_Folder_Path + "\\" + Points_Fileend_Bext + ".txt" # Full path to the points file # Put the points_path and filename in the sync_main dictionary self.sync_main.update({'Points_Path': Points_Path}) # Get additional parameters Speed = self.Additional_Params[2] # Perform Cooldowns according to the self.Bext_Gradient_List and Bext_List Cooldown_index = 0 for Gradient_index, Gradient in enumerate(self.Bext_Gradient_List): for Bext_index, Bext in enumerate(self.Bext_List): if self.Status_Perform_Measurement == False: # If self.Status_Perform_Measurement is False, break the loop break # Update gradient in line_gradient self.line_Gradient.setText(str(Gradient)) # Update Bext in line_Bext self.line_Bext.setText(str(Bext)) # Perform Cooldown with Gradient, Bext and Speed self.Perform_Cooldown(Gradient, Bext, Speed) # Perform Cooldown with Gradient, Bext and Speed # Update Cooldown number in GUI self.line_Number_Cooldowns.setText(f"{Cooldown_index + 1} / {self.Number_of_Measurements}") # Update progress bar # progress_value = int((Cooldown_index + 1) / self.Number_of_Measurements * 100) # self.progressBar.setValue(progress_value) Cooldown_index = Cooldown_index + 1 # Update list Widget Gradient Progress entry with index Gradient_index according to progress_value progress_value_gradient = int((Bext_index + 1) / len(self.Bext_List) * 100) self.listWidget_Gradients_Progress.item(Gradient_index).setText(f"{progress_value_gradient} %") if progress_value_gradient == 100: # If progress is 100%, set the item to green self.listWidget_Gradients_Progress.item(Gradient_index).setBackground(QColor(0, 255, 0)) # Set background color to green else: # If progress is not 100%, set the item to grey self.listWidget_Gradients_Progress.item(Gradient_index).setBackground(QColor(200, 200, 200)) # Set background color to grey if self.pause == True: #Pause measurement series if True #turn off coils self.sync_BK_9174B.update({'OutputOn':[False,False]}) self.sync_BK_9174B_2.update({'OutputOn':[False,False]}) #turn off relais self.sync_BK_9131B.update({'OutputOn':[False,False,False]}) #Set PID to T=0 self.sync_main.update({'T_set':[0, 0]}) self.sync_main.update({'T_reset':True}) while self.pause == True: time.sleep(0.1) #Set GUI properties after measurement has been stopped self.line_Status.setText("Measurement stopped.") self.enable_line_edits(self.Params_Lines, True) self.comboBox_Current_Mode.setEnabled(True) self.pushButton_Calculate_Parameters.setEnabled(True) # self.progressBar.setEnabled(False) def Update_GUI(self): # Update PID_Monitor plots with the latest temperature data # self.Update_PID_Monitor() X=1 def Update_PID_Monitor(self, T): # Calculate Temp buffer, etc. self.Temperature_Monitor(T) # Convert buffered temperature data to numpy array for plotting Temp_Array = np.empty(shape=(0,3)) for i in range(len(self.Temp_Buffer)): timestamp = self.Temp_Buffer[i][0] if timestamp >= time.time() - get_float(self.line_Plot_Seconds): # Only consider temperatures within the last line_Plot_Seconds seconds time_diff = -(time.time() - timestamp) # Calculate time difference from current time T_top = np.round(self.Temp_Buffer[i][1][0],3) # Round T to third digit T_bottom = np.round(self.Temp_Buffer[i][1][1],3) # Round T to third digit Temp_Array = np.append(Temp_Array, [[time_diff, T_top, T_bottom]], axis=0) # Append time_diff, T_top, T_bottom # Convert Temp_Average_Buffer to numpy array for plotting Temp_Average_Array = np.empty(shape=(0,3)) for i in range(len(self.Temp_Average_Buffer)): timestamp = self.Temp_Average_Buffer[i][0] if timestamp >= time.time() - get_float(self.line_Plot_Seconds): # Only consider average temperatures within the last line_Plot_Seconds seconds time_diff = -(time.time() - timestamp) MeanTemp_top = np.round(self.Temp_Average_Buffer[i][1][0],3) # Round T to third digit MeanTemp_bottom = np.round(self.Temp_Average_Buffer[i][1][1],3) # Round T to third digit Temp_Average_Array = np.append(Temp_Average_Array, [[time_diff, MeanTemp_top, MeanTemp_bottom]], axis=0) # Append time_diff, MeanTemp_Top, MeanTemp_Bottom # Update the plots with the new temperature data if len(Temp_Array) > 0: # If there is at least one temperature in the array self.plot_top_T.setData(Temp_Array[:,0], Temp_Array[:,1]) # Top temperature self.plot_bottom_T.setData(Temp_Array[:,0], Temp_Array[:,2]) # Bottom temperature self.plot_top_T_average.setData(Temp_Average_Array[:,0], Temp_Average_Array[:,1]) # Mean temperature Top self.plot_bottom_T_average.setData(Temp_Average_Array[:,0], Temp_Average_Array[:,2]) # Mean temperature Bottom # If PID_Temperature_Checker is running, plot Tset_top_Threshold and self.Tset_bottom_Threshold from - self.line_Plot_Seconds to 0 seconds time_diff = time.time() - get_float(self.line_Plot_Seconds) time_diff = - time_diff time_diff = -get_float(self.line_Plot_Seconds) if self.PID_Temperature_Checker_On: self.plot_top_Tset_range_lower.show() self.plot_top_Tset_range_upper.show() self.plot_bottom_Tset_range_lower.show() self.plot_bottom_Tset_range_upper.show() self.plot_top_Tset_range_lower.setData([time_diff, 0], [self.Tset_top_Threshold[0], self.Tset_top_Threshold[0]]) # Tset_top lower threshold self.plot_top_Tset_range_upper.setData([time_diff, 0], [self.Tset_top_Threshold[1], self.Tset_top_Threshold[1]]) # Tset_top upper threshold self.plot_bottom_Tset_range_lower.setData([time_diff, 0], [self.Tset_bottom_Threshold[0], self.Tset_bottom_Threshold[0]]) # Tset_bottom lower threshold self.plot_bottom_Tset_range_upper.setData([time_diff, 0], [self.Tset_bottom_Threshold[1], self.Tset_bottom_Threshold[1]]) # Tset_bottom upper threshold else: # If PID_Temperature_Checker is not running, clear the Tset plots self.plot_top_Tset_range_lower.hide() self.plot_top_Tset_range_upper.hide() self.plot_bottom_Tset_range_lower.hide() self.plot_bottom_Tset_range_upper.hide() # If Cooldown_Finished_Checker is running, plot Cooldown_Finished_Temperature from - self.line_Plot_Seconds to 0 seconds if self.Cooldown_Finished_Checker_On: Cooldown_Finished_Temperature = get_float(self.line_Cooldown_Finished_Temperature) time_diff = -get_float(self.line_Plot_Seconds) self.plot_top_Tset_cooldown_finished.show() self.plot_bottom_Tset_cooldown_finished.show() self.plot_top_Tset_cooldown_finished.setData([time_diff, 0], [Cooldown_Finished_Temperature, Cooldown_Finished_Temperature]) self.plot_bottom_Tset_cooldown_finished.setData([time_diff, 0], [Cooldown_Finished_Temperature, Cooldown_Finished_Temperature]) else: # If Cooldown_Finished_Checker is not running, clear the Cooldown_Finished_Temperature plots self.plot_top_Tset_cooldown_finished.hide() self.plot_bottom_Tset_cooldown_finished.hide() def PID_Temperature_Checker(self, Tset_top, Tset_bottom): #Checks if temperatures reach the set values before cooldown. Function ends when temperatures reach the values print(f"T_set_top = {Tset_top}") print(f"T_set_bottom = {Tset_bottom}") self.PID_Temperature_Checker_On = True # Variable to check if Temperature_Checker is running self.Tset_top_Threshold = [Tset_top - get_float(self.line_PID_Temperature_Tolerance), Tset_top + get_float(self.line_PID_Temperature_Tolerance)] self.Tset_bottom_Threshold = [Tset_bottom - get_float(self.line_PID_Temperature_Tolerance), Tset_bottom + get_float(self.line_PID_Temperature_Tolerance)] PID_Temperature_Time = get_float(self.line_PID_Temperature_Time) # Create array with MeanTemp_Top / _Bottom values for entries of self.Temp_Average_Buffer that are not older than PID_Temperature_Time Temp_Array_for_MinMax = np.empty(shape=(0,2)) for i in range(len(self.Temp_Average_Buffer)): timestamp = self.Temp_Average_Buffer[i][0] if timestamp >= time.time() - PID_Temperature_Time: Temp_Array_for_MinMax = np.append(Temp_Array_for_MinMax, [self.Temp_Average_Buffer[i][1]], axis=0) # Calculate max and min of MeanTemp_Top / _Bottom values in Temp_Array_for_MinMax if len(Temp_Array_for_MinMax) > 0: # If there is at least one temperature in the array Temp_Top_Max = np.max(Temp_Array_for_MinMax[:,0]) Temp_Top_Min = np.min(Temp_Array_for_MinMax[:,0]) Temp_Bottom_Max = np.max(Temp_Array_for_MinMax[:,1]) Temp_Bottom_Min = np.min(Temp_Array_for_MinMax[:,1]) else: Temp_Top_Max = 200 Temp_Top_Min = 100 Temp_Bottom_Max = 200 Temp_Bottom_Min = 100 # Wait until for both Top / Bottom the max and min values are within the Tset_Thresholds or until the stop_wait_process is set to True while ((Temp_Top_Max > self.Tset_top_Threshold[1] or Temp_Top_Min < self.Tset_top_Threshold[0]) or (Temp_Bottom_Max > self.Tset_bottom_Threshold[1] or Temp_Bottom_Min < self.Tset_bottom_Threshold[0])) and not self.stop_wait_process: time.sleep(0.1) self.Tset_top_Threshold = [Tset_top - get_float(self.line_PID_Temperature_Tolerance), Tset_top + get_float(self.line_PID_Temperature_Tolerance)] self.Tset_bottom_Threshold = [Tset_bottom - get_float(self.line_PID_Temperature_Tolerance), Tset_bottom + get_float(self.line_PID_Temperature_Tolerance)] # Update Temp_Array_for_MinMax Temp_Array_for_MinMax = np.empty(shape=(0,2)) for i in range(len(self.Temp_Average_Buffer)): try: timestamp = self.Temp_Average_Buffer[i][0] except: timestamp = 0 print("Error in Temp_Average_Buffer index") if timestamp >= time.time() - PID_Temperature_Time: Temp_Array_for_MinMax = np.append(Temp_Array_for_MinMax, [self.Temp_Average_Buffer[i][1]], axis=0) # Calculate max and min of MeanTemp_Top / _Bottom values in Temp_Array_for_MinMax if len(Temp_Array_for_MinMax) > 0: Temp_Top_Max = np.max(Temp_Array_for_MinMax[:,0]) Temp_Top_Min = np.min(Temp_Array_for_MinMax[:,0]) Temp_Bottom_Max = np.max(Temp_Array_for_MinMax[:,1]) Temp_Bottom_Min = np.min(Temp_Array_for_MinMax[:,1]) else: Temp_Top_Max = 200 Temp_Top_Min = 100 Temp_Bottom_Max = 200 Temp_Bottom_Min = 100 # set stop_wait_process to False to allow the next measurement to start self.stop_wait_process = False self.PID_Temperature_Checker_On = False # Variable to check if Temperature_Checker is running def Cooldown_Finished_Checker(self): #Checks if temperatures fall below T_threshold, i.e. if cooldown finished self.Cooldown_Finished_Checker_On = True # Variable to check if Cooldown_Finished_Checker is running Cooldown_Finished_Temperature = get_float(self.line_Cooldown_Finished_Temperature) MeanTemp_Top = self.Temp_Average_Buffer[-1][1][0] if len(self.Temp_Average_Buffer) > 0 else 0 MeanTemp_Bottom = self.Temp_Average_Buffer[-1][1][1] if len(self.Temp_Average_Buffer) > 0 else 0 # Wait until both temperatures are below the Cooldown_Finished_Temperature or until the stop_wait_process is set to True while (MeanTemp_Top >= Cooldown_Finished_Temperature or MeanTemp_Bottom >= Cooldown_Finished_Temperature) and not self.stop_wait_process: time.sleep(0.1) MeanTemp_Top = self.Temp_Average_Buffer[-1][1][0] if len(self.Temp_Average_Buffer) > 0 else 0 MeanTemp_Bottom = self.Temp_Average_Buffer[-1][1][1] if len(self.Temp_Average_Buffer) > 0 else 0 Cooldown_Finished_Temperature = get_float(self.line_Cooldown_Finished_Temperature) # set stop_wait_process to False to allow the next measurement to start self.stop_wait_process = False self.Cooldown_Finished_Checker_On = False # Variable to check if Cooldown_Finished_Checker is running def Perform_Cooldown(self, Gradient, Bext, CooldownSpeed): Bext = [0,Bext,0] BaseTemperature = get_float(self.line_Base_Temperature) Sensor_Distance = get_float(self.line_Sensor_Distance) if Gradient >= 0: Tset_top = BaseTemperature + Gradient*Sensor_Distance Tset_bottom = BaseTemperature if Gradient < 0: Tset_top = BaseTemperature Tset_bottom = BaseTemperature - Gradient*Sensor_Distance #Set Temperatures, Cooldown Speed self.sync_main.update({'T_set':[Tset_top, Tset_bottom]}) self.sync_main.update({'T_reset':True}) self.sync_main.update({'Cooldown_Speed':CooldownSpeed}) self.line_Status.setText(f"Waiting for temperatures to reach Tset.") self.PID_Temperature_Checker(Tset_top, Tset_bottom) #Wait until right temperatures are reached #Set 0-Field and Field 1 for Bext-Compensation #Search for the right I and Flip for Bext in self.Bext_Compensations_Current_List I0 = [0] Flip0 = [0] I1 = [0] Flip1 = [0] if not len(self.Bext_Compensations_Current_List) == 0: #Bext_Compensation has been performed and List is filled with params for index, Params in enumerate(self.Bext_Compensations_Current_List): Params[0] = [round(float(x), 2) for x in Params[0]] Bext = [round(float(x), 2) for x in Bext] Bext0 = [round(float(x), 2) for x in [0,0,0]] if Params[0] == Bext: #If the right Bext entry has been found in self.Bext_Compensations_Current_List, save current and flip I1 = Params[1] Flip1 = Params[2] if Params[0] == Bext0: #If the 0-field [0,0,0] entry has been found in self.Bext_Compensations_Current_List, save current and flip I0 = Params[1] Flip0 = Params[2] if I0 == [0] or Flip0 == [0]: self.line_Status.setText(f"No 0-field params found.") print("No 0-field params found.") return if I1 == [0] or Flip1 == [0]: self.line_Status.setText(f"No field 1 params found.") print("No field 1 params found.") return self.sync_main.update({'0-Field':[I0, Flip0]}) self.sync_main.update({'1-Field':[I1, Flip1]}) time.sleep(0.3) self.sync_main.update({'Set_1field':True}) time.sleep(1) else: print("No Bext compensation currents available. Did you perform Bext compensation? Starting measurement anyway (just for debugging).") self.sync_main.update({'Start_ramp':True}) # Start Cooldown self.line_Status.setText(f"Waiting for cooldown to finish.") self.Cooldown_Finished_Checker() # Wait until temperatures are below specified temperature self.sync_main.update({'Stop_ramp':True}) self.line_Status.setText(f"Cooldown finished. Performing measurement.") time.sleep(10) # Wait X seconds to ensure that the measurement is performed after the cooldown is finished self.line_Status.setText("Cooldown finished. Measurement performed.") def Temperature_Monitor(self, T): # Check T_top and T_bottom and calc. their mean, etc. currenttime = time.time() #save newest temperature data + timestamp in a queue self.Temp_Buffer.append([currenttime, T]) #check for Saved_seconds limit in self.Temp_Buffer. In case of older measurements -> Delete them needfordelete = True i = 0 while needfordelete and i<=len(self.Temp_Buffer): #Just if needfordelete = True: Check and delete old entries timestamp = self.Temp_Buffer[i][0] if timestamp < currenttime - get_float(self.line_Buffer_Length): #if timestamp is older than current time minus saved_seconds_value self.Temp_Buffer.popleft() #Delete oldest entry else: needfordelete = False #If all entries are within the time interval: No need for continuing with deleting-for-loop i=i+1 #create queue in which only temperature data is stored which is not older than self.line_PID_Temperature_Average_Time seconds Temp_Array_for_Average = np.empty(shape=(0,2)) for i in range(len(self.Temp_Buffer)): timestamp = self.Temp_Buffer[i][0] if timestamp >= currenttime - get_float(self.line_PID_Temperature_Average_Time): Temp_Array_for_Average = np.append(Temp_Array_for_Average, [self.Temp_Buffer[i][1]], axis=0) #Calculate mean temperature if len(Temp_Array_for_Average) > 0: #If there is at least one temperature in the array T_mean = np.mean(Temp_Array_for_Average, axis=0) self.Temp_Average_Buffer.append([currenttime, T_mean]) #check for saved_seconds limit in self.Temp_Average_Buffer needfordelete = True i = 0 while needfordelete and i<=len(self.Temp_Average_Buffer): #Just if needfordelete = True: Check and delete old entries timestamp = self.Temp_Average_Buffer[i][0] if timestamp < currenttime - get_float(self.line_Buffer_Length): #if timestamp is older than current time minus saved_seconds_value self.Temp_Average_Buffer.popleft() #Delete oldest entry else: needfordelete = False #If all entries are within the time interval: No need for continuing with deleting-for-loop i=i+1 def Perform_all_Bext_Compensations(self, progress_callback): #Perform all Bext compensations before performing measurement series Bext_List = self.Bext_Compensation_List if len(Bext_List) == 0: self.line_Status.setText("Please calculate parameters first.") self.Perform_all_Bext_Compensations_Boolean = False return # self.sync_main.update({'Measurement_Running':True}) #Change state so that parameters can be changed in Main # Check if temperature is above self.Bext_Compensations_Current_List = [] #List with [[Bext, Bext, Bext], [I, I, I, I], [Flip, Flip, Flip]] for index, Bext in enumerate(Bext_List): # Iterate over all Bext values to be compensated (and saved) Compensation_Parameter = 0 # Status_Compensation = 0 #In the beginning status = 0, i.e. no compensation has been performed Status_Compensation = self.syncdict.get('Status_Compensation') while Status_Compensation == 1: # Wait until old compensation finished time.sleep(0.1) Status_Compensation = self.syncdict.get('Status_Compensation') Status_Compensation = 0 #After waiting for old compensation to finish, set status to 0 (i.e. "no compensation has been performed") while not Status_Compensation == 2: #Perform the following code until compensation was successfull if self.Perform_all_Bext_Compensations_Boolean == False: # End function print("Compensation aborted.") self.pushButton_Compensation_Take_It.setEnabled(False) # self.sync_main.update({'Measurement_Running':False}) #Change state return # Update List Widget for compensation status if Status_Compensation == 0: self.listWidget_Bext_Progress.item(index).setText("Compensating") self.listWidget_Bext_Progress.item(index).setBackground(QColor(200, 200, 200)) if self.Take_It_Current == True: self.Take_It_Current = False self.pushButton_Compensation_Take_It.setEnabled(False) Compensation_Parameter = Compensation_Parameter_from_last_one #Guarantees that the compensation parameters from the last failed compensation are used. break if Status_Compensation == 3: #Compensation failed self.listWidget_Bext_Progress.item(index).setText("Failed") self.listWidget_Bext_Progress.item(index).setBackground(QColor(255, 0, 0)) self.pushButton_Compensation_Take_It.setEnabled(True) Compensation_Parameter_from_last_one = Compensation_Parameter Compensation_Parameter = self.Perform_single_Bext_Compensation(Bext) #Perform Bext Compensation and save [Currents, Coil-Flips, Compensation_Status] I = Compensation_Parameter[0] Flip = Compensation_Parameter[1] Status_Compensation = Compensation_Parameter[2] # Compensation succeeded. Next: Save Bext, I and Flip in self.Bext_Compensations_Current_List self.Bext_Compensations_Current_List.append([Bext, I, Flip]) self.pushButton_Compensation_Take_It.setEnabled(False) if Status_Compensation == 2: self.listWidget_Bext_Progress.item(index).setText("Succeeded") self.listWidget_Bext_Progress.item(index).setBackground(QColor(0, 255, 0)) else: self.listWidget_Bext_Progress.item(index).setText("Failed, but ok") self.listWidget_Bext_Progress.item(index).setBackground(QColor(180, 255, 180)) # self.sync_main.update({'Measurement_Running':False}) #Change state print(self.Bext_Compensations_Current_List) self.save_Bext_Compensation_parameters() self.Perform_all_Bext_Compensations_Boolean = False def Perform_single_Bext_Compensation(self, Bset): #Perform single Bext compensation and return Currents, Coil-Flips, Compensation_Status Status_Compensation = 0 self.syncdict.update({"B_set":Bset}) time.sleep(0.1) self.syncdict.update({"Start_Compensation":True}) while not Status_Compensation == 2: #Execute the following until compensation is succeeded: if self.Perform_all_Bext_Compensations_Boolean == False: # Read currents and flip status from power supplies Current_Flip = self.Read_Coil_Current_and_Flip() I = Current_Flip[0] Flip = Current_Flip[1] return [I, Flip, 3] if Status_Compensation == 3: #Compensation is failed print("Compensation failed!") # Read currents and flip status from power supplies Current_Flip = self.Read_Coil_Current_and_Flip() I = Current_Flip[0] Flip = Current_Flip[1] return [I, Flip, 3] # Status = 3 means compensation failed if self.Take_It_Current == True: print("Compensation failed, but ok.") # Read currents and flip status from power supplies Current_Flip = self.Read_Coil_Current_and_Flip() I = Current_Flip[0] Flip = Current_Flip[1] return [I, Flip, 4] # Status = 4 means "Failed, but ok" time.sleep(1) Status_Compensation = self.syncdict.get('Status_Compensation') print("Compensation succeeded!") # Read currents and flip status from power supplies Current_Flip = self.Read_Coil_Current_and_Flip() I = Current_Flip[0] Flip = Current_Flip[1] return [I, Flip, Status_Compensation] def Read_Coil_Current_and_Flip(self): # Read currents and flip status from power supplies I = [0,0,0,0] Flip = [False, False, False] I[0] = self.sync_BK_9174B.get('setI')[0] #x-coil I[1] = self.sync_BK_9174B.get('setI')[1] #y-coil I[2] = self.sync_BK_9174B_2.get('setI')[1] #y2-coil I[3] = self.sync_BK_9174B_2.get('setI')[0] #z-coil for index, state in enumerate(self.sync_BK_9131B.get('OutputOn')): #Check the power supplies output for flip status Flip[index] = state return [I, Flip] def Run_Perform_all_Bext_Compensations(self): #Change boolean and start compensation in different thread # Check if a compensation is already running: if self.Perform_all_Bext_Compensations_Boolean == True: self.line_Status.setText("Compensation already running.") return self.Perform_all_Bext_Compensations_Boolean = True #Start Thread self.worker_Compensation = Worker(self.Perform_all_Bext_Compensations) self.threadpool.start(self.worker_Compensation) def Abort_Perform_all_Bext_Compensations(self): #Change boolean to False -> Abort compensation if self.Perform_all_Bext_Compensations_Boolean == False: self.line_Status.setText("Compensation is not running.") self.Perform_all_Bext_Compensations_Boolean = False def Set_Take_It_Current(self): #Set Take_It_Current = True so that failed compensation currents can be saved self.Take_It_Current = True def set_Current_Mode(self, value): self.Current_Mode = value #0= TF vs. DT, 1= TF vs. Bext, 2= TF vs. Speed #Change line_edit enable-status according to measurement mode Lines = [self.line_Gradient, self.line_Bext, self.line_Speed] for i, line in enumerate(Lines): if i == value: line.setEnabled(False) else: line.setEnabled(True) if value == 1: # Also disable line_Gradient since the Gradient-List is used Lines[0].setEnabled(False) def set_Additional_Params(self): Lines = [self.line_Gradient, self.line_Bext, self.line_Speed] for i, line in enumerate(Lines): self.Additional_Params[i] = get_float(line) #Write value of line in Additional_Params List def Start_Measurement(self): #executed after pressing "Start Measurement" Button # Check if a measurement is already running: if self.Status_Perform_Measurement == True: self.line_Status.setText("Measurement already running.") return self.Status_Perform_Measurement = True self.sync_main.update({'Measurement_Running':True}) #Start Thread self.worker_Measurement = Worker(self.Perform_Measurement) self.threadpool.start(self.worker_Measurement) def Stop_Measurement(self): #executed after pressing "Stop Measurement" Button self.Status_Perform_Measurement = False self.sync_main.update({'Measurement_Running':False}) def enable_line_edits(self, Lines, Status): # Enable / Disable all line_edits in Lines-List according to Status-Boolean for i, line in enumerate(Lines): line.setEnabled(Status) def set_Bext_Gradient_List(self): # executed after pressing "Enter" in lineEdit_Gradient_List # Create list with Gradients from self.lineEdit_Gradient_List string, separated by ;. Ignore " " try: self.Bext_Gradient_List = [self.lineEdit_Gradient_List.text().replace(" ","").split(";")] except: self.line_Status.setText("Error in Bext Gradient List.") self.Bext_Gradient_List = [0] self.Bext_Gradient_List = [np.round(float(self.Bext_Gradient_List[0][i]),3) for i in range(len(self.Bext_Gradient_List[0]))] #Convert string to float and round to 3 digits # Fill Gradients into listWidget_Gradients self.listWidget_Gradients.clear() # Clear old entries self.listWidget_Gradients_Progress.clear() # Clear old entries for i in range(len(self.Bext_Gradient_List)): item = QListWidgetItem(str(self.Bext_Gradient_List[i])+ " K/cm") self.listWidget_Gradients.addItem(item) self.listWidget_Gradients_Progress.addItem(QListWidgetItem("0 %")) def set_stop_wait_process(self): self.stop_wait_process = True # Set stop_wait_process to True to stop the waiting process for reaching Tset or Cooldown_Finished_Temperature def set_Pause(self): if self.pause == True: self.pause = False self.pushButton_Pause_Measurement.setStyleSheet("background-color: rgb(200, 200, 200)") self.pushButton_Pause_Measurement.setText("Click to pause") else: self.pause = True self.pushButton_Pause_Measurement.setStyleSheet("background-color: rgb(255, 0, 0)") self.pushButton_Pause_Measurement.setText("PAUSED") def save_Bext_Compensation_parameters(self): path = self.line_Bext_Compensation_Path.text() if len(self.Bext_Compensations_Current_List) > 0: with open(path, 'w') as f: json.dump(self.Bext_Compensations_Current_List, f) else: self.line_Status.setText("No compensation data to be saved.") def load_Bext_Compensation_parameters(self): path = self.line_Bext_Compensation_Path.text() with open(path, 'r') as f: self.Bext_Compensations_Current_List = json.load(f) # Clear Bext list widget self.listWidget_Bext.clear() # Clear old entries self.listWidget_Bext_Progress.clear() # Clear old entries #Update Bext list widget for index, params in enumerate(self.Bext_Compensations_Current_List): Bext = params[0] I = params[1] self.listWidget_Bext.addItem(str(Bext)) if not I == [0,0,0,0]: self.listWidget_Bext_Progress.addItem("Succeeded") self.listWidget_Bext_Progress.item(index).setBackground(QColor(0, 255, 0)) else: self.listWidget_Bext_Progress.addItem("[0,0,0]A (?)") self.listWidget_Bext_Progress.item(index).setBackground(QColor(255, 180, 180)) 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\\Automation_Measurement_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 #self.lines_config_float = [self.line_Min_Gradient, self.line_Max_Gradient, self.line_Gradient_Stepwidth, self.line_Min_Bext, self.line_Max_Bext, self.line_Stepwidth_Bext, self.line_Base_Temperature, self.line_Cooldown_Finished_Temperature, self.line_Sensor_Distance, self.line_Gradient, self.line_Bext, self.line_Speed, self.line_time_per_cooldown, self.line_PID_Temperature_Average_Time, self.line_PID_Temperature_Tolerance, self.line_PID_Temperature_Time, self.line_Buffer_Length, self.line_Plot_Seconds]#is used for config file 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\\Automation_Measurement_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','.0f', '.0f','.0f','.2f', '.2f' , '.2f' , '.2f', '.0f', '.3f', '.0f','.2f', '.2f' , '.1f' , '.0f', '.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 self.sync_main.update({'Measurement_Running':False}) #Change state self.Perform_all_Bext_Compensations_Boolean = False self.Status_Perform_Measurement = False time.sleep(1) event.accept() app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()