HAND

Dependents:   HAND

Committer:
condato_mbed
Date:
Wed Nov 03 15:59:01 2021 +0000
Revision:
1:a9cc51956082
Parent:
0:010b908e2187
HAND

Who changed what in which revision?

UserRevisionLine numberNew contents of line
AVELARDEV 0:010b908e2187 1 /*
AVELARDEV 0:010b908e2187 2 Arduino-MAX30100 oximetry / heart rate integrated sensor library
AVELARDEV 0:010b908e2187 3 Copyright (C) 2016 OXullo Intersecans <x@brainrapers.org>
AVELARDEV 0:010b908e2187 4 This program is free software: you can redistribute it and/or modify
AVELARDEV 0:010b908e2187 5 it under the terms of the GNU General Public License as published by
AVELARDEV 0:010b908e2187 6 the Free Software Foundation, either version 3 of the License, or
AVELARDEV 0:010b908e2187 7 (at your option) any later version.
AVELARDEV 0:010b908e2187 8 This program is distributed in the hope that it will be useful,
AVELARDEV 0:010b908e2187 9 but WITHOUT ANY WARRANTY; without even the implied warranty of
AVELARDEV 0:010b908e2187 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
AVELARDEV 0:010b908e2187 11 GNU General Public License for more details.
AVELARDEV 0:010b908e2187 12 You should have received a copy of the GNU General Public License
AVELARDEV 0:010b908e2187 13 along with this program. If not, see <http://www.gnu.org/licenses/>.
AVELARDEV 0:010b908e2187 14 */
AVELARDEV 0:010b908e2187 15
AVELARDEV 0:010b908e2187 16 #include "MAX30100_BeatDetector.h"
AVELARDEV 0:010b908e2187 17
AVELARDEV 0:010b908e2187 18 BeatDetector::BeatDetector() :
AVELARDEV 0:010b908e2187 19 state(BEATDETECTOR_STATE_INIT),
AVELARDEV 0:010b908e2187 20 threshold(BEATDETECTOR_MIN_THRESHOLD),
AVELARDEV 0:010b908e2187 21 beatPeriod(0),
AVELARDEV 0:010b908e2187 22 lastMaxValue(0),
AVELARDEV 0:010b908e2187 23 tsLastBeat(0)
AVELARDEV 0:010b908e2187 24 {
AVELARDEV 0:010b908e2187 25 t.start();
AVELARDEV 0:010b908e2187 26 }
AVELARDEV 0:010b908e2187 27
AVELARDEV 0:010b908e2187 28 bool BeatDetector::addSample(float sample)
AVELARDEV 0:010b908e2187 29 {
AVELARDEV 0:010b908e2187 30 return checkForBeat(sample);
AVELARDEV 0:010b908e2187 31 }
AVELARDEV 0:010b908e2187 32
AVELARDEV 0:010b908e2187 33 float BeatDetector::getRate()
AVELARDEV 0:010b908e2187 34 {
AVELARDEV 0:010b908e2187 35 if (beatPeriod != 0) {
AVELARDEV 0:010b908e2187 36 return 1 / beatPeriod * 1000 * 60;
AVELARDEV 0:010b908e2187 37 } else {
AVELARDEV 0:010b908e2187 38 return 0;
AVELARDEV 0:010b908e2187 39 }
AVELARDEV 0:010b908e2187 40 }
AVELARDEV 0:010b908e2187 41
AVELARDEV 0:010b908e2187 42 float BeatDetector::getCurrentThreshold()
AVELARDEV 0:010b908e2187 43 {
AVELARDEV 0:010b908e2187 44 return threshold;
AVELARDEV 0:010b908e2187 45 }
AVELARDEV 0:010b908e2187 46
AVELARDEV 0:010b908e2187 47 bool BeatDetector::checkForBeat(float sample)
AVELARDEV 0:010b908e2187 48 {
AVELARDEV 0:010b908e2187 49 bool beatDetected = false;
AVELARDEV 0:010b908e2187 50
AVELARDEV 0:010b908e2187 51 switch (state) {
AVELARDEV 0:010b908e2187 52 case BEATDETECTOR_STATE_INIT:
AVELARDEV 0:010b908e2187 53 if (t.read_ms() > BEATDETECTOR_INIT_HOLDOFF) {
AVELARDEV 0:010b908e2187 54 state = BEATDETECTOR_STATE_WAITING;
AVELARDEV 0:010b908e2187 55 }
AVELARDEV 0:010b908e2187 56 break;
AVELARDEV 0:010b908e2187 57
AVELARDEV 0:010b908e2187 58 case BEATDETECTOR_STATE_WAITING:
AVELARDEV 0:010b908e2187 59 if (sample > threshold) {
AVELARDEV 0:010b908e2187 60 threshold = std::min((uint32_t)sample, (uint32_t)BEATDETECTOR_MAX_THRESHOLD);
AVELARDEV 0:010b908e2187 61 state = BEATDETECTOR_STATE_FOLLOWING_SLOPE;
AVELARDEV 0:010b908e2187 62 }
AVELARDEV 0:010b908e2187 63
AVELARDEV 0:010b908e2187 64 // Tracking lost, resetting
AVELARDEV 0:010b908e2187 65 if (t.read_ms() > BEATDETECTOR_INVALID_READOUT_DELAY) {
AVELARDEV 0:010b908e2187 66 beatPeriod = 0;
AVELARDEV 0:010b908e2187 67 lastMaxValue = 0;
AVELARDEV 0:010b908e2187 68 }
AVELARDEV 0:010b908e2187 69
AVELARDEV 0:010b908e2187 70 decreaseThreshold();
AVELARDEV 0:010b908e2187 71 break;
AVELARDEV 0:010b908e2187 72
AVELARDEV 0:010b908e2187 73 case BEATDETECTOR_STATE_FOLLOWING_SLOPE:
AVELARDEV 0:010b908e2187 74 if (sample < threshold) {
AVELARDEV 0:010b908e2187 75 state = BEATDETECTOR_STATE_MAYBE_DETECTED;
AVELARDEV 0:010b908e2187 76 } else {
AVELARDEV 0:010b908e2187 77 threshold = std::min((uint32_t)sample, (uint32_t)BEATDETECTOR_MAX_THRESHOLD);
AVELARDEV 0:010b908e2187 78 }
AVELARDEV 0:010b908e2187 79 break;
AVELARDEV 0:010b908e2187 80
AVELARDEV 0:010b908e2187 81 case BEATDETECTOR_STATE_MAYBE_DETECTED:
AVELARDEV 0:010b908e2187 82 if (sample + BEATDETECTOR_STEP_RESILIENCY < threshold) {
AVELARDEV 0:010b908e2187 83 // Found a beat
AVELARDEV 0:010b908e2187 84 beatDetected = true;
AVELARDEV 0:010b908e2187 85 lastMaxValue = sample;
AVELARDEV 0:010b908e2187 86 state = BEATDETECTOR_STATE_MASKING;
AVELARDEV 0:010b908e2187 87 float delta = t.read_ms();
AVELARDEV 0:010b908e2187 88 if (delta) {
AVELARDEV 0:010b908e2187 89 beatPeriod = BEATDETECTOR_BPFILTER_ALPHA * delta +
AVELARDEV 0:010b908e2187 90 (1 - BEATDETECTOR_BPFILTER_ALPHA) * beatPeriod;
AVELARDEV 0:010b908e2187 91 }
AVELARDEV 0:010b908e2187 92
AVELARDEV 0:010b908e2187 93 t.reset();
AVELARDEV 0:010b908e2187 94 } else {
AVELARDEV 0:010b908e2187 95 state = BEATDETECTOR_STATE_FOLLOWING_SLOPE;
AVELARDEV 0:010b908e2187 96 }
AVELARDEV 0:010b908e2187 97 break;
AVELARDEV 0:010b908e2187 98
AVELARDEV 0:010b908e2187 99 case BEATDETECTOR_STATE_MASKING:
AVELARDEV 0:010b908e2187 100 if (t.read_ms() > BEATDETECTOR_MASKING_HOLDOFF) {
AVELARDEV 0:010b908e2187 101 state = BEATDETECTOR_STATE_WAITING;
AVELARDEV 0:010b908e2187 102 }
AVELARDEV 0:010b908e2187 103 decreaseThreshold();
AVELARDEV 0:010b908e2187 104 break;
AVELARDEV 0:010b908e2187 105 }
AVELARDEV 0:010b908e2187 106
AVELARDEV 0:010b908e2187 107 return beatDetected;
AVELARDEV 0:010b908e2187 108 }
AVELARDEV 0:010b908e2187 109
AVELARDEV 0:010b908e2187 110 void BeatDetector::decreaseThreshold()
AVELARDEV 0:010b908e2187 111 {
AVELARDEV 0:010b908e2187 112 // When a valid beat rate readout is present, target the
AVELARDEV 0:010b908e2187 113 if (lastMaxValue > 0 && beatPeriod > 0) {
AVELARDEV 0:010b908e2187 114 threshold -= lastMaxValue * (1 - BEATDETECTOR_THRESHOLD_FALLOFF_TARGET) /
AVELARDEV 0:010b908e2187 115 (beatPeriod / BEATDETECTOR_SAMPLES_PERIOD);
AVELARDEV 0:010b908e2187 116 } else {
AVELARDEV 0:010b908e2187 117 // Asymptotic decay
AVELARDEV 0:010b908e2187 118 threshold *= BEATDETECTOR_THRESHOLD_DECAY_FACTOR;
AVELARDEV 0:010b908e2187 119 }
AVELARDEV 0:010b908e2187 120
AVELARDEV 0:010b908e2187 121 if (threshold < BEATDETECTOR_MIN_THRESHOLD) {
AVELARDEV 0:010b908e2187 122 threshold = BEATDETECTOR_MIN_THRESHOLD;
AVELARDEV 0:010b908e2187 123 }
AVELARDEV 0:010b908e2187 124 }