coniferconifer / ESP32_MAX30102_simple-SpO2_plotter

Simple SpO2 plotter from scratch for Arduno IDE by reading MH-ET LIVE MAX30102 raw RED/IR data
Apache License 2.0
42 stars 17 forks source link

Equation for SPO2, SpO2 = -23.3 * (R - 0.4) + 100; #1

Open shahanHasan opened 2 years ago

shahanHasan commented 2 years ago
Screen Shot 2022-05-30 at 3 18 45 AM

Could you please explain to us, how you derived this equation from the calibration curve in the document AN1525 (Pulse Oximeter Design Using Microchip’s Analog Devices and dsPIC® Digital Signal Controllers (DSCs))

coniferconifer commented 2 years ago

Thank you for your interest. This is because a linear approximation of SpO2 from 100 to about 80 is sufficient for practical purposes. SpO2 below 80 is a difficult value for survival. let SpO2 = A(Ratio - 0.4 )+ B (Ratio is 0.4 at left bottom of the graph)
How to calculate A and B because SpO2=100 at Ratio=0.4 , then B=100 Let's read out the points at (Rasio,SpO2)=( 0.4, 100 ) and ( 1, 86 ) for Ratio-axis difference is 1 - 0.4 => 0.6 for SpO2-axis difference is 86 - 100 => -14 therefore A = -14/0.6 =>-23.3 SpO2 = -23.3
(Ratio - 0.4 )+ 100 SpO2 below 86 to 80 is slightly lower than by this formula.

shahanHasan commented 2 years ago

Ok , I think got it now. So Spo2 is calculated using a linear equation like y = mx + c where y is spo2, m is A, c is B. However to follow up the above, you used x = (Ratio - 0.4) is this because the graph starts at 0.4 and a ration of below 0.4 is undefined based on this graph ? Can we think of B / c (in case of y = mx + c ) as the y intercept ? and A is the slope of the linear approximation function / in other words the derivative of the function. so m = - dy/dx in this case where the 2 points on the line are (100,0.4) and (86,1) ?

Is it possible to have 3 different linear approximation functions based on the value of 0.4 inferred from the curve above. So from 0.4 to 1 , 1 to 2 and 2 to 3.5 and then perhaps depending on the ration and the linear approximation function a fairly accurate spo2 can be calculated ?

shahanHasan commented 2 years ago

I have some more queries if you don't mind me asking.

  1. Could you please explain the digital low pass filter algorithm you used for IR and RED led to eliminate the AC component. Could you also provide the sources for all the equations you used in that regard. The equations : avered = avered frate + (double)red (1.0 - frate); //average red level by low pass filter aveir = aveir frate + (double)ir (1.0 - frate); //average IR level by low pass filter

  2. Could you please explain the filter factor for SPO2 (FSpO2= 0.7) and the theory regarding that. Could you please also explain the digital low pass filter algorithm used for calculation of SPO2 and provide all the relevant sources. The equation : ESpO2 = FSpO2 ESpO2 + (1.0 - FSpO2) SpO2

  3. Could you please explain the IR for graph and RED for graph equations, ie the scaling algorithm for scaling the low pass filtered IR and RED led values. Could you also share some reference theory in that regard. The equations : float ir_forGraph = (2.0 fir - aveir) / aveir SCALE; float red_forGraph = (2.0 fred - avered) / avered SCALE;

  4. Currently I am using Sparkfun's SPO2 algorithm with MAX30102 and ESP32 modules. This SPO2 algorithm does not use FIFO. Could you please clarify the theory behind FIFO. The difference between using sensor.getIR() function and sensor.getFIFOIR() function for example. To clarify as far as I have understood, getIR() function returns the head of the struct / raw sensor values whereas the getFIFOIR() function returns the tail. However, getIR() function in my implementation (which does not use FIFO) is returning a single raw IR value (like 55000 for example when hand is on) however the getIR() function in your sketch seems to return the sum of 3 raw IR value read (for example 130000). You then proceed by scaling it to 80 to 100 for serial plotter.

Thank you in advance for all the clarifications.

Regards,

coniferconifer commented 2 years ago

It is OK to have three different linear approximation for ranges from 0.4 to 1, 1 to 2 and 3 to 3.5 , but less than SpO2 < 80 is quite hard to test , indicating hypoxia.

https://www.mcgurrin.info/robots/154/ is a good explanation of digital low pass filter. FSpO2 is selected by watching raw data SpO2 and filtered data ESpO2 graph as ESpO2(estimated SpO2) should change slowly as I hold my breath.

float ir_forGraph = (2.0 fir - aveir) / aveir SCALE; float red_forGraph = (2.0 fred - avered) / avered SCALE; are used to monitor AC component of IR and RED data in the same Arduino Plotter graph. I forget why I used these , this code was not ideal. I should use following code ,

float ir_forGraph = 3.0 (fir - aveIr) / aveIr SCALE + (MIN_SPO2 + MAX_SPO2) / 2.0; float red_forGraph = 3.0 (fred - aveRed) / aveRed SCALE + (MIN_SPO2 + MAX_SPO2) / 2.0; // assuming SCALE is unchanged , factor 3.0 is used instead of 2.0 to enlarge the amplitude of ir_forGraph/red_forGraph in the Arduino plotter graph.

than expected , so 2.0 is changed to 3.0 Then , ir_forGraph and red_forGraph swing around (MIN_SPO2+MAX_SPO2)/2.0

MAX3010X is configured to sample at 200Hz and sampleAverage = 4 , then MAX3010X can out put data at 50Hz. While ESP32 computes SpO2, draws graph on LCD display , communicates via Bluetooth , MAX3010X can store multiple data in FIFO independently. If inner loop() of ESP32 exceeds 20msec ( 50Hz), then data may be lost without FIFO. so I prefer to use getFIFOIR()/getFIFORed(). I have no idea about the absolute value of getIR().

shahanHasan commented 2 years ago

Thank you for your replies. However I was wondering , how would you calculate heart rate with getFIROIR() value. As far as I have understood from base spark fun library, getFIFOIR() returns sum of 3 samples contrary to getIR() which only returns the current IR value.

As such do you have any formula or recommendations as to how we could calculate heart rate from getFIFOIR() ? Thanks

coniferconifer commented 2 years ago

I can not find where Sparkfun's library out puts an average of three raw data. Heart rate is calculated by finding zero crossing at falling point of AC component of IR signal. from line 365 to line 385 of https://github.com/coniferconifer/ESP32_MAX30102_simple-SpO2_plotter/blob/master/ESP32_MAX30102_simple-SpO2_plotter-BLE/ESP32_MAX30102_simple-SpO2_plotter-BLE.ino

AliAlzuabi commented 1 year ago

Thanks for explanation!