代码挺漂亮
发一个之前做的血氧心率检测的小东西,使用的是美信的MAX30100和30102
芯片框图:
携带氧气的红血球能吸收较多红外光(850-1000nm),未携带氧气的红血球则是吸收较多的红光(600-750nm),通过这个特性就可以计算血液的血氧饱和度。
大概效果如下图:
数据处理方式:
首先配置传感器工作在FIFO模式下然后周期性读取FIFO,通过1024点的FFT变换得到频域数据,然后选择频带内的最高幅值为心率,通过对比两个幅值的幅度计算出血氧饱和度。通过平均其他频点的差值来标定两个波长数据。
数据波形图:
部分算法代码:
struct compx FFTBUF1[FFT_N+16]; struct compx FFTBUF2[FFT_N+16]; uint16_t g_fft_index = 0; BloodData g_blooddata = {0}; void test(float data1,float data2) { static uint8_t str[50]; sprintf((char *)str,"%f,%f\r\n",data1,data2); HAL_UART_Transmit_DMA(&huart1,str,sizeof(str)); } //血液检测信息更新 void blood_data_update(void) { static DC_FilterData dc1 = {.w = 0,.init = 0,.a = 0.8}; static DC_FilterData dc2 = {.w = 0,.init = 0,.a = 0.8}; static float data1buf[20]; static uint8_t data1cur = 0; static float data2buf[20]; static uint8_t data2cur = 0; uint16_t temp_num=0; uint16_t fifo_word_buff[1][2]; temp_num = max30100_Bus_Read(INTERRUPT_REG); if (INTERRUPT_REG_A_FULL&temp_num) { max30100_FIFO_Read(0x05,fifo_word_buff,1); //read the hr and spo2 data form fifo in reg=0x05 float data1 = dc_filter(fifo_word_buff[0][0],&dc1)+100.0; float data2 = dc_filter(fifo_word_buff[0][1],&dc2)+100.0; data1buf[data1cur] = data1; data2buf[data2cur] = data2; data1 = 0; data2 = 0; for(int i = 0;i < 20;i++) { data1 += data1buf[i]; data2 += data2buf[i]; } data1 /= 20; data2 /= 20; data1cur = (data1cur < 19) ? data1cur + 1 : 0; data2cur = (data2cur < 19) ? data2cur + 1 : 0; // fifo_word_buff[0][0] = data1; // fifo_word_buff[0][1] = data2; // test(data1,data2); g_blooddata.hb = data1 + 50; g_blooddata.hbo2 = data2 + 50; //将数据写入fft输入并清除输出 for(int i = 0;i < 1;i++) { if(g_fft_index < FFT_N) { FFTBUF1[g_fft_index].real = fifo_word_buff[i][0]; FFTBUF1[g_fft_index].imag= 0; FFTBUF2[g_fft_index].real = fifo_word_buff[i][1]; FFTBUF2[g_fft_index].imag= 0; g_fft_index++; } } //信息更新标志位 g_blooddata.update++; } } //血液信息转换 void blood_data_translate(void) { //缓冲区写入结束 if(g_fft_index>=FFT_N) { //快速傅里叶变换 FFT(FFTBUF1); FFT(FFTBUF2); //解平方 for(int i = 0;i < FFT_N;i++) { FFTBUF1[i].real = sqrtf(FFTBUF1[i].real * FFTBUF1[i].real + FFTBUF1[i].imag * FFTBUF1[i].imag); FFTBUF2[i].real = sqrtf(FFTBUF2[i].real * FFTBUF2[i].real + FFTBUF2[i].imag * FFTBUF2[i].imag); } //读取峰值点 10-100带通 频率范围30-292次/分钟 uint16_t s1_max_index = find_max_num_index(FFTBUF1, 100); uint16_t s2_max_index = find_max_num_index(FFTBUF2, 100); //检查HbO2和Hb的变化频率是否一致 if(s1_max_index == s2_max_index) { //心率计算 uint16_t Heart_Rate = 60 * SAMPLES_PER_SECOND * s2_max_index / FFT_N; g_blooddata.heart = Heart_Rate; //血氧含量计算 float sp02_num = (FFTBUF1[s1_max_index].real * FFTBUF1[0].real) /(FFTBUF2[s1_max_index].real * FFTBUF2[0].real); sp02_num = sp02_num * SAMPLES_PER_SECOND + CORRECTED_VALUE; g_blooddata.SpO2 = sp02_num; //状态正常 g_blooddata.state = BLD_NORMAL; // for(int i = 0;i < FFT_N;i++) // { // static uint8_t str[50]; // sprintf((char *)str,"%f,%f\r\n\0",FFTBUF1[i].real,FFTBUF2[i].real); // HAL_UART_Transmit(&huart1,str,sizeof(str),20); // } // static uint8_t str[50]; // sprintf((char *)str,"H:%d,S:%f\r\n",g_blooddata.heart,g_blooddata.SpO2 ); // HAL_UART_Transmit(&huart1,str,sizeof(str),20); } else //数据发生异常 { g_blooddata.heart = 0; g_blooddata.SpO2 = 0; g_blooddata.state = BLD_ERROR; } g_fft_index = 0; } }
时段 | 个数 |
---|---|
{{f.startingTime}}点 - {{f.endTime}}点 | {{f.fileCount}} |
200字以内,仅用于支线交流,主线讨论请采用回复功能。