Die Anzahl der Maxima einer Kurve abspeichern

Hallo, ich habe folgendes Problem:
Ich habe einen Pulssensor, welcher den unten folgenden Graph ausgibt.
Um jetzt die BPM zu ermitteln muss ich über einen Zeitraum von 15 Sekunden die Anzahl der Peaks zählen.
Das Problem: ich kann mich NICHT an den gemessenen Sensorwerten auf der y-Achse orientieren und sagen: "Ist der Wert über einem festgelegten Grenzwert: Zähle ihn als Maxima, liegt er drunter: ignorier ihn". Das liegt daran, dass die ganze Kurve nach oben springt wenn ich den Sensor fester drücke; bzw nach unten springt wenn ich weniger drücke und somit sehr instabil agiert.
Jetzt meine Frage: Wie kann ich bspw. einen Algorythmus o.ä. schreiben, welcher ausschließlich die deutlich sichtbaren Ausschläge als Pulsschlag wertet und dementsprechend zählt. Wie würde der als Code aussehen?
Komme da echt nicht weiter, weil ich noch recht unerfahren bin.
Vielen Dank im voraus!

gleitenden Schnitt mitrechnen und eben dann als "Puls" zählen, wenn es deutlich über den gleitenden war und einen zeitlichen Mindestabstand vom letzten "Puls" hatte.

Und immer gilt: was spuckt Google aus dazu?

Hallo,

wenn ich Dein Problem jetzt richtig verstanden habe , dann nimm doch die Differenz zum letzten Messwert. Wenn nur ein Messwert nicht reicht dann musst Du halt die Steigung über mehrere zurück liegende Messwerte auswerten . Nennt sich "lineare Interpolation". Wenn das Ergebniss dann "steil" genug ist in dem überwachten Bereich dann ist das ein passendes Ereigniss.

oder etwas Einfacher geht es eventuell auch so: Wenn der neue Messwert um x grösser ist als der Mittelwert der letzten 5 Messungen dann ist es Dein gesuchtes Ereigniss.

Für eine grafische Darstellung auf dem Plotter müsstest Du eventuell den Mittelwert der letzten x Messungen vom Messwert abziehen, aber ob das funzt, müsste man mal probieren

Heinz

Oder mit der Hand am Arm das tun, was Du intuitiv beim Betrachten der Kurve machst, um die Spitzen zu erkennen:
Ein Maximum ist dadurch gekennzeichnet, dass die Werte links und rechts davon kleiner sind.

Das Verfahren kann aber zu viele (oder auch zu wenige) Maxima liefern, wenn die Breite dieses "Fensters", das Du über die Daten laufenlässt, unpassend gewählt ist.

Mathematisch auch ganz nett wäre sowas Ähnliches wie die erste Ableitung der Kurve: Die Steigung der Gerade zwischen jeweils zwei aufeinander folgenden Punkten berechnen. Wenn die vom positiven ins negative kippt, hast Du ein lokales Maximum gefunden.

EDIT: Direkt aufeinander folgende Punkte wären ein sehr kleines Fenster, das die kleinen Zucker auch mitnehmen würde. Da bin ich dann eher bei Heinz oder noasica - mehrere Werte verwenden.

pho3nix:
Pulssensor, welcher den unten folgenden Graph ausgibt.

muss ich über einen Zeitraum von 15 Sekunden die Anzahl der Peaks zählen.

die ganze Kurve nach oben springt wenn ich den Sensor fester drücke;

Zwischenfragen:
wieviele Werte bekommst Du in den 15 Sekunden?
kannst Du mal eine Messreihe für sagen wir mal 30 oder 60 sekunden mit Werten zur Verfügung stellen?
(also längere Ausgabe der Werte auf dem serMon und einfach hier als txt - Anhang )

Das bilden eines gleitenden Mittelwertes könnte von Nachteil sein, wenn der Sprung evtl. nicht ausreichend ist zum Mittelwert wäre. Da böte sich ggfls. ein Zwischenschritt an, aber ich würd das aber gerne mal austesten, wie sich das real abbildet.

Hello again :),
Erstmal vielen Dank für eure schnelle Hilfe und die Vorschläge. Ich versuche mich gerade in das Thema “Gleitender Mittelwert” einzulesen und bin am ausprobieren- ist aber momentan bei mir eine einfache Miittelwertsrechnung. Gibts da evtl schon fertige Libs dir ihr empfehlen könnt?

Nun zu deiner frage @my_xy_project: Ich habe zwischen den einzelnen Messwerten einen Delay von 10. somit müssten das 100 Werte pro sekunde sein.
Im Anhang habe ich dir drei Dateien mit Messwerten (gemessen über ca. 30 Sekunden). Der Sensor ist , wie erwähnt sehr Druckempfindlich weshalb es schwierig ist Saubere Messwerte zu bekommen(ich hab mir Mühe gegeben :smiley: ).
Ich hoffe es hilft dir :slight_smile:
Vielen Dank!!

Messwerte .txt (15.8 KB)

mw2.txt (14.4 KB)

mw3.txt (14.7 KB)

pho3nix:
Ich habe zwischen den einzelnen Messwerten einen Delay von 10. somit müssten das 100 Werte pro sekunde sein.

Hab ich mir fast gedacht - Ist schon mal ne Größenordnung....

