Browse Source

steamlined dataflow

subDesTagesMitExtraKaese 4 years ago
parent
commit
deb631cced
6 changed files with 104 additions and 60 deletions
  1. 13 5
      software/appWindow.py
  2. 52 18
      software/database.py
  3. 10 4
      software/ui/Page_1.py
  4. 11 6
      software/ui/Page_2.py
  5. 1 21
      software/ui/Plot.py
  6. 17 6
      software/ui/plotim.py

+ 13 - 5
software/appWindow.py

@@ -17,9 +17,14 @@ import time
 
 class Main(tk.Tk, Table):
   def __init__(self, *args, **kwargs):
+    print('initializing window...')
     tk.Tk.__init__(self, *args, **kwargs)
     tk.Tk.wm_title(self, "Windkanal-Tool")
 
+    #early response to user
+    self.update_idletasks()
+
+    print('initializing sensors...')
     self.adc = MCP3008(0,0)
     self.pressureSensors = Spd610Array()
     self.forceSensors = LoadCells()
@@ -29,16 +34,17 @@ class Main(tk.Tk, Table):
 
     self.motorEnabled = False
     
+    print('initializing database...')
     Table.__init__(self, 
-    ["time", "windspeed", "motor_pwm"] + 
+    ["windspeed", "motor_pwm"] + 
     ["pressure_{}".format(i) for i in range(8)] + 
     ["adc_{}".format(i) for i in range(1)] + 
     ["force_X_1", "force_Y_1", "force_Z_1"] +
     ["force_X_2", "force_Y_2", "force_Z_2"] + 
     ["force_X_3", "force_Y_3", "force_Z_3"])
-    
-    self.saveAsCsv("test.csv")
 
+
+    print('initializing GUI...')
     container = tk.Frame(self)
     container.pack(side="top", fill="both", expand = True)
     container.grid_rowconfigure(0, weight=1)
@@ -86,7 +92,9 @@ class Main(tk.Tk, Table):
 
     self.show_frame(Page_1)
 
-    self.interval()
+    self.after(5000,self.interval)
+
+    print('program ready!')
 
   def show_frame(self, cont):
     self.currentFrame = self.frames[cont]
