From 88f85607beb37534662bbb59e13efa210091790a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20Teichr=C3=B6b?= Date: Tue, 16 Aug 2022 15:27:06 +0200 Subject: [PATCH] Added transformation matrix input to gui --- 2022-08_2Do_Helmholtz_tmp.txt | 12 +++ src/user_interface.py | 142 +++++++++++++++++++++++++++++++--- 2 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 2022-08_2Do_Helmholtz_tmp.txt diff --git a/2022-08_2Do_Helmholtz_tmp.txt b/2022-08_2Do_Helmholtz_tmp.txt new file mode 100644 index 0000000..d970a33 --- /dev/null +++ b/2022-08_2Do_Helmholtz_tmp.txt @@ -0,0 +1,12 @@ +Magnetometer Calibration +-Magnetometer Results Code Kopieren (entries read only) +- "Manual Input Mode" -> Input abschauen +- User Interfaces -> Right colum (zwei spalten, in rechte spalte muss matrixeinfabe eingefügt werden +- User Interfaces 1045-ende +--row_counter wird benutzt um dynamisch Zeile um eins erhöht werden -> kopieren und unten drunter angeben +- von anderen entries datentypen abschauen (TK Datentypen) +- an Kalibrationsklasse übergeben +- export_csv ggf erweitern um Matrix abzusoeichern +-Utility.py -> csv_writer.writerheader +- Magnetometer auf Helmholtzteststand +- calibration. py -> g.MAGNETOMETER.field draufrechnen \ No newline at end of file diff --git a/src/user_interface.py b/src/user_interface.py index 4bc7045..2bcc2c5 100644 --- a/src/user_interface.py +++ b/src/user_interface.py @@ -332,7 +332,8 @@ class ManualMode(Frame): pass else: # this really should never happen ui_print("Unexpected value encountered: compensate =", compensate) - messagebox.showerror("Unexpected Value!", ("Unexpected value encountered: compensate =", compensate)) + messagebox.showerror("Unexpected Value!", + ("Unexpected value encountered: compensate =", compensate)) except helmholtz_cage_device.DeviceBusy: ui_print("Error: Could not acquire control. Is the HW already in use?") @@ -644,7 +645,7 @@ class CalibrateAmbientField(Frame): ambient_field_results_frame.grid(row=row_counter, column=1, padx=(100, 0), pady=5, sticky="nw") for i, label in enumerate(['X', 'Y', 'Z']): axis_label = Label(ambient_field_results_frame, text=label) - axis_label.grid(row=0, column=i+1, padx=5, pady=(5, 0), sticky="nw") + axis_label.grid(row=0, column=i + 1, padx=5, pady=(5, 0), sticky="nw") # Ambient field value (A) ambient_field_results_label = Label(ambient_field_results_frame, text="Ambient Field:") ambient_field_results_label.grid(row=1, column=0, padx=5, pady=5, sticky="nw") @@ -653,7 +654,7 @@ class CalibrateAmbientField(Frame): textvariable=self.ambient_field_result_vars[i], width=15, state='readonly') - axis_data.grid(row=1, column=i+1, padx=5, pady=5, sticky="nw") + axis_data.grid(row=1, column=i + 1, padx=5, pady=5, sticky="nw") ambient_field_results_unit = Label(ambient_field_results_frame, text="A") ambient_field_results_unit.grid(row=1, column=4, padx=5, pady=5, sticky="nw") # Ambient field value (microtesla) @@ -675,7 +676,7 @@ class CalibrateAmbientField(Frame): textvariable=self.ambient_field_residual_vars[i], width=15, state='readonly') - axis_data.grid(row=3, column=i+1, padx=5, pady=5, sticky="nw") + 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 buttons @@ -791,7 +792,7 @@ class CalibrateAmbientField(Frame): messagebox.showerror("Calibration error", "Error occured during calibration:\n{}".format(arg)) self.reactivate_buttons() elif cmd == 'progress': - self.calibration_procedure_progress_var.set(min(int(arg*100), 100)) + self.calibration_procedure_progress_var.set(min(int(arg * 100), 100)) elif cmd == 'ambient_data': self.update_ambient_calibration_results(arg) elif cmd == 'coil_constant_results': @@ -975,6 +976,9 @@ class CalibrateMagnetometer(Frame): self.residual_result_vars = [StringVar(), StringVar(), StringVar()] self.calibration_raw_results = None # Cached raw experiment data to allow for saving to csv. self.clipboard = "" # Clipboard string containing results + self.mgm_to_helmholtz_cos_trans = [[DoubleVar(value=1), DoubleVar(value=0), DoubleVar(value=0)], + [DoubleVar(value=0), DoubleVar(value=1), DoubleVar(value=0)], + [DoubleVar(value=0), DoubleVar(value=0), DoubleVar(value=1)]] # UI Elements row_counter = 0 @@ -1120,6 +1124,93 @@ class CalibrateMagnetometer(Frame): self.copy_calibration_button.grid(row=0, column=1, padx=5, pady=5) row_counter += 1 + # RIGHT Bottom COLUMN + # Input coordinate system conversion matrix + row_counter = 0 + input_cos_frame = LabelFrame(self.right_column, text="Input MGM to Helmholtz COS Transformation Matrix") + input_cos_frame.grid(row=row_counter, column=2, padx=(100, 0), pady=20, sticky="nw") + for i, label in enumerate(['X', 'Y', 'Z']): + axis_label = Label(input_cos_frame, text=label) + axis_label.grid(row=0, column=i + 1, padx=5, pady=5, sticky="nw") + # Axis sensitivities + sensitivity_results_label = Label(input_cos_frame, text="X") + sensitivity_results_label.grid(row=1, column=0, padx=5, pady=5, sticky="nw") + for i in range(3): + axis_data = Entry(input_cos_frame, + textvariable=self.mgm_to_helmholtz_cos_trans[0][i], + width=15) + axis_data.grid(row=1, column=i + 1, padx=5, pady=5, sticky="nw") + sensitivity_results_unit = Label(input_cos_frame, text="-") + sensitivity_results_unit.grid(row=1, column=4, padx=5, pady=5, sticky="nw") + # Axis offsets + offset_results_label = Label(input_cos_frame, text="Y") + offset_results_label.grid(row=2, column=0, padx=5, pady=5, sticky="nw") + for i in range(3): + if i == 0: + axis_data = Entry(input_cos_frame, + textvariable=self.mgm_to_helmholtz_cos_trans[0][1], + width=15, + state='readonly') + self.mgm_to_helmholtz_cos_trans[1][0] = self.mgm_to_helmholtz_cos_trans[0][1] + if i == 1: + axis_data = Entry(input_cos_frame, + textvariable=self.mgm_to_helmholtz_cos_trans[1][i], + width=15) + if i == 2: + axis_data = Entry(input_cos_frame, + textvariable=self.mgm_to_helmholtz_cos_trans[1][i], + width=15) + axis_data.grid(row=2, column=i + 1, padx=5, pady=5, sticky="nw") + offset_results_unit = Label(input_cos_frame, text="-") + offset_results_unit.grid(row=2, column=4, padx=5, pady=5, sticky="nw") + # Angle to XY coil plane + angle_to_plane_label = Label(input_cos_frame, text="Z") + angle_to_plane_label.grid(row=3, column=0, padx=5, pady=5, sticky="nw") + for i in range(3): + if i == 0: + axis_data = Entry(input_cos_frame, + textvariable=self.mgm_to_helmholtz_cos_trans[0][2], + width=15, + state='readonly') + self.mgm_to_helmholtz_cos_trans[2][0] = self.mgm_to_helmholtz_cos_trans[0][2] + if i == 1: + axis_data = Entry(input_cos_frame, + textvariable=self.mgm_to_helmholtz_cos_trans[1][2], + width=15, + state='readonly') + self.mgm_to_helmholtz_cos_trans[2][1] = self.mgm_to_helmholtz_cos_trans[1][2] + if i == 2: + axis_data = Entry(input_cos_frame, + textvariable=self.mgm_to_helmholtz_cos_trans[2][i], + width=15) + axis_data.grid(row=3, column=i + 1, padx=5, pady=5, sticky="nw") + angle_to_plane_unit = Label(input_cos_frame, text="-") + angle_to_plane_unit.grid(row=3, column=4, padx=5, pady=5, sticky="nw") + # Note on input + label = "Note: Input orthogonal, normalized transformation Matrix." + axis_note = Label(input_cos_frame, text=label) + axis_note.grid(row=4, column=0, padx=5, pady=5, columnspan=5, sticky="nw") + # Save calibration buttons + save_input_cos_frame = Frame(input_cos_frame) + save_input_cos_frame.grid(row=6, column=0, columnspan=5) + # Save and apply + self.export_cos_trans_button = Button(save_input_cos_frame, text="Export raw to CSV", + command=self.export_csv, + state="normal", + pady=5, padx=5) + self.export_cos_trans_button.grid(row=0, column=0, padx=5, pady=5) + self.copy_cos_trans_matrix_button = Button(save_input_cos_frame, text="Copy to clipboard", + command=self.copy_to_clipboard, + state="normal", + pady=5, padx=5) + self.copy_cos_trans_matrix_button.grid(row=0, column=1, padx=5, pady=5) + self.normalize_matrix_button = Button(save_input_cos_frame, text="Normalize matrix", + command=self.matrix_normalize, + state="normal", + pady=5, padx=5) + self.normalize_matrix_button.grid(row=0, column=2, padx=5, pady=5) + row_counter += 1 + # This starts an endless polling loop self.update_view() @@ -1154,7 +1245,7 @@ class CalibrateMagnetometer(Frame): messagebox.showerror("Calibration error", "Error occured during calibration:\n{}".format(arg)) self.reactivate_buttons() elif cmd == 'progress': - self.calibration_procedure_progress_var.set(min(int(arg*100), 100)) + self.calibration_procedure_progress_var.set(min(int(arg * 100), 100)) elif cmd == 'calibration_data': self.display_calibration_results(arg) else: @@ -1182,8 +1273,8 @@ class CalibrateMagnetometer(Frame): for i in range(3): self.sensitivity_result_vars[i].set("{:.3f}".format(results[i]['sensitivity'])) self.offset_result_vars[i].set("{:.3f}".format(results[i]['offset'] * 1e6)) - self.angle_to_plane_result_vars[i].set("{:.3f}".format(results[i]['alpha'] * 180/pi)) - self.angle_in_plane_result_vars[i].set("{:.3f}".format(results[i]['beta'] * 180/pi)) + self.angle_to_plane_result_vars[i].set("{:.3f}".format(results[i]['alpha'] * 180 / pi)) + self.angle_in_plane_result_vars[i].set("{:.3f}".format(results[i]['beta'] * 180 / pi)) self.residual_result_vars[i].set("{:.3e}".format(results[i]['residual'] * 1e6)) # Populate clipboard string @@ -1196,7 +1287,7 @@ class CalibrateMagnetometer(Frame): self.clipboard += "\t{:.3f}".format(results[i]['offset'] * 1e6) self.clipboard += "\nAngle to XY Plane [deg]" for i in range(3): - self.clipboard += "\t{:.3f}".format(results[i]['alpha'] * 180/pi) + self.clipboard += "\t{:.3f}".format(results[i]['alpha'] * 180 / pi) self.clipboard += "\nAngle in XY Plane [deg]" for i in range(3): self.clipboard += "\t{:.3f}".format(results[i]['beta'] * 180 / pi) @@ -1207,6 +1298,7 @@ class CalibrateMagnetometer(Frame): # Enable save buttons self.export_calibration_button.configure(state="normal") self.copy_calibration_button.configure(state="normal") + self.export_mgm_button.configure(state="normal") def start_calibration_procedure(self): try: @@ -1233,6 +1325,33 @@ class CalibrateMagnetometer(Frame): self.clipboard_append(self.clipboard) self.update() + def matrix_normalize(self): + try: + ui_print("Input matrix to be normalized:") + # Normalize Matrix + matrix = [[self.mgm_to_helmholtz_cos_trans[0][0].get(), self.mgm_to_helmholtz_cos_trans[0][1].get(), + self.mgm_to_helmholtz_cos_trans[0][2].get()], + [self.mgm_to_helmholtz_cos_trans[1][0].get(), self.mgm_to_helmholtz_cos_trans[1][1].get(), + self.mgm_to_helmholtz_cos_trans[1][2].get()], + [self.mgm_to_helmholtz_cos_trans[2][0].get(), self.mgm_to_helmholtz_cos_trans[2][1].get(), + self.mgm_to_helmholtz_cos_trans[2][2].get()]] + matrix = np.array(matrix) + ui_print(matrix) + matrix_max = matrix.max() + matrix_min = matrix.min() + matrix = (matrix - matrix_min) / (matrix_max - matrix_min) + ui_print("Normalized matrix:") + ui_print(matrix) + for i in range(3): + for j in range(3): + self.mgm_to_helmholtz_cos_trans[i][j].set(matrix[i][j]) + except: + # Couldn't compute matrix -> use unity matrix + ui_print("Could not normalize matrix, reverted to unity matrix!") + self.mgm_to_helmholtz_cos_trans = [[DoubleVar(value=1), DoubleVar(value=0), DoubleVar(value=0)], + [DoubleVar(value=0), DoubleVar(value=1), DoubleVar(value=0)], + [DoubleVar(value=0), DoubleVar(value=0), DoubleVar(value=1)]] + class HardwareConfiguration(Frame): """Settings window to set program constants""" @@ -1431,7 +1550,8 @@ class HardwareConfiguration(Frame): # Check if value is within safe limits config_key = self.entries[key][3] # get handle by which value is indexed in config file - value_ok = helmholtz_cage_device.value_in_limits(g.AXIS_NAMES[i], config_key, value) # perform value check + value_ok = helmholtz_cage_device.value_in_limits(g.AXIS_NAMES[i], config_key, + value) # perform value check if value_ok == 'OK': # value is within safe limits config.edit_config(g.AXIS_NAMES[i], config_key, value) # write new value to config file @@ -1637,7 +1757,7 @@ class ConfigureLogging(Frame): self.checkbox_vars[key] = BooleanVar(value=True) # create variable for checkbox and put it in dictionary checkbox = Checkbutton(self.checkbox_frame, text=name, # generate checkbox variable=self.checkbox_vars[key], onvalue=True, offvalue=False) - checkbox.grid(row=row+1, column=column, padx=(0, 20), sticky=W) # place checkbox in UI + checkbox.grid(row=row + 1, column=column, padx=(0, 20), sticky=W) # place checkbox in UI self.checkboxes.append(checkbox) # add created checkbox to list of all checkboxes row += 1 if row > 8: