完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
2020年电赛结束好久了,A题的步数部分并没有做好,但是心率部分做的还行,得到了测评老师的赞赏。上一篇文章对心电信号的噪声进行了理论的分析,并且用matlab简单的设计了滤波器。这篇文章将介绍以下如何在STM32的平台上设计、搭建滤波器。
这次平台选用的是STM32F407,因为毕竟要进行滤波运算,用有FPU的F4系列会比F1舒服很多。当然,在现场也看到许多用F1做的,效果也非常好。 滤波器形式 由于我们对滤波的实时性要求比较高,所以这里选中FIR滤波器进行设计,FIR滤波器的群延迟是固定的,在处理数据上会更加舒服一些。但是FIR滤波的计算量会比较大,后文中如何减少FIR的计算量是一大重点。 网上能找到的常见的滤波器教程用的都是以下形式: 这样的滤波器结构是比较常见的,但是有几个地方不是特别如意,一、滤波器的延迟取决于n的数量,n越大延迟越高。 二、和其他滤波器配合的时候不是特别灵活。 于是,在上面滤波器结构的基础上进行改进: 这样做的好处就是:一、能减少单次计算的计算量,相当于每次只用计算群延时+1的数据。 二、减少单次计算的n值,最大程度减少由于数据采集带来的延迟,保持好的效果的同时保持较高的实时性。 滤波器实现 这里的低通滤波器主要采用以下这两个函数 void arm_fir_init_f32(arm_fir_instance_f32 S, uint16_t numTaps,const float32_t pCoeffs,float32_t* pState,uint32_t blockSize)**这个函数主要是对滤波器进行初始化 **void arm_fir_f32(const arm_fir_instance * S,const float32_t pSrc,float32_t * pDst,uint32_T blockSize)**这个函数是最终进行滤波器的函数。 具体这两个函数的用法和参数在这个网站有非常详细的解释了,这里就不过多赘述了。 下面是包装了以下的滤波器函数 #include "FIR_48.h" #include "sys.h" static float32_t firStateF32_48[BLOCK_SIZE+NUM_TAPS-1]; arm_fir_instance_f32 S; uint32_t block_size = BLOCK_SIZE; const int BL = 49; const float32_t B[49] = { -0.0009602747741,-0.0007406222285,-0.000344334956,0.0003267489665, 0.00132522604, 0.002570599085, 0.003790664719, 0.004526928533, 0.00422275858, 0.002387276152, -0.001199811231,-0.006298475899, -0.01209692098, -0.01723066717, -0.01995631494, -0.01846508868, -0.01128097717, 0.002341947285, 0.02211954445, 0.0466186665, 0.07336764783, 0.09919441491, 0.1207369491, 0.1350278109, 0.1400325894, 0.1350278109, 0.1207369491, 0.09919441491, 0.07336764783, 0.0466186665, 0.02211954445, 0.002341947285, -0.01128097717, -0.01846508868, -0.01995631494, -0.01723066717, -0.01209692098,-0.006298475899,-0.001199811231, 0.002387276152, 0.00422275858, 0.004526928533, 0.003790664719, 0.002570599085, 0.00132522604, 0.0003267489665,-0.000344334956,-0.0007406222285,-0.0009602747741 }; void arm_fir_f32_lp_48(float32_t *Input_buffer,float32_t *Output_buffer) { float32_t *inputF32,*outputF32; inputF32 = Input_buffer; outputF32 = Output_buffer; arm_fir_f32(&S,inputF32,outputF32,block_size); } void arm_fir48_init(void) { arm_fir_init_f32(&S,NUM_TAPS,(float32_t *)&B[0],&firStateF32_48[0],block_size); } 其中B[49]这个滤波器参数的生成使用matlab来做的,具体操作可以参考这篇文章 后续要使用滤波器的话只要使用这两个函数就可以了 下面是实现上述滤波器结构的具体代码 arm_fir48_init(); if(ads1292_recive_flag) { cannle[0]=ads1292_Cache[3]<<16 | ads1292_Cache[4]<<8 | ads1292_Cache[5];//获取原始数据 cannle[1]=ads1292_Cache[6]<<16 | ads1292_Cache[7]<<8 | ads1292_Cache[8]; p_Temp[0] = get_volt(cannle[0]); //把采到的3个字节转成有符号32位数 p_Temp[1] = get_volt(cannle[1]); //把采到的3个字节转成有符号32位数 //有符号数为再转为无符号,无符号数为逻辑右移 cannle[0] = p_Temp[0]; cannle[1] = p_Temp[1]; val1 = cannle[1]*(a1)+b1; //将数据改为能在串口屏显示的数值 calculate_cache[j] = val1; //将数据存入滤波计算缓存数组中 j++; z++; if(j == 19) { j=18; arm_fir_f32_lp_48(calculate_cache,fir_put); //对数据进行FIR 48Hz低通滤波 if(mid_filt_start_flag == 0) { mid_filt_cache[mid_filt_num] = fir_put[0]; mid_filt_num++; if(mid_filt_num == midfilt_num) { mid_filt_start_flag = 1; } } else if(mid_filt_start_flag == 1) { arm_copy_f32(mid_filt_cache+1,mid_filt_cache1,midfilt_num-1); mid_filt_cache1[midfilt_num-1] = fir_put[0]; mid_val=midfilt1(mid_filt_cache1,midfilt_num,midfilt_num); bpm_cache[n] = (fir_put[0]-mid_val+100); n++; if(n>1300) { n=0; maxim_peaks_above_min_height(pn_locs,&pn_npks,bpm_cache,1300,135); //寻找135以上的峰 bpm = bpm_calculate(pn_locs,pn_npks); //计算心率 算法:两峰之间点数*采样率 warning_flag = find_bad_bpm(pn_locs,pn_npks); int_wifi_bpm_val = (int)bpm; wifi_bpm_val = int_wifi_bpm_val; if(half_send_flag == 0) { if(debug_flag == 1) { printf("n0.val=%d",(int)bpm); send_ending_flag(); half_send_flag = 1; } else{ HAL_UART_Transmit(&huart1,&wifi_bpm_flag,1,0xFFFF); HAL_UART_Transmit(&huart1,&wifi_bpm_val,1,0xFFFF); half_send_flag = 1; } } else half_send_flag = 0; //printf("n0.val=%d",(int)bpm); //输出心率数据 //send_ending_flag(); } //printf("add 2,0,%0.f",fir_put[0]-mid_val+100); bpm_val = fir_put[0]-mid_val+100; if(debug_flag == 1) { printf("add 9,0,%0.f",fir_put[0]-mid_val+100); send_ending_flag(); } else{ HAL_UART_Transmit(&huart1,&bpm_val,1,0xFFFF); } //send_ending_flag(); arm_copy_f32(mid_filt_cache1,mid_filt_cache,midfilt_num); } arm_copy_f32(calculate_cache+1,calculate_cache1,18); //将前一数组的后18位拷贝到缓存数组中,作为FIR滤波器的群延时 arm_copy_f32(calculate_cache1,calculate_cache,18); //将缓存数组的18位拷贝到后一数组中 } ads1292_recive_flag=0; } 这里包含了心率的计算和中值滤波的过程,这两个过程相对简单,就不再这里具体介绍了,下面贴一张整个程序过程的框图: |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1609 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1540 浏览 1 评论
970 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
681 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1587 浏览 2 评论
1861浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
644浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
515浏览 3评论
528浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
503浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-20 23:20 , Processed in 0.719171 second(s), Total 77, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号