diff --git a/User_Interface.py b/User_Interface.py index a7c6f1f..3967320 100644 --- a/User_Interface.py +++ b/User_Interface.py @@ -279,7 +279,6 @@ class Configuration(Frame): self.file_select_frame.grid(row=row_counter, column=0, sticky=W, padx=20) # Create and place buttons - # ToDo: comments load_file_button = Button(self.file_select_frame, text="Load config file...", command=self.load_config, pady=5, padx=5, font=SMALL_BUTTON_FONT) load_file_button.grid(row=0, column=0, padx=5) @@ -299,17 +298,17 @@ class Configuration(Frame): port_frame.grid(row=row_counter, column=0, sticky=W) entry_texts = ["XY PSU Serial Port:", "Z PSU Serial Port:"] - self.XY_port = StringVar(value=g.XY_PORT) + self.XY_port = StringVar(value=g.XY_PORT) # create variables to store the port names and set to current names self.Z_port = StringVar(value=g.Z_PORT) port_vars = [self.XY_port, self.Z_port] row = 0 for text in entry_texts: - field = Entry(port_frame, textvariable=port_vars[row]) + field = Entry(port_frame, textvariable=port_vars[row]) # create entry field field.grid(row=row, column=1, sticky=W) axis_label = Label(port_frame, text=text, padx=5, pady=10) axis_label.grid(row=row, column=0, sticky=W) - unit_label = Label(port_frame, text="e.g. COM10") - unit_label.grid(row=row, column=2, sticky=W) + info_label = Label(port_frame, text="e.g. COM10") + info_label.grid(row=row, column=2, sticky=W) row += 1 row_counter += 1 @@ -514,7 +513,6 @@ class Configuration(Frame): class ExecuteCSVMode(Frame): # generate configuration window to set program constants - # ToDo (optional): Generate graph to show sequence to be executed def __init__(self, parent, controller): Frame.__init__(self, parent) @@ -606,13 +604,13 @@ class ExecuteCSVMode(Frame): if exists(filename): # does the file exist? ui_print("File selected:", filename) try: - self.sequence_array = csv.read_csv_to_array(filename) + self.sequence_array = csv.read_csv_to_array(filename) # read array from csv except BaseException as e: ui_print("Error while opening file:", e) messagebox.showerror("Error!", "Error while opening file: \n%s" % e) - csv.check_array(self.sequence_array) - self.display_plot() + csv.check_array_ok(self.sequence_array) # check for values exceeding limits + self.display_plot() # plot data and display self.execute_button["state"] = "normal" # activate run button elif filename == '': # this happens when file selection window is closed without selecting a file @@ -641,8 +639,8 @@ class ExecuteCSVMode(Frame): self.stop_button["state"] = "disabled" self.reinit_button["state"] = "normal" - def display_plot(self): # ToDo: comments - # calculate available height for plot: + def display_plot(self): + # calculate available height for plot (in pixels): height_others = 0 for element in self.row_elements: # go through all rows in the widget except the plot frame height_others += element.winfo_height() # add up heights @@ -650,10 +648,10 @@ class ExecuteCSVMode(Frame): width = min(self.parent.winfo_width() - 100, 1100) # set width to available space but max. 1100 - figure = csv.plot_field_sequence(self.sequence_array, width, height) - plotCanvas = FigureCanvasTkAgg(figure, self.plotFrame) - plotCanvas.draw() - plotCanvas.get_tk_widget().grid(row=0, column=0, sticky="nesw") + figure = csv.plot_field_sequence(self.sequence_array, width, height) # create figure to be displayed + plotCanvas = FigureCanvasTkAgg(figure, self.plotFrame) # create canvas to draw figure on + plotCanvas.draw() # equivalent to matplotlib.show() + plotCanvas.get_tk_widget().grid(row=0, column=0, sticky="nesw") # place canvas in UI class StatusDisplay(Frame): diff --git a/cage_func.py b/cage_func.py index 0d07be8..ab6355b 100644 --- a/cage_func.py +++ b/cage_func.py @@ -364,16 +364,17 @@ def set_current_vec(vector): # sets needed currents on each axis for given vect def devices_ok(xy_off=False, z_off=False, arduino_off=False): - # ToDo: comments - try: - if not xy_off: - if g.XY_DEVICE is not None: - g.X_AXIS.update_status_info() - if g.X_AXIS.connected != "Connected": - return False - else: + # check if all devices are connected, return True if yes + # checks for individual devices can be disabled by parameters above (default not disabled) + try: # handle errors while checking connections + if not xy_off: # if check for this device is not disabled + if g.XY_DEVICE is not None: # has the handle for this device been set? + g.X_AXIS.update_status_info() # update info --> this actually communicates with the device + if g.X_AXIS.connected != "Connected": # if not connected + return False # return and exit function + else: # if handle has not been set the device is inactive --> not ok return False - if not z_off: + if not z_off: # same as above if g.Z_DEVICE is not None: g.Z_AXIS.update_status_info() if g.Z_AXIS.connected != "Connected": @@ -381,12 +382,12 @@ def devices_ok(xy_off=False, z_off=False, arduino_off=False): else: return False - if not arduino_off: - g.ARDUINO.update_status_info() + if not arduino_off: # check not disabled + g.ARDUINO.update_status_info() # update status info --> attempts communication if g.ARDUINO.connected != "Connected": return False - except Exception as e: - messagebox.showerror("Error!", "Error while checking devices: \n%s" % e) - return False - else: + except Exception as e: # if an error is encountered while checking the devices + messagebox.showerror("Error!", "Error while checking devices: \n%s" % e) # show error pop-up + return False # clearly something is not ok + else: # if nothing has triggered so far all devices are ok --> return True return True diff --git a/csv_threading.py b/csv_threading.py index b814ef3..e49c0dc 100644 --- a/csv_threading.py +++ b/csv_threading.py @@ -11,7 +11,6 @@ import globals as g class ExecCSVThread(Thread): - # ToDo: handling for disconnected devices def __init__(self, threadID, array, parent, controller): Thread.__init__(self) @@ -79,46 +78,57 @@ def execute_sequence(array, delay, parent, controller): # runs through array co def read_csv_to_array(filepath): # csv format: time (s); xField (T); yField (T); zField (T) (german excel) # decimal commas - ui.ui_print("Reading File:", filepath) file = pandas.read_csv(filepath, sep=';', decimal=',', header=0) # read csv file array = file.to_numpy() # convert csv to array return array -def check_array(array): - # ToDo: message formatting, pop up warning - # ToDo: comments - concerns = [] - for row in array: - i = 1 - for axis in g.AXES: - value = row[i] - if value > axis.max_comp_field[1]: - concerns.append(row) - elif value < axis.max_comp_field[0]: - concerns.append(row) - i += 1 - ui.ui_print("Checked csv, found %i concerns." % len(concerns)) - if len(concerns) > 0: - ui.ui_print(concerns) +def check_array_ok(array): # check if any magnetic fields in an array exceed the limits + values_ok = True + for i in [0, 1, 2]: # go through axes + max_val = g.AXES[i].max_comp_field[1] # get limits + min_val = g.AXES[i].max_comp_field[0] + data = array[:, i + 1] # extract data for this axis from array + # noinspection PyTypeChecker + if any(data > max_val) or any(data < min_val): # if any datapoint is out of bounds + values_ok = False + if not values_ok: # show warning pop-up if values are exceeding limits + messagebox.showwarning("Value Limits Warning!", "Found field values exceeding limits of test stand." + "\nSee plot and check values in csv.") -def plot_field_sequence(array, width, height): # ToDo: comments - # ToDo: make pretty - fig_dpi = 100 - px = 1/fig_dpi - figure = plt.Figure(figsize=(width*px, height*px), dpi=fig_dpi) +def plot_field_sequence(array, width, height): # create plot of fixed size 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 + 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 # noinspection PyTypeChecker,SpellCheckingInspection - axes = figure.subplots(3, sharex=True, sharey=True, gridspec_kw={'hspace': 0.4}) + axes = figure.subplots(3, sharex=True, sharey=True, gridspec_kw={'hspace': 0.4}) # create subplots with shared axes figure.suptitle("Magnetic Field Sequence") - t = array[:, 0] - for i in [0, 1, 2]: - data = array[:, i + 1] * 1e6 - plot = axes[i] - plot.plot(t, data) - plot.set_title(g.AXIS_NAMES[i]) + t = 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 + 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 - return figure + plot.plot(t, data, linestyle='solid', marker='.') # plot data + + if any(data > max_val): # if any value is higher than the maximum + plot.axhline(y=max_val, linestyle='dashed', color='r') # plot horizontal line to show maximum + # add label to line: + plot.text(t[-1], max_val, "max", horizontalalignment='center', verticalalignment='top', color='r') + if any(data < min_val): # same as above + plot.axhline(y=min_val, linestyle='dashed', color='r') + plot.text(t[-1], min_val, "min", horizontalalignment='center', color='r') + plot.set_title(g.AXIS_NAMES[i], size=10) # set subplot title (e.g. "X-Axis") + + # set shared axis labels: + axes[2].set_xlabel("Time (s)") + axes[1].set_ylabel("Magnetic Field (\u03BCT)") + + return figure # return the created figure to be inserted somewhere else diff --git a/out of bounds.csv b/out of bounds.csv new file mode 100644 index 0000000..d3c377e --- /dev/null +++ b/out of bounds.csv @@ -0,0 +1,12 @@ +Time (s);xField (T);yField (T);zField (T); +0;0,00015;-0,00015;0,00002;150 +1;0,00017;-0,00017;0,00002;170 +2;0,00018;-0,00018;0,00002;180 +3;0,00019;-0,00019;0,00002;190 +4;0,0002;-0,0002;0,00002;200 +5;0,00021;-0,00021;0,00002;210 +6;0,00022;-0,00022;0,00002;220 +7;0,0002;-0,0002;0,00002;200 +8;0,00018;-0,00018;0,00002;180 +9;0,00005;-0,00005;0,00002;50 +10;-0,00004;0,00004;0,00002;-40