forked from zietzm/Helmholtz_Test_Bench
Introduced adaptable rotation rates
This commit is contained in:
+83
-37
@@ -14,10 +14,13 @@ import matplotlib.pyplot as plt
|
||||
|
||||
# import general packages:
|
||||
import numpy as np
|
||||
from scipy.optimize import fsolve
|
||||
import os
|
||||
import os.path
|
||||
from datetime import datetime
|
||||
from math import pi
|
||||
import warnings
|
||||
warnings.filterwarnings("error")
|
||||
|
||||
# import other project files:
|
||||
import src.globals as g
|
||||
@@ -411,9 +414,11 @@ class ExecuteCSVMode(Frame):
|
||||
# Generate CSV sequence variables
|
||||
self.rot_vector_vars = [DoubleVar(value=1), DoubleVar(value=0), DoubleVar(value=0)]
|
||||
self.rot_center_vars = [DoubleVar(value=0), DoubleVar(value=0), DoubleVar(value=0)]
|
||||
self.rot_mag_vars = StringVar(value=100)
|
||||
self.rot_rate_vars = StringVar(value=1)
|
||||
self.time_step_vars = StringVar(value=1)
|
||||
self.rot_mag_vars = DoubleVar(value=100)
|
||||
self.rot_time_step_vars = DoubleVar(value=1)
|
||||
self.rot_cycle_number_vars = IntVar(value=1)
|
||||
self.rot_rate_vars = [DoubleVar(value=1), DoubleVar(value=0), DoubleVar(value=0),
|
||||
DoubleVar(value=0), DoubleVar(value=0), DoubleVar(value=0)]
|
||||
|
||||
# --- UI ELEMENTS ---
|
||||
row_counter = 0 # keep track of which grid row we are in
|
||||
@@ -510,7 +515,8 @@ class ExecuteCSVMode(Frame):
|
||||
pady=5, padx=5)
|
||||
self.generate_load_csv_button.grid(row=0, column=1, padx=5, pady=5)
|
||||
row_counter += 1
|
||||
info_text = Label(self, text="Generate data of a circular, counter clockwise motion around an arbitrary axis and strength.",
|
||||
info_text = Label(self,
|
||||
text="Generate data of a circular, counter clockwise motion around an arbitrary axis and strength.",
|
||||
padx=100, pady=3)
|
||||
info_text.grid(row=row_counter, column=col_counter, padx=0, sticky=W)
|
||||
row_counter += 1
|
||||
@@ -549,19 +555,35 @@ class ExecuteCSVMode(Frame):
|
||||
rot_mag_unit = Label(input_csv_gen_frame, text="\u03BCT")
|
||||
rot_mag_unit.grid(row=row_counter, column=4, padx=5, pady=5, sticky="nw")
|
||||
row_counter += 1
|
||||
rot_rate_label = Label(input_csv_gen_frame, text="Rotation rate: ")
|
||||
rot_rate_label.grid(row=row_counter, column=0, padx=5, pady=5, sticky="nw")
|
||||
rot_rate_data = Entry(input_csv_gen_frame, textvariable=self.rot_rate_vars, width=15)
|
||||
rot_rate_data.grid(row=row_counter, column=1, padx=5, pady=5, sticky="nw")
|
||||
rot_rate_unit = Label(input_csv_gen_frame, text="\u00b0/s")
|
||||
rot_rate_unit.grid(row=row_counter, column=4, padx=5, pady=5, sticky="s")
|
||||
row_counter += 1
|
||||
time_step_label = Label(input_csv_gen_frame, text="Time step: ")
|
||||
time_step_label.grid(row=row_counter, column=0, padx=5, pady=5, sticky="nw")
|
||||
time_step_data = Entry(input_csv_gen_frame, textvariable=self.time_step_vars, width=15)
|
||||
time_step_data = Entry(input_csv_gen_frame, textvariable=self.rot_time_step_vars, width=15)
|
||||
time_step_data.grid(row=row_counter, column=1, padx=5, pady=5, sticky="nw")
|
||||
time_step_unit = Label(input_csv_gen_frame, text="s")
|
||||
time_step_unit.grid(row=row_counter, column=4, padx=5, pady=5, sticky="s")
|
||||
time_step_unit.grid(row=row_counter, column=4, padx=5, pady=5, sticky="nw")
|
||||
row_counter += 1
|
||||
time_step_label = Label(input_csv_gen_frame, text="Cycle number: ")
|
||||
time_step_label.grid(row=row_counter, column=0, padx=5, pady=5, sticky="nw")
|
||||
time_step_data = Entry(input_csv_gen_frame, textvariable=self.rot_cycle_number_vars, width=15)
|
||||
time_step_data.grid(row=row_counter, column=1, padx=5, pady=5, sticky="nw")
|
||||
time_step_unit = Label(input_csv_gen_frame, text="-")
|
||||
time_step_unit.grid(row=row_counter, column=4, padx=5, pady=5, sticky="nw")
|
||||
row_counter += 1
|
||||
rot_rate_label = Label(input_csv_gen_frame, text="Rotation rate: ")
|
||||
rot_rate_label.grid(row=row_counter, column=0, padx=5, pady=5, sticky="nw")
|
||||
for i in range(3):
|
||||
for j in range(2):
|
||||
rot_rate_data = Entry(input_csv_gen_frame, textvariable=self.rot_rate_vars[i + 3 * j], width=15)
|
||||
rot_rate_data.grid(row=row_counter + j, column=1 + i, padx=5, pady=5, sticky="nw")
|
||||
rot_rate_unit = Label(input_csv_gen_frame, text="\u00b0/s, \u00b0/s^2, \u00b0/s^3")
|
||||
rot_rate_unit.grid(row=row_counter, column=4, padx=5, pady=5, sticky="nw")
|
||||
row_counter += 1
|
||||
rot_rate_unit = Label(input_csv_gen_frame, text="\u00b0/s, 1/s, -")
|
||||
rot_rate_unit.grid(row=row_counter, column=4, padx=5, pady=5, sticky="nw")
|
||||
row_counter += 1
|
||||
|
||||
rot_rate_label = Label(input_csv_gen_frame, text="r(t) = r_0 + r_1*t + r_2*t^2 + r3 * sin( r_4*t + r_5 )")
|
||||
rot_rate_label.grid(row=row_counter, column=1, columnspan=4, padx=5, pady=5, sticky="nw")
|
||||
|
||||
def page_switch(self): # function that is called when switching to this window
|
||||
# every class in the UI needs this, even if it doesn't do anything
|
||||
@@ -709,12 +731,14 @@ class ExecuteCSVMode(Frame):
|
||||
# Initialize and get vectors
|
||||
rot_vector = [0, 0, 0]
|
||||
rot_center = [0, 0, 0]
|
||||
r = [0, 0, 0, 0, 0, 0]
|
||||
for i in range(len(rot_vector)):
|
||||
rot_vector[i] = float(self.rot_vector_vars[i].get()) # [-]
|
||||
rot_center[i] = float(self.rot_center_vars[i].get()) # [uT]
|
||||
rot_mag = float(self.rot_mag_vars.get()) # [uT]
|
||||
rot_rate = float(self.rot_rate_vars.get()) # [deg/s]
|
||||
rot_time_step = float(self.time_step_vars.get()) # [s]
|
||||
for i in range(len(r)):
|
||||
r[i] = float(self.rot_rate_vars[i].get()) # [deg/s, deg/s^2, deg/s^3, deg/s, 1/s, -]
|
||||
rot_time_step = float(self.rot_time_step_vars.get()) # [s]
|
||||
# Normalize rotation vector
|
||||
if np.linalg.norm(rot_vector) == 0:
|
||||
ui_print("Error: Rotation axis cannot be singular.")
|
||||
@@ -737,22 +761,11 @@ class ExecuteCSVMode(Frame):
|
||||
rot_mag = rot_mag_default
|
||||
self.rot_mag_vars.set("{:.3f}".format(rot_mag))
|
||||
# Checking center point
|
||||
if np.sqrt(rot_center[0]**2+rot_center[1]**2+rot_center[2]**2) > rot_center_geom_mean_max:
|
||||
if np.sqrt(rot_center[0] ** 2 + rot_center[1] ** 2 + rot_center[2] ** 2) > rot_center_geom_mean_max:
|
||||
ui_print("Warning: Rotation center excessive. Setting to zero automatically.")
|
||||
rot_center = rot_center_default
|
||||
for i in range(len(rot_center)):
|
||||
self.rot_center_vars[i].set("{:.3f}".format(rot_center[i]))
|
||||
# Checking rotation rate
|
||||
if rot_rate < 0:
|
||||
ui_print("Warning: Rotation rate cannot be negative. Changing sign automatically.")
|
||||
rot_rate = -rot_rate
|
||||
elif rot_mag == 0:
|
||||
ui_print("Warning: Rotation rate cannot be zero. Setting default automatically.")
|
||||
rot_rate = rot_rate_default
|
||||
elif rot_rate > rot_rate_max:
|
||||
ui_print("Warning: Rotation rate too large. Setting default automatically.")
|
||||
rot_rate = rot_rate_default
|
||||
self.rot_rate_vars.set("{:.3f}".format(rot_rate))
|
||||
# Check time step
|
||||
if rot_time_step < 0:
|
||||
ui_print("Warning: Time step cannot be negative. Changing sign automatically.")
|
||||
@@ -763,16 +776,48 @@ class ExecuteCSVMode(Frame):
|
||||
elif rot_time_step < rot_time_step_min:
|
||||
ui_print("Warning: Time step too small. Setting default automatically.")
|
||||
rot_time_step = rot_time_step_default
|
||||
self.time_step_vars.set("{:.3f}".format(rot_time_step))
|
||||
self.rot_time_step_vars.set("{:.3f}".format(rot_time_step))
|
||||
# Check cycle number
|
||||
rot_cycle_number = self.rot_cycle_number_vars.get()
|
||||
if rot_cycle_number < 1:
|
||||
ui_print("Warning: cycle number cannot be smaller than one!")
|
||||
rot_cycle_number = 1
|
||||
elif isinstance(rot_cycle_number, float):
|
||||
if not rot_cycle_number.is_integer():
|
||||
ui_print("Warning: cycle number must be an integer. Rounding to nearest integer")
|
||||
rot_cycle_number = round(rot_cycle_number)
|
||||
self.rot_cycle_number_vars.set("{:d}".format(rot_cycle_number))
|
||||
# Variable rotation rate
|
||||
# Solve integral of r(t) = r_0 + r_1 * t + r_2 * t ^ 2 + r3 * sin(r_4 * t + r_5) from 0 to tau
|
||||
func = lambda tau2: r[0] + r[1] * tau2 + r[2] * tau2 ** 2 + r[3] * (np.sin(r[4] * tau2 + r[5]))
|
||||
func_integral = lambda tau: 360 - (r[0] * tau + r[1] / 2 * tau ** 2 + r[2] / 3 * tau ** 3
|
||||
- r[3] * (np.cos(r[4] * tau + r[5]) + np.cos(r[5]))
|
||||
+ r[3] * r[4] * (np.sin(r[4] * tau + r[5]) - np.sin(r[5])))
|
||||
tau_solution = -1
|
||||
i = 0 # iterator and guess variable [s]
|
||||
while tau_solution < 0 or abs(func_integral(tau_solution)) > 0.5:
|
||||
tau_initial_guess = i
|
||||
try:
|
||||
tau_solution = fsolve(func_integral, tau_initial_guess)
|
||||
except RuntimeWarning as w:
|
||||
ui_print("Calculating the cycle time yielded: ", w)
|
||||
i = i + 1
|
||||
if i == 1000:
|
||||
ui_print(
|
||||
"Warning: the user inputs for a rotation rate lead to no solution. Rate inputs reset to default")
|
||||
r = [1, 0, 0, 0, 0, 0, 0]
|
||||
for j in range(6): self.rot_rate_vars[j].set("{:.3f}".format(r[j]))
|
||||
ui_print(
|
||||
"The cycle_time is tau = {:3f} with f(tau) = {:3f}".format(tau_solution[0], func_integral(tau_solution)[0]))
|
||||
# Calculate timing
|
||||
cycle_time = tau_solution
|
||||
arr_len = int(np.floor(cycle_time / rot_time_step)) * rot_cycle_number
|
||||
# Find perpendicular vectors
|
||||
if v[1] == 0 and v[2] == 0:
|
||||
a = np.cross(v, [0, 1, 0])
|
||||
else:
|
||||
a = np.cross(v, [1, 0, 0])
|
||||
b = np.cross(v, a)
|
||||
# Calculate timing
|
||||
cycle_time = (360 / rot_rate)
|
||||
arr_len = int(np.floor(cycle_time / rot_time_step))
|
||||
# Initialize vectors
|
||||
th = 0 # [rad]
|
||||
t = np.zeros(arr_len) # [s]
|
||||
@@ -781,11 +826,12 @@ class ExecuteCSVMode(Frame):
|
||||
z = np.zeros(arr_len) # [T]
|
||||
# Calculate vectors
|
||||
for i in range(arr_len):
|
||||
th = th + rot_rate * np.pi / 180 * rot_time_step
|
||||
t[i] = i * rot_time_step
|
||||
x[i] = (rot_center[0] + rot_mag * np.cos(th) * a[0] + rot_mag * np.sin(th) * b[0])*1e-6
|
||||
y[i] = (rot_center[1] + rot_mag * np.cos(th) * a[1] + rot_mag * np.sin(th) * b[1])*1e-6
|
||||
z[i] = (rot_center[2] + rot_mag * np.cos(th) * a[2] + rot_mag * np.sin(th) * b[2])*1e-6
|
||||
rot_rate = func(t[i])
|
||||
th = th + rot_rate * np.pi / 180 * rot_time_step
|
||||
x[i] = (rot_center[0] + rot_mag * np.cos(th) * a[0] + rot_mag * np.sin(th) * b[0]) * 1e-6
|
||||
y[i] = (rot_center[1] + rot_mag * np.cos(th) * a[1] + rot_mag * np.sin(th) * b[1]) * 1e-6
|
||||
z[i] = (rot_center[2] + rot_mag * np.cos(th) * a[2] + rot_mag * np.sin(th) * b[2]) * 1e-6
|
||||
# Return vectors
|
||||
return t, x, y, z
|
||||
|
||||
@@ -1618,7 +1664,7 @@ class CalibrateMagnetometerSimple(Frame):
|
||||
try:
|
||||
calibration_points = self.calibration_points_var.get()
|
||||
calibration_interval = self.calibration_interval_var.get()
|
||||
compensated_field = self.self.compensated_field_var .get()
|
||||
compensated_field = self.self.compensated_field_var.get()
|
||||
calibration_mag_field = self.mag_field_magnitude_var.get() * 1e-6 # converted to micro Tesla
|
||||
if calibration_mag_field <= 0 or calibration_mag_field > g.MAG_MAG_FIELD:
|
||||
raise MagFieldOutOfBounds
|
||||
@@ -2159,7 +2205,7 @@ class CalibrateMagnetometerComplete(Frame):
|
||||
calibration_interval = self.calibration_interval_var.get()
|
||||
calibration_mag_field = self.mag_field_magnitude_var.get() * 1e-6 # converted to micro Tesla
|
||||
calibration_oversampling = self.calibration_oversampling_var.get()
|
||||
compensated_field = self.compensated_field_var.get()
|
||||
compensated_field = self.compensated_field_var.get()
|
||||
if calibration_mag_field <= 0 or calibration_mag_field > g.MAG_MAG_FIELD:
|
||||
raise MagFieldOutOfBounds
|
||||
self.calibration_thread = MagnetometerCalibrationComplete(self.view_mpi_queue,
|
||||
|
||||
Reference in New Issue
Block a user