forked from zietzm/Helmholtz_Test_Bench
Cleaned up minor issues
This commit is contained in:
+61
-46
@@ -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
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user