M5Unit-HEART 0.2.1 git rev:e0975a4
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>
17#include <m5_utility/log/library_log.hpp>
18
19namespace m5 {
24namespace heart {
25
30class EMA {
31public:
34 explicit EMA(float factor) : _alpha(factor)
35 {
36 }
37
39 inline void clear()
40 {
41 _ema_value = std::numeric_limits<float>::quiet_NaN();
42 }
43
47 inline float update(float new_value)
48 {
49 if (!std::isnan(_ema_value)) {
50 _ema_value = _alpha * new_value + (1.0f - _alpha) * _ema_value;
51 } else {
52 _ema_value = new_value;
53 }
54 return _ema_value;
55 }
56
57private:
58 float _alpha{}, _ema_value{std::numeric_limits<float>::quiet_NaN()};
59};
60
65class Filter {
66public:
70 Filter(const float cutoff, const float sampling_rate)
71 {
72 setSamplingRate(cutoff, sampling_rate);
73 }
74
78 void setSamplingRate(const float cutoff, const float sampling_rate)
79 {
80 constexpr float pi{3.14159265358979323846f};
81 _cutoff = cutoff;
82 _samplingRate = sampling_rate;
83 _prevIn = _prevOut = 0.0f;
84 auto dt = 1.0f / _samplingRate;
85 auto RC = 1.0f / (2.0f * pi * _cutoff);
86 _alpha = RC / (RC + dt);
87 _ema.clear();
88 }
89
93 float process(const float value)
94 {
95 float out = _ema.update(_alpha * (_prevOut + value - _prevIn));
96 _prevIn = value;
97 _prevOut = out;
98 return -out;
99 }
100
101private:
102 EMA _ema{0.95f};
103 float _cutoff{}, _samplingRate{};
104 float _prevIn{}, _prevOut{};
105 float _alpha{};
106};
107
113public:
119 explicit PulseMonitor(const uint32_t samplingRate = 100, const uint32_t sec = 5)
120 : _range{sec},
121 _sampling_rate{(float)samplingRate},
122 _max_samples{static_cast<size_t>(samplingRate) * sec},
123 _filterIR(5.0f, samplingRate)
124 {
125 assert(sec >= 1 && "sec must be greater or equal than 1");
126 assert(samplingRate >= 1.0f && "SamplingRate must be greater or equal than 1.0f");
127 }
128
130 inline bool isBeat() const
131 {
132 return _beat;
133 }
135 inline float bpm() const
136 {
137 return _bpm;
138 }
143 inline float SpO2() const
144 {
145 return _spo2;
146 }
147
153 void setSamplingRate(const uint32_t samplingRate);
154
159 void push_back(const float ir);
166 void push_back(const float ir, const float red);
167
172 void update();
173
175 void clear();
176
178 inline float latestIR() const
179 {
180 return !_dataIR.empty() ? _dataIR.back() : std::numeric_limits<float>::quiet_NaN();
181 }
182
183protected:
184 float calculate_bpm();
185
186private:
187 uint32_t _range{}; // Sec.
188 float _sampling_rate{};
189 size_t _max_samples{};
190
191 Filter _filterIR{0.5f, 100.f};
192 std::deque<float> _dataIR;
193
194 bool _beat{};
195 float _bpm{};
196 float _spo2{};
197
198 uint32_t _count{};
199 float _avered{}, _aveir{};
200 float _sumredrms{}, _sumirrms{};
201};
202
203} // namespace heart
204} // namespace m5
205#endif
Exponential Moving Average.
Definition pulse_monitor.hpp:30
EMA(float factor)
Constructor.
Definition pulse_monitor.hpp:34
float update(float new_value)
Update with a new value and return the smoothed result.
Definition pulse_monitor.hpp:47
void clear()
Clear the stored value.
Definition pulse_monitor.hpp:39
Apply a high-pass filter and invert polarity.
Definition pulse_monitor.hpp:65
float process(const float value)
Process a sample through the filter.
Definition pulse_monitor.hpp:93
void setSamplingRate(const float cutoff, const float sampling_rate)
Set the sampling rate and reset filter state.
Definition pulse_monitor.hpp:78
Filter(const float cutoff, const float sampling_rate)
Constructor.
Definition pulse_monitor.hpp:70
Calculate BPM and SpO2, and detect the pulse beat.
Definition pulse_monitor.hpp:112
bool isBeat() const
Detect beat?
Definition pulse_monitor.hpp:130
void push_back(const float ir)
Push back IR.
Definition pulse_monitor.cpp:39
PulseMonitor(const uint32_t samplingRate=100, const uint32_t sec=5)
Constructor.
Definition pulse_monitor.hpp:119
void clear()
Clear inner data.
Definition pulse_monitor.cpp:29
float SpO2() const
Gets the SpO2.
Definition pulse_monitor.hpp:143
void setSamplingRate(const uint32_t samplingRate)
Set the sampling rate.
Definition pulse_monitor.cpp:16
float latestIR() const
Filtered latest ir value.
Definition pulse_monitor.hpp:178
void update()
Update status.
Definition pulse_monitor.cpp:72
float bpm() const
Gets the BPM.
Definition pulse_monitor.hpp:135
Unit-HEART related.
Top level namespace of M5Stack.