blood.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #include "blood.h"
  2. uint16_t g_fft_index = 0; //fft输入输出下标
  3. struct compx s1[FFT_N+16]; //FFT输入和输出:从S[1]开始存放,根据大小自己定义
  4. struct compx s2[FFT_N+16]; //FFT输入和输出:从S[1]开始存放,根据大小自己定义
  5. struct
  6. {
  7. float Hp ; //血红蛋白
  8. float HpO2; //氧合血红蛋白
  9. }g_BloodWave;//血液波形数据
  10. BloodData g_blooddata = {0}; //血液数据存储
  11. #define CORRECTED_VALUE 47 //标定血液氧气含量
  12. #define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
  13. #define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
  14. #define GET_FLOAT_WORD(w,d) \
  15. do { \
  16. (w) = asuint(d); \
  17. } while (0)
  18. #define SET_FLOAT_WORD(d,w) \
  19. do { \
  20. (d) = asfloat(w); \
  21. } while (0)
  22. static const float tiny = 1.0e-30;
  23. float sqrtf(float x)
  24. {
  25. float z;
  26. int32_t sign = (int)0x80000000;
  27. int32_t ix,s,q,m,t,i;
  28. uint32_t r;
  29. GET_FLOAT_WORD(ix, x);
  30. /* take care of Inf and NaN */
  31. if ((ix&0x7f800000) == 0x7f800000)
  32. return x*x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
  33. /* take care of zero */
  34. if (ix <= 0) {
  35. if ((ix&~sign) == 0)
  36. return x; /* sqrt(+-0) = +-0 */
  37. if (ix < 0)
  38. return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
  39. }
  40. /* normalize x */
  41. m = ix>>23;
  42. if (m == 0) { /* subnormal x */
  43. for (i = 0; (ix&0x00800000) == 0; i++)
  44. ix<<=1;
  45. m -= i - 1;
  46. }
  47. m -= 127; /* unbias exponent */
  48. ix = (ix&0x007fffff)|0x00800000;
  49. if (m&1) /* odd m, double x to make it even */
  50. ix += ix;
  51. m >>= 1; /* m = [m/2] */
  52. /* generate sqrt(x) bit by bit */
  53. ix += ix;
  54. q = s = 0; /* q = sqrt(x) */
  55. r = 0x01000000; /* r = moving bit from right to left */
  56. while (r != 0) {
  57. t = s + r;
  58. if (t <= ix) {
  59. s = t+r;
  60. ix -= t;
  61. q += r;
  62. }
  63. ix += ix;
  64. r >>= 1;
  65. }
  66. /* use floating add to find out rounding direction */
  67. if (ix != 0) {
  68. z = 1.0f - tiny; /* raise inexact flag */
  69. if (z >= 1.0f) {
  70. z = 1.0f + tiny;
  71. if (z > 1.0f)
  72. q += 2;
  73. else
  74. q += q & 1;
  75. }
  76. }
  77. ix = (q>>1) + 0x3f000000;
  78. SET_FLOAT_WORD(z, ix + ((uint32_t)m << 23));
  79. return z;
  80. }
  81. /*funcation start ------------------------------------------------------------*/
  82. //血液检测信息更新
  83. void blood_data_update(void)
  84. {
  85. //标志位被使能时 读取FIFO
  86. g_fft_index=0;
  87. while(g_fft_index < FFT_N)
  88. {
  89. while(GetInit()==0)
  90. {
  91. //读取FIFO
  92. max30102_read_fifo(); //read from MAX30102 FIFO2
  93. //将数据写入fft输入并清除输出
  94. if(g_fft_index < FFT_N)
  95. {
  96. //将数据写入fft输入并清除输出
  97. s1[g_fft_index].real = fifo_red;
  98. s1[g_fft_index].imag= 0;
  99. s2[g_fft_index].real = fifo_ir;
  100. s2[g_fft_index].imag= 0;
  101. g_fft_index++;
  102. }
  103. }
  104. }
  105. }
  106. //血液信息转换
  107. void blood_data_translate(void)
  108. {
  109. float n_denom;
  110. uint16_t i;
  111. //直流滤波
  112. float dc_red =0;
  113. float dc_ir =0;
  114. float ac_red =0;
  115. float ac_ir =0;
  116. for (i=0 ; i<FFT_N ; i++ )
  117. {
  118. dc_red += s1[i].real ;
  119. dc_ir += s2[i].real ;
  120. }
  121. dc_red =dc_red/FFT_N ;
  122. dc_ir =dc_ir/FFT_N ;
  123. for (i=0 ; i<FFT_N ; i++ )
  124. {
  125. s1[i].real = s1[i].real - dc_red ;
  126. s2[i].real = s2[i].real - dc_ir ;
  127. }
  128. //移动平均滤波
  129. printf("***********8 pt Moving Average red******************************************************\r\n");
  130. for(i = 1;i < FFT_N-1;i++)
  131. {
  132. n_denom= ( s1[i-1].real + 2*s1[i].real + s1[i+1].real);
  133. s1[i].real= n_denom/4.00;
  134. n_denom= ( s2[i-1].real + 2*s2[i].real + s2[i+1].real);
  135. s2[i].real= n_denom/4.00;
  136. }
  137. //八点平均滤波
  138. for(i = 0;i < FFT_N-8;i++)
  139. {
  140. 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);
  141. s1[i].real= n_denom/8.00;
  142. 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);
  143. s2[i].real= n_denom/8.00;
  144. printf("%f\r\n",s1[i].real);
  145. }
  146. printf("************8 pt Moving Average ir*************************************************************\r\n");
  147. for(i = 0;i < FFT_N;i++)
  148. {
  149. printf("%f\r\n",s2[i].real);
  150. }
  151. printf("**************************************************************************************************\r\n");
  152. //开始变换显示
  153. g_fft_index = 0;
  154. //快速傅里叶变换
  155. FFT(s1);
  156. FFT(s2);
  157. //解平方
  158. printf("开始FFT算法****************************************************************************************************\r\n");
  159. for(i = 0;i < FFT_N;i++)
  160. {
  161. s1[i].real=sqrtf(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag);
  162. s1[i].real=sqrtf(s2[i].real*s2[i].real+s2[i].imag*s2[i].imag);
  163. }
  164. //计算交流分量
  165. for (i=1 ; i<FFT_N ; i++ )
  166. {
  167. ac_red += s1[i].real ;
  168. ac_ir += s2[i].real ;
  169. }
  170. for(i = 0;i < FFT_N/2;i++)
  171. {
  172. printf("%f\r\n",s1[i].real);
  173. }
  174. printf("****************************************************************************************\r\n");
  175. for(i = 0;i < FFT_N/2;i++)
  176. {
  177. printf("%f\r\n",s2[i].real);
  178. }
  179. printf("结束FFT算法***************************************************************************************************************\r\n");
  180. //读取峰值点的横坐标 结果的物理意义为
  181. int s1_max_index = find_max_num_index(s1, 30);
  182. int s2_max_index = find_max_num_index(s2, 30);
  183. printf("%d\r\n",s1_max_index);
  184. printf("%d\r\n",s2_max_index);
  185. //检查HbO2和Hb的变化频率是否一致
  186. float Heart_Rate = 60.00 * ((100.0 * s1_max_index )/ 512.00);
  187. g_blooddata.heart = Heart_Rate;
  188. float R = (ac_ir*dc_red)/(ac_red*dc_ir);
  189. float sp02_num =-45.060*R*R+ 30.354 *R + 94.845;
  190. g_blooddata.SpO2 = sp02_num;
  191. }
  192. void blood_Loop(void)
  193. {
  194. //血液信息获取
  195. blood_data_update();
  196. //血液信息转换
  197. blood_data_translate();
  198. //显示血液状态信息
  199. // OLED_Printf_EN(2,0,"heart:%3d/min ",g_blooddata.heart);
  200. g_blooddata.SpO2 = (g_blooddata.SpO2 > 99.99) ? 99.99:g_blooddata.SpO2;
  201. // OLED_Printf_EN(4,0,"SpO2:%2.2f%% ",g_blooddata.SpO2);
  202. printf("指令心率%3d",g_blooddata.heart);
  203. osDelay(10);
  204. printf("指令血氧%0.2f",g_blooddata.SpO2);
  205. //tft显示刷新
  206. //LED 蜂鸣器信息更新
  207. }