diff --git a/settings/workouts.csv b/settings/workouts.csv
index 7afcf49..7cea173 100644
--- a/settings/workouts.csv
+++ b/settings/workouts.csv
@@ -2,3 +2,4 @@ Name;Description;Sets;Set Pause;Repetitions;Repetition Active;Repetition Pause
Critical Force Test;The classical finger flexor critical force test (ff-CF). 7 sec on, 3 sec off for 4 min in total. Pull as hard as you can.;1;5;24;7;3
Max Isometric Finger Strength;Test the maximal isometric finger strength (MIFS). Hang for 5 sec with 120 sec pause (3 sets).;3;120;1;5;0
Warm-up;This can be used as warm-up for the critical force test. Switch hands after each repetition (10 min).;10;35;2;10;5
+Speed test;This is a test;2;120;1;5;0
\ No newline at end of file
diff --git a/ui/CalibrationGui.py b/ui/CalibrationGui.py
index 54dfd4f..7a4133c 100644
--- a/ui/CalibrationGui.py
+++ b/ui/CalibrationGui.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'CalibrationGui.ui'
##
-## Created by: Qt User Interface Compiler version 6.4.2
+## Created by: Qt User Interface Compiler version 6.6.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@@ -119,7 +119,7 @@ def setupUi(self, Form):
self.verticalLayout.addWidget(self.line_3)
- self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
+ self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.verticalLayout.addItem(self.verticalSpacer)
diff --git a/ui/CompareresultGui.py b/ui/CompareresultGui.py
index fd001e5..5831d93 100644
--- a/ui/CompareresultGui.py
+++ b/ui/CompareresultGui.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'CompareresultGui.ui'
##
-## Created by: Qt User Interface Compiler version 6.4.2
+## Created by: Qt User Interface Compiler version 6.6.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
diff --git a/ui/DataGui.py b/ui/DataGui.py
index b694570..f0d2898 100644
--- a/ui/DataGui.py
+++ b/ui/DataGui.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'DataGui.ui'
##
-## Created by: Qt User Interface Compiler version 6.4.2
+## Created by: Qt User Interface Compiler version 6.6.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
diff --git a/ui/MeasurementCtrl.py b/ui/MeasurementCtrl.py
index 2ea76c4..c50734b 100644
--- a/ui/MeasurementCtrl.py
+++ b/ui/MeasurementCtrl.py
@@ -20,6 +20,8 @@
from PySide6.QtWidgets import QWidget
from PySide6.QtGui import QAction
+from PySide6.QtWidgets import QDialog
+from PySide6.QtCore import Qt
import pyqtgraph as pg
from psychopy import prefs
@@ -32,10 +34,12 @@
import time, datetime
from ui.MeasurementGui import Ui_Form
+from ui.SpeedtestGui import Ui_Dialog
from util.repeatedTimer import RepeatedTimer
from util.params import Params
from util.workouts import WorkoutHandler
from util.criticalForce import computeRepetitionMean, computeCriticalForceAndWPrime, computeMaxForce
+from util.Speed_test import analyse_measurements, acceleration, RFD, computeSchnellkraftParameter
from util.preferencesHandling import loadPreferences
class MeasurementCtrl(QWidget):
@@ -55,23 +59,27 @@ def __init__(self, weightSensor):
self.delayInSamples = round(pref['delayCompensation']/1000 * self.fsMeas)
#========================================
- # Init class members
+ # Init class members1,5
+
#========================================
self.running = False
self.lookupTable = 0
self.countdown = 0
- self.numMeasSamples = 0
+ self.numMeasSamples_1 = 0
+ self.numMeasSamples_2 = 0
self.numSets = 0
self.numRepsPerSet = 0
self.measCnt = 0
self.secCnt = 0
self.repCnt = 0
self.setCnt = 1
- self.currentWeight = 0
- self.tare = 0
+ self.currentWeight_1 = 0
+ self.tare_1 = 0
+ self.tare_2 = 0
# Data, that will be stored in result file
- self.measDataKg = np.asarray([])
+ self.measDataKg_1 = np.asarray([])
+ self.measDataKg_2 = np.asarray([])
self.timestamp = 'unknown'
self.bodyWeight = form.bodyWeightSpinBox.value()
self.criticalForce = 0
@@ -83,7 +91,8 @@ def __init__(self, weightSensor):
#========================================
form.startButton.pressed.connect(self.onStartMeasurement)
form.stopButton.pressed.connect(self.onStopMeasurement)
- form.tareButton.pressed.connect(self.onTareButtonClicked)
+ form.tareButton_1.pressed.connect(self.onTareButtonClicked_1)
+ form.tareButton_2.pressed.connect(self.onTareButtonClicked_2)
form.bodyWeightSpinBox.valueChanged.connect(self.onBodyWeightChanged)
# Action, triggered when measurement is finished
@@ -97,11 +106,13 @@ def __init__(self, weightSensor):
self.workoutComboBox = form.workoutComboBox
self.workoutLabel = form.workoutLabel
self.weightSpinBox = form.bodyWeightSpinBox
- self.graphicsView = form.graphicsView
- self.tareButton = form.tareButton
- self.tareLabel = form.tareLabel
+ self.graphicsView_1 = form.graphicsView
+ self.tareButton_1 = form.tareButton_1
+ self.tareButton_2 = form.tareButton_2
+ self.tareLabel_1 = form.tareLabel_1
+ self.tareLabel_2 = form.tareLabel_2
- self.graphicsView.setBackground('w')
+ self.graphicsView_1.setBackground('w')
#========================================
# Workout handling
@@ -131,15 +142,28 @@ def __init__(self, weightSensor):
self.OLD_TIME = time.time()
##################################################
+ #=======================================
+ #Initialising speed test window
+ #=======================================
+
+ self.speedtestWindow = QDialog(self)
+ self.speedtestUi = Ui_Dialog()
+ self.speedtestUi.setupUi(self.speedtestWindow)
+ self.speedtestWindow.setWindowFlags( Qt.Window | Qt.WindowMinimizeButtonHint |Qt.WindowMaximizeButtonHint |Qt.WindowCloseButtonHint)
+ self.speedtestWindow.setWindowTitle("Speedtest-Auswertung")
+
def onStartMeasurement(self):
if not self.running:
self.tareTimer.stop()
- self.numMeasSamples = len(self.lookupTable) * self.fsMeas
- self.measDataKg = np.zeros(self.numMeasSamples)
+ self.numMeasSamples_1 = len(self.lookupTable) * self.fsMeas
+ self.numMeasSamples_2 = len(self.lookupTable) * self.fsMeas
+ self.measDataKg_1 = np.zeros(self.numMeasSamples_1)
+ self.measDataKg_2 = np.zeros(self.numMeasSamples_2)
self.workoutComboBox.setEnabled(False)
self.weightSpinBox.setEnabled(False)
- self.tareButton.setEnabled(False)
+ self.tareButton_1.setEnabled(False)
+ self.tareButton_2.setEnabled(False)
self.measurementTimer = RepeatedTimer(1/self.fsMeas, self.onMeasurementCallback)
@@ -160,7 +184,8 @@ def onStopMeasurement(self):
self.workoutComboBox.setEnabled(True)
self.weightSpinBox.setEnabled(True)
- self.tareButton.setEnabled(True)
+ self.tareButton_1.setEnabled(True)
+ self.tareButton_2.setEnabled(True)
self.tareTimer = RepeatedTimer(1/self.fsMeas, self.onTareVisualization)
@@ -170,14 +195,17 @@ def onStopMeasurement(self):
def onMeasurementCallback(self):
secCnt = self.secCnt
- if self.measCnt >= self.numMeasSamples:
+ if self.measCnt >= self.numMeasSamples_1:
# Measurement finished
self.measFinished.trigger()
else:
# Read value from sensor and save it to array
- valueKg = self.weightSensor.getValueInKg() - self.tare
- self.tareLabel.setText(str(np.around(valueKg, decimals=2)) + 'kg')
- self.measDataKg[self.measCnt] = valueKg
+ valueKg_1 = self.weightSensor.getValueInKg_1() - self.tare_1
+ valueKg_2 = self.weightSensor.getValueInKg_2() - self.tare_2
+ self.tareLabel_1.setText(str(np.around(valueKg_1, decimals=2)) + 'kg')
+ self.tareLabel_2.setText(str(np.around(valueKg_2, decimals=2)) + 'kg')
+ self.measDataKg_1[self.measCnt] = valueKg_1
+ self.measDataKg_2[self.measCnt] = valueKg_2
# Workout timer handling
if self.measCnt % self.fsMeas == 0:
@@ -222,12 +250,17 @@ def onMeasurementCallback(self):
self.measCnt += 1
def onTareVisualization(self):
- self.currentWeight = self.weightSensor.getValueInKg()
- weightString = str(np.around(self.currentWeight - self.tare, decimals=2))
- self.tareLabel.setText(weightString + 'kg')
-
- def onTareButtonClicked(self):
- self.tare = self.currentWeight
+ self.currentWeight_1 = self.weightSensor.getValueInKg_1()
+ self.currentWeight_2 = self.weightSensor.getValueInKg_2()
+ weightString_1 = str(np.around(self.currentWeight_1 - self.tare_1, decimals=2))
+ weightString_2 = str(np.around(self.currentWeight_2 - self.tare_2, decimals=2))
+ self.tareLabel_1.setText(weightString_1 + 'kg')
+ self.tareLabel_2.setText(weightString_2 + 'kg')
+
+ def onTareButtonClicked_1(self):
+ self.tare_1 = self.currentWeight_1
+ def onTareButtonClicked_2(self):
+ self.tare_2 = self.currentWeight_2
def onWorkoutChanged(self, id):
self.workoutDescriptionLabel.setText(self.workoutHandler.getWorkoutDescription(id))
@@ -237,7 +270,7 @@ def onWorkoutChanged(self, id):
def onBodyWeightChanged(self, value):
self.bodyWeight = value
- if len(self.measDataKg) > 0:
+ if len(self.measDataKg_1) > 0:
self.computeResultAndPlot()
def onCloseApplication(self):
@@ -249,27 +282,29 @@ def onCloseApplication(self):
#========================================
def computeResultAndPlot(self):
# Compute result (force as percentage of body weight)
- measDataPercentBw = self.measDataKg / self.bodyWeight * 100
-
+ measDataPercentBw_1 = self.measDataKg_1 / self.bodyWeight * 100
+ measDataPercentBw_2 = self.measDataKg_2 / self.bodyWeight * 100
# Compensate delay between audio clicks and measurement
- measDataPercentBw = np.roll(measDataPercentBw, -self.delayInSamples)
- measDataPercentBw[-self.delayInSamples:] = 0
+ measDataPercentBw_1 = np.roll(measDataPercentBw_1, -self.delayInSamples)
+ measDataPercentBw_2 = np.roll(measDataPercentBw_2, -self.delayInSamples)
+ measDataPercentBw_1[-self.delayInSamples:] = 0
+ measDataPercentBw_2[-self.delayInSamples:] = 0
# Compute the mean force during repetition active times
- repMean = computeRepetitionMean(measDataPercentBw, self.lookupTable, self.fsMeas)
+ repMean = computeRepetitionMean(measDataPercentBw_1, self.lookupTable, self.fsMeas)
# Prepare plot
- t = np.linspace(0, len(measDataPercentBw) / self.fsMeas, len(measDataPercentBw))
- self.graphicsView.clear()
- self.graphicsView.addLegend().anchor(itemPos=(1,0), parentPos=(1,0), offset=(-10,10))
+ t = np.linspace(0, len(measDataPercentBw_1) / self.fsMeas, len(measDataPercentBw_1))
+ self.graphicsView_1.clear()
+ self.graphicsView_1.addLegend().anchor(itemPos=(1,0), parentPos=(1,0), offset=(-10,10))
# Plot raw measurement data
- pen = pg.mkPen(color=(150,150,150), width=2)
- self.graphicsView.plot(t, measDataPercentBw, name="Raw Data", pen=pen)
+ pen = pg.mkPen(color=(150,150,150), width=2)
+ self.graphicsView_1.plot(t, measDataPercentBw_1, name="Raw Data_1", pen=pen)
# Plot mean of each repetition block
pen = pg.mkPen(color=(80,80,80), width=2)
- self.graphicsView.plot(t, repMean, name="Rep. Mean", pen=pen)
+ self.graphicsView_1.plot(t, repMean, name="Rep. Mean", pen=pen)
# Compute the critical force, if necessary
cf = 0
@@ -282,16 +317,57 @@ def computeResultAndPlot(self):
W = np.around(W, decimals = 2)
pen = pg.mkPen(color=(0,180,0), width=2)
- self.graphicsView.plot([t[0],t[-1]], [cf,cf], name="CF = " + str(cf) + " %BW | W\' = " + str(W) + " %BWs", pen=pen)
+ self.graphicsView_1.plot([t[0],t[-1]], [cf,cf], name="CF = " + str(cf) + " %BW | W\' = " + str(W) + " %BWs", pen=pen)
+
+ #===========================
+ #speed test
+ #===========================
+
+ workout_name = self.workoutHandler.getWorkoutName(self.selectedWorkoutId)
+
+ if workout_name == 'Speed test':
+
+ pen = pg.mkPen(color=(255, 255, 255), width=2)
+
+ if not self.speedtestWindow.isVisible():
+ self.speedtestWindow.show()
+
+ self.speedtestUi.graphicsView.clear()
+ self.speedtestUi.graphicsView_2.clear()
+
+ #showing new Data
+ self.speedtestUi.graphicsView_2.plot(t, measDataPercentBw_1, name="Raw Data 1", pen=pen)
+ self.speedtestUi.graphicsView.plot(t, measDataPercentBw_2, name="Raw Data 2", pen=pen)
+
+ self.speedtestUi.graphicsView_2.addLegend().anchor(itemPos=(1,0), parentPos=(1,0), offset=(-10,10))
+ self.speedtestUi.graphicsView.addLegend().anchor(itemPos=(1,0), parentPos=(1,0), offset=(-10,10))
+
+ # Speedtest parameters calculating
+ peaks1, tp1, starts1, tsp1, acc_1, rfd_1 = computeSchnellkraftParameter(measDataPercentBw_1, self.lookupTable, self.fsMeas, self.bodyWeight)
+ peaks2, tp2, starts2, tsp2, acc_2, rfd_2 = computeSchnellkraftParameter(measDataPercentBw_2, self.lookupTable, self.fsMeas, self.bodyWeight)
+
+ self.speedtestUi.graphicsView_2.plot(tp1, peaks1,pen=None, symbol='o', symbolBrush=(0,0,255),name="max Power 1 ="+ str(np.round(peaks1, 2)) + " kg")
+ self.speedtestUi.graphicsView.plot(tp2, peaks2,pen=None, symbol='o', symbolBrush=(0,0,255),name="max Power 2 ="+ str(np.round(peaks2,2)) + " kg")
+
+ self.speedtestUi.graphicsView_2.plot(tsp1, starts1,pen=None, symbol='o', symbolBrush=(0,255,0),name="Start pullingpoint 1 ="+ str(np.round(starts1, 2)) + " %")
+ self.speedtestUi.graphicsView.plot(tsp2, starts2,pen=None, symbol='o', symbolBrush=(0,255,0),name="Start pullingpoint 2 ="+ str(np.round(starts2, 2)) + " %")
+
+ self.speedtestUi.graphicsView_2.plot([0], [0], pen=None, symbol=None, name="Max. Acceleration = " + str(acc_1) + " m/s²")
+ self.speedtestUi.graphicsView.plot([0], [0], pen=None, symbol=None, name="Max. Acceleration = " + str(acc_2) + " m/s²")
+
+ self.speedtestUi.graphicsView_2.plot([0], [0], pen=None, symbol=None, name="RFD = " + str(round(rfd_1, 2)) + " kg/s")
+ self.speedtestUi.graphicsView.plot([0], [0], pen=None, symbol=None, name="RFD = " + str(round(rfd_2, 2)) + " kg/s")
+
+ #=============================
- # Plot maximum force
+ # Plot maximum force
pen = pg.mkPen(color=(180,0,0), width=2)
mf = computeMaxForce(repMean)
- self.graphicsView.plot([t[0],t[-1]], [mf,mf], name="Max. Force = " + str(mf) + " %BW", pen=pen)
+ self.graphicsView_1.plot([t[0],t[-1]], [mf,mf], name="Max. Force = " + str(mf) + " %BW", pen=pen)
- self.graphicsView.showGrid(x=True, y=True)
- self.graphicsView.setLabel('left', "%BW")
- self.graphicsView.setLabel('bottom', "Time [sec]")
+ self.graphicsView_1.showGrid(x=True, y=True)
+ self.graphicsView_1.setLabel('left', "%BW")
+ self.graphicsView_1.setLabel('bottom', "Time [sec]")
# Store result in class member variables
self.criticalForce = cf
@@ -309,7 +385,8 @@ def getData(self):
data['criticalForce'] = float(self.criticalForce)
data['wPrime'] = float(self.wPrime)
data['maxForce'] = float(self.maxForce)
- data['measDataKg'] = self.measDataKg.tolist()
+ data['measDataKg_1'] = self.measDataKg_1.tolist()
+ data['measDataKg_2'] = self.measDataKg_2.tolist()
return data
def setData(self, data, reset=False):
@@ -317,12 +394,13 @@ def setData(self, data, reset=False):
workoutId = self.workoutHandler.getIdFromName(self.workoutName)
self.workoutComboBox.setCurrentIndex(workoutId)
self.timestamp = data['timestamp']
- self.measDataKg = np.asarray(data['measDataKg'])
+ self.measDataKg_1 = np.asarray(data['measDataKg_1'])
+ self.measDataKg_2 = np.asarray(data['measDataKg_2'])
# The order is critical, always do this at the end
self.weightSpinBox.setValue(data['weight'])
- if not reset and len(self.measDataKg) > 0:
+ if not reset and len(self.measDataKg_1) > 0:
# Since critical force, W' and max force will be re-calculated in
# the following function, it's not necessary to load them here.
self.computeResultAndPlot()
@@ -331,5 +409,5 @@ def setData(self, data, reset=False):
self.criticalForce = 0
self.wPrime = 0
self.maxForce = 0
- self.graphicsView.clear()
+ self.graphicsView_1.clear()
diff --git a/ui/MeasurementGui.py b/ui/MeasurementGui.py
index d2fdacf..692d88e 100644
--- a/ui/MeasurementGui.py
+++ b/ui/MeasurementGui.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'MeasurementGui.ui'
##
-## Created by: Qt User Interface Compiler version 6.4.2
+## Created by: Qt User Interface Compiler version 6.6.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@@ -25,7 +25,7 @@ class Ui_Form(object):
def setupUi(self, Form):
if not Form.objectName():
Form.setObjectName(u"Form")
- Form.resize(542, 488)
+ Form.resize(595, 488)
self.verticalLayout = QVBoxLayout(Form)
self.verticalLayout.setObjectName(u"verticalLayout")
self.horizontalLayout_2 = QHBoxLayout()
@@ -66,6 +66,13 @@ def setupUi(self, Form):
self.verticalLayout.addWidget(self.line_3)
+ self.line_4 = QFrame(Form)
+ self.line_4.setObjectName(u"line_4")
+ self.line_4.setFrameShape(QFrame.HLine)
+ self.line_4.setFrameShadow(QFrame.Sunken)
+
+ self.verticalLayout.addWidget(self.line_4)
+
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.verticalLayout_2 = QVBoxLayout()
@@ -110,32 +117,52 @@ def setupUi(self, Form):
self.verticalLayout_3 = QVBoxLayout()
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.verticalLayout_3.setSizeConstraint(QLayout.SetDefaultConstraint)
- self.tareLabel = QLabel(Form)
- self.tareLabel.setObjectName(u"tareLabel")
- self.tareLabel.setMinimumSize(QSize(70, 0))
- self.tareLabel.setFont(font)
- self.tareLabel.setAlignment(Qt.AlignCenter)
+ self.horizontalLayout_3 = QHBoxLayout()
+ self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
+ self.tareLabel_1 = QLabel(Form)
+ self.tareLabel_1.setObjectName(u"tareLabel_1")
+ sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.tareLabel_1.sizePolicy().hasHeightForWidth())
+ self.tareLabel_1.setSizePolicy(sizePolicy)
+ font1 = QFont()
+ font1.setPointSize(15)
+ self.tareLabel_1.setFont(font1)
+ self.tareLabel_1.setAlignment(Qt.AlignCenter)
- self.verticalLayout_3.addWidget(self.tareLabel)
+ self.horizontalLayout_3.addWidget(self.tareLabel_1)
- self.tareButton = QPushButton(Form)
- self.tareButton.setObjectName(u"tareButton")
- self.tareButton.setMinimumSize(QSize(70, 0))
+ self.tareLabel_2 = QLabel(Form)
+ self.tareLabel_2.setObjectName(u"tareLabel_2")
+ self.tareLabel_2.setFont(font1)
+ self.tareLabel_2.setAlignment(Qt.AlignCenter)
- self.verticalLayout_3.addWidget(self.tareButton)
+ self.horizontalLayout_3.addWidget(self.tareLabel_2)
- self.horizontalLayout.addLayout(self.verticalLayout_3)
+ self.verticalLayout_3.addLayout(self.horizontalLayout_3)
+ self.horizontalLayout_4 = QHBoxLayout()
+ self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
+ self.tareButton_1 = QPushButton(Form)
+ self.tareButton_1.setObjectName(u"tareButton_1")
- self.verticalLayout.addLayout(self.horizontalLayout)
+ self.horizontalLayout_4.addWidget(self.tareButton_1)
- self.line_4 = QFrame(Form)
- self.line_4.setObjectName(u"line_4")
- self.line_4.setFrameShape(QFrame.HLine)
- self.line_4.setFrameShadow(QFrame.Sunken)
+ self.tareButton_2 = QPushButton(Form)
+ self.tareButton_2.setObjectName(u"tareButton_2")
- self.verticalLayout.addWidget(self.line_4)
+ self.horizontalLayout_4.addWidget(self.tareButton_2)
+
+
+ self.verticalLayout_3.addLayout(self.horizontalLayout_4)
+
+
+ self.horizontalLayout.addLayout(self.verticalLayout_3)
+
+
+ self.verticalLayout.addLayout(self.horizontalLayout)
self.graphicsView = PlotWidget(Form)
self.graphicsView.setObjectName(u"graphicsView")
@@ -156,7 +183,9 @@ def retranslateUi(self, Form):
self.startButton.setText(QCoreApplication.translate("Form", u"Start", None))
self.stopButton.setText(QCoreApplication.translate("Form", u"Stop", None))
self.workoutLabel.setText(QCoreApplication.translate("Form", u"Stopped", None))
- self.tareLabel.setText(QCoreApplication.translate("Form", u"0kg", None))
- self.tareButton.setText(QCoreApplication.translate("Form", u"Tare", None))
+ self.tareLabel_1.setText(QCoreApplication.translate("Form", u"0kg", None))
+ self.tareLabel_2.setText(QCoreApplication.translate("Form", u"0kg", None))
+ self.tareButton_1.setText(QCoreApplication.translate("Form", u"Tare 1", None))
+ self.tareButton_2.setText(QCoreApplication.translate("Form", u"Tare 2", None))
# retranslateUi
diff --git a/ui/MeasurementGui.ui b/ui/MeasurementGui.ui
index 33f816d..7717913 100644
--- a/ui/MeasurementGui.ui
+++ b/ui/MeasurementGui.ui
@@ -6,7 +6,7 @@
0
0
- 542
+ 595
488
@@ -67,6 +67,13 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
-
-
@@ -128,50 +135,67 @@
QLayout::SetDefaultConstraint
-
-
-
-
- 70
- 0
-
-
-
-
- 13
-
-
-
- 0kg
-
-
- Qt::AlignCenter
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 15
+
+
+
+ 0kg
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 15
+
+
+
+ 0kg
+
+
+ Qt::AlignCenter
+
+
+
+
-
-
-
-
- 70
- 0
-
-
-
- Tare
-
-
+
+
-
+
+
+ Tare 1
+
+
+
+ -
+
+
+ Tare 2
+
+
+
+
- -
-
-
- Qt::Horizontal
-
-
-
-
diff --git a/ui/PreferencesGui.py b/ui/PreferencesGui.py
index c53473f..fed964d 100644
--- a/ui/PreferencesGui.py
+++ b/ui/PreferencesGui.py
@@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'PreferencesGui.ui'
##
-## Created by: Qt User Interface Compiler version 6.4.2
+## Created by: Qt User Interface Compiler version 6.6.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@@ -58,7 +58,7 @@ def setupUi(self, Form):
self.verticalLayout.addWidget(self.warningLabel)
- self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
+ self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.verticalLayout.addItem(self.verticalSpacer)
diff --git a/ui/SpeedtestGui.py b/ui/SpeedtestGui.py
new file mode 100644
index 0000000..9ebae79
--- /dev/null
+++ b/ui/SpeedtestGui.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+
+################################################################################
+## Form generated from reading UI file 'SpeedtestGui.ui'
+##
+## Created by: Qt User Interface Compiler version 6.6.2
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
+ QMetaObject, QObject, QPoint, QRect,
+ QSize, QTime, QUrl, Qt)
+from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
+ QFont, QFontDatabase, QGradient, QIcon,
+ QImage, QKeySequence, QLinearGradient, QPainter,
+ QPalette, QPixmap, QRadialGradient, QTransform)
+from PySide6.QtWidgets import (QApplication, QDialog, QHBoxLayout, QSizePolicy,
+ QWidget)
+
+from pyqtgraph import PlotWidget
+
+class Ui_Dialog(object):
+ def setupUi(self, Dialog):
+ if not Dialog.objectName():
+ Dialog.setObjectName(u"Dialog")
+ Dialog.resize(499, 348)
+ self.horizontalLayout = QHBoxLayout(Dialog)
+ self.horizontalLayout.setObjectName(u"horizontalLayout")
+ self.graphicsView_2 = PlotWidget(Dialog)
+ self.graphicsView_2.setObjectName(u"graphicsView_2")
+
+ self.horizontalLayout.addWidget(self.graphicsView_2)
+
+ self.graphicsView = PlotWidget(Dialog)
+ self.graphicsView.setObjectName(u"graphicsView")
+
+ self.horizontalLayout.addWidget(self.graphicsView)
+
+
+ self.retranslateUi(Dialog)
+
+ QMetaObject.connectSlotsByName(Dialog)
+ # setupUi
+
+ def retranslateUi(self, Dialog):
+ Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None))
+ # retranslateUi
+
diff --git a/ui/SpeedtestGui.ui b/ui/SpeedtestGui.ui
new file mode 100644
index 0000000..6758a9d
--- /dev/null
+++ b/ui/SpeedtestGui.ui
@@ -0,0 +1,34 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 499
+ 348
+
+
+
+ Dialog
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+ PlotWidget
+ QGraphicsView
+
+
+
+
+
+
diff --git a/ui/compileUi.bat b/ui/compileUi.bat
index ec7f84a..170e3b8 100644
--- a/ui/compileUi.bat
+++ b/ui/compileUi.bat
@@ -2,4 +2,5 @@ pyside6-uic MeasurementGui.ui -o MeasurementGui.py
pyside6-uic DataGui.ui -o DataGui.py
pyside6-uic CalibrationGui.ui -o CalibrationGui.py
pyside6-uic PreferencesGui.ui -o PreferencesGui.py
-pyside6-uic CompareresultGui.ui -o CompareresultGui.py
\ No newline at end of file
+pyside6-uic CompareresultGui.ui -o CompareresultGui.py
+pyside6-uic SpeedtestGui.ui -o SpeedtestGui.py
\ No newline at end of file
diff --git a/util/Speed_test.py b/util/Speed_test.py
new file mode 100644
index 0000000..b58fc8a
--- /dev/null
+++ b/util/Speed_test.py
@@ -0,0 +1,84 @@
+import numpy as np
+from ui import MeasurementCtrl
+
+def find_monotonic_rise_start(force_data):
+ peak_index = np.argmax(force_data)
+ for i in range(peak_index - 1, 0, -1):
+ if force_data[i] < force_data[i - 1]:
+ start_index = i
+ break
+ else:
+ start_index = 0
+ return start_index
+
+def analyse_measurements(force_data, sampling_rate=10):
+ force_data = np.array(force_data)
+ start_idx = find_monotonic_rise_start(force_data)
+
+ start_time = round(start_idx / sampling_rate, 2)
+ start_value = round(force_data[start_idx], 2)
+
+ return start_value, start_time
+
+def acceleration(force_max, bodyweight):
+ acceleration = (force_max * 10)/bodyweight
+ acceleration_round = round(acceleration, 2)
+
+ return acceleration_round
+
+def RFD(startofpullingtimepoint, maxforcetimepoint, maxforce, startpullingpointforce):
+ rfd = (maxforce - startpullingpointforce) / (maxforcetimepoint - startofpullingtimepoint)
+
+ return rfd
+
+def computeSchnellkraftParameter(measData, lookupTable, sampleRate, bodyweight):
+ #cpmoute RFD and max. acceleration
+ t = np.linspace(0, len(measData) / sampleRate, len(measData))
+ peak_alltime = np.max(measData)
+ peak_timepoint_alltime = t[np.argmax(measData)]
+ max_force_in_kg_alltime = (peak_alltime / 100) * bodyweight
+ startpointpullingvalue_alltime, startpointpulling_timepoint_alltime = analyse_measurements(measData)
+
+
+ #acceleration
+ max_acceleration = acceleration(max_force_in_kg_alltime, bodyweight)
+
+ #RFD
+ rfd_value = RFD(startpointpulling_timepoint_alltime, peak_timepoint_alltime, peak_alltime, startpointpullingvalue_alltime)
+
+ #compute Startingpoints and max. peaks
+ lookupRsmpl = np.repeat(lookupTable, sampleRate)
+ assert len(measData) == len(lookupRsmpl)
+ numSamples = len(lookupRsmpl)
+
+ indStart = 0
+
+ allPeaks = []
+ allPeaks_timepoint = []
+ allStartingpoints = []
+ allStartingpoints_timepoint = []
+
+ for i in range(1, numSamples):
+ diff = lookupRsmpl[i] - lookupRsmpl[i-1]
+
+ if diff == 1:
+ # New Active Time begins
+ indStart = i
+
+ elif diff == -1:
+ # Active Time endet → hier auswerten
+ segment = measData[indStart:i]
+ # Peak
+ local_peak = np.max(segment)
+ local_peak_idx = np.argmax(segment)
+ allPeaks.append(local_peak)
+ allPeaks_timepoint.append(t[indStart + local_peak_idx])
+
+ # Start-Zeitpunkt
+ sp_val, sp_time = analyse_measurements(segment, sampling_rate=sampleRate)
+ allStartingpoints.append(sp_val)
+ sp_time_abs = indStart/sampleRate + sp_time
+ allStartingpoints_timepoint.append(sp_time_abs)
+
+ return allPeaks, allPeaks_timepoint, allStartingpoints, \
+ allStartingpoints_timepoint, max_acceleration, rfd_value
diff --git a/util/cedargrove_nau7802.py b/util/cedargrove_nau7802.py
index 1634ee6..9fe2d59 100644
--- a/util/cedargrove_nau7802.py
+++ b/util/cedargrove_nau7802.py
@@ -97,7 +97,7 @@ class CalibrationMode:
INTERNAL = 0x0 # Offset Calibration Internal; _CTRL2[1:0] = 0 (chip default)
OFFSET = 0x2 # Offset Calibration System; _CTRL2[1:0] = 2
- GAIN = 0x3 # Gain Calibration System; _CTRL2[1:0] = 3
+ GAIN = 0x3 # Gain Calibration System; _CTRL2[1:0] = 3
class NAU7802:
diff --git a/util/sensor.py b/util/sensor.py
index 8d2147e..46026a1 100644
--- a/util/sensor.py
+++ b/util/sensor.py
@@ -31,7 +31,8 @@
#========================================
class WeightSensor():
def __init__(self):
- self.sensorValue = 0
+ self.sensorValue_1 = 0
+ self.sensorValue_2 = 0
self.scalingFactor = self.calcScalingFactor(Params.calibrationFile.value)
# Set environment variable for MCP2221A
@@ -44,13 +45,23 @@ def __init__(self):
try:
import board
from util.cedargrove_nau7802 import NAU7802
+ from adafruit_tca9548a import TCA9548A
+
+ #Multiplexer initialisieren
+ multiplexer = TCA9548A(board.I2C())
# Instantiate 24-bit load sensor ADC; two channels, default gain of 128
- self.nau7802 = NAU7802(board.I2C(), address=0x2A, active_channels=2)
- self.nau7802.enable(True)
- self.nau7802.channel = 1
+ self.nau7802_1 = NAU7802(multiplexer[0], address=0x2A, active_channels=2)
+ self.nau7802_1.enable(True)
+ self.nau7802_1.channel = 1
self.zero_channel()
+ #2.Wägezelle
+ self.nau7802_2 = NAU7802(multiplexer[1], address=0x2A, active_channels=2)
+ self.nau7802_2.enable(True)
+ self.nau7802_2.channel = 1
+ self.zero_channel_2()
+
self.connected = True
self.stopThreadEvent = Event()
@@ -70,10 +81,12 @@ def onNewMeasurement(self, stopEvent):
if stopEvent.is_set():
stopEvent.clear()
break
- elif self.connected and self.nau7802.available:
- self.sensorValue = self.nau7802.read()
+ elif self.connected and self.nau7802_1.available and self.nau7802_2.available:
+ self.sensorValue_1 = self.nau7802_1.read()
+ self.sensorValue_2 = self.nau7802_2.read()
else:
- self.sensorValue = 0
+ self.sensorValue_1 = 0
+ self.sensorValue_2 = 0
time.sleep(0.001)
def zero_channel(self):
@@ -84,20 +97,41 @@ def zero_channel(self):
msg = QMessageBox()
msg.setWindowTitle("Warning")
msg.setIcon(QMessageBox.Warning)
- msg.setText("Checking sensor...\nRemove any weight, then click \"OK\" to proceed.")
+ msg.setText("Checking sensor 1 ...\nRemove any weight, then click \"OK\" to proceed.")
msg.exec_()
- self.nau7802.calibrate("INTERNAL")
- self.nau7802.calibrate("OFFSET")
+ self.nau7802_1.calibrate("INTERNAL")
+ self.nau7802_1.calibrate("OFFSET")
for _ in range(100):
- self.nau7802.read() # Read 100 samples to establish zero offset
+ self.nau7802_1.read() # Read 100 samples to establish zero offset
+
+ def zero_channel_2(self):
+ """Initiate internal calibration for current channel; return raw zero
+ offset value. Use when scale is started, a new channel is selected, or to
+ adjust for measurement drift. Remove weight and tare from load cell before
+ executing."""
+ msg = QMessageBox()
+ msg.setWindowTitle("Warning")
+ msg.setIcon(QMessageBox.Warning)
+ msg.setText("Checking sensor 2 ...\nRemove any weight, then click \"OK\" to proceed.")
+ msg.exec_()
+
+ self.nau7802_2.calibrate("INTERNAL")
+ self.nau7802_2.calibrate("OFFSET")
+
+ for _ in range(100):
+ self.nau7802_2.read() # Read 100 samples to establish zero offset
- def getValueInKg(self):
- return self.sensorValue * self.scalingFactor
+ def getValueInKg_1(self):
+ return self.sensorValue_1 * self.scalingFactor
+ def getValueInKg_2(self):
+ return self.sensorValue_2 * self.scalingFactor
- def getRawValue(self):
- return self.sensorValue
+ def getRawValue_1(self):
+ return self.sensorValue_1
+ def getRawValue_2(self):
+ return self.sensorValue_2
def isConnected(self):
return self.connected