M5Unit-HEART 0.0.2 git rev:70607f7
Loading...
Searching...
No Matches
pulse_monitor.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_HEART_UTILITY_PULSE_MONITOR_HPP
11#define M5_UNIT_HEART_UTILITY_PULSE_MONITOR_HPP
12
13#include <limits>
14#include <cmath>
15#include <cassert>
16#include <deque>
18
19namespace m5 {
24namespace heart {
25
30class EMA {
31public:
32 explicit EMA(float factor) : _alpha(factor)
33 {
34 }
35
36 inline void clear()
37 {
38 _ema_value = std::numeric_limits<float>::quiet_NaN();
39 }
40
41 inline float update(float new_value)
42 {
43 if (!std::isnan(_ema_value)) {
44 _ema_value = _alpha * new_value + (1.0f - _alpha) * _ema_value;
45 } else {
46 _ema_value = new_value;
47 }
48 return _ema_value;
49 }
50
51private:
52 float _alpha{}, _ema_value{std::numeric_limits<float>::quiet_NaN()};
53};
54
59class Filter {
60public:
61 Filter(const float cutoff, const float sampling_rate)
62 {
63 setSamplingRate(cutoff, sampling_rate);
64 }
65
66 void setSamplingRate(const float cutoff, const float sampling_rate)
67 {
68 _cutoff = cutoff;
69 _samplingRate = sampling_rate;
70 _prevIn = _prevOut = 0.0f;
71 auto dt = 1.0f / _samplingRate;
72 auto RC = 1.0f / (2.0f * M_PI * _cutoff);
73 _alpha = RC / (RC + dt);
74 _ema.clear();
75 }
76
77 float process(const float value)
78 {
79 float out = _ema.update(_alpha * (_prevOut + value - _prevIn));
80 _prevIn = value;
81 _prevOut = out;
82 return -out;
83 }
84
85private:
86 EMA _ema{0.95f};
87 float _cutoff{}, _samplingRate{};
88 float _prevIn{}, _prevOut{};
89 float _alpha{};
90};
91
97public:
103 PulseMonitor(const float samplingRate, const uint32_t sec = 5)
104 : _range{sec},
105 _sampling_rate{samplingRate},
106 _max_samples{(size_t)samplingRate * sec},
107 _filterIR(5.0f, samplingRate)
108 {
109 assert(sec >= 1 && "sec must be greater or eaual than 1");
110 assert(samplingRate >= 1.0f && "SamplingRate must be greater or equal than 1.0f");
111 }
112
114 bool isBeat() const
115 {
116 return _beat;
117 }
119 float bpm() const
120 {
121 return _bpm;
122 }
127 float SpO2() const
128 {
129 return _SpO2;
130 }
131
137 void setSamplingRate(const float samplingRate);
138
143 void push_back(const float ir);
150 void push_back(const float ir, const float red);
151
156 void update();
157
159 void clear();
160
161 // filterd ir value
162 float latestIR() const
163 {
164 return !_dataIR.empty() ? _dataIR.back() : std::numeric_limits<float>::quiet_NaN();
165 }
166
167protected:
168 float calculate_bpm();
169
170private:
171 uint32_t _range{}; // Sec.
172 float _sampling_rate{};
173 size_t _max_samples{};
174
175 Filter _filterIR{0.5f, 100.f};
176 std::deque<float> _dataIR;
177
178 bool _beat{};
179 float _bpm{};
180 float _SpO2{};
181
182 uint32_t _count{};
183 float _avered{}, _aveir{};
184 float _sumredrms{}, _sumirrms{};
185};
186
187} // namespace heart
188} // namespace m5
189#endif
Exponential Moving Average.
Definition pulse_monitor.hpp:30
Apply a high-pass filter and reverse polarity.
Definition pulse_monitor.hpp:59
Calculate BPM and SpO2, and detect the pulse beat.
Definition pulse_monitor.hpp:96
PulseMonitor(const float samplingRate, const uint32_t sec=5)
Costructor.
Definition pulse_monitor.hpp:103
bool isBeat() const
Detect beat?
Definition pulse_monitor.hpp:114
void push_back(const float ir)
Push back IR.
Definition pulse_monitor.cpp:39
void clear()
Clear inner data.
Definition pulse_monitor.cpp:29
float SpO2() const
Gets the SpO2.
Definition pulse_monitor.hpp:127
void update()
Update status.
Definition pulse_monitor.cpp:65
float bpm() const
Gets the BPM.
Definition pulse_monitor.hpp:119
void setSamplingRate(const float samplingRate)
Set the sampling rate.
Definition pulse_monitor.cpp:16
Top level namespace of M5stack.
MAX30100 Unit for M5UnitUnified.