Ich muss für ein Projekt in der FH einen einfachen Pulssensor programmieren. Ich bin leider ein absoluter Arduino-Neuling und komme gerade nich weiter. Ich habe es bisher geschafft den Peak eines jeden Pulsschlages zu finden und dazu den zeitwert.
Ich möchte jetzt den durchschnittlichen Abstand der letzten 10 Zeitwerte errechnen um dann den Puls daraus zu berechnen.
Wie schaffe ich es den Zeitwert (in meinem fall "timestamp") aus meiner if Bedingung in ein Array zu speichern um dann den Average zu berechnen? Oder gibt es auch andere möglichkeiten den durchschnittlichen Zeitwert zwischen den letzten 10 werten zu errechnen?
Mein Code:
#include <TimerOne.h>
#define groesseGlaettung 100
unsigned long time;
int peakValue = 0;
int threshold = 600; //set your own value based on your sensors
int val = 0;
boolean trigger = false;
int puffer[groesseGlaettung];
long mittelwert = 0;
void setup() {
Timer1.initialize(10);
Timer1.attachInterrupt(callback);
Serial.begin(9600);
while(!Serial){
;
}
for(int i=0; i < groesseGlaettung; i++){
puffer[i] = 0;
}
}
void loop() {
if(trigger == true){
// put your main code here, to run repeatedly:
val = analogRead(0);
for(int j=0; j < (groesseGlaettung - 1); j++){
puffer[j] = puffer[j +1];
}
puffer[groesseGlaettung - 1] = val;
mittelwert = 0;
for(int k = 0; k < groesseGlaettung; k++){
mittelwert += puffer[k];
}
mittelwert = round(mittelwert / groesseGlaettung);
//Serial.println(mittelwert);
trigger = false;
}
//read sensor on pin A0:
int sensorValue = mittelwert;
unsigned long timestamp = millis();
// check if it's higher than the current peak:
if (sensorValue > peakValue) {
peakValue = sensorValue;
}
if (sensorValue <= threshold && peakValue > threshold) {
// you have a peak value:
Serial.println(peakValue);
Serial.println(timestamp);
// reset the peak variable:
peakValue = 0;
delay(300);
}
}
void callback()
{
trigger = true;
}
MAn sieht vielleicht am Code schon, dass ich kein waschechter Programmierer bin Aber auch dieses Nebenfach muss ich im Studium schaffen. Nachdem ich jetzt schon tagelang an diesem Problem sitze, hoffe ich hier auf Hilfe.
Am einfachsten geht es mit einem Ringbuffer.
Du verschiebst nicht die Werte im Array sondern änderst den Index wo Du den aktuellen Wert abspeicherst. Kommst Du mit dem Index am letzten Element des Arrays an, so setzt Du den Index wieder auf null.
reMison:
MAn sieht vielleicht am Code schon, dass ich kein waschechter Programmierer bin Aber auch dieses Nebenfach muss ich im Studium schaffen. Nachdem ich jetzt schon tagelang an diesem Problem sitze, hoffe ich hier auf Hilfe.
Was bist Du denn, wenn kein angehender Programmierer? Angehender Mathematiker? Mediziner? Ingenieur?
Wenn ich mir mal eine (nur mal schnell gegoogelte) Herzschlag-Aufzeichnung ansehe, dann erkenne ich: Nicht jeder Peak ist ein Herzschlag!
In diesem Diagramm liegen zwischen zwei Herzschlägen ("steilster und höchster Peak") immer noch zwei weitere Zwischen-Peaks, die niedriger und auch weniger steil sind
Der menschliche Herzschlag ist deutlich komplexer als "Peak und Pause" und mit Deiner Programmlogik, die zwischen zwei Samples eine blockierende Pause von 300ms einlegt (delay(300), kannst Du in Sachen Pulsschlagauswertung nnichts werden.
Um den Herzschlag einigermaßen genau zu erfassen müßtest Du zwischen zwei Herzschlägen mindestens 10 Werte erfassen, sonst kannst Du weder die steilen Peaks ("Herzschlag") noch die flacheren Peaks dazwischen sicher erkennen.
D.h. bei einemPuls von 60 pro Minute müßtest Du in einer Minute mdinestens 600 oder mehr Samples zur Auswertung erfassen und nicht nur 200 Samples im 300ms Zeitabstand,
u
jurs:
Was bist Du denn, wenn kein angehender Programmierer? Angehender Mathematiker? Mediziner? Ingenieur?
Ich komme ursprünglich aus dem Gesundheitswesen (Radiologietechnologie) und mache derzeit ein Masterstudium (Digital Healthcare). Dabei schnuppern wir in "Einführung in die angewandte Sensorik" eben in die Arduino-Materie.
reMison:
Ich komme ursprünglich aus dem Gesundheitswesen (Radiologietechnologie) und mache derzeit ein Masterstudium (Digital Healthcare). Dabei schnuppern wir in "Einführung in die angewandte Sensorik" eben in die Arduino-Materie.
Also das würde ich mal grob unter Ingenieurwissenschaften einstufen und davon ausgehen, dass Du nicht nur bis zum Abitur Mathe gehabt hast, sondern auch im Studium
Zuerst mal zu Deinen Samples, die Du im Programm mit "val = analogRead(0);! erfasst.
Einerseits sieht es zwar aus, als wenn Du die Samples tatsächlich schnell genug im Zeitabstand von 10 Millisekunden erfassen möchtest, und dafür installierst Du Dir extra eine externe Timer-Library und schreibst aufwändig eine Interruptverarbeitung, aber tatsächlich erfasst Du Samples nur mit 300 ms Zeitabstand wegen des delay(300); in der loop()-Funktion.
So kannst Du Deine Samples im Zeitabstand von 10ms erfassen und brauchst dafür keine Timer-Interrupt-Library und Timer-Interrrupt-Callbackfunktion, der Durchschnitt wird nach je 10 Werten (alle 100ms) auf Serial ausgegeben, ich versuch's mal (ungetestet, ggf. sind Fixes notwendig):
//define some variables for average calculation
const int numReadings = 10;
int avgReadings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
const byte inputPin = A0;
void setup() {
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the average readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
avgReadings[thisReading] = 0;
}
}
unsigned long lastSampleTime;
void loop()
{
if (micros()- lastSampleTime>=10000) // at least 10000µs=10ms have passed since we took last sample
{
lastSampleTime+=10000;
// subtract the last reading:
total = total - avgReadings[readIndex];
// read from the sensor:
avgReadings[readIndex] = analogRead(inputPin);
// add the reading to the total:
total = total + avgReadings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) //// ...wrap around to the beginning, calculate and print average to Serial
{
readIndex = 0;
// calculate the average:
average = total / numReadings;
Serial.println(average); // send it to the computer as ASCII digits
}
}
}
Die Form des EKGs hängt von den Positionen ab wo das Signal abgenommen wird. Damit man etwas interpretieren kann sind Punkte für die Elektroden definiert: Hände, Füße und 6 Punkte nach bestimmten Regeln auf dem Brustkorb.
Das einfachste und auch um keine Probleme mit der Sicherheit zu haben ist ein Pulsmeßband welches man beim Sport benutzt und ein dementsprechender Empfänger.
const int numReadings = 10;
int avgReadings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
const byte inputPin = A0;
void setup() {
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the average readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
avgReadings[thisReading] = 0;
}
}
unsigned long lastSampleTime;
void loop()
{
if (micros()- lastSampleTime>=10000) // at least 10000µs=10ms have passed since we took last sample
{
lastSampleTime+=10000;
// subtract the last reading:
total = total - avgReadings[readIndex];
// read from the sensor:
avgReadings[readIndex] = analogRead(inputPin);
// add the reading to the total:
total = total + avgReadings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) //// ...wrap around to the beginning, calculate and print average to Serial
{
readIndex = 0;
// calculate the average:
average = total / numReadings;
Serial.println(average); // send it to the computer as ASCII digits
}
}
}
Vielen Dank für deine Hilfe. Der Code funktioniert einwandfrei.
Das einzige was mir noch nicht ganz klar ist: Ich hätte gerne ja gerne einen Average aus den Zeitwerten der jeweiligen "Peaks" (ob der Peak bei mir jetzt richtig definiert ist oder nicht, sei mal dahingestellt). Dafür müsste ich ja immer den Zeitwert des vorherigen Peaks von dem Zeitwert des aktuellen Peaks abziehen. Das ganze dann 10 mal und einen Average aus den Zeitabständen zwischen den Peaks zu bekommen. wenn ich dann 6000ms durch den Average der letzten 10 Zeitabstände zwischen den Peaks dividiere sollte ich ja den aktuellen Pulswert bekommen. So weit meine Theorie. Beim Umsetzen scheiterts leider
reMison:
Vielen Dank für deine Hilfe. Der Code funktioniert einwandfrei.
Das einzige was mir noch nicht ganz klar ist: Ich hätte gerne ja gerne einen Average aus den Zeitwerten der jeweiligen "Peaks"
Ja, das ist das, wo Du am Ende hin möchtest, aber davon bist Du noch ganz weit weg.
In Deinem Anfangs geposteten Code hast Du Sensorsamples nur alle 300 Millisekunden gemacht und es ist keine funktionierende Peak-Erkennung drin.
In meinem Code werden Sensorsamples alle 10 Millisekunden gemacht und alle 10 Samples (also nach jeweils 100 Millisekunden) wird der Mittelwert der letzten 10 Samples auf Serial ausgegeben. Eine funktionierende Peakerkennung ist da aber auch nicht drin.
reMison:
(ob der Peak bei mir jetzt richtig definiert ist oder nicht, sei mal dahingestellt).
Nein, da ist überhaupt nichts hingestellt. Wenn Du nicht weißt, wonach Du in der Zahlenwüste Deiner Sensormesswerte suchen mußt und wie Du das zu erkennende Herzschlag-Peak-Muster mathematisch definieren kannst, wirst Du keinen einzigen Herzschlag in Deinen Daten entdecken. Und solange Du nicht mehrere aufeinanderfolgende Herzschläge in Deinen Daten zuverlässig und einwandfrei identifizieren kannst, kannst Du auch keine Mittelwerte über die Zeitabstände zwischen den Herzschlägen (Inter-Beat-Pause IBP) ausrechnen.