Test program for a Max30102 heartrate sensor on a STM32L476RG specific board ENSMM
Dependencies: mbed
These two pictures show how to connect the Mheuve Sensor to the ST-Link debugger (don't forget to disable ST-link jumpers and JP5 on the board! ):
These two pictures show how to connect the Mheuve Sensor TX RX to the ST-Link debugger (don't forget to cross TX and RX, it means Mheuve sensor TX on ST-Link RX and ST-Link TX on Mheuve sensor RX ):
The Mheuve sensor board needs to be powered by an external battery.
The result appears on the terminal, speed config is 115200 bds.
Diff: algorithm/algorithm.cpp
- Revision:
- 2:560e76e77544
- Parent:
- 1:e88f22c6c1b0
- Child:
- 3:7c0fb55eb3ff
diff -r e88f22c6c1b0 -r 560e76e77544 algorithm/algorithm.cpp --- 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; } }