123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- #include "blood.h"
- uint16_t g_fft_index = 0; //fft输入输出下标
- struct compx s1[FFT_N+16]; //FFT输入和输出:从S[1]开始存放,根据大小自己定义
- struct compx s2[FFT_N+16]; //FFT输入和输出:从S[1]开始存放,根据大小自己定义
- struct
- {
- float Hp ; //血红蛋白
- float HpO2; //氧合血红蛋白
-
- }g_BloodWave;//血液波形数据
- BloodData g_blooddata = {0}; //血液数据存储
- #define CORRECTED_VALUE 47 //标定血液氧气含量
- #define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
- #define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
- #define GET_FLOAT_WORD(w,d) \
- do { \
- (w) = asuint(d); \
- } while (0)
- #define SET_FLOAT_WORD(d,w) \
- do { \
- (d) = asfloat(w); \
- } while (0)
- static const float tiny = 1.0e-30;
- float sqrtf(float x)
- {
- float z;
- int32_t sign = (int)0x80000000;
- int32_t ix,s,q,m,t,i;
- uint32_t r;
- GET_FLOAT_WORD(ix, x);
- /* take care of Inf and NaN */
- if ((ix&0x7f800000) == 0x7f800000)
- return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
- /* take care of zero */
- if (ix <= 0) {
- if ((ix&~sign) == 0)
- return x; /* sqrt(+-0) = +-0 */
- if (ix < 0)
- return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
- }
- /* normalize x */
- m = ix>>23;
- if (m == 0) { /* subnormal x */
- for (i = 0; (ix&0x00800000) == 0; i++)
- ix<<=1;
- m -= i - 1;
- }
- m -= 127; /* unbias exponent */
- ix = (ix&0x007fffff)|0x00800000;
- if (m&1) /* odd m, double x to make it even */
- ix += ix;
- m >>= 1; /* m = [m/2] */
- /* generate sqrt(x) bit by bit */
- ix += ix;
- q = s = 0; /* q = sqrt(x) */
- r = 0x01000000; /* r = moving bit from right to left */
- while (r != 0) {
- t = s + r;
- if (t <= ix) {
- s = t+r;
- ix -= t;
- q += r;
- }
- ix += ix;
- r >>= 1;
- }
- /* use floating add to find out rounding direction */
- if (ix != 0) {
- z = 1.0f - tiny; /* raise inexact flag */
- if (z >= 1.0f) {
- z = 1.0f + tiny;
- if (z > 1.0f)
- q += 2;
- else
- q += q & 1;
- }
- }
- ix = (q>>1) + 0x3f000000;
- SET_FLOAT_WORD(z, ix + ((uint32_t)m << 23));
- return z;
- }
- /*funcation start ------------------------------------------------------------*/
- //血液检测信息更新
- void blood_data_update(void)
- {
- //标志位被使能时 读取FIFO
- g_fft_index=0;
- while(g_fft_index < FFT_N)
- {
- while(GetInit()==0)
- {
- //读取FIFO
- max30102_read_fifo(); //read from MAX30102 FIFO2
- //将数据写入fft输入并清除输出
- if(g_fft_index < FFT_N)
- {
- //将数据写入fft输入并清除输出
- s1[g_fft_index].real = fifo_red;
- s1[g_fft_index].imag= 0;
- s2[g_fft_index].real = fifo_ir;
- s2[g_fft_index].imag= 0;
- g_fft_index++;
- }
- }
- }
- }
- //血液信息转换
- void blood_data_translate(void)
- {
- float n_denom;
- uint16_t i;
- //直流滤波
- float dc_red =0;
- float dc_ir =0;
- float ac_red =0;
- float ac_ir =0;
-
- for (i=0 ; i<FFT_N ; i++ )
- {
- dc_red += s1[i].real ;
- dc_ir += s2[i].real ;
- }
- dc_red =dc_red/FFT_N ;
- dc_ir =dc_ir/FFT_N ;
- for (i=0 ; i<FFT_N ; i++ )
- {
- s1[i].real = s1[i].real - dc_red ;
- s2[i].real = s2[i].real - dc_ir ;
- }
-
- //移动平均滤波
- printf("***********8 pt Moving Average red******************************************************\r\n");
- for(i = 1;i < FFT_N-1;i++)
- {
- n_denom= ( s1[i-1].real + 2*s1[i].real + s1[i+1].real);
- s1[i].real= n_denom/4.00;
-
- n_denom= ( s2[i-1].real + 2*s2[i].real + s2[i+1].real);
- s2[i].real= n_denom/4.00;
- }
- //八点平均滤波
- for(i = 0;i < FFT_N-8;i++)
- {
- n_denom= ( s1[i].real+s1[i+1].real+ s1[i+2].real+ s1[i+3].real+ s1[i+4].real+ s1[i+5].real+ s1[i+6].real+ s1[i+7].real);
- s1[i].real= n_denom/8.00;
-
- n_denom= ( s2[i].real+s2[i+1].real+ s2[i+2].real+ s2[i+3].real+ s2[i+4].real+ s2[i+5].real+ s2[i+6].real+ s2[i+7].real);
- s2[i].real= n_denom/8.00;
-
- printf("%f\r\n",s1[i].real);
- }
- printf("************8 pt Moving Average ir*************************************************************\r\n");
- for(i = 0;i < FFT_N;i++)
- {
- printf("%f\r\n",s2[i].real);
- }
- printf("**************************************************************************************************\r\n");
- //开始变换显示
- g_fft_index = 0;
- //快速傅里叶变换
- FFT(s1);
- FFT(s2);
-
- //解平方
- printf("开始FFT算法****************************************************************************************************\r\n");
- for(i = 0;i < FFT_N;i++)
- {
- s1[i].real=sqrtf(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag);
- s1[i].real=sqrtf(s2[i].real*s2[i].real+s2[i].imag*s2[i].imag);
- }
- //计算交流分量
- for (i=1 ; i<FFT_N ; i++ )
- {
- ac_red += s1[i].real ;
- ac_ir += s2[i].real ;
- }
-
- for(i = 0;i < FFT_N/2;i++)
- {
- printf("%f\r\n",s1[i].real);
- }
- printf("****************************************************************************************\r\n");
- for(i = 0;i < FFT_N/2;i++)
- {
- printf("%f\r\n",s2[i].real);
- }
-
- printf("结束FFT算法***************************************************************************************************************\r\n");
- //读取峰值点的横坐标 结果的物理意义为
- int s1_max_index = find_max_num_index(s1, 30);
- int s2_max_index = find_max_num_index(s2, 30);
- printf("%d\r\n",s1_max_index);
- printf("%d\r\n",s2_max_index);
- //检查HbO2和Hb的变化频率是否一致
-
- float Heart_Rate = 60.00 * ((100.0 * s1_max_index )/ 512.00);
-
- g_blooddata.heart = Heart_Rate;
-
- float R = (ac_ir*dc_red)/(ac_red*dc_ir);
- float sp02_num =-45.060*R*R+ 30.354 *R + 94.845;
- g_blooddata.SpO2 = sp02_num;
-
- }
- void blood_Loop(void)
- {
- //血液信息获取
- blood_data_update();
- //血液信息转换
- blood_data_translate();
- //显示血液状态信息
- // OLED_Printf_EN(2,0,"heart:%3d/min ",g_blooddata.heart);
- g_blooddata.SpO2 = (g_blooddata.SpO2 > 99.99) ? 99.99:g_blooddata.SpO2;
- // OLED_Printf_EN(4,0,"SpO2:%2.2f%% ",g_blooddata.SpO2);
- printf("指令心率%3d",g_blooddata.heart);
- osDelay(10);
- printf("指令血氧%0.2f",g_blooddata.SpO2);
- //tft显示刷新
- //LED 蜂鸣器信息更新
- }
|