Der Sensor ist , wie erwähnt sehr Druckempfindlich weshalb es schwierig ist Saubere Messwerte zu bekommen(ich hab mir Mühe gegeben :smiley: ).
Ich hoffe es hilft dir :slight_smile:

Ich schau drauf - heute ist aber Schluss für mich. Wird die erste Nacht mit Bett und Schlaf seit Langem...
Auch die veränderlichen Drücke wären nicht schlecht - vielleicht kannst Du da noch was nachreichen - dann hätte ich eine Kontrollmöglichkeit.
Gerne in das Post oben noch modifizieren und einhängen. Dafür brauchst wirklich keinen neuen replay :slight_smile:
Danke schonmal und ich komm morgen mit einer Antwort....

Zwischenfrage: Was für ein Board /Arduino (oder clone) benutzt Du? Und bist Du darauf angewiesen?

Moin hast schon mal in die lib geschaut:

Da gibts zwei bpm-Example zu.
Vielleicht das Rad nicht komplett neu erfinden.

Guten Morgen,
Ich benutze einen Node MCU ESP 8266 Mikrocontroller und ja, auf den bin ich leider angewiesen(macht das einen großen Unterschied bezüglich meines Problems zum Arduino Uno?).

Die Pulsesensor Playground Lib ist mir bekannt. Allerdings wird mir damit kein BPM berechnet sondern nur graphisch dargestellt und das Problem mit dem Verschieben der Kurve bei stärkerem Druck ist ebenfalls vorhanden.
Ich hab die Datei mit unterschiedlichem Druck hier beigelegt ( erst leicht, dann stärker, zum Schluss wieder leicht).
Vielen Dank für die Hilfe!

Unterschiedliche_druecke.txt (21.1 KB)

pho3nix:
Ich benutze einen Node MCU ESP 8266 Mikrocontroller und ja, auf den bin ich leider angewiesen(macht das einen großen Unterschied bezüglich meines Problems zum Arduino Uno?).

Einen kleinen Unterschied, weil er mehr Speicher hat und mit 32 Bit rechnet, manche Bibliotheken werden nicht funktionieren.

Ich habe passend mit einem ESP32 probiert, ob ich Dir helfen kann. Leider bin ich kein mathematisches Genie, weshalb das Ergebnis eigentlich nicht vorzeigbar ist. Aber möglicherweise kannst Du eine Anregung aufgreifen.

Theoretisch

  • Glättung
  • Differenz bilden
  • Spitzen erkennen

Die ersten beiden Punkte:

#include "Messwerte.h"

const size_t len_werte = sizeof(werte) / sizeof(werte[0]);
const uint16_t GLAETTUNG = 20;

void setup() {
  Serial.begin(115200);
  delay(3000);
}

void loop() {
  float g_wert =  pgm_read_word(werte + 0); // ohne "+ 0" meckert der Kompiler!
  for (uint16_t j = 0; j < len_werte; j++) {
    uint16_t val = pgm_read_word(werte + j);
    g_wert = ((GLAETTUNG - 1) * g_wert + val) / GLAETTUNG;
    //Serial.print(val); Serial.print(','); Serial.print(g_wert,0); Serial.print(','); Serial.print(g_wert+5,0);
    int32_t diff = val - g_wert;
    Serial.print(diff);
    Serial.println();
    delay(10); // zum Mitlesen
  }
  delay(10000);
}

Messwerte.h

const uint16_t werte[] PROGMEM = {586,586,
586,
586,

...

594,
595
};

Aus dem Ergebnis kann ich leider keinen Pulsschlag erkennen.

pho3nix:
Ich hab die Datei mit unterschiedlichem Druck hier beigelegt ( erst leicht, dann stärker, zum Schluss wieder leicht).

Da schau ich rein und hab jetzt doch etwas Bedenken das sich das so leicht abbilden lässt.

Hm. Ich werd mir die Werte mal nehmen und sehen, was der Plotter ausgibt und ob ich da irgendwie rankomme.
Es dürfte drauf rauslaufen, das das maximum allein nicht reichen reichen wird. vermutlich muss noch eine Zeitkomponente mit rein...

Ich denk drüber. Wird aber nen Moment dauern...

Guten Abend!
Erstmal wieder vielen Dank an euch, dass ihr euch da so rein hängt. Ich habe mittlerweile einen 2. Sensor da, welcher schönere Werte bietet und nicht ganz so druckempfindlich ist wie der alte(aber immernoch ist). Mein Problem hat sich dadurch nicht behoben aber die neuen Werte könnten es etwas leichter machen (hoffe ich zumindest :D)
Ich hab sie hier im Anhang
LG und bleibt gesund!

schoeneWerte.txt (21.9 KB)

pho3nix:
Problem hat sich dadurch nicht behoben aber die neuen Werte könnten es etwas leichter machen (hoffe ich zumindest :D)

Ich hab kurz drüber geschaut.... geht evtl. besser, aber unabhängig davon muss es auch mit dem bisherigen machbar sein.

Meine Überlegung war, einen Durchschnitt zu bilden und min/max + Zeit einfliessen zu lassen.
Das passte schon in der Logik, aber zum code reichte es bisher nicht.
Wird auch heute und morgen nichts - aber ich halt mir das vor und bau immer mal wieder dran.
Ich glaub, das nennt man Herausforderung....

Deine "SchoeneWerte"-Datei hat in Zeile 20 einen bösen Ausreißer: 3313
Ist vielleicht 313 gemeint? - das würde zu den Werten in der Umgebung passen.