From 7c3c8aa420aea155e8a18c714652d17a78d22611 Mon Sep 17 00:00:00 2001 From: Leon Teichroeb Date: Sun, 24 Oct 2021 15:12:57 +0200 Subject: [PATCH] Improved and extended calibration export functionality. --- src/user_interface.py | 105 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 19 deletions(-) diff --git a/src/user_interface.py b/src/user_interface.py index 90fcfc9..2ccbb1f 100644 --- a/src/user_interface.py +++ b/src/user_interface.py @@ -572,12 +572,14 @@ class CalibrateAmbientField(Frame): self.ambient_field_residual_vars = [StringVar(), StringVar(), StringVar()] self.ambient_field_raw_data = None # Used for export to csv self.ambient_field_result = None # Used for saving to config file + self.ambient_field_clipboard = "" # Used for copying to clipboard # Contains results for coil constant calibration self.coil_constant_vars = [StringVar(), StringVar(), StringVar()] self.coil_constant_dev_vars = [StringVar(), StringVar(), StringVar()] self.coil_angle_vars = [StringVar(), StringVar(), StringVar()] self.coil_constant_raw_data = None # Used for export to csv self.coil_constant_results = None # Used for saving to config file + self.coil_constant_clipboard = "" # Used for copying to clipboard row_counter = 0 @@ -615,24 +617,14 @@ class CalibrateAmbientField(Frame): # 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=self.save_to_csv_ambient_field, - 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=1, column=0, padx=10, pady=10) + self.start_ambient_calibration_button.grid(row=0, 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=1, column=1, padx=10, pady=10) + self.start_k_calibration_button.grid(row=0, column=1, padx=10, pady=10) row_counter += 1 # Calibration progress bar @@ -646,7 +638,7 @@ class CalibrateAmbientField(Frame): calibration_procedure_progress.grid(row=0, column=1, padx=10, pady=10, sticky="we") row_counter += 1 - # Ambient field calibration results + # --- Ambient field calibration results --- row_counter = 0 ambient_field_results_frame = LabelFrame(self.right_column, text="Ambient Field Results") ambient_field_results_frame.grid(row=row_counter, column=1, padx=(100, 0), pady=5, sticky="nw") @@ -686,14 +678,27 @@ class CalibrateAmbientField(Frame): axis_data.grid(row=3, column=i+1, padx=5, pady=5, sticky="nw") ambient_field_residual_unit = Label(ambient_field_results_frame, text="\u03BCT") ambient_field_residual_unit.grid(row=3, column=4, padx=5, pady=5, sticky="nw") - # Save calibration to config - self.ambient_field_save_results_button = Button(ambient_field_results_frame, text="Save to config and apply", + # Save calibration buttons + save_ambient_field_results_frame = Frame(ambient_field_results_frame) + save_ambient_field_results_frame.grid(row=4, column=0, columnspan=5) + # Save and apply + self.ambient_field_save_results_button = Button(save_ambient_field_results_frame, text="Save and apply", command=self.save_and_apply_ambient_calibration, state="disabled") - self.ambient_field_save_results_button.grid(row=4, column=0, columnspan=5, padx=5, pady=5) + self.ambient_field_save_results_button.grid(row=0, column=0, padx=5, pady=5) + self.save_ambient_calibration_button = Button(save_ambient_field_results_frame, text="Export to CSV", + command=self.save_to_csv_ambient_field, + state="disabled", + pady=5, padx=5) + self.save_ambient_calibration_button.grid(row=0, column=1, padx=5, pady=5) + self.copy_ambient_calibration_button = Button(save_ambient_field_results_frame, text="Copy to clipboard", + command=self.copy_to_clipboard_ambient_field, + state="disabled", + pady=5, padx=5) + self.copy_ambient_calibration_button.grid(row=0, column=2, padx=5, pady=5) row_counter += 1 - # Coil constant results + # --- Coil constant results --- coil_constants_results_frame = LabelFrame(self.right_column, text="Coil Constants") coil_constants_results_frame.grid(row=row_counter, column=1, padx=(100, 0), pady=5, sticky="nw") for i, label in enumerate(['X', 'Y', 'Z']): @@ -736,10 +741,26 @@ class CalibrateAmbientField(Frame): axis_data.grid(row=4, column=i + 1, padx=5, pady=5, sticky="nw") coil_angles_unit = Label(coil_constants_results_frame, text="°") coil_angles_unit.grid(row=4, column=4, padx=5, pady=5, sticky="nw") - self.coil_constant_save_results_button = Button(coil_constants_results_frame, text="Save to config and apply", + # Save calibration buttons + save_coil_constant_results_frame = Frame(coil_constants_results_frame) + save_coil_constant_results_frame.grid(row=5, column=0, columnspan=5) + # Save and apply + self.coil_constant_save_results_button = Button(save_coil_constant_results_frame, text="Save and apply", command=self.save_and_apply_coil_constants, state="disabled") - self.coil_constant_save_results_button.grid(row=5, column=0, columnspan=5, padx=5, pady=5) + self.coil_constant_save_results_button.grid(row=0, column=0, padx=5, pady=5) + self.save_k_calibration_button = Button(save_coil_constant_results_frame, text="Export to CSV", + command=self.save_to_csv_coil_constants, + state="disabled", + pady=5, padx=5) + self.save_k_calibration_button.grid(row=0, column=1, padx=5, pady=5) + self.copy_coil_constant_button = Button(save_coil_constant_results_frame, text="Copy to clipboard", + command=self.copy_to_clipboard_coil_constants, + state="disabled", + pady=5, padx=5) + self.copy_coil_constant_button.grid(row=0, column=2, padx=5, pady=5) + row_counter += 1 + # This starts an endless polling loop self.update_view() @@ -797,17 +818,35 @@ class CalibrateAmbientField(Frame): self.start_k_calibration_button.configure(state=DISABLED) def update_ambient_calibration_results(self, results): + # Update gui for i in range(3): self.ambient_field_result_vars[i].set("{:.3f}".format(results['ambient'][i])) 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)) + # Populate clipboard string + self.ambient_field_clipboard = "\tX\tY\tZ\n" + self.ambient_field_clipboard += "Ambient Field [A]" + for i in range(3): + self.ambient_field_clipboard += "\t{:.3f}".format(results['ambient'][i]) + self.ambient_field_clipboard += "\nAmbient Field [uT]" + for i in range(3): + self.ambient_field_clipboard += "\t{:.3f}".format(results['ambient_ut'][i]) + self.ambient_field_clipboard += "\nResidual Field [uT]" + for i in range(3): + self.ambient_field_clipboard += "\t{:.3f}".format(results['residual'][i] * 1e6) + + # Cache other data that the user may want to save self.ambient_field_raw_data = results['raw_data'] self.ambient_field_result = results['ambient_ut'] * 1e-6 + + # Update save-button states self.save_ambient_calibration_button.configure(state='normal') self.ambient_field_save_results_button.configure(state='normal') + self.copy_ambient_calibration_button.configure(state='normal') def update_coil_constant_results(self, results): + # Update UI for i in range(3): # Remember to convert from T/A to microT/A self.coil_constant_vars[i].set("{:.3f}".format(results['k'][i] * 1e6)) @@ -817,10 +856,28 @@ 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'])) + # Populate clipboard string + self.coil_constant_clipboard = "\tX\tY\tZ\n" + self.coil_constant_clipboard += "K [uT/A]" + for i in range(3): + self.coil_constant_clipboard += "\t{:.3f}".format(results['k'][i] * 1e6) + self.coil_constant_clipboard += "\nK Std. Dev. [uT/A]" + for i in range(3): + self.coil_constant_clipboard += "\t{:.3f}".format(results['k_dev'][i] * 1e6) + self.coil_constant_clipboard += "\n\tX-Y\tY-Z\tX-Z" + self.coil_constant_clipboard += "\nAngles [deg]" + self.coil_constant_clipboard += "\t{:.3f}".format(results['angle']['xy']) + self.coil_constant_clipboard += "\t{:.3f}".format(results['angle']['yz']) + self.coil_constant_clipboard += "\t{:.3f}".format(results['angle']['xz']) + + # Cache other data that the user may want to save self.coil_constant_raw_data = results['raw_data'] self.coil_constant_results = results['k'] + + # Update save-button states self.save_k_calibration_button.configure(state='normal') self.coil_constant_save_results_button.configure(state='normal') + self.copy_coil_constant_button.configure(state='normal') def calibration_procedure_ambient(self): try: @@ -876,6 +933,16 @@ class CalibrateAmbientField(Frame): ui_print("Reinitializing devices...") g.CAGE_DEVICE.reconnect_hardware_async() # setup everything with the defaults + def copy_to_clipboard_ambient_field(self): + self.clipboard_clear() + self.clipboard_append(self.ambient_field_clipboard) + self.update() + + def copy_to_clipboard_coil_constants(self): + self.clipboard_clear() + self.clipboard_append(self.coil_constant_clipboard) + self.update() + class CalibrateMagnetometer(Frame): def __init__(self, parent, controller):