From ff0f0331dc7b9b5f3ff1dd4552944c49ce25ffe2 Mon Sep 17 00:00:00 2001 From: Martin Zietz Date: Wed, 24 Feb 2021 16:43:22 +0100 Subject: [PATCH] Changed csv plots to show instantaneous field changes --- User_Interface.py | 6 +++--- cage_func.py | 7 ++++--- csv_threading.py | 21 +++++++++++++++++---- globals.py | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/User_Interface.py b/User_Interface.py index 94cb111..d56c128 100644 --- a/User_Interface.py +++ b/User_Interface.py @@ -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: diff --git a/cage_func.py b/cage_func.py index 75dd911..bd834de 100644 --- a/cage_func.py +++ b/cage_func.py @@ -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()) diff --git a/csv_threading.py b/csv_threading.py index 6ec1fc8..528ac42 100644 --- a/csv_threading.py +++ b/csv_threading.py @@ -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 diff --git a/globals.py b/globals.py index 281add2..ffaf387 100644 --- a/globals.py +++ b/globals.py @@ -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: