element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Design For A Cause 2021
  • Challenges & Projects
  • Design Challenges
  • Design For A Cause 2021
  • More
  • Cancel
Design For A Cause 2021
Blog Vital Care - 02.b SPO2 [MAX30102]
  • Blog
  • Forum
  • Documents
  • Polls
  • Files
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: sunnyiut
  • Date Created: 27 May 2021 8:58 PM Date Created
  • Views 1811 views
  • Likes 3 likes
  • Comments 0 comments
  • design for a cause 2021
  • spo2
  • max30102
  • heart rate
Related
Recommended

Vital Care - 02.b SPO2 [MAX30102]

sunnyiut
sunnyiut
27 May 2021

Title: Vital Care

By: Md. Kamrul Hussain

Project Category: Design Challenge

Project Name: Design For A Cause 2021

Blog post: 03

 

Previous Blogs:

image

Blog No.Title
01

Introduction

02.a

SpO2 basics [PPG]

 

In my previous blog I shared my experiment with PPG signal from scratch, using basic transimpedance amplifier and filter circuits. In this blog I'll share my work on measuring Heart Rate and SPO2 using MAX30102 module. I am using the MAXREFDES117# which utilizes the heart-rate/SpO2 sensor (MAX30102), an efficient, low-power step-down converter (MAX1921), and an accurate level translator (MAX14595). The entire design typically operates at less than 5.5mW and the module can be placed on a person’s fingertip, earlobe, or other fleshy extremity.

The step-down converter MAX1921 converts the 2V to 5.5V supply input and generates the 1.8V rail for the heart-rate sensor. The MAX14595 level translator provides an interface between the heart-rate/SpO2 sensor and the controller board, which generally use a different logic level.

 

 

System Diagram:                                                                                          Functional Diagram:

imageimage

 

I have used Arduino NANO 33 IOT to configure the MAX30102 module and read sampled data, calculated heart rate and SpO2 and display through a terminal program. I have utilized the RD117_ARDUINO library from MAXIM, which was modified by Sparkfun for their MAX30105 particle sensor module. Both MAX30102 and MAX30105 shares the same chip identification number, therefore the library works for both the chips. I slightly modified it according to my requirements where the process flow is shown below.

 

Process flow:

imageimage

 

Configuration:

Sampling Rate and Pulse width -

A pulse width tells how long in time a signal is active for. In terms of power consumption, the longer a signal is active, the more energy it consumes. The drive frequency for the LEDs is selected by the sample rate. Correspondingly, a higher sample rate results in a higher drive frequency, thereby consuming more energy. In this Arduino platforms store 4 seconds of samples collected at 25sps. A Pulse width of 411usec is chosen which gives 18bit resolution.

 

Mode-

SpO2 mode [0x011] is selected and ADC is configured for Full Scale range at 4096nA

imageimage

The LED current can be programmed from 0 to 50mA with proper supply voltage. At finger tip 0x1B [~6mA] provides enough strong PPG signals to process.

image

 

Post-processing requires several steps which include filtering, peak-to-peak detection, normalization, and digital signal processing.

PPG signal has two peaks - systolic and diastolic. Heart rate is found by measuring the time between consecutive systolic peaks and then multiplying it by 60.

DC and AC components should be verified first. The next step is to normalize the two (by taking the ratio of AC to DC) and then finding a value “R,” which is the ratio of normalized Red to normalized IR data. Finally, a linear approximation can be used to find SpO2. AN6409 application note from Maxim Integrated presents an effective concept of finding out the DC and AC components from the PPG signal.

the DC component was found by using a straight-line approximation between two valleys. Let’s label the points first. Call the valley between 50 to 100 “1” and the valley between 150 to 200 “3.” The peak between 150 and 200 is called “2.”

The DC component is the offset of the AC signal, which can be found by first drawing a line between 1 and 3 and then drawing a line parallel to the y axis from 2 to the line connecting 1 and 3. The DC value is the point where the two lines intersect.

The AC component on the other hand is the distance between the peak (“2”) and the DC value.

image

The AC and DC components are labeled above each graph. The following equations were used to first find “R” and then SpO2.

image

SpO2 = 104 – 17R = 104 – 17 (0.43) = 96.8%

 

Output:

{gallery} MAX30102 output

image

Serial Terminal prints: RED and IR PPG values and calculated Heart Rate with SpO2

image

Plot PPG: Lower red plot represents RED PPG and upper orange plot represents IR PPG

image

Plot PPG HR and SpO2: Heart Rate and SpO2 variations are plotted for the time being with PPG signals. Both HR and SpO2 plots are multiplied by 1000 to fit with the PPG plot for better visualization

 

#include <Wire.h>
#include "MAX30105.h"
#include "spo2_algorithm.h"


MAX30105 particleSensor;


#define MAX_BRIGHTNESS 255


#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
//Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
//To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data.
uint16_t irBuffer[50]; //infrared LED sensor data
uint16_t redBuffer[50];  //red LED sensor data
#else
uint32_t irBuffer[50]; //infrared LED sensor data
uint32_t redBuffer[50];  //red LED sensor data
#endif


int32_t bufferLength; //data length
int32_t spo2; //SPO2 value
int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
int32_t heartRate; //heart rate value
int8_t validHeartRate; //indicator to show if the heart rate calculation is valid


byte pulseLED = 9; //Must be on PWM pin
byte readLED = 13; //Blinks with each data read


void setup()
{
  Serial.begin(115200); // initialize serial communication at 115200 bits per second:
  while (!Serial);
  
  pinMode(pulseLED, OUTPUT);
  pinMode(readLED, OUTPUT);


  // Initialize sensor
  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println(F("MAX30105 was not found. Please check wiring/power."));
    while (1);
  }


  Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion"));
  while (Serial.available() == 0) ; //wait until user presses a key
  Serial.read();


  byte ledBrightness = 27; //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
  byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth = 411; //Options: 69, 118, 215, 411
  int adcRange = 4096; //Options: 2048, 4096, 8192, 16384


  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
}


void loop()
{
  bufferLength = 50; //buffer length of 50 stores 2 seconds of samples running at 25sps


  //read the first 100 samples, and determine the signal range
  for (byte i = 0 ; i < bufferLength ; i++)
  {
    while (particleSensor.available() == false) //do we have new data?
      particleSensor.check(); //Check the sensor for new data


    redBuffer[i] = particleSensor.getRed();
    irBuffer[i] = particleSensor.getIR();
    particleSensor.nextSample(); //We're finished with this sample so move to next sample


    Serial.print(F("red="));
    Serial.print(redBuffer[i], DEC);
    Serial.print(F(", ir="));
    Serial.println(irBuffer[i], DEC);
  }


  //calculate heart rate and SpO2 after first 50 samples (first 2 seconds of samples)
  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);


  //Continuously taking samples from MAX30102.  Heart rate and SpO2 are calculated every 1 second
  while (1)
  {
    //dumping the first 15 sets of samples in the memory and shift the last 15 sets of samples to the top
    for (byte i = 15; i < 50; i++)
    {
      redBuffer[i - 15] = redBuffer[i];
      irBuffer[i - 15] = irBuffer[i];
    }


    heartRate = heartRate * 1000;
    spo2 = spo2 * 1000;
    
    //take 15 sets of samples before calculating the heart rate.
    for (byte i = 35; i < 50; i++)
    {
      while (particleSensor.available() == false) //do we have new data?
        particleSensor.check(); //Check the sensor for new data


      digitalWrite(readLED, !digitalRead(readLED)); //Blink onboard LED with every data read


      redBuffer[i] = particleSensor.getRed();
      irBuffer[i] = particleSensor.getIR();
      particleSensor.nextSample(); //We're finished with this sample so move to next sample


      //send samples and calculation result to terminal program through UART
      Serial.print(F("RED= "));
      Serial.print(redBuffer[i], DEC);
      Serial.print('\t');
      
      Serial.print(F("IR= "));
      Serial.print(irBuffer[i], DEC);
      Serial.print('\t');


      Serial.print(F("HR= "));
      Serial.print(heartRate, DEC);
      Serial.print('\t');


      //Serial.print(F(", HRvalid="));
      //Serial.print(validHeartRate, DEC);


      Serial.print(F("SPO2= "));
      Serial.println(spo2, DEC);


      //Serial.print(F(", SPO2Valid="));
      //Serial.println(validSPO2, DEC);
    }


    //After gathering 15 new samples recalculate HR and SP02
    maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
  }
}

  • Sign in to reply
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube