forked from zietzm/Helmholtz_Test_Bench
Dublicates calibration method, added notes
This commit is contained in:
+460
-8
@@ -25,7 +25,8 @@ import src.globals as g
|
||||
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
|
||||
from src.calibration_simple import AmbientFieldCalibration, CoilConstantCalibration, MagnetometerCalibration
|
||||
from src.calibration_complete import AmbientFieldCalibration, CoilConstantCalibration, MagnetometerCalibration
|
||||
from src.exceptions import DeviceAccessError
|
||||
from src.utility import ui_print, save_dict_list_to_csv
|
||||
import src.helmholtz_cage_device as helmholtz_cage_device
|
||||
@@ -78,7 +79,8 @@ class HelmholtzGUI(Tk):
|
||||
for P in [ManualMode,
|
||||
HardwareConfiguration,
|
||||
CalibrateAmbientField,
|
||||
CalibrateMagnetometer,
|
||||
CalibrateMagnetometerSimple,
|
||||
CalibrateMagnetometerComplete,
|
||||
ExecuteCSVMode,
|
||||
ConfigureLogging]: # do this for every mode page
|
||||
page = P(main_area, self) # initialize the page with the main_area frame as the parent
|
||||
@@ -106,7 +108,8 @@ class TopMenu:
|
||||
mode_selector.add_command(label="Static Manual Input", command=self.manual_mode)
|
||||
mode_selector.add_command(label="Execute CSV Sequence", command=self.execute_csv_mode)
|
||||
mode_selector.add_command(label="Calibrate Ambient Field", command=self.calibrate_ambient)
|
||||
mode_selector.add_command(label="Calibrate Magnetometer", command=self.calibrate_magnetometer)
|
||||
mode_selector.add_command(label="Calibrate Magnetometer Simple", command=self.calibrate_magnetometer_simple)
|
||||
mode_selector.add_command(label="Calibrate Magnetometer Complete", command=self.calibrate_magnetometer_complete)
|
||||
mode_selector.add_separator()
|
||||
mode_selector.add_command(label="Configure Data Logging", command=self.logging)
|
||||
mode_selector.add_command(label="Settings...", command=self.configuration)
|
||||
@@ -120,8 +123,11 @@ class TopMenu:
|
||||
def calibrate_ambient(self):
|
||||
self.window.show_frame(CalibrateAmbientField)
|
||||
|
||||
def calibrate_magnetometer(self):
|
||||
self.window.show_frame(CalibrateMagnetometer)
|
||||
def calibrate_magnetometer_simple(self):
|
||||
self.window.show_frame(CalibrateMagnetometerSimple)
|
||||
|
||||
def calibrate_magnetometer_complete(self):
|
||||
self.window.show_frame(CalibrateMagnetometerComplete)
|
||||
|
||||
def execute_csv_mode(self): # switch to the CSV execution page
|
||||
self.window.show_frame(ExecuteCSVMode)
|
||||
@@ -940,7 +946,7 @@ class CalibrateAmbientField(Frame):
|
||||
self.update()
|
||||
|
||||
|
||||
class CalibrateMagnetometer(Frame):
|
||||
class CalibrateMagnetometerSimple(Frame):
|
||||
def __init__(self, parent, controller):
|
||||
Frame.__init__(self, parent)
|
||||
self.parent = parent
|
||||
@@ -986,7 +992,447 @@ class CalibrateMagnetometer(Frame):
|
||||
row_counter = 0
|
||||
|
||||
# Create headline
|
||||
header = Label(self.left_column, text="Magnetometer Calibration", font=HEADER_FONT)
|
||||
header = Label(self.left_column, text="Magnetometer Calibration\n-simlified method-", font=HEADER_FONT)
|
||||
header.grid(row=row_counter, column=0, columnspan=2, padx=100, pady=20, sticky="nw")
|
||||
row_counter += 1
|
||||
|
||||
# Magnetometer connected indicator
|
||||
connected_status_frame = Frame(self.left_column)
|
||||
connected_status_frame.grid(row=row_counter, column=0, sticky="nw")
|
||||
connected_label = Label(connected_status_frame, text="Magnetometer state:", font=SUB_HEADER_FONT)
|
||||
connected_label.grid(row=0, column=0, padx=10, pady=20, sticky="nw")
|
||||
self.connected_state_label = Label(connected_status_frame, textvariable=self.connected_state_var, fg="red")
|
||||
self.connected_state_label.grid(row=0, column=1, padx=10, pady=20, sticky="nw")
|
||||
row_counter += 1
|
||||
|
||||
# Magnetometer field data grid
|
||||
field_data_frame = Frame(self.left_column)
|
||||
field_data_frame.grid(row=row_counter, column=0, sticky="nw")
|
||||
field_data_label = Label(field_data_frame, text="Field data:", font=SUB_HEADER_FONT)
|
||||
field_data_label.grid(row=0, column=0, padx=10, pady=3, sticky="nw")
|
||||
axis_labels = ['X:', 'Y:', 'Z:']
|
||||
for i in range(3):
|
||||
field_data_axis_label = Label(field_data_frame, text=axis_labels[i])
|
||||
field_data_axis_label.grid(row=i, column=1, padx=10, pady=3)
|
||||
|
||||
field_data_axis_data = Label(field_data_frame, textvariable=self.field_value_vars[i])
|
||||
field_data_axis_data.grid(row=i, column=2, padx=(20, 0), pady=3)
|
||||
|
||||
field_data_axis_units = Label(field_data_frame, text="\u03BCT")
|
||||
field_data_axis_units.grid(row=i, column=3, padx=5, pady=3)
|
||||
row_counter += 1
|
||||
|
||||
# Centered controls
|
||||
controls_frame = Frame(self.left_column)
|
||||
controls_frame.grid(row=row_counter, column=0, sticky="sw")
|
||||
# Number of calibration points
|
||||
calibration_point_nr_label = Label(controls_frame, text="# of calibration points")
|
||||
calibration_point_nr_label.grid(row=0, column=0, pady=5, sticky="w")
|
||||
calibration_point_nr_entry = Entry(controls_frame, textvariable=self.calibration_points_var)
|
||||
calibration_point_nr_entry.grid(row=0, column=1, pady=5, sticky="w")
|
||||
# Measurement interval
|
||||
calibration_point_nr_label = Label(controls_frame, text="Measurement interval [s]")
|
||||
calibration_point_nr_label.grid(row=1, column=0, pady=5, sticky="w")
|
||||
calibration_point_nr_entry = Entry(controls_frame, textvariable=self.calibration_interval_var)
|
||||
calibration_point_nr_entry.grid(row=1, column=1, pady=5, sticky="w")
|
||||
# Calibration start buttons
|
||||
start_button_frame = Frame(controls_frame)
|
||||
start_button_frame.grid(row=2, column=0, columnspan=2)
|
||||
self.start_calibration_button = Button(start_button_frame, text="Start Calibration",
|
||||
command=self.start_calibration_procedure,
|
||||
pady=5, padx=5, font=SMALL_BUTTON_FONT)
|
||||
self.start_calibration_button.grid(row=0, column=0, padx=10, pady=(30, 10))
|
||||
# Calibration progress bar
|
||||
progress_bar_frame = Frame(controls_frame)
|
||||
progress_bar_frame.grid(row=3, column=0, columnspan=2)
|
||||
calibration_procedure_progress_label = Label(progress_bar_frame, text="Progress:")
|
||||
calibration_procedure_progress_label.grid(row=0, column=0, padx=10, pady=10)
|
||||
calibration_procedure_progress = ttk.Progressbar(progress_bar_frame,
|
||||
length=240,
|
||||
variable=self.calibration_procedure_progress_var)
|
||||
calibration_procedure_progress.grid(row=0, column=1, padx=10, pady=10, sticky="we")
|
||||
row_counter += 1
|
||||
|
||||
# CENTER COLUMN
|
||||
# Magnetometer calibration results
|
||||
row_counter = 0
|
||||
calibration_results_frame = LabelFrame(self.right_column, text="Magnetometer Results")
|
||||
calibration_results_frame.grid(row=row_counter, column=1, padx=(100, 0), pady=20, sticky="nw")
|
||||
for i, label in enumerate(['X', 'Y', 'Z']):
|
||||
axis_label = Label(calibration_results_frame, text=label)
|
||||
axis_label.grid(row=0, column=i + 1, padx=5, pady=5, sticky="nw")
|
||||
# Axis sensitivities
|
||||
sensitivity_results_label = Label(calibration_results_frame, text="Sensitivity:")
|
||||
sensitivity_results_label.grid(row=1, column=0, padx=5, pady=5, sticky="nw")
|
||||
for i in range(3):
|
||||
axis_data = Entry(calibration_results_frame,
|
||||
textvariable=self.sensitivity_result_vars[i],
|
||||
width=15,
|
||||
state='readonly')
|
||||
axis_data.grid(row=1, column=i + 1, padx=5, pady=5, sticky="nw")
|
||||
sensitivity_results_unit = Label(calibration_results_frame, text="-")
|
||||
sensitivity_results_unit.grid(row=1, column=4, padx=5, pady=5, sticky="nw")
|
||||
# Axis offsets
|
||||
offset_results_label = Label(calibration_results_frame, text="Offset:")
|
||||
offset_results_label.grid(row=2, column=0, padx=5, pady=5, sticky="nw")
|
||||
for i in range(3):
|
||||
axis_data = Entry(calibration_results_frame,
|
||||
textvariable=self.offset_result_vars[i],
|
||||
width=15,
|
||||
state='readonly')
|
||||
axis_data.grid(row=2, column=i + 1, padx=5, pady=5, sticky="nw")
|
||||
offset_results_unit = Label(calibration_results_frame, text="\u03BCT")
|
||||
offset_results_unit.grid(row=2, column=4, padx=5, pady=5, sticky="nw")
|
||||
# Angle to XY coil plane
|
||||
angle_to_plane_label = Label(calibration_results_frame, text="Angle to XY plane:")
|
||||
angle_to_plane_label.grid(row=3, column=0, padx=5, pady=5, sticky="nw")
|
||||
for i in range(3):
|
||||
axis_data = Entry(calibration_results_frame,
|
||||
textvariable=self.angle_to_plane_result_vars[i],
|
||||
width=15,
|
||||
state='readonly')
|
||||
axis_data.grid(row=3, column=i + 1, padx=5, pady=5, sticky="nw")
|
||||
angle_to_plane_unit = Label(calibration_results_frame, text="°")
|
||||
angle_to_plane_unit.grid(row=3, column=4, padx=5, pady=5, sticky="nw")
|
||||
# Angle in XY coil plane
|
||||
angle_in_plane_label = Label(calibration_results_frame, text="Angle in XY plane:")
|
||||
angle_in_plane_label.grid(row=4, column=0, padx=5, pady=5, sticky="nw")
|
||||
for i in range(3):
|
||||
axis_data = Entry(calibration_results_frame,
|
||||
textvariable=self.angle_in_plane_result_vars[i],
|
||||
width=15,
|
||||
state='readonly')
|
||||
axis_data.grid(row=4, column=i + 1, padx=5, pady=5, sticky="nw")
|
||||
angle_in_plane_unit = Label(calibration_results_frame, text="°")
|
||||
angle_in_plane_unit.grid(row=4, column=4, padx=5, pady=5, sticky="nw")
|
||||
# Residual in system of equations
|
||||
residual_label = Label(calibration_results_frame, text="Residual:")
|
||||
residual_label.grid(row=5, column=0, padx=5, pady=5, sticky="nw")
|
||||
for i in range(3):
|
||||
axis_data = Entry(calibration_results_frame,
|
||||
textvariable=self.residual_result_vars[i],
|
||||
width=15,
|
||||
state='readonly')
|
||||
axis_data.grid(row=5, column=i + 1, padx=5, pady=5, sticky="nw")
|
||||
residual_unit = Label(calibration_results_frame, text="\u03BCT")
|
||||
residual_unit.grid(row=5, column=4, padx=5, pady=5, sticky="nw")
|
||||
# Save calibration buttons
|
||||
save_calibration_results_frame = Frame(calibration_results_frame)
|
||||
save_calibration_results_frame.grid(row=6, column=0, columnspan=5)
|
||||
# Notes on the calibration method
|
||||
sensitivity_results_label = Label(calibration_results_frame, text="Sensitivity:")
|
||||
sensitivity_results_label.grid(row=1, column=0, padx=5, pady=5, sticky="nw")
|
||||
|
||||
# Save and apply
|
||||
self.export_calibration_button = Button(save_calibration_results_frame, text="Export raw to CSV",
|
||||
command=self.export_csv_calibration_raw_results,
|
||||
state="disabled",
|
||||
pady=5, padx=5)
|
||||
self.export_calibration_button.grid(row=0, column=0, padx=5, pady=5)
|
||||
self.copy_calibration_button = Button(save_calibration_results_frame, text="Copy to clipboard",
|
||||
command=self.copy_to_clipboard,
|
||||
state="disabled",
|
||||
pady=5, padx=5)
|
||||
self.copy_calibration_button.grid(row=0, column=1, padx=5, pady=5)
|
||||
row_counter += 1
|
||||
# Notes on the calibration method
|
||||
calibration_method_notes_frame = LabelFrame(self.right_column, text="Calibration method notes:")
|
||||
calibration_method_notes_frame.grid(row=row_counter, column=1, padx=(100, 0), pady=20, sticky="nw")
|
||||
label = "-Implementation according to Zikmund et al. [DOI: 10.1109/I2MTC.2014.6860790]\n-Points created by Fibonacci sphere\n-Only accounts for hard-iron offset and MGM scaling errors!"
|
||||
calibration_method_notes = Label(calibration_method_notes_frame, anchor='w', justify='left', text=label)
|
||||
calibration_method_notes.grid(row=3, column=0, padx=5, pady=5, sticky="nw")
|
||||
# FLAG
|
||||
|
||||
# RIGHT 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):
|
||||
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):
|
||||
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:"
|
||||
axis_note = Label(input_cos_frame, text=label)
|
||||
axis_note.grid(row=4, column=0, padx=5, pady=5, sticky="nw")
|
||||
label = "-Transfers fields value of Helmholtz cage to COS of MGM\n-B_mgm = mgm_T_hh * B_hh"
|
||||
axis_note = Label(input_cos_frame, anchor='w', justify='left', text=label)
|
||||
axis_note.grid(row=4, column=1, padx=5, pady=5, columnspan=4, 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 to CSV",
|
||||
command=self.export_csv_cos_trans_matrix,
|
||||
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_cos_trans_matrix,
|
||||
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="Orthonormalize 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()
|
||||
|
||||
def page_switch(self):
|
||||
# every class in the UI needs this, even if it doesn't do anything
|
||||
pass
|
||||
|
||||
def update_view(self):
|
||||
# Get new connected status
|
||||
if g.MAGNETOMETER.connected:
|
||||
self.connected_state_var.set("connected")
|
||||
self.connected_state_label.configure(fg="green")
|
||||
else:
|
||||
self.connected_state_var.set("Not connected")
|
||||
self.connected_state_label.configure(fg="red")
|
||||
|
||||
# Get new field data
|
||||
new_field = g.MAGNETOMETER.field
|
||||
for i in range(3):
|
||||
# Display in uT
|
||||
self.field_value_vars[i].set("{:.3f}".format(new_field[i] * 1e6))
|
||||
|
||||
# Get mpi messages from calibration procedures
|
||||
try:
|
||||
while True:
|
||||
msg = self.view_mpi_queue.get(block=False)
|
||||
cmd = msg['cmd']
|
||||
arg = msg['arg']
|
||||
if cmd == 'finished':
|
||||
self.reactivate_buttons()
|
||||
elif cmd == 'failed':
|
||||
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))
|
||||
elif cmd == 'calibration_data':
|
||||
self.display_calibration_results(arg)
|
||||
else:
|
||||
ui_print("Error: Unexpected mpi command '{}' in CalibrationTool".format(cmd))
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
self.controller.after(500, self.update_view)
|
||||
|
||||
def reactivate_buttons(self):
|
||||
self.start_calibration_button.configure(text="Start Calibration", state=NORMAL)
|
||||
self.calibration_procedure_progress_var.set(0)
|
||||
|
||||
def deactivate_buttons(self):
|
||||
self.start_calibration_button.configure(text="Running...", state=DISABLED)
|
||||
|
||||
def display_calibration_results(self, results):
|
||||
# Cache raw experiment data for saving later
|
||||
self.calibration_raw_results = results['raw_data']
|
||||
|
||||
# Unpack the dict
|
||||
results = results['results']
|
||||
|
||||
# Display calibration in GUI
|
||||
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.residual_result_vars[i].set("{:.3e}".format(results[i]['residual'] * 1e6))
|
||||
|
||||
# Populate clipboard string
|
||||
self.clipboard = "\tX\tY\tZ\n"
|
||||
self.clipboard += "Sensitivity [-]"
|
||||
for i in range(3):
|
||||
self.clipboard += "\t{:.3f}".format(results[i]['sensitivity'])
|
||||
self.clipboard += "\nOffset [uT]"
|
||||
for i in range(3):
|
||||
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 += "\nAngle in XY Plane [deg]"
|
||||
for i in range(3):
|
||||
self.clipboard += "\t{:.3f}".format(results[i]['beta'] * 180 / pi)
|
||||
self.clipboard += "\nResidual [uT]"
|
||||
for i in range(3):
|
||||
self.clipboard += "\t{:.3e}".format(results[i]['residual'] * 1e6)
|
||||
|
||||
# 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:
|
||||
calibration_points = self.calibration_points_var.get()
|
||||
calibration_interval = self.calibration_interval_var.get()
|
||||
self.calibration_thread = MagnetometerCalibration(self.view_mpi_queue,
|
||||
calibration_points,
|
||||
calibration_interval,
|
||||
self.mgm_to_helmholtz_cos_trans)
|
||||
self.calibration_thread.start()
|
||||
self.deactivate_buttons()
|
||||
except (DeviceAccessError, TclError) as e:
|
||||
messagebox.showwarning("Calibration failed", "Failed to start calibration:\n{}".format(e))
|
||||
|
||||
def export_csv_calibration_raw_results(self):
|
||||
if self.calibration_raw_results is None:
|
||||
ui_print("Error: Failed to export non-existent calibration data.")
|
||||
return
|
||||
save_dict_list_to_csv('magnetometer_calibration.csv', self.calibration_raw_results, query_path=True)
|
||||
ui_print("Saved calibration results to magnetometer_calibration.csv.")
|
||||
|
||||
def export_csv_cos_trans_matrix(self):
|
||||
cos_trans_matrix = [
|
||||
{'XX': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[0][0].get()),
|
||||
'XY': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[0][1].get()),
|
||||
'XZ': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[0][2].get()),
|
||||
'YX': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[1][0].get()),
|
||||
'YY': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[1][1].get()),
|
||||
'YZ': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[1][2].get()),
|
||||
'ZX': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[2][0].get()),
|
||||
'ZY': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[2][1].get()),
|
||||
'ZZ': "{:.5f}".format(self.mgm_to_helmholtz_cos_trans[2][2].get())}
|
||||
]
|
||||
if cos_trans_matrix is None:
|
||||
ui_print("Error: Failed to export non-existent coordinate transformation matrix.")
|
||||
return
|
||||
save_dict_list_to_csv('magnetometer_cos_trans_matrix.csv', cos_trans_matrix, query_path=True)
|
||||
ui_print("Saved MGM to Helmholtz coordinate transformation matrix to magnetometer_cos_trans_matrix.csv.")
|
||||
|
||||
def copy_to_clipboard(self):
|
||||
self.clipboard_clear()
|
||||
self.clipboard_append(self.clipboard)
|
||||
self.update()
|
||||
|
||||
def copy_to_clipboard_cos_trans_matrix(self):
|
||||
# Populate clipboard for coordinate transformation matrix
|
||||
self.cos_trans_matrix_clipboard = "\tX\tY\tZ\n"
|
||||
self.cos_trans_matrix_clipboard += "X\t{:.5f}".format(self.mgm_to_helmholtz_cos_trans[0][0].get())
|
||||
self.cos_trans_matrix_clipboard += "\t{:.5f}".format(self.mgm_to_helmholtz_cos_trans[0][1].get())
|
||||
self.cos_trans_matrix_clipboard += "\t{:.5f}\n".format(self.mgm_to_helmholtz_cos_trans[0][2].get())
|
||||
self.cos_trans_matrix_clipboard += "Y\t{:.5f}".format(self.mgm_to_helmholtz_cos_trans[1][0].get())
|
||||
self.cos_trans_matrix_clipboard += "\t{:.5f}".format(self.mgm_to_helmholtz_cos_trans[1][1].get())
|
||||
self.cos_trans_matrix_clipboard += "\t{:.5f}\n".format(self.mgm_to_helmholtz_cos_trans[1][2].get())
|
||||
self.cos_trans_matrix_clipboard += "Z\t{:.5f}".format(self.mgm_to_helmholtz_cos_trans[2][0].get())
|
||||
self.cos_trans_matrix_clipboard += "\t{:.5f}".format(self.mgm_to_helmholtz_cos_trans[2][1].get())
|
||||
self.cos_trans_matrix_clipboard += "\t{:.5f}\n".format(self.mgm_to_helmholtz_cos_trans[2][2].get())
|
||||
self.clipboard_clear()
|
||||
self.clipboard_append(self.cos_trans_matrix_clipboard)
|
||||
self.update()
|
||||
|
||||
def matrix_normalize(self):
|
||||
try:
|
||||
ui_print("Input matrix to be normalized:")
|
||||
# Normalize Matrix
|
||||
matrix = [[x.get() for x in row] for row in self.mgm_to_helmholtz_cos_trans]
|
||||
matrix = np.array(matrix)
|
||||
ui_print(matrix)
|
||||
#matrix_max = matrix.max()
|
||||
#matrix_min = matrix.min()
|
||||
#matrix = (matrix - matrix_min) / (matrix_max - matrix_min)
|
||||
|
||||
def gram_schmidt_columns(X):
|
||||
Q, R = np.linalg.qr(X)
|
||||
return Q
|
||||
|
||||
matrix = gram_schmidt_columns(matrix)
|
||||
ui_print("Normalized matrix (Gram-Schmidt):")
|
||||
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 CalibrateMagnetometerComplete(Frame):
|
||||
def __init__(self, parent, controller):
|
||||
Frame.__init__(self, parent)
|
||||
self.parent = parent
|
||||
self.controller = controller
|
||||
|
||||
# To center window
|
||||
# self.columnconfigure(0, weight=1)
|
||||
self.rowconfigure(0, weight=1)
|
||||
self.left_column = Frame(self)
|
||||
self.left_column.grid(row=0, column=0, sticky="nsew")
|
||||
self.right_column = Frame(self)
|
||||
self.right_column.grid(row=0, column=1, sticky="nsew")
|
||||
self.left_column.rowconfigure(3, weight=1)
|
||||
|
||||
# Thread variables
|
||||
self.calibration_thread = None
|
||||
self.view_mpi_queue = Queue() # Receives status information from calibration procedure threads.
|
||||
|
||||
# UI variables
|
||||
self.connected_state_var = StringVar(value="Not connected")
|
||||
self.field_value_vars = [StringVar(value="No data"),
|
||||
StringVar(value="No data"),
|
||||
StringVar(value="No data")]
|
||||
self.calibration_procedure_progress_var = IntVar(value=0)
|
||||
# Calibration parameters
|
||||
self.calibration_points_var = IntVar(value=8)
|
||||
self.calibration_interval_var = DoubleVar(value=5)
|
||||
# Calibration results
|
||||
self.sensitivity_result_vars = [StringVar(), StringVar(), StringVar()]
|
||||
self.offset_result_vars = [StringVar(), StringVar(), StringVar()]
|
||||
self.angle_to_plane_result_vars = [StringVar(), StringVar(), StringVar()]
|
||||
self.angle_in_plane_result_vars = [StringVar(), StringVar(), StringVar()]
|
||||
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.cos_trans_matrix_clipboard = "" # Clipboard string containing coordinate transformation 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)]]
|
||||
|
||||
# UI Elements
|
||||
row_counter = 0
|
||||
|
||||
# Create headline
|
||||
header = Label(self.left_column, text="Magnetometer Calibration\n-ellipsoid fitting method-", font=HEADER_FONT)
|
||||
header.grid(row=row_counter, column=0, columnspan=2, padx=100, pady=20, sticky="nw")
|
||||
row_counter += 1
|
||||
|
||||
@@ -1125,6 +1571,13 @@ class CalibrateMagnetometer(Frame):
|
||||
pady=5, padx=5)
|
||||
self.copy_calibration_button.grid(row=0, column=1, padx=5, pady=5)
|
||||
row_counter += 1
|
||||
# Notes on the calibration method
|
||||
calibration_method_notes_frame = LabelFrame(self.right_column, text="Calibration method notes:")
|
||||
calibration_method_notes_frame.grid(row=row_counter, column=1, padx=(100, 0), pady=20, sticky="nw")
|
||||
label = "-Implementation of calibration according to Kok et al. [ISBN: 978-0-9824438-5-9]\n-Implementation of ellipsoid fit according to Li et al. [DOI: 10.1109/GMAP.2004.1290055]\n-Points created by Fibonacci sphere\n-Accounts for soft-iron and hard-iron effects!"
|
||||
calibration_method_notes = Label(calibration_method_notes_frame, anchor='w', justify='left', text=label)
|
||||
calibration_method_notes.grid(row=1, column=0, padx=5, pady=5, sticky="nw")
|
||||
#FLAG
|
||||
|
||||
# RIGHT COLUMN
|
||||
# Input coordinate system conversion matrix
|
||||
@@ -1193,7 +1646,6 @@ class CalibrateMagnetometer(Frame):
|
||||
|
||||
row_counter += 1
|
||||
|
||||
|
||||
# This starts an endless polling loop
|
||||
self.update_view()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user