Cleaned up minor issues

This commit is contained in:
2022-10-07 16:01:00 +02:00
parent 283ef5fd24
commit effcc72966
2 changed files with 121 additions and 106 deletions
+61 -46
View File
@@ -5,7 +5,6 @@ from threading import Thread
import numpy as np
from numpy.lib.scimath import sqrt as csqrt
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from tkinter import LabelFrame
import scipy.optimize
@@ -14,7 +13,6 @@ from scipy import linalg as linalg_scipy
from src.utility import ui_print
from src.exceptions import DeviceBusy, DeviceAccessError
import src.globals as g
# from src.user_interface import CalibrateMagnetometerComplete.mgm_to_helmholtz_cos_trans
class AmbientFieldCalibration(Thread):
@@ -28,6 +26,7 @@ class AmbientFieldCalibration(Thread):
P_CONTROL = -7e3 # 0.2 A/s slew-rate at 40uT
I_CONTROL = 0 # -1e4 # 0.01A/s slew-rate for 1uTs
I_LIMIT = 1e-7 # uTs, Limit I to 0.025 A/s slew-rate to prevent wind-up
# D_CONTROL = Not implemented for now
def __init__(self, view_queue):
@@ -70,7 +69,7 @@ class AmbientFieldCalibration(Thread):
target_time = 0
current_time = datetime.now()
while (current_time - start_time).seconds < self.SETTLE_TIME:
# Each axis runs its own PID controller. They are slightly coupled by unorthogonality, which should
# Each axis runs its own PID controller. They are slightly coupled by non-orthogonality, which should
# hopefully not destabilize the feedback loop
for i in range(3):
# Error in tesla
@@ -78,11 +77,11 @@ class AmbientFieldCalibration(Thread):
e = g.MAGNETOMETER.field[i]
# Change in control current
du = e * self.P_CONTROL + self.error_integral[i] * self.I_CONTROL
self.axis_currents[i] += du*dt
self.axis_currents[i] += du * dt
# Update integral
# Add increment
self.error_integral[i] += e*dt
self.error_integral[i] += e * dt
# Clamp range
self.error_integral = np.clip(self.error_integral, -self.I_LIMIT, self.I_LIMIT)
@@ -156,7 +155,7 @@ class CoilConstantCalibration(Thread):
# All generated fields will be compared to this using a simple difference method
ambient_field = g.MAGNETOMETER.field
# This generates linearly spaced current setpoints and excludes zero
# This generates linearly spaced current set points and excludes zero
currents = np.linspace(-self.MEASUREMENT_RANGE, self.MEASUREMENT_RANGE, self.MEASUREMENT_POINTS * 2 + 1)
currents = np.delete(currents, self.MEASUREMENT_POINTS)
@@ -347,12 +346,13 @@ class MagnetometerCalibrationSimple(Thread):
b_e_x = g.CAGE_DEVICE.axes[0].ambient_field
b_e_y = g.CAGE_DEVICE.axes[1].ambient_field
b_e_z = g.CAGE_DEVICE.axes[2].ambient_field
b_e = sqrt(b_e_x**2 + b_e_y**2 + b_e_z**2)
b_e = sqrt(b_e_x ** 2 + b_e_y ** 2 + b_e_z ** 2)
# Perform least squares optimization on all magnetometer axes
sensor_parameters = []
for axis, axis_samples in enumerate(samples):
result = scipy.optimize.least_squares(self.residual_function, (1.0, pi/4, pi/4, pi/4), args=(b_e, axis_samples), gtol=1e-13)
result = scipy.optimize.least_squares(self.residual_function, (1.0, pi / 4, pi / 4, pi / 4),
args=(b_e, axis_samples), gtol=1e-13)
s, alpha_e, alpha, beta = result.x
residual = np.max(np.abs(result.fun))
sensor_parameters.append({'sensitivity': s,
@@ -377,7 +377,9 @@ class MagnetometerCalibrationSimple(Thread):
b_x = sample['b_x']
b_y = sample['b_y']
b_z = sample['b_z']
res.append(m - s * (b_e*sin(alpha_e) + b_x*cos(alpha)*cos(beta) + b_y*cos(alpha)*sin(beta) + b_z*sin(alpha)))
res.append(m - s * (
b_e * sin(alpha_e) + b_x * cos(alpha) * cos(beta) + b_y * cos(alpha) * sin(beta) + b_z * sin(
alpha)))
return res
@staticmethod
@@ -453,9 +455,8 @@ class MagnetometerCalibrationComplete(Thread):
self.cage_dev.set_field_compensated([0, 0, 0])
# Sleep for a certain duration to allow psu to stabilize output and magnetometer to supply readings
time.sleep(self.calibration_interval)
matrix_trans_mgm_to_hh_np = np.array(self.matrix_trans_mgm_to_hh)
# The offsets can easily be read from the magnetometer
offsets = matrix_trans_mgm_to_hh_np.dot(g.MAGNETOMETER.field)
offsets = g.MAGNETOMETER.field
# Save data point to raw_data list
raw_data.append({'applied_x': 0, 'applied_y': 0, 'applied_z': 0,
'measured_x': offsets[0], 'measured_y': offsets[1], 'measured_z': offsets[2]})
@@ -465,7 +466,7 @@ class MagnetometerCalibrationComplete(Thread):
# Generate our set of test vectors
test_vectors = self.fibonacci_sphere(self.calibration_points)
# Holds the knowns for each row of our system of equations. These are M, B_x, B_y, B_z
# Holds the known variables for each row of our system of equations. These are M, B_x, B_y, B_z
# (B_E is constant for the test and not stored in the array)
# Each sensor axis has its own independent system of equations
samples = [[], [], []]
@@ -479,7 +480,7 @@ class MagnetometerCalibrationComplete(Thread):
time.sleep(self.calibration_interval)
# Read output and save to array for solver later
raw_reading = matrix_trans_mgm_to_hh_np.dot(g.MAGNETOMETER.field)
raw_reading = g.MAGNETOMETER.field
reading = raw_reading - offsets
for i in range(3):
row = {'m': reading[i], 'b_x': applied_vec[0], 'b_y': applied_vec[1], 'b_z': applied_vec[2]}
@@ -497,7 +498,9 @@ class MagnetometerCalibrationComplete(Thread):
self.cage_dev.idle()
# Use collected data to build and solve system of equations
sensor_parameters = self.solve_system(raw_data) # FLAG: compare to csv import
# sensor_parameters = self.solve_system(raw_data) # FLAG: untested!
sensor_parameters, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m, cal_x, cal_y, cal_z, mag_amp_avg_set = MagnetometerCalibrationComplete.solve_system(
self.view_queue, raw_data, self.mgm_to_helmholtz_cos_trans)
# Pass results to UI
self.put_message('calibration_data', {'results': sensor_parameters, 'raw_data': raw_data})
@@ -528,8 +531,8 @@ class MagnetometerCalibrationComplete(Thread):
for row in range(3):
for col in range(3):
matrix_trans_mgm_to_hh_np[row][col] = matrix_trans_mgm_to_hh_tk[row][col].get()
# matrix_trans_mgm_to_hh_np = [[-1, 0, 0], [0, 1, 0], [0, 0, -1]] # FLAG: Hardcoded! for MGM 1 / 3
# matrix_trans_mgm_to_hh_np = [[0, 1, 0], [-1, 0, 0], [0, 0, 1]] # FLAG: Hardcoded! for MGM 0 / 2
# matrix_trans_mgm_to_hh_np = [[-1, 0, 0], [0, 1, 0], [0, 0, -1]] # hardcoded for MGM 1 / 3
# matrix_trans_mgm_to_hh_np = [[0, 1, 0], [-1, 0, 0], [0, 0, 1]] # hardcoded for MGM 0 / 2
ui_print("Applying transformation matrix to data. h_{set,mgm} = mgm_T_hh * h_{set,hh}")
ui_print(matrix_trans_mgm_to_hh_np)
# Transform hh set magnetic field cos to sensor cos
@@ -538,7 +541,6 @@ class MagnetometerCalibrationComplete(Thread):
mag_x_set = mag_xyz_set_hh[:, 0]
mag_y_set = mag_xyz_set_hh[:, 1]
mag_z_set = mag_xyz_set_hh[:, 2]
# FLAG: Currently the coordinate transformation is applied two times (see calibration class)
# Calculate total error
err_x = 0
err_y = 0
@@ -549,12 +551,14 @@ class MagnetometerCalibrationComplete(Thread):
err_z += (mag_z_m[i] - mag_z_set[i]) ** 2
err_t = np.sqrt(err_x ** 2 + err_y ** 2 + err_z ** 2)
ui_print('Error in X/Y/Z/total: {:.2e} / {:.2e} / {:.2e} / {:.2e} [uT]'.format(err_x * u_tesla, err_y * u_tesla,
err_z * u_tesla, err_t * u_tesla))
err_z * u_tesla,
err_t * u_tesla))
# Filter raw data
try:
mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m = \
MagnetometerCalibrationComplete.filter_magnetometer_data(self, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m)
MagnetometerCalibrationComplete.filter_magnetometer_data(mag_x_set, mag_y_set, mag_z_set,
mag_x_m, mag_y_m, mag_z_m)
except Warning as waring_filter_mgm_data:
ui_print(f"{waring_filter_mgm_data}")
# Get general magnitude of the set magnetic filed
@@ -567,10 +571,10 @@ class MagnetometerCalibrationComplete(Thread):
# Calculate ellipsoid fit
try:
q_mat, n, d = MagnetometerCalibrationComplete.fit_ellipsoid(self, mag_x_m, mag_y_m, mag_z_m)
q_mat, n, d = MagnetometerCalibrationComplete.fit_ellipsoid(mag_x_m, mag_y_m, mag_z_m)
ui_print('Q matrix =')
ui_print(q_mat)
ui_print('n =')
ui_print('n = [T]')
ui_print(n)
# Retrieve calibration parameters
q_mat_inv = np.linalg.inv(q_mat)
@@ -584,7 +588,7 @@ class MagnetometerCalibrationComplete(Thread):
total_error = 0
for i in range(len(mag_x_m)):
h = np.array([[mag_x_m[i], mag_y_m[i], mag_z_m[i]]]).T
h_hat = np.matmul(a_mat_inv, h - b) # FLAG: Scaling issue
h_hat = np.matmul(a_mat_inv, h - b) # Scaling issue
cal_x[i] = h_hat[0] * mag_amp_avg_set
cal_y[i] = h_hat[1] * mag_amp_avg_set
cal_z[i] = h_hat[2] * mag_amp_avg_set
@@ -598,9 +602,9 @@ class MagnetometerCalibrationComplete(Thread):
mag_amp_avg_set * 10 ** 6, mag_amp_avg_m * 10 ** 6))
ui_print('Soft-iron correction matrix a_mat_inv = ')
ui_print(a_mat_inv)
ui_print('Hard-iron offset b =')
ui_print('Hard-iron offset b = [T]')
ui_print(b)
ui_print('Total error E = ', total_error)
ui_print("Normalized total error E = {:4e} [0..1]]".format(total_error))
sensor_parameters = [{'a_mat': a_mat.tolist(),
'a_mat_inv': a_mat_inv.tolist(),
'b': b.tolist(),
@@ -613,18 +617,19 @@ class MagnetometerCalibrationComplete(Thread):
ui_print('A_inv could not be calculated! A warning occurred.')
ui_print('Please check if transformation matrix is input correctly.')
ui_print(f"{warning_message}")
except Exception as exception_message:
except Exception as exception_message:
ui_print('A_inv could not be calculated! An unknown error occurred.')
ui_print('Please check if transformation matrix is input correctly.')
ui_print(f"{exception_message}")
def filter_magnetometer_data(self, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m):
@staticmethod
def filter_magnetometer_data(mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m):
flag_validity = np.ones(len(mag_x_set))
# Issue 1: Sometimes, the old and new measurement are very similar.
# The set magnetic field has not changed fast enough.
for i in range(1, len(mag_x_set)):
# Flag entry if all measurement results are very close to one another
# Filter entry if all measurement results are very close to one another
if mag_x_m[i - 1] != 0:
div_x_m = mag_x_m[i] / mag_x_m[i - 1]
else:
@@ -657,7 +662,7 @@ class MagnetometerCalibrationComplete(Thread):
flag_validity[i] = 0
if bound_low < div_z_m < bound_up and not bound_low < div_z_set < bound_up:
flag_validity[i] = 0
# Flag entry if signs of measurement result and set result are different
# Filter entry if signs of measurement result and set result are different
thresh = 70.0e-06 # [T] threshold value, difference in magnetic field component too large to be reasonable
if np.abs(mag_x_set[i] - mag_x_m[i]) > thresh or np.abs(mag_y_set[i] - mag_y_m[i]) > thresh or np.abs(
mag_z_set[i] - mag_z_m[i]) > thresh:
@@ -691,7 +696,8 @@ class MagnetometerCalibrationComplete(Thread):
else:
return mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m
def fit_ellipsoid(self, mag_x_m, mag_y_m, mag_z_m):
@staticmethod
def fit_ellipsoid(mag_x_m, mag_y_m, mag_z_m):
# Script is adapted version from ThePoorEngineer - Calibrating the magnetometer
# https://thepoorengineer.com/en/calibrating-the-magnetometer/#Calibration
a1 = mag_x_m ** 2
@@ -755,13 +761,13 @@ class MagnetometerCalibrationComplete(Thread):
# Plot calibrated results
fig1 = plt.figure('MGM_cal_complete_left', figsize=(2.5, 3), dpi=100)
fig1.clf() # clear figure from previous use
fig1.clf() # clear figure from previous use
canvas1 = FigureCanvasTkAgg(fig1, plot_frame)
u_tesla = 10 ** 6 # Tesla to microTesla conversion factor
meas_no = len(mag_x_set) # Measurement number
# uncalibrated result plot
ax1 = fig1.add_subplot(211, projection='3d')
ax1 = fig1.add_subplot(221, projection='3d')
# ax1.clf()
ax1.set_xlabel(r'$B_x [{\mu}T]$', fontsize=plot_fontsize)
ax1.set_ylabel(r'$B_y [{\mu}T]$', fontsize=plot_fontsize)
@@ -773,11 +779,11 @@ class MagnetometerCalibrationComplete(Thread):
mag_z_m * u_tesla):
ax1.plot([i, l], [j, m], [k, n], linewidth=0.5, color='b')
# set magnetic vectors
ax1.scatter(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, s=5, color='k',
label="$B_{set}$ Helmholtz field")
l1 = ax1.scatter(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, s=5, color='k',
label="$B_{set}$ Helmholtz field")
# measured values
ax1.scatter(mag_x_m * u_tesla, mag_y_m * u_tesla, mag_z_m * u_tesla, s=5, color='b',
label="$B_{raw}$ uncalibrated")
l2 = ax1.scatter(mag_x_m * u_tesla, mag_y_m * u_tesla, mag_z_m * u_tesla, s=5, color='b',
label="$B_{raw}$ uncalibrated")
# plot sphere with magnitude
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
@@ -786,10 +792,10 @@ class MagnetometerCalibrationComplete(Thread):
z = np.outer(np.ones(np.size(u)), np.cos(v)) * mag_amp_avg_set
ax1.plot_wireframe(x * u_tesla, y * u_tesla, z * u_tesla, rstride=10, cstride=10, alpha=0.7, color='y')
ax1.plot_surface(x * u_tesla, y * u_tesla, z * u_tesla, alpha=0.3, color='y')
ax1.legend(loc='upper right', fontsize=plot_fontsize)
# ax1.legend(loc='upper right', fontsize=plot_fontsize)
# Calibrated result plot
ax2 = fig1.add_subplot(212, projection='3d')
ax2 = fig1.add_subplot(223, projection='3d')
ax2.set_xlabel(r'$B_x [\mu T]$', fontsize=plot_fontsize)
ax2.set_ylabel(r'$B_y [\mu T]$', fontsize=plot_fontsize)
ax2.set_zlabel(r'$B_z [\mu T]$', fontsize=plot_fontsize)
@@ -800,11 +806,11 @@ class MagnetometerCalibrationComplete(Thread):
cal_z * u_tesla):
ax2.plot([i, l], [j, m], [k, n], linewidth=0.5, color='r')
# set magnetic vectors
ax2.scatter(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, s=5, color='k',
label="$B_{set}$ Helmholtz field")
l3 = ax2.scatter(mag_x_set * u_tesla, mag_y_set * u_tesla, mag_z_set * u_tesla, s=5, color='k',
label="$B_{set}$ Helmholtz field")
# calibrated values ellipsoid fit
ax2.scatter(cal_x * u_tesla, cal_y * u_tesla, cal_z * u_tesla, s=5, color='r',
label="$B_{cal,el}$ ellipsoid fit")
l4 = ax2.scatter(cal_x * u_tesla, cal_y * u_tesla, cal_z * u_tesla, s=5, color='r',
label="$B_{cal,el}$ ellipsoid fit")
# plot sphere with magnitude
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
@@ -813,13 +819,21 @@ class MagnetometerCalibrationComplete(Thread):
z = np.outer(np.ones(np.size(u)), np.cos(v)) * mag_amp_avg_set
ax2.plot_wireframe(x * u_tesla, y * u_tesla, z * u_tesla, rstride=10, cstride=10, alpha=0.7, color='y')
ax2.plot_surface(x * u_tesla, y * u_tesla, z * u_tesla, alpha=0.3, color='y')
ax2.legend(loc='upper right', fontsize=plot_fontsize)
# ax2.legend(loc='upper right', fontsize=plot_fontsize)
ax3 = fig1.add_subplot(222)
ax3.axis('off')
ax3.legend([l1, l2], ["$B_{set}$", "$B_{raw}$"],
loc='upper right', fontsize=plot_fontsize)
ax4 = fig1.add_subplot(224)
ax4.axis('off')
ax4.legend([l3, l4], ["$B_{set}$", "$B_{cal,el}$"],
loc='upper right', fontsize=plot_fontsize)
canvas1.draw()
canvas1.get_tk_widget().grid(row=0, column=0)
# 2d_math plots
fig2 = plt.figure('MGM_cal_complete_right',figsize=(4, 3), dpi=100)
fig2.clf() # clear figure from previous use
fig2 = plt.figure('MGM_cal_complete_right', figsize=(4, 3), dpi=100)
fig2.clf() # clear figure from previous use
canvas2 = FigureCanvasTkAgg(fig2, plot_frame)
# x panel
ax3 = fig2.add_subplot(311)
@@ -873,7 +887,8 @@ class MagnetometerCalibrationComplete(Thread):
b_x = sample['b_x']
b_y = sample['b_y']
b_z = sample['b_z']
res.append(m - s * (b_e*sin(alpha_e) + b_x*cos(alpha)*cos(beta) + b_y*cos(alpha)*sin(beta) + b_z*sin(alpha)))
res.append(m - s * (b_e * sin(alpha_e) + b_x * cos(alpha) * cos(beta)
+ b_y * cos(alpha) * sin(beta) + b_z * sin(alpha)))
return res
@staticmethod
@@ -898,4 +913,4 @@ class MagnetometerCalibrationComplete(Thread):
return points
def put_message(self, command, arg):
self.view_queue.put({'cmd': command, 'arg': arg})
self.view_queue.put({'cmd': command, 'arg': arg})
+60 -60
View File
@@ -9,10 +9,7 @@ from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog
import matplotlib as plt
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
# import general packages:
import numpy as np
@@ -26,7 +23,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, MagnetometerCalibrationSimple, MagnetometerCalibrationComplete
from src.calibration import AmbientFieldCalibration, CoilConstantCalibration, MagnetometerCalibrationSimple, \
MagnetometerCalibrationComplete
from src.exceptions import DeviceAccessError
from src.utility import ui_print, save_dict_list_to_csv, load_dict_list_from_csv
import src.helmholtz_cage_device as helmholtz_cage_device
@@ -991,7 +989,7 @@ class CalibrateMagnetometerSimple(Frame):
row_counter = 0
# Create headline
header = Label(self.left_column, text="Magnetometer Calibration\n-simlified method-", font=HEADER_FONT)
header = Label(self.left_column, text="Magnetometer Calibration\n-simplified method-", font=HEADER_FONT)
header.grid(row=row_counter, column=0, columnspan=2, padx=100, pady=20, sticky="nw")
row_counter += 1
@@ -1140,7 +1138,6 @@ class CalibrateMagnetometerSimple(Frame):
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
@@ -1175,8 +1172,8 @@ class CalibrateMagnetometerSimple(Frame):
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)
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")
@@ -1303,9 +1300,9 @@ class CalibrateMagnetometerSimple(Frame):
calibration_points = self.calibration_points_var.get()
calibration_interval = self.calibration_interval_var.get()
self.calibration_thread = MagnetometerCalibrationSimple(self.view_mpi_queue,
calibration_points,
calibration_interval,
self.mgm_to_helmholtz_cos_trans)
calibration_points,
calibration_interval,
self.mgm_to_helmholtz_cos_trans)
self.calibration_thread.start()
self.deactivate_buttons()
except (DeviceAccessError, TclError) as e:
@@ -1364,13 +1361,14 @@ class CalibrateMagnetometerSimple(Frame):
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_max = matrix.max()
# matrix_min = matrix.min()
# matrix = (matrix - matrix_min) / (matrix_max - matrix_min)
def gram_schmidt_columns(x_mat):
q_mat, r_mat = np.linalg.qr(x_mat)
return q_mat
matrix = gram_schmidt_columns(matrix)
ui_print("Normalized matrix (Gram-Schmidt):")
@@ -1385,6 +1383,7 @@ class CalibrateMagnetometerSimple(Frame):
[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)
@@ -1416,17 +1415,16 @@ class CalibrateMagnetometerComplete(Frame):
self.calibration_points_var = IntVar(value=8)
self.calibration_interval_var = DoubleVar(value=5)
# Calibration results
# FLAG
self.a_mat_result_vars = [[DoubleVar(), DoubleVar(), DoubleVar()],
[DoubleVar(), DoubleVar(), DoubleVar()],
[DoubleVar(), DoubleVar(), DoubleVar()],]
[DoubleVar(), DoubleVar(), DoubleVar()], ]
self.a_mat_inv_result_vars = [[DoubleVar(), DoubleVar(), DoubleVar()],
[DoubleVar(), DoubleVar(), DoubleVar()],
[DoubleVar(), DoubleVar(), DoubleVar()],]
[DoubleVar(), DoubleVar(), DoubleVar()], ]
self.b_result_vars = [DoubleVar(), DoubleVar(), DoubleVar()]
self.q_mat_result_vars = [[DoubleVar(), DoubleVar(), DoubleVar()],
[DoubleVar(), DoubleVar(), DoubleVar()],
[DoubleVar(), DoubleVar(), DoubleVar()],]
[DoubleVar(), DoubleVar(), DoubleVar()], ]
self.n_result_vars = [DoubleVar(), DoubleVar(), DoubleVar()]
self.mag_amp_avg_set_result_vars = DoubleVar()
self.total_error_result_vars = DoubleVar()
@@ -1578,14 +1576,14 @@ class CalibrateMagnetometerComplete(Frame):
row_counter += 1
# A_mat_inv
results_label_a_mat_inv = Label(calibration_results_frame, text="A^-1 =")
results_label_a_mat_inv.grid(row=row_counter+1, column=0, padx=5, pady=5, sticky="nw")
results_label_a_mat_inv.grid(row=row_counter + 1, column=0, padx=5, pady=5, sticky="nw")
for row in range(3):
for column in range(3):
axis_data = Entry(calibration_results_frame,
textvariable=self.a_mat_inv_result_vars[row][column],
width=15,
state='readonly')
axis_data.grid(row=row_counter+row, column=1 + column, padx=5, pady=5, sticky="nw")
axis_data.grid(row=row_counter + row, column=1 + column, padx=5, pady=5, sticky="nw")
row_counter += 3
"""
# A_mat
@@ -1604,11 +1602,11 @@ class CalibrateMagnetometerComplete(Frame):
results_label_a_mat_inv = Label(calibration_results_frame, text="b^T =")
results_label_a_mat_inv.grid(row=row_counter, column=0, padx=5, pady=5, sticky="nw")
for row in range(3):
axis_data = Entry(calibration_results_frame,
textvariable=self.b_result_vars[row], #FLAG _result_vars does not compute
width=15,
state='readonly')
axis_data.grid(row=row_counter, column=1 + row, padx=5, pady=5, sticky="nw")
axis_data = Entry(calibration_results_frame,
textvariable=self.b_result_vars[row],
width=15,
state='readonly')
axis_data.grid(row=row_counter, column=1 + row, padx=5, pady=5, sticky="nw")
row_counter += 1
# Save calibration buttons
@@ -1626,9 +1624,9 @@ class CalibrateMagnetometerComplete(Frame):
pady=5, padx=5)
self.copy_calibration_button.grid(row=0, column=1, padx=5, pady=5)
self.import_calibration_data_button = Button(save_calibration_results_frame, text="Import data set",
command=self.import_csv_calibration_raw_data,
state="active",
pady=5, padx=5)
command=self.import_csv_calibration_raw_data,
state="active",
pady=5, padx=5)
self.import_calibration_data_button.grid(row=0, column=2, padx=5, pady=5)
# RIGHT COLUMN
@@ -1695,7 +1693,7 @@ class CalibrateMagnetometerComplete(Frame):
self.calibration_raw_results = results['raw_data']
# Unpack the dict
result = results['results'] # Flag: 'results' replaced with 'raw_data'
result = results['results']
# Display calibration in GUI
self.mag_amp_avg_set_result_vars.set("{:.3e}".format(result[0]['mag_amp_avg_set']))
@@ -1704,7 +1702,6 @@ class CalibrateMagnetometerComplete(Frame):
self.b_result_vars[row].set("{:.3e}".format(result[0]['b'][row][0]))
self.n_result_vars[row].set("{:.3e}".format(result[0]['n'][row][0]))
for column in range(3):
#FLAG
self.a_mat_result_vars[row][column].set("{:.6f}".format(result[0]['a_mat'][row][column]))
self.a_mat_inv_result_vars[row][column].set("{:.6f}".format(result[0]['a_mat_inv'][row][column]))
self.q_mat_result_vars[row][column].set("{:.6f}".format(result[0]['q_mat'][row][column]))
@@ -1732,7 +1729,7 @@ class CalibrateMagnetometerComplete(Frame):
for column in range(3):
self.clipboard += "{:.6e}\t".format(result[0]['q_mat'][row][column])
self.clipboard += "\n"
self.clipboard += "n [-]\n"
self.clipboard += "n [T]\n"
for row in range(3):
self.clipboard += "{:.6e}\t".format(result[0]['n'][row][0])
@@ -1745,9 +1742,9 @@ class CalibrateMagnetometerComplete(Frame):
calibration_points = self.calibration_points_var.get()
calibration_interval = self.calibration_interval_var.get()
self.calibration_thread = MagnetometerCalibrationComplete(self.view_mpi_queue,
calibration_points,
calibration_interval,
self.mgm_to_helmholtz_cos_trans)
calibration_points,
calibration_interval,
self.mgm_to_helmholtz_cos_trans)
self.calibration_thread.start()
self.deactivate_buttons()
except (DeviceAccessError, TclError) as e:
@@ -1774,9 +1771,11 @@ class CalibrateMagnetometerComplete(Frame):
self.calibration_raw_results = raw_data
# Execute calibration function and display results
sensor_parameters, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m, cal_x, cal_y, cal_z, mag_amp_avg_set = MagnetometerCalibrationComplete.solve_system(self.view_mpi_queue, raw_data, self.mgm_to_helmholtz_cos_trans)
MagnetometerCalibrationComplete.plot_magnetometer_calibration(self, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m, cal_x, cal_y,
cal_z, mag_amp_avg_set)
sensor_parameters, mag_x_set, mag_y_set, mag_z_set, mag_x_m, mag_y_m, mag_z_m, cal_x, cal_y, cal_z, mag_amp_avg_set = MagnetometerCalibrationComplete.solve_system(
self.view_mpi_queue, raw_data, self.mgm_to_helmholtz_cos_trans)
MagnetometerCalibrationComplete.plot_magnetometer_calibration(self, mag_x_set, mag_y_set, mag_z_set, mag_x_m,
mag_y_m, mag_z_m, cal_x, cal_y,
cal_z, mag_amp_avg_set)
# Pass results to UI
self.put_message('calibration_data', {'results': sensor_parameters, 'raw_data': raw_data})
@@ -1799,7 +1798,7 @@ class CalibrateMagnetometerComplete(Frame):
ui_print("Saved MGM to Helmholtz coordinate transformation matrix to magnetometer_cos_trans_matrix.csv.")
def put_message(self, command, arg):
self.view_mpi_queue.put({'cmd': command, 'arg': arg}) #FLAG not used?
self.view_mpi_queue.put({'cmd': command, 'arg': arg})
def copy_to_clipboard(self):
self.clipboard_clear()
@@ -1829,13 +1828,14 @@ class CalibrateMagnetometerComplete(Frame):
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_max = matrix.max()
# matrix_min = matrix.min()
# matrix = (matrix - matrix_min) / (matrix_max - matrix_min)
def gram_schmidt_columns(x_mat):
q_mat, r_mat = np.linalg.qr(x_mat)
return q_mat
matrix = gram_schmidt_columns(matrix)
ui_print("Normalized matrix (Gram-Schmidt):")
@@ -2251,7 +2251,7 @@ class ConfigureLogging(Frame):
# generate and place all checkboxes:
row = 0
column = 0
for key, name in log.logging_selection_options.items(): # go through all loggable values
for key, name in log.logging_selection_options.items(): # go through all logging values
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)
@@ -2386,26 +2386,26 @@ class StatusDisplay(Frame):
self.grid_rowconfigure(ALL, weight=1)
self.grid_columnconfigure(ALL, weight=1)
rowCounter = 0 # keep track of which row we are at in the grid layout
row_counter = 0 # keep track of which row we are at in the grid layout
x_pad = 10 # centrally set padding
# create column headers (X-Axis etc.)
col = 0
for header in ["", "X-Axis", "Y-Axis", "Z-Axis"]: # define Column headers
# create label:
headLabel = Label(self, text=header, font=SUB_HEADER_FONT, borderwidth=1,
relief="flat", anchor="w", padx=x_pad)
headLabel.grid(row=rowCounter, column=col, sticky="ew")
head_label = Label(self, text=header, font=SUB_HEADER_FONT, borderwidth=1,
relief="flat", anchor="w", padx=x_pad)
head_label.grid(row=row_counter, column=col, sticky="ew")
col = col + 1 # move to next column
rowCounter += 1 # increase row counter to place future stuff below header
row_counter += 1 # increase row counter to place future stuff below header
# define content of row entries:
TextLabels = ["PSU Serial Port:", "PSU Channel:", "PSU Status:", "Arduino Status:", "", "Output:",
"Remote Control:",
"Voltage Setpoint:", "Actual Voltage:", "Current Setpoint:", "Actual Current:", "",
"Target Field:", "Trgt. Field Raw:", "Target Current:", "Inverted:"]
self.rowNo = len(TextLabels) # get number of label rows
text_labels = ["PSU Serial Port:", "PSU Channel:", "PSU Status:", "Arduino Status:", "", "Output:",
"Remote Control:",
"Voltage Setpoint:", "Actual Voltage:", "Current Setpoint:", "Actual Current:", "",
"Target Field:", "Trgt. Field Raw:", "Target Current:", "Inverted:"]
self.rowNo = len(text_labels) # get number of label rows
self.columnNo = 4 # number of label columns
# prepare list of lists to contain all labels for row entries in all columns:
@@ -2413,7 +2413,7 @@ class StatusDisplay(Frame):
# create dictionary to associate (changing) label variables with their labels:
self.label_dict = {} # initialize dictionary
for name in TextLabels: # go through all rows
for name in text_labels: # go through all rows
self.label_dict[name] = [StringVar() for _ in range(self.columnNo - 1)] # create variables for labels
# add static labels for row titles:
self.Labels[0].append(Label(self, text=name, borderwidth=1, relief="flat", anchor="w", padx=x_pad))
@@ -2426,7 +2426,7 @@ class StatusDisplay(Frame):
col = 0
for LabelCol in self.Labels: # go through table columns
for row in range(self.rowNo): # go through table rows
LabelCol[row].grid(row=row + rowCounter, column=col, sticky="nsew") # place label
LabelCol[row].grid(row=row + row_counter, column=col, sticky="nsew") # place label
col += 1
# Register callback to populate new data: