Introduced adaptable rotation rates

This commit is contained in:
2023-02-20 16:51:30 +01:00
parent 6194035099
commit 5662a73345
+83 -37
View File
@@ -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,