Arduino version , update and tested on NUCLEO-L073RZ

Dependencies:   mbed

Oximeter and pulse sensor, based on the Beer-Lambert gas absorption law

MAXREFDES117 ( MAX30102 ) from MAXIM, based on MAXIM library for Arduino

adaptation C.Dupaty 07-2017

Tested on STM32 NUCLEO-F411RE and NUCLEO-L073RZ

https://os.mbed.com/media/uploads/cdupaty/max30102.jpg

Revision:
2:560e76e77544
Parent:
1:e88f22c6c1b0
Child:
3:7c0fb55eb3ff
--- a/algorithm/algorithm.cpp	Wed Apr 20 23:05:38 2016 +0000
+++ b/algorithm/algorithm.cpp	Thu Apr 21 18:25:34 2016 +0000
@@ -84,31 +84,31 @@
 {
 
 
-        uint32_t irMean ,onlyOnce ;
-        int32_t k ,iRatioCount;
-        int32_t i,s ,m, exact_ir_valley_locs_count ,middleIdx;
-        int32_t th1, n_npks,cMin;      
-        int32_t ir_valley_locs[15] ;
-        int32_t exact_ir_valley_locs[15] ;
-        int32_t dx_peak_locs[15] ;
-        int32_t  peakintervalSum;
+        uint32_t un_ir_mean ,un_only_once ;
+        int32_t k ,n_i_ratio_count;
+        int32_t i,s ,m, n_exact_ir_valley_locs_count ,n_middle_idx;
+        int32_t n_th1, n_npks,n_c_min;      
+        int32_t n_ir_valley_locs[15] ;
+        int32_t n_exact_ir_valley_locs[15] ;
+        int32_t n_dx_peak_locs[15] ;
+        int32_t n_peak_interval_sum;
         
-        int32_t yAC, xAC;
-        int32_t spo2calc; 
-        int32_t yDCmax, xDCmax; 
-        int32_t yDCmaxIdx, xDCmaxIdx; 
-        int32_t ratio[5],ratioAverage; 
-        int32_t nume,  denom ;
+        int32_t n_y_ac, n_x_ac;
+        int32_t n_spo2_calc; 
+        int32_t n_y_dc_max, n_x_dc_max; 
+        int32_t n_y_dc_max_idx, n_x_dc_max_idx; 
+        int32_t n_ratio[5],n_ratio_average; 
+        int32_t n_nume,  n_denom ;
         // remove DC of ir signal    
-        irMean =0; 
-        for (k=0 ; k<n_ir_buffer_length ; k++ ) irMean += un_ir_buffer[k] ;
-        irMean =irMean/n_ir_buffer_length ;
-        for (k=0 ; k<n_ir_buffer_length ; k++ )  n_x[k] =  un_ir_buffer[k] - irMean ; 
+        un_ir_mean =0; 
+        for (k=0 ; k<n_ir_buffer_length ; k++ ) un_ir_mean += un_ir_buffer[k] ;
+        un_ir_mean =un_ir_mean/n_ir_buffer_length ;
+        for (k=0 ; k<n_ir_buffer_length ; k++ )  n_x[k] =  un_ir_buffer[k] - un_ir_mean ; 
         
         // 4 pt Moving Average
         for(k=0; k< BUFFER_SIZE-MA4_SIZE; k++){
-          denom= ( n_x[k]+n_x[k+1]+ n_x[k+2]+ n_x[k+3]);
-          n_x[k]=  denom/(int32_t)4; 
+          n_denom= ( n_x[k]+n_x[k+1]+ n_x[k+2]+ n_x[k+3]);
+          n_x[k]=  n_denom/(int32_t)4; 
         }
 
         // get difference of smoothed IR signal
@@ -132,20 +132,20 @@
         }
     
      
-        th1=0; // threshold calculation
+        n_th1=0; // threshold calculation
         for ( k=0 ; k<BUFFER_SIZE-HAMMING_SIZE ;k++){
-                th1 += ((n_dx[k]>0)? n_dx[k] : ((int32_t)0-n_dx[k])) ;
+                n_th1 += ((n_dx[k]>0)? n_dx[k] : ((int32_t)0-n_dx[k])) ;
         }
-        th1= th1/ ( BUFFER_SIZE-HAMMING_SIZE);
+        n_th1= n_th1/ ( BUFFER_SIZE-HAMMING_SIZE);
         // peak location is acutally index for sharpest location of raw signal since we flipped the signal         
-        maxim_find_peaks( dx_peak_locs, &n_npks, n_dx, BUFFER_SIZE-HAMMING_SIZE, th1, 8, 5 );//peak_height, peak_distance, max_num_peaks 
+        maxim_find_peaks( n_dx_peak_locs, &n_npks, n_dx, BUFFER_SIZE-HAMMING_SIZE, n_th1, 8, 5 );//peak_height, peak_distance, max_num_peaks 
 
-        peakintervalSum =0;
+        n_peak_interval_sum =0;
                 if (n_npks>=2){
                       for (k=1; k<n_npks; k++)
-                             peakintervalSum += (dx_peak_locs[k] -dx_peak_locs[k -1] ) ;
-                      peakintervalSum =peakintervalSum/(n_npks-1);
-                     *n_heart_rate =(int32_t)( 6000/ peakintervalSum );// beats per minutes
+                             n_peak_interval_sum += (n_dx_peak_locs[k] -n_dx_peak_locs[k -1] ) ;
+                      n_peak_interval_sum =n_peak_interval_sum/(n_npks-1);
+                     *n_heart_rate =(int32_t)( 6000/ n_peak_interval_sum );// beats per minutes
                       //prlongf(">>>  *n_heart_rate= %d \n", *n_heart_rate) ;
                       *ch_hr_valid  = 1;
                 }
@@ -155,7 +155,7 @@
                 }
                 
         for ( k=0 ; k<n_npks ;k++)
-            ir_valley_locs[k]= dx_peak_locs[k] +HAMMING_SIZE /2; 
+            n_ir_valley_locs[k]= n_dx_peak_locs[k] +HAMMING_SIZE /2; 
 
 
           // raw value : RED(=y) and IR(=X)
@@ -165,26 +165,26 @@
                 n_y[k] =  un_red_buffer[k] ; 
             }
 
-        // find precise min near ir_valley_locs
-        exact_ir_valley_locs_count =0; 
+        // find precise min near n_ir_valley_locs
+        n_exact_ir_valley_locs_count =0; 
         for ( k=0 ; k<n_npks ;k++){
-            onlyOnce =1;
-            m=ir_valley_locs[k];
-            cMin= 16777216;//2^24;
+            un_only_once =1;
+            m=n_ir_valley_locs[k];
+            n_c_min= 16777216;//2^24;
             if (m+5 <  BUFFER_SIZE-HAMMING_SIZE  && m-5 >0){
                
                 for(i= m-5;i<m+5; i++)
-                   if (n_x[i]<cMin){
-                        if (onlyOnce >0){
-                           onlyOnce =0;
+                   if (n_x[i]<n_c_min){
+                        if (un_only_once >0){
+                           un_only_once =0;
                        } 
-                       cMin= n_x[i] ;
-                       exact_ir_valley_locs[k]=i;
+                       n_c_min= n_x[i] ;
+                       n_exact_ir_valley_locs[k]=i;
                    }
-                if (onlyOnce ==0)   exact_ir_valley_locs_count ++ ;
+                if (un_only_once ==0)   n_exact_ir_valley_locs_count ++ ;
             }
         }
-        if (exact_ir_valley_locs_count <2 ){
+        if (n_exact_ir_valley_locs_count <2 ){
            *n_spo2 =  -999 ; // do not use SPO2 since signal ratio is out of range
            *ch_spo2_valid  = 0; 
            return;
@@ -196,14 +196,14 @@
           
         }
 
-        //using exact_ir_valley_locs , find ir-red DC andir-red AC for SPO2 calibration ratio
+        //using n_exact_ir_valley_locs , find ir-red DC andir-red AC for SPO2 calibration ratio
         //finding AC/DC maximum of raw ir * red between two valley locations
-        ratioAverage =0; 
-        iRatioCount = 0; 
+        n_ratio_average =0; 
+        n_i_ratio_count = 0; 
         
-        for(k=0; k< 5; k++) ratio[k]=0;
-        for (k=0; k< exact_ir_valley_locs_count; k++){
-             if (exact_ir_valley_locs[k] > BUFFER_SIZE ){             
+        for(k=0; k< 5; k++) n_ratio[k]=0;
+        for (k=0; k< n_exact_ir_valley_locs_count; k++){
+             if (n_exact_ir_valley_locs[k] > BUFFER_SIZE ){             
                   *n_spo2 =  -999 ; // do not use SPO2 since valley loc is out of range
                   *ch_spo2_valid  = 0; 
                    return;
@@ -212,50 +212,50 @@
         // find max between two valley locations 
         // and use ratio betwen AC compoent of Ir & Red and DC compoent of Ir & Red for SPO2 
     
-        for (k=0; k< exact_ir_valley_locs_count-1; k++){
-              yDCmax= -16777216 ; 
-              xDCmax= - 16777216; 
-           //   printf("range=%d: %d\n ", exact_ir_valley_locs[k], exact_ir_valley_locs[k+1]);
-              if (exact_ir_valley_locs[k+1]-exact_ir_valley_locs[k] >10){
-                    for (i=exact_ir_valley_locs[k]; i< exact_ir_valley_locs[k+1]; i++){
+        for (k=0; k< n_exact_ir_valley_locs_count-1; k++){
+              n_y_dc_max= -16777216 ; 
+              n_x_dc_max= - 16777216; 
+           //   printf("range=%d: %d\n ", n_exact_ir_valley_locs[k], n_exact_ir_valley_locs[k+1]);
+              if (n_exact_ir_valley_locs[k+1]-n_exact_ir_valley_locs[k] >10){
+                    for (i=n_exact_ir_valley_locs[k]; i< n_exact_ir_valley_locs[k+1]; i++){
                 
-                          if (n_x[i]> xDCmax) {xDCmax =n_x[i];xDCmaxIdx =i; }
-                          if (n_y[i]> yDCmax) {yDCmax =n_y[i];yDCmaxIdx=i;}
+                          if (n_x[i]> n_x_dc_max) {n_x_dc_max =n_x[i];n_x_dc_max_idx =i; }
+                          if (n_y[i]> n_y_dc_max) {n_y_dc_max =n_y[i];n_y_dc_max_idx=i;}
                       }
-                    yAC= (n_y[exact_ir_valley_locs[k+1]] - n_y[exact_ir_valley_locs[k] ] )*(yDCmaxIdx -exact_ir_valley_locs[k]); //red
-                    yAC=  n_y[exact_ir_valley_locs[k]] + yAC/ (exact_ir_valley_locs[k+1] - exact_ir_valley_locs[k])  ; 
+                    n_y_ac= (n_y[n_exact_ir_valley_locs[k+1]] - n_y[n_exact_ir_valley_locs[k] ] )*(n_y_dc_max_idx -n_exact_ir_valley_locs[k]); //red
+                    n_y_ac=  n_y[n_exact_ir_valley_locs[k]] + n_y_ac/ (n_exact_ir_valley_locs[k+1] - n_exact_ir_valley_locs[k])  ; 
             
             
-                    yAC=  n_y[yDCmaxIdx] - yAC;    // subracting linear DC compoenents from raw 
-                    xAC= (n_x[exact_ir_valley_locs[k+1]] - n_x[exact_ir_valley_locs[k] ] )*(xDCmaxIdx -exact_ir_valley_locs[k]); // ir
-                    xAC=  n_x[exact_ir_valley_locs[k]] + xAC/ (exact_ir_valley_locs[k+1] - exact_ir_valley_locs[k]); 
-                    xAC=  n_x[yDCmaxIdx] - xAC;      // subracting linear DC compoenents from raw 
-                    nume=( yAC *xDCmax)>>7 ; //prepare X100 to preserve floating value
-                    denom= ( xAC *yDCmax)>>7;
-                    if (denom>0  && iRatioCount <5 &&  nume != 0)
+                    n_y_ac=  n_y[n_y_dc_max_idx] - n_y_ac;    // subracting linear DC compoenents from raw 
+                    n_x_ac= (n_x[n_exact_ir_valley_locs[k+1]] - n_x[n_exact_ir_valley_locs[k] ] )*(n_x_dc_max_idx -n_exact_ir_valley_locs[k]); // ir
+                    n_x_ac=  n_x[n_exact_ir_valley_locs[k]] + n_x_ac/ (n_exact_ir_valley_locs[k+1] - n_exact_ir_valley_locs[k]); 
+                    n_x_ac=  n_x[n_y_dc_max_idx] - n_x_ac;      // subracting linear DC compoenents from raw 
+                    n_nume=( n_y_ac *n_x_dc_max)>>7 ; //prepare X100 to preserve floating value
+                    n_denom= ( n_x_ac *n_y_dc_max)>>7;
+                    if (n_denom>0  && n_i_ratio_count <5 &&  n_nume != 0)
                     {   
-                         ratio[iRatioCount]= (nume*100)/denom ; //formular is ( yAC *xDCmax) / ( xAC *yDCmax) ;
-                         iRatioCount++;
+                         n_ratio[n_i_ratio_count]= (n_nume*100)/n_denom ; //formular is ( n_y_ac *n_x_dc_max) / ( n_x_ac *n_y_dc_max) ;
+                         n_i_ratio_count++;
                     }
               }
             
-    //  prlongf("ratio[%d]= %d exact_ir_valley_locs[k] =%d , exact_ir_valley_locs[%d] =%d \n",k, ratio[k] ,exact_ir_valley_locs[k] ,k+1,  exact_ir_valley_locs[k+1]  ) ;
-    //  prlongf("nume= %d ,denom= %d  yAC = %d, xDCmax = %d, xAC= %d, yDCmax = %d\n",nume, denom,  yAC ,xDCmax ,xAC ,yDCmax );
+    //  prlongf("n_ratio[%d]= %d n_exact_ir_valley_locs[k] =%d , n_exact_ir_valley_locs[%d] =%d \n",k, n_ratio[k] ,n_exact_ir_valley_locs[k] ,k+1,  n_exact_ir_valley_locs[k+1]  ) ;
+    //  prlongf("n_nume= %d ,n_denom= %d  n_y_ac = %d, n_x_dc_max = %d, n_x_ac= %d, n_y_dc_max = %d\n",n_nume, n_denom,  n_y_ac ,n_x_dc_max ,n_x_ac ,n_y_dc_max );
 
         }
 
-        maxim_sort_ascend(ratio, iRatioCount);
-        middleIdx= iRatioCount/2;
+        maxim_sort_ascend(n_ratio, n_i_ratio_count);
+        n_middle_idx= n_i_ratio_count/2;
 
-        if (middleIdx >1)
-          ratioAverage =( ratio[middleIdx-1] +ratio[middleIdx])/2; // use median
+        if (n_middle_idx >1)
+          n_ratio_average =( n_ratio[n_middle_idx-1] +n_ratio[n_middle_idx])/2; // use median
         else
-           ratioAverage = ratio[middleIdx ];
+           n_ratio_average = n_ratio[n_middle_idx ];
 
-        if( ratioAverage>2 && ratioAverage <184){
-                   spo2calc= uch_spo2_table[ratioAverage] ;
-            *n_spo2 = spo2calc ;
-            *ch_spo2_valid  = 1;//  float_SPO2 =  -45.060*ratioAverage* ratioAverage/10000 + 30.354 *ratioAverage/100 + 94.845 ;  // for comparison with table
+        if( n_ratio_average>2 && n_ratio_average <184){
+                   n_spo2_calc= uch_spo2_table[n_ratio_average] ;
+            *n_spo2 = n_spo2_calc ;
+            *ch_spo2_valid  = 1;//  float_SPO2 =  -45.060*n_ratio_average* n_ratio_average/10000 + 30.354 *n_ratio_average/100 + 94.845 ;  // for comparison with table
         }
         else{
             *n_spo2 =  -999 ; // do not use SPO2 since signal ratio is out of range
@@ -289,21 +289,21 @@
 * \retval       None
 */
 {
-    int32_t i = 1, width;
+    int32_t i = 1, n_width;
     *n_npks = 0;
     
     while (i < n_size-1){
         if (n_x[i] > n_min_height && n_x[i] > n_x[i-1]){            // find left edge of potential peaks
-            width = 1;
-            while (i+width < n_size && n_x[i] == n_x[i+width])    // find flat peaks
-                width++;
-            if (n_x[i] > n_x[i+width] && (*n_npks) < 15 ){                            // find right edge of peaks
+            n_width = 1;
+            while (i+n_width < n_size && n_x[i] == n_x[i+n_width])    // find flat peaks
+                n_width++;
+            if (n_x[i] > n_x[i+n_width] && (*n_npks) < 15 ){                            // find right edge of peaks
                 n_locs[(*n_npks)++] = i;        
               // for flat peaks, peak location is left edge
-                i += width+1;
+                i += n_width+1;
             }
             else
-                i += width;
+                i += n_width;
         }
         else
             i++;
@@ -321,17 +321,17 @@
 */
 {
     
-    int32_t i, j, old_npks, dist;
+    int32_t i, j, n_old_npks, n_dist;
     
     /* Order peaks from large to small */
     maxim_sort_indices_descend( n_x, n_locs, *n_npks );
 
     for ( i = -1; i < *n_npks; i++ ){
-        old_npks = *n_npks;
+        n_old_npks = *n_npks;
         *n_npks = i+1;
-        for ( j = i+1; j < old_npks; j++ ){
-            dist =  n_locs[j] - ( i == -1 ? -1 : n_locs[i] ); // lag-zero peak of autocorr is at index -1
-            if ( dist > n_min_distance || dist < -n_min_distance )
+        for ( j = i+1; j < n_old_npks; j++ ){
+            n_dist =  n_locs[j] - ( i == -1 ? -1 : n_locs[i] ); // lag-zero peak of autocorr is at index -1
+            if ( n_dist > n_min_distance || n_dist < -n_min_distance )
                 n_locs[(*n_npks)++] = n_locs[j];
         }
     }
@@ -349,12 +349,12 @@
 * \retval       None
 */
 {
-    int32_t i, j, temp;
+    int32_t i, j, n_temp;
     for (i = 1; i < n_size; i++) {
-        temp = n_x[i];
-        for (j = i; j > 0 && temp < n_x[j-1]; j--)
+        n_temp = n_x[i];
+        for (j = i; j > 0 && n_temp < n_x[j-1]; j--)
             n_x[j] = n_x[j-1];
-        n_x[j] = temp;
+        n_x[j] = n_temp;
     }
 }
 
@@ -367,12 +367,12 @@
 * \retval       None
 */ 
 {
-    int32_t i, j, temp;
+    int32_t i, j, n_temp;
     for (i = 1; i < n_size; i++) {
-        temp = n_indx[i];
-        for (j = i; j > 0 && n_x[temp] > n_x[n_indx[j-1]]; j--)
+        n_temp = n_indx[i];
+        for (j = i; j > 0 && n_x[n_temp] > n_x[n_indx[j-1]]; j--)
             n_indx[j] = n_indx[j-1];
-        n_indx[j] = temp;
+        n_indx[j] = n_temp;
     }
 }