@@ -113,7 +121,7 @@ class Main(tk.Tk, Table):
     i2cValues = self.pressureSensors.getValues()
 
     self.addRow(
-      [time.time(), windSpeed, pwmValue] + 
+      [windSpeed, pwmValue] + 
       i2cValues +
       [adcValue] +
       self.forceSensors.getForces(0) +

+ 52 - 18
software/database.py

@@ -1,34 +1,68 @@
-
+import numpy as np
+from datetime import datetime
 import csv
 
 class Table:
-  columnNames = []
-  rows = []
-  def __init__(self, columns):
-    self.columnNames = columns
+  def __init__(self, columns, nRows = 2**16):
+    self.columnNames = ['datetime'] + columns
+    self.nCols = len(columns)
+    self.nRows = nRows
+    self.rows = self.ys = np.ndarray(shape=(self.nRows, self.nCols), dtype=float)
+    self.rows.fill(float('NaN'))
+    self.timestamps = np.ndarray(shape=(self.nRows), dtype='datetime64[ns]')
+    self.rowIndex = 0
+
+  def rowIdToOffset(self, id):
+    return self.nRows - (id % self.nRows) - 1
 
   def addRow(self, values):
-    self.rows.append(values)
+    offset = self.rowIdToOffset(self.rowIndex)
+    self.rows[offset] = values
+    self.timestamps[offset] = datetime.now()
+    self.rowIndex += 1
 
-  def getLastRow(self):
-    if len(self.rows) > 0:
-      return self.rows[len(self.rows)-1]
+  def getLastRows(self, n):
+    nRead = min(n, self.nRows)
+    readStart = self.rowIdToOffset(self.rowIndex - 1)
+    readEnd = self.rowIdToOffset(self.rowIndex - nRead - 1)
+    if readEnd > readStart:
+      return self.rows[readStart:readEnd]
     else:
-      return [0] * len(self.columnNames)
+      return np.concatenate((self.rows[readStart:], self.rows[:readEnd]), axis=0)
 
-  def getLastValue(self, column):
+  def getLastTimestamps(self, n):
+    nRead = min(n, self.nRows)
+    readStart = self.rowIdToOffset(self.rowIndex - 1)
+    readEnd = self.rowIdToOffset(self.rowIndex - nRead - 1)
+    if readEnd > readStart:
+      return self.timestamps[readStart:readEnd]
+    else:
+      return np.concatenate((self.timestamps[readStart:], self.timestamps[:readEnd]), axis=0)
+
+
+  def getLastValues(self, n, column):
     col = self.columnNames.index(column)
-    return self.getLastRow()[col]
+    if col > 0:
+      return self.getLastRows(n)[:,col-1]
+    else:
+      return self.getLastTimestamps(n)
+
+  def getLastValue(self, column):
+    return self.getLastValues(1, column)[0]
 
   def saveAsCsv(self, filename):
     with open(filename,"w+", newline='') as my_csv:
       csvWriter = csv.writer(my_csv,delimiter=',')
       csvWriter.writerow(self.columnNames)
-      csvWriter.writerows(self.rows)
+      timestamps = self.getLastTimestamps(self.rowIndex)
+      for ts, vals in zip(self.getLastTimestamps(self.rowIndex), self.getLastRows(self.rowIndex)):
+        csvWriter.writerow([ts] + list(vals))
 
 if __name__ == "__main__":
-  t = Table(["time", "col1", "col2"])
-  t.addRow([time.time(), 1, 2])
-  t.addRow([time.time(), 3, 4])
-  print(len(t.rows))
-  print(t.getLastRow())
+  t = Table(["col1", "col2"])
+  for i in range(99):
+    t.addRow([i, 2])
+  print(t.getLastRows(100))
+  t.addRow([3, 4])
+  print(t.getLastRows(1))
+  t.saveAsCsv('test.csv')

+ 10 - 4
software/ui/Page_1.py

@@ -1,19 +1,21 @@
 import tkinter as tk
 import tk_tools
-import time
+import numpy as np
+from datetime import datetime
 from .Plot import Plot
 from .globals import *
 
 class Page_1(tk.Frame):
+  plotLen = 100
   def __init__(self, parent, controller):
     tk.Frame.__init__(self, parent)
     self.t = 0
     self.controller = controller
 
     # graph
-    self.serialPlot = Plot(nPoints=100, xaxis=(0, 100), yaxis=(0, 5), nGraphs=2,
+    self.serialPlot = Plot(xaxis=(0, self.plotLen * .3), yaxis=(0, 5),
                       ytitle="Windgeschwindigkeit m/s",
-                      xtitle="Messpunkte [1/3-Sekunde]",
+                      xtitle="vergangene Zeit in s",
                       title="Geschwindigkeitsverlauf",
                       line_colors=["#2222ff", "#22ff22", "#ff2222"])
 
@@ -44,6 +46,10 @@ class Page_1(tk.Frame):
     controller.pid.SetPoint = 0.4 # m/s
 
   def update(self, visible):
-    self.serialPlot.update([self.controller.getLastValue("adc_0"), (time.time()/0.3) % 1 * 5], visible=visible)
     if visible:
+      timestamps = (np.datetime64(datetime.now()) - self.controller.getLastValues(self.plotLen, "datetime")) / np.timedelta64(1,'s')
+      self.serialPlot.plot_data(
+        xs=[timestamps, timestamps],
+        ys=[self.controller.getLastValues(self.plotLen, "adc_0"), np.linspace(0, 5, self.plotLen)]
+      )
       self.label4.config(text="{:5.3f} V".format(self.controller.getLastValue("adc_0")))

+ 11 - 6
software/ui/Page_2.py

@@ -1,9 +1,12 @@
 import tkinter as tk
 import tk_tools
+import numpy as np
+from datetime import datetime
 from .Plot import Plot
 from .globals import *
 
 class Page_2(tk.Frame):
+  plotLen = 100
   def __init__(self, parent, controller):
     tk.Frame.__init__(self, parent)
     self.controller = controller
@@ -11,17 +14,19 @@ class Page_2(tk.Frame):
     label.pack(pady=10,padx=10)
     
     # graphs
-    self.forcePlot = Plot(nPoints=100, xaxis=(-2, 2), yaxis=(-2, 2), nGraphs=3,
+    self.forcePlot = Plot(xaxis=(-2, 2), yaxis=(-2, 2),
           ytitle="y-Kraft [mV]",
           xtitle="x-Kraft [mV]",
           title="XY-Graph",
-          line_colors=["#2222ff", "#22ff22", "#ff2222"])
+          line_colors=["#2222ff", "#22ff22", "#ff2222", "#000000"])
     canvas = self.forcePlot.create_canvas(self)
     canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
 
   def update(self, visible):
-      self.forcePlot.update(
-        xs=[self.controller.getLastValue("force_X_{}".format(i+1)) for i in range(3)],
-        ys=[self.controller.getLastValue("force_Y_{}".format(i+1)) for i in range(3)],
-        visible=visible
+    if visible:
+      self.forcePlot.plot_data(
+        xs=[self.controller.getLastValues(self.plotLen, "force_X_{}".format(i+1)) for i in range(3)] +
+            [np.sin(np.linspace(0, 6.282, self.plotLen))],
+        ys=[self.controller.getLastValues(self.plotLen, "force_Y_{}".format(i+1)) for i in range(3)] + 
+            [np.cos(np.linspace(0, 6.282, self.plotLen))]
       )

+ 1 - 21
software/ui/Plot.py

@@ -4,27 +4,7 @@ from .globals import *
 from .plotim import linear_plot
        
 class Plot(linear_plot):
-  def __init__(self, nPoints, xaxis, yaxis, nGraphs = 1, **kwargs):
+  def __init__(self, xaxis, yaxis, **kwargs):
 
-    self.xs = np.ndarray(shape=(nGraphs, nPoints), dtype=float)
-    self.xs.fill(0)
-    self.ys = np.ndarray(shape=(nGraphs, nPoints), dtype=float)
-    self.ys.fill(float('NaN'))
-    self.i = 0
-    self.nPoints = nPoints
-    self.nGraphs = nGraphs
     linear_plot.__init__(self, **kwargs)
     self.set_scale(xaxis, yaxis)
-
-  def update(self, ys, xs=None, visible=True):
-    for g in range(self.nGraphs):
-      if xs == None:
-        self.xs[g][self.i] = self.i
-      else:
-        self.xs[g] = np.append([xs[g]], self.xs[g][:-1])
-      self.ys[g] = np.append([ys[g]], self.ys[g][:-1])
-
-    if visible:
-      self.plot_data(self.xs, self.ys)
-
-    self.i = (self.i+1) % self.nPoints

+ 17 - 6
software/ui/plotim.py

@@ -7,6 +7,7 @@
 
 import tkinter as tk
 import math
+import numpy as np
 
 
 def vertical_text(text):
@@ -158,6 +159,10 @@ class linear_plot(object):
       return ((x - self.xrangemin) * (self.windowx - self.bordereast - self.borderwest) / (self.xrangemax - self.xrangemin) + self.borderwest + offsetX, 
               (self.windowy - self.bordersouth) - (y - self.yrangemin) * (self.windowy - self.bordernorth - self.bordersouth) / (self.yrangemax - self.yrangemin) + offsetY)
 
+    def point_to_coords_np(self, coords, offsetX=0, offsetY=0):
+      coords[:,0] = (coords[:,0] - self.xrangemin) * (self.windowx - self.bordereast - self.borderwest) / (self.xrangemax - self.xrangemin) + self.borderwest + offsetX
+      coords[:,1] = (self.windowy - self.bordersouth) - (coords[:,1] - self.yrangemin) * (self.windowy - self.bordernorth - self.bordersouth) / (self.yrangemax - self.yrangemin) + offsetY
+
     ovals = []
     images = []
     def plot_data(self, xs, ys):
@@ -169,12 +174,18 @@ class linear_plot(object):
             xpoints = xs[plot]
             ypoints = ys[plot]
             linecolor = self.linecolors[plot]
-            coords = []
-            for point in range(0, len(xpoints)):
-              if not math.isnan(ypoints[point]):
-                coord = self.point_to_coords(xpoints[point], ypoints[point])
-                coords.append(coord[0])
-                coords.append(coord[1])
+            if isinstance(xpoints, (np.ndarray)) and isinstance(ypoints, (np.ndarray)):
+              coords = np.stack((xpoints, ypoints), axis=1)
+              coords = coords[~np.isnan(coords[:,1])]
+              self.point_to_coords_np(coords)
+              coords = coords.flatten().tolist()
+            else:
+              coords = []
+              for point in range(0, len(xpoints)):
+                if not math.isnan(ypoints[point]):
+                  coord = self.point_to_coords(xpoints[point], ypoints[point])
+                  coords.append(coord[0])
+                  coords.append(coord[1])
 
             if len(coords) > 2:
               self.canvas.create_line(