I have recently purchased a MAX30101 breakout board / sensor and have been using it with a Raspberry Pi 4 and Python. I have been using the sparkfun-qwiic-max3010x library provided by Sparkfun to communicate with the sensor and collect data. The GitHub page for the Python sparkfun-qwiic-max3010x library includes an example for calculating heart rate but not SpO2. The Arduino library includes an example for calculating heart rate and SpO2.
I was wondering if there is an algorithm available or if it is possible to calculate SpO2 accurately in Python on the Raspberry Pi 4.
I have seen an algorithm in the user guide of the MAX30101 sensor but have not been able to accurately get an SpO2 reading with it in Python in the following code. The SpO2 value sometimes goes in the negatives and will give extremely different consecutive values.
import time
import numpy as np
import qwiic_max3010x
# Initialize the MAX30101 sensor
sensor = qwiic_max3010x.QwiicMax3010x()
sensor.begin()
sensor.setup()
sensor.setPulseAmplitudeGreen(0)
# Function to read raw values from the sensor
def read_raw_values(num_samples=100):
red_values = []
ir_values = []
for _ in range(num_samples):
red = sensor.getRed()
ir = sensor.getIR()
red_values.append(red)
ir_values.append(ir)
time.sleep(0.01) # Adjust the delay as needed
sensor.shutDown()
return np.array(red_values), np.array(ir_values)
# Function to calculate AC and DC components
def calculate_ac_dc(raw_values):
dc = np.mean(raw_values) # DC component
ac = raw_values - dc # AC component
return ac, dc
def calculate_spo2(red_ac, red_dc, ir_ac, ir_dc):
r = (np.mean(red_ac) / red_dc) / (np.mean(ir_ac) / ir_dc)
spo2 = 104 - (17 * r)
return spo2
# Main loop
try:
while True:
# Read raw values
red_raw, ir_raw = read_raw_values(num_samples=100)
# Calculate AC and DC components
red_ac, red_dc = calculate_ac_dc(red_raw)
ir_ac, ir_dc = calculate_ac_dc(ir_raw)
spo2 = calculate_spo2(red_ac, red_dc, ir_ac, ir_dc)
print("Spo2: ", spo2)
# Wait for a bit before the next reading
time.sleep(1) # Adjust the sleep time as needed
except KeyboardInterrupt:
print("Program stopped.")
I have recently purchased a MAX30101 breakout board / sensor and have been using it with a Raspberry Pi 4 and Python. I have been using the sparkfun-qwiic-max3010x library provided by Sparkfun to communicate with the sensor and collect data. The GitHub page for the Python sparkfun-qwiic-max3010x library includes an example for calculating heart rate but not SpO2. The Arduino library includes an example for calculating heart rate and SpO2.
I was wondering if there is an algorithm available or if it is possible to calculate SpO2 accurately in Python on the Raspberry Pi 4.
I have seen an algorithm in the user guide of the MAX30101 sensor but have not been able to accurately get an SpO2 reading with it in Python in the following code. The SpO2 value sometimes goes in the negatives and will give extremely different consecutive values.
import time
import numpy as np
import qwiic_max3010x
# Initialize the MAX30101 sensor
sensor = qwiic_max3010x.QwiicMax3010x()
sensor.begin()
sensor.setup()
sensor.setPulseAmplitudeGreen(0)
# Function to read raw values from the sensor
def read_raw_values(num_samples=100):
red_values = []
ir_values = []
for _ in range(num_samples):
red = sensor.getRed()
ir = sensor.getIR()
red_values.append(red)
ir_values.append(ir)
time.sleep(0.01) # Adjust the delay as needed
sensor.shutDown()
return np.array(red_values), np.array(ir_values)
# Function to calculate AC and DC components
def calculate_ac_dc(raw_values):
dc = np.mean(raw_values) # DC component
ac = raw_values - dc # AC component
return ac, dc
def calculate_spo2(red_ac, red_dc, ir_ac, ir_dc):
r = (np.mean(red_ac) / red_dc) / (np.mean(ir_ac) / ir_dc)
spo2 = 104 - (17 * r)
return spo2
# Main loop
try:
while True:
# Read raw values
red_raw, ir_raw = read_raw_values(num_samples=100)
# Calculate AC and DC components
red_ac, red_dc = calculate_ac_dc(red_raw)
ir_ac, ir_dc = calculate_ac_dc(ir_raw)
spo2 = calculate_spo2(red_ac, red_dc, ir_ac, ir_dc)
print("Spo2: ", spo2)
# Wait for a bit before the next reading
time.sleep(1) # Adjust the sleep time as needed
except KeyboardInterrupt:
print("Program stopped.")
Share
Improve this question
asked Mar 28 at 2:29
Ish18Ish18
231 silver badge3 bronze badges
1
- see whether it is related to difference in n-bit arithmetics. numpy arrays use int64 in your code, float64 for mean. While C++ code uses uint32, int32 (and even uint16,int16 sometimes) github/sparkfun/SparkFun_MAX3010x_Sensor_Library/blob/… – jfs Commented Mar 28 at 5:26
1 Answer
Reset to default 4Calculating r
the way you do is incorrect. By the very nature of red_ac
its mean
is almost zero (it is not exactly zero because of rounding errors). Same for ir_ic
. Dividing two such values results in a huge meaningless error, precisely what you observe.
Notice that in the Maxim paper you linked they do not divide averages. They divide instant readings, normalized by the averages. So the first thing you shall try is to
calculate instant values of r[i] = (red_ac[i]/red_dc) / (ir_ac[i]/ir_dc)
and average them over the observation window. In the ideal case you'll get reasonable results.
Then you'd have to deal with the noise. The signals you sample are far from ideal, and it is not coincidental that the Arduino code does not resemble the simple formula. Most of the SpO2 computation is fighting noise.