blob: 2f8a1faa006c07e9afbc4e36cb223db85e2a2e33 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
// Note: Change internal define 'sqrt_internal sqrt' to
// 'sqrt_internal sqrtf' to save ~3KB of flash.
#define FFT_SPEED_OVER_PRECISION
#include "libs/arduinoFFT-develop/src/arduinoFFT.h"
namespace Pinetime {
namespace Controllers {
class Ppg {
public:
Ppg();
int8_t Preprocess(uint32_t hrs, uint32_t als);
int HeartRate();
void Reset(bool resetDaqBuffer);
static constexpr int deltaTms = 100;
// Daq dataLength: Must be power of 2
static constexpr uint16_t dataLength = 64;
static constexpr uint16_t spectrumLength = dataLength >> 1;
private:
// The sampling frequency (Hz) based on sampling time in milliseconds (DeltaTms)
static constexpr float sampleFreq = 1000.0f / static_cast<float>(deltaTms);
// The frequency resolution (Hz)
static constexpr float freqResolution = sampleFreq / dataLength;
// Number of samples before each analysis
// 0.5 second update rate at 10Hz
static constexpr uint16_t overlapWindow = 5;
// Maximum number of spectrum running averages
// Note: actual number of spectra averaged = spectralAvgMax + 1
static constexpr uint16_t spectralAvgMax = 2;
// Multiple Peaks above this threshold (% of max) are rejected
static constexpr float peakDetectionThreshold = 0.6f;
// Maximum peak width (bins) at threshold for valid peak.
static constexpr float maxPeakWidth = 2.5f;
// Metric for spectrum noise level.
static constexpr float signalToNoiseThreshold = 3.0f;
// Heart rate Region Of Interest begin (bins)
static constexpr uint16_t hrROIbegin = static_cast<uint16_t>((30.0f / 60.0f) / freqResolution + 0.5f);
// Heart rate Region Of Interest end (bins)
static constexpr uint16_t hrROIend = static_cast<uint16_t>((240.0f / 60.0f) / freqResolution + 0.5f);
// Minimum HR (Hz)
static constexpr float minHR = 40.0f / 60.0f;
// Maximum HR (Hz)
static constexpr float maxHR = 230.0f / 60.0f;
// Threshold for high DC level after filtering
static constexpr float dcThreshold = 0.5f;
// ALS detection factor
static constexpr float alsFactor = 2.0f;
// Raw ADC data
std::array<uint16_t, dataLength> dataHRS;
// Stores Real numbers from FFT
std::array<float, dataLength> vReal;
// Stores Imaginary numbers from FFT
std::array<float, dataLength> vImag;
// Stores power spectrum calculated from FFT real and imag values
std::array<float, (spectrumLength)> spectrum;
// Stores each new HR value (Hz). Non zero values are averaged for HR output
std::array<float, 20> dataAverage;
uint16_t avgIndex = 0;
uint16_t spectralAvgCount = 0;
float lastPeakLocation = 0.0f;
uint16_t alsThreshold = UINT16_MAX;
uint16_t alsValue = 0;
uint16_t dataIndex = 0;
float peakLocation;
bool resetSpectralAvg = true;
int ProcessHeartRate(bool init);
float HeartRateAverage(float hr);
void SpectrumAverage(const float* data, float* spectrum, int length, bool reset);
};
}
}
|