Heart Rate Measurement with ESP32 and Pulse Oximeter Module using FFT
Code listing used in video:
// Tinker Foundry
// Heart Rate Measurement with the MAX30102 breakout board using FFT
// Connections from WEMOS D1 R32 board to MAX30102 Breakout Board as follows:
// SCL (ESP32) to SCL (breakout board)
// SDA (ESP32) to SDA (breakout board)
// 3V3 (ESP32) to VIN (breakout board)
// GND (ESP32) to GND (breakout board)
#include <Wire.h>
#include "MAX30105.h" // sparkfun MAX3010X library
MAX30105 particleSensor;
#include "arduinoFFT.h"
arduinoFFT FFT;
double avered = 0;
double aveir = 0;
double sumirrms = 0;
double sumredrms = 0;
int i = 0;
int Num = 100; // calculate SpO2 by this sampling interval
int Temperature;
int temp;
float ESpO2; // initial value of estimated SpO2
double FSpO2 = 0.7; // filter factor for estimated SpO2
double frate = 0.95; // low pass filter for IR/red LED value to eliminate AC component
#define TIMETOBOOT 3000 // wait for this time(msec) to output SpO2
#define SCALE 88.0 // adjust to display heart beat and SpO2 in the same scale
#define SAMPLING 100 //25 //5 // if you want to see heart beat more precisely, set SAMPLING to 1
#define FINGER_ON 30000 // if red signal is lower than this, it indicates your finger is not on the sensor
#define USEFIFO
#define PULSE_SAMPLES 256
#define SAMPLE_FREQ 50
// --- For Heart Rate ---
byte rateSpot = 0;
long lastBeat = 0; // Time at which the last beat occurred
int beatAvg = 0;
bool detect_high = 0;
// ----------------------
double redArray[PULSE_SAMPLES]; // array to store samples from the sensor
double vReal[PULSE_SAMPLES];
double vImag[PULSE_SAMPLES];
double beatsPerMinute = 0;
void setup()
{
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
Serial.println("Running...");
delay(3000);
// Initialize sensor
while (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
Serial.println("MAX30102 was not found. Please check wiring/power/solder jumper at MH-ET LIVE MAX30102 board. ");
//while (1);
}
//Setup to sense a nice looking saw tooth on the plotter
byte ledBrightness = 0x7F; // Options: 0=Off to 255=50mA
byte sampleAverage = 4; // Options: 1, 2, 4, 8, 16, 32
byte ledMode = 2; // Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
//Options: 1 = IR only, 2 = Red + IR on MH-ET LIVE MAX30102 board
int sampleRate = 200; // Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 411; // Options: 69, 118, 215, 411
int adcRange = 16384; // Options: 2048, 4096, 8192, 16384
// Set up the wanted parameters
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
particleSensor.enableDIETEMPRDY();
}
void loop()
{
uint32_t ir, red, green;
double fred, fir;
double SpO2 = 0; //raw SpO2 before low pass filtered
float red_beat = 0;
#ifdef USEFIFO
particleSensor.check(); // Check the sensor, read up to 3 samples
while (particleSensor.available())
{ // Do we have new data
#ifdef MAX30105
red = particleSensor.getFIFORed(); // Sparkfun's MAX30105
ir = particleSensor.getFIFOIR(); // Sparkfun's MAX30105
#else
red = particleSensor.getFIFOIR(); // why getFOFOIR output Red data by MAX30102 on MH-ET LIVE breakout board
ir = particleSensor.getFIFORed(); // why getFIFORed output IR data by MAX30102 on MH-ET LIVE breakout board
#endif
i++;
i = i % PULSE_SAMPLES; // wrap around every 256 samples
fred = (double)red;
redArray[i] = fred; // populate the array
particleSensor.nextSample(); // We're finished with this sample so move to next sample
if (i == 0) // execute every PULSE_SAMPLES
{
Serial.print("Time: ");
Serial.println(millis()); // can use this to determine time it takes to collect 256 samples (sample rate)
for (int idx=0; idx < PULSE_SAMPLES; idx++)
{
vReal[idx] = redArray[idx];
vImag[idx] = 0.0;
//Serial.println(redArray[idx]);
}
FFT = arduinoFFT(vReal, vImag, PULSE_SAMPLES, SAMPLE_FREQ); /* Create FFT object */
FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); /* Weigh data */
FFT.Compute(FFT_FORWARD); /* Compute FFT */
FFT.ComplexToMagnitude(); /* Compute magnitudes */
double peak = FFT.MajorPeak();
//Serial.println(peak, 6);
// print in beats per minute
beatsPerMinute = peak * 60;
Serial.print("BPM: ");
Serial.println(beatsPerMinute);
}
}
#endif
//Serial.println(i);
}
Comments
Post a Comment