Changed csv plots to show instantaneous field changes

This commit is contained in:
Martin Zietz
2021-02-24 16:43:22 +01:00
parent d3b41cae7c
commit ff0f0331dc
4 changed files with 25 additions and 11 deletions
+3 -3
View File
@@ -30,7 +30,7 @@ SMALL_BUTTON_FONT = ("Arial", 9)
class HelmholtzGUI(Tk):
# main application window, almost everything else here es called from this class
# main application window, almost everything else here is called from this class
# Inherited base class: Tk(), main application window class
def __init__(self):
Tk.__init__(self)
@@ -84,7 +84,7 @@ class TopMenu:
window.config(menu=menu) # put menu at the top of the window
ModeSelector = Menu(menu) # create a submenu object
menu.add_cascade(label="Mode", menu=ModeSelector) # add a dropdown with the submenu object
menu.add_cascade(label="Menu", menu=ModeSelector) # add a dropdown with the submenu object
# create the different options in the dropdown:
ModeSelector.add_command(label="Static Manual Input", command=lambda: self.manual_mode(window))
ModeSelector.add_command(label="Execute CSV Sequence", command=lambda: self.execute_csv_mode(window))
@@ -451,7 +451,7 @@ class ExecuteCSVMode(Frame):
self.stop_button["state"] = "normal"
self.reinit_button["state"] = "disabled"
# setup thread for running the sequence:
# setup thread for running the sequence
# More info: https://www.tutorialspoint.com/python/python_multithreading.htm
g.threadLock = threading.Lock() # create thread locking object, used to ensure all devices switch at once later
# create thread object:
+4 -3
View File
@@ -22,7 +22,7 @@ class Axis:
def __init__(self, index, device, PSU_channel, arduino_pin):
# static information
self.index = index # index of this axis, 0->X, 1->Y, 2->Z
self.device = device # power supply object for this axis (PS2000B class)
self.device = device # power supply object for this axis (PS2000B class object)
self.channel = PSU_channel # power supply unit channel (0 or 1)
self.ardPin = arduino_pin # output pin on the arduino for switching polarity on this axis
@@ -94,7 +94,7 @@ class Axis:
else: # no communications error
self.connected = "Connected" # PSU is connected
def print_status(self): # print out the current status of the device (not used at the moment)
def print_status(self): # print out the current status of the PSU channel (not used at the moment)
ui_print("%s, %0.2f V, %0.2f A"
% (self.device.get_device_status_information(self.channel),
self.device.get_voltage(self.channel), self.device.get_current(self.channel)))
@@ -235,7 +235,8 @@ def setup_all(): # main test stand initialization function
# this throws an exception, which can be ignored
g.ARDUINO = ArduinoCtrl() # initialize the arduino object from the control class, connects and sets up
except Exception as e: # some unforeseen error occurred
except Exception as e: # some unforeseen error occurred (not connected issue handled in ArduinoCtrl class)
# show error messages to alert user
ui_print("Arduino setup failed:", e)
ui_print(traceback.print_exc())
+17 -4
View File
@@ -4,6 +4,7 @@
# import packages:
import time
import pandas
import numpy as np
from threading import *
from tkinter import messagebox
import matplotlib.pyplot as plt
@@ -13,6 +14,7 @@ import User_Interface as ui
import cage_func as func
import globals as g
import traceback # ToDo: remove!
class ExecCSVThread(Thread):
# main class for executing a CSV sequence
@@ -28,7 +30,7 @@ class ExecCSVThread(Thread):
self.__stop_event = Event() # event which can be set to stop the thread execution if needed
def run(self): # called to start the execution of the thread
ui.ui_print("Starting Sequence Execution...")
ui.ui_print("\nStarting Sequence Execution...")
self.execute_sequence(self.array, 0.1, self.parent, self.controller) # run sequence
# when the sequence has ended, reset buttons on the UI:
if not g.exitFlag: # main window is open
@@ -130,7 +132,6 @@ def check_array_ok(array):
def plot_field_sequence(array, width, height): # create plot of fixed size (pixels) from array
# ToDo (optional): polar plots, plots of angle...
# ToDo (optional): show graphs as steps (as performed by test stand)
fig_dpi = 100 # set figure resolution (dots per inch)
px = 1/fig_dpi # get pixel to inch size conversion
figure = plt.Figure(figsize=(width*px, height*px), dpi=fig_dpi) # create figure with correct size
@@ -140,9 +141,21 @@ def plot_field_sequence(array, width, height): # create plot of fixed size (pix
figure.suptitle("Magnetic Field Sequence") # set figure title
t = array[:, 0] # extract time column
# modify data to show instantaneous jumps in field to reflect test stand operation
new_array = np.array([[0, 0, 0, 0]], dtype=float) # initialize modified array, zeros to show start from no fields
last_vals = [0, 0, 0] # [x,y,z] field values from last data point (zero here), used to create step in data
for row in array[:, 0:4]: # go through each row in the original array
# create extra datapoint at current timestamp, with field values from last, this creates "step" in plot:
new_array = np.append(new_array, [[row[0], *last_vals]], axis=0)
new_array = np.append(new_array, [row], axis=0) # add actual datapoint for current timestamp
last_vals = row[1:4] # save values from current timestamp for next
new_array = np.append(new_array, [[new_array[-1, 0], 0, 0, 0]], axis=0) # append last datapoint with 0 fields
# extract data and plot:
t = new_array[:, 0] # extract time column
for i in [0, 1, 2]: # go through all three axes
data = array[:, i + 1] * 1e6 # extract field column of this axis and convert to microtesla
data = new_array[:, i + 1] * 1e6 # extract field column of this axis and convert to microtesla
max_val = g.AXES[i].max_comp_field[1] * 1e6 # get limits of achievable field
min_val = g.AXES[i].max_comp_field[0] * 1e6
plot = axes[i] # get appropriate subplot
+1 -1
View File
@@ -29,7 +29,7 @@ exitFlag = True # False when main window is open, True otherwise
# Create dictionaries with default Constants and maximum/minimum values
# Used to create default configs and to check if user inputs are within safe limits
# ToDo: check actual maximum ratings (or refine after testing)
# ToDo: check actual maximum ratings / refine after testing
# ToDo: put this into a config file
# Dictionary for numerical values: