diff --git a/src/calibration.py b/src/calibration.py index 590190e..0a37f83 100644 --- a/src/calibration.py +++ b/src/calibration.py @@ -150,7 +150,7 @@ class CoilConstantCalibration(Thread): # Result variables coil_constants = np.zeros(3) k_deviations = np.zeros(3) - raw_experiment_data = {'I_x': [], 'I_y': [], 'I_z': [], 'delta_mag_B': [], 'sign': [], 'K': []} + raw_experiment_data = [] # The coil constant must be determined for every axis for i in range(3): @@ -177,12 +177,13 @@ class CoilConstantCalibration(Thread): self.put_message('progress', ((c_idx / (self.MEASUREMENT_POINTS * 2)) + i) / 3) # Save into raw data vector - raw_experiment_data['I_x'].append(c_vec[0]) - raw_experiment_data['I_y'].append(c_vec[1]) - raw_experiment_data['I_z'].append(c_vec[2]) - raw_experiment_data['delta_mag_B'].append(field_diff_mag) - raw_experiment_data['sign'].append(sign) - raw_experiment_data['K'].append(k) + raw_experiment_data.append({'axis': i, + 'I_x': c_vec[0], + 'I_y': c_vec[1], + 'I_z': c_vec[2], + 'delta_mag_B': field_diff_mag, + 'sign': sign, + 'K': k}) # Average samples for axis coil_constants[i] = np.average(k_samples) diff --git a/src/user_interface.py b/src/user_interface.py index 95e4d31..0278aa2 100644 --- a/src/user_interface.py +++ b/src/user_interface.py @@ -22,7 +22,7 @@ import csv # import other project files: import src.globals as g -import src.csv_threading as csv +import src.csv_threading as csv_threading import src.config_handling as config import src.csv_logging as log from src.calibration import AmbientFieldCalibration, CoilConstantCalibration, MagnetometerCalibration @@ -454,14 +454,14 @@ class ExecuteCSVMode(Frame): if exists(filename): # does the file exist? ui_print("File selected:", filename) try: # try to read data to an array - self.sequence_array = csv.read_csv_to_array(filename) # read array from csv + self.sequence_array = csv_threading.read_csv_to_array(filename) # read array from csv except BaseException as e: # something went wrong, probably wrong format in csv # display error messages: ui_print("Error while opening file:", e) messagebox.showerror("Error!", "Error while opening file: \n%s" % e) try: # try to check the values and display the plot - csv.check_array_ok(self.sequence_array) # check for values exceeding limits + csv_threading.check_array_ok(self.sequence_array) # check for values exceeding limits self.display_plot() # plot data and display except BaseException as e: # something went wrong, probably wrong format in csv # display error messages: @@ -488,7 +488,7 @@ class ExecuteCSVMode(Frame): g.threadLock = threading.Lock() # create thread locking object, used to ensure all devices switch at once later # create thread object: - self.csv_thread = csv.ExecCSVThread(self.sequence_array, self, self.controller, logging_enabled) + self.csv_thread = csv_threading.ExecCSVThread(self.sequence_array, self, self.controller, logging_enabled) self.csv_thread.start() # start thread def stop_run(self): # called on stop button press, interrupts sequence execution @@ -522,7 +522,7 @@ class ExecuteCSVMode(Frame): width = min(self.parent.winfo_width() - 100, 1100) # set width to available space but max. 1100 - figure = csv.plot_field_sequence(self.sequence_array, width, height) # create figure to be displayed + figure = csv_threading.plot_field_sequence(self.sequence_array, width, height) # create figure to be displayed plotCanvas = FigureCanvasTkAgg(figure, self.plotFrame) # create canvas to draw figure on plotCanvas.draw() # equivalent to matplotlib.show() plotCanvas.get_tk_widget().grid(row=0, column=0, sticky="nesw") # place canvas in the UI @@ -597,17 +597,27 @@ class CalibrateAmbientField(Frame): field_data_axis_units.grid(row=i, column=3, padx=5, pady=3) row_counter += 1 - # Calibration start buttons + # Calibration start and save to csv buttons start_button_frame = Frame(self.left_column) start_button_frame.grid(row=row_counter, column=0, sticky="sw") + self.save_ambient_calibration_button = Button(start_button_frame, text="Save results to CSV", + command=None, + state="disabled", + pady=5, padx=5, font=SMALL_BUTTON_FONT) + self.save_ambient_calibration_button.grid(row=0, column=0) + self.save_k_calibration_button = Button(start_button_frame, text="Save results to CSV", + command=self.save_to_csv_coil_constants, + state="disabled", + pady=5, padx=5, font=SMALL_BUTTON_FONT) + self.save_k_calibration_button.grid(row=0, column=1) self.start_ambient_calibration_button = Button(start_button_frame, text="Calibrate Ambient Field", command=self.calibration_procedure_ambient, pady=5, padx=5, font=SMALL_BUTTON_FONT) - self.start_ambient_calibration_button.grid(row=0, column=0, padx=10, pady=(30, 10)) + self.start_ambient_calibration_button.grid(row=1, column=0, padx=10, pady=10) self.start_k_calibration_button = Button(start_button_frame, text="Calibrate Coil Constants", command=self.calibration_procedure_coil_constants, pady=5, padx=5, font=SMALL_BUTTON_FONT) - self.start_k_calibration_button.grid(row=0, column=1, padx=10, pady=(30, 10)) + self.start_k_calibration_button.grid(row=1, column=1, padx=10, pady=10) row_counter += 1 # Calibration progress bar @@ -768,6 +778,8 @@ class CalibrateAmbientField(Frame): self.ambient_field_ut_result_vars[i].set("{:.3f}".format(results['ambient_ut'][i])) self.ambient_field_residual_vars[i].set("{:.3f}".format(results['residual'][i] * 1e6)) + self.save_ambient_calibration_button.configure(state='normal') + def update_coil_constant_results(self, results): for i in range(3): # Remember to convert from T/A to microT/A @@ -778,6 +790,9 @@ class CalibrateAmbientField(Frame): self.coil_angle_vars[1].set("{:.2f}".format(results['angle']['yz'])) self.coil_angle_vars[2].set("{:.2f}".format(results['angle']['xz'])) + self.coil_constant_raw_data = results['raw_data'] + self.save_k_calibration_button.configure(state='normal') + def calibration_procedure_ambient(self): try: self.calibration_ambient_thread = AmbientFieldCalibration(self.view_mpi_queue) @@ -797,13 +812,18 @@ class CalibrateAmbientField(Frame): messagebox.showwarning("Calibration failed", "Failed to start calibration:\n{}".format(e)) def save_to_csv_coil_constants(self): - with open('coil_constant_calibration.csv', mode='w') as csv_file: - fieldnames = self.coil_constant_raw_data.keys() - csv_writer = csv.writer(csv_file, fieldnames=fieldnames, delimiter=',', quotechar='"', quoting=csv.QUOTE_NONNUMERIC) + if self.coil_constant_raw_data is None: + ui_print("Error: Failed to export non-existent calibration data.") + return + + with open('coil_constant_calibration.csv', mode='w', newline='') as csv_file: + fieldnames = self.coil_constant_raw_data[0].keys() + csv_writer = csv.DictWriter(csv_file, fieldnames=fieldnames, delimiter=',', quotechar='"', quoting=csv.QUOTE_NONNUMERIC) csv_writer.writeheader() - for row in self.coil_constant_raw_data. - csv_writer.writerow() + for row in self.coil_constant_raw_data: + csv_writer.writerow(row) + class CalibrateMagnetometer(Frame): def __init__(self, parent, controller):