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

1111 lines
58 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 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()