日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

基于STM32F4的心电监护仪

發(fā)布時(shí)間:2023/12/3 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于STM32F4的心电监护仪 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

基于STM32F4的心電監(jiān)護(hù)儀

    • 一、硬件設(shè)計(jì)
    • 二、GUI的設(shè)計(jì)
    • 三、導(dǎo)聯(lián)體系的選擇
    • 四、心電電極選擇
    • 五、心電信號(hào)時(shí)域和頻域特征
    • 六、軟件設(shè)計(jì)
      • 6.1、系統(tǒng)總體設(shè)計(jì)
      • 6.2、系統(tǒng)總體設(shè)計(jì)
      • 6.3、心電信號(hào)濾波
      • 6.4、心率和QRS寬度檢測
    • 七、實(shí)機(jī)演示
    • 八、總結(jié)與展望

從題目中可以看出該課題來源于2020年省電賽A題的無線運(yùn)動(dòng)傳感器節(jié)點(diǎn)的設(shè)計(jì),該作品得過湖北省電賽二等獎(jiǎng),同時(shí)也是我本科畢業(yè)設(shè)計(jì),這里我把自己做的關(guān)于心電部分的工作進(jìn)行一次總結(jié),也對(duì)我的大學(xué)四年進(jìn)行一次總結(jié)。

一、硬件設(shè)計(jì)

  • 處理器板子的選擇
  • 本研究的處理器模塊選擇正點(diǎn)原子公司的STM32F4最小系統(tǒng)板子,如圖1所示,該最小系統(tǒng)板子搭載STM32F407ZGT6芯片,并具有 192KB的SRAM、1024KB的FLASH、豐富的定時(shí)器資源(12個(gè)16位定時(shí)器,2個(gè)32位定時(shí)器)、112個(gè)通用I/O口、2個(gè)DMA控制器以及1個(gè)FSMC接口,其中通過FSMC接口可以使得刷屏的速度可達(dá)3300W像素/秒,另外該板子還外擴(kuò)了1M字節(jié)的SRAM芯片,更加有利于該處理器驅(qū)動(dòng)4.3寸的LCD,這樣極大加快心電監(jiān)測儀的刷屏速度,而且STM32F407ZGT6這款芯片還集成FPU和DSP指令,可以加快數(shù)字濾波器的處理速度,而且該最小系統(tǒng)板子還將FSMC接口和其他IO口一并引出。

  • 心電采集板—ADS1292R模塊的介紹
  • 本研究最重要的地方便是心電采集板,關(guān)于心電信號(hào)的采集板的芯片選擇TI公司的ADS1292R,外圍電路參考TI公司所給的原理圖和建議繪制,如圖所示。

    關(guān)于ADS1292R的外圍電路的介紹和使用,這里推薦這篇博文,ADS1292R的使用

  • 溫度模塊----LMT70
  • 溫度檢測模塊采用LMT70溫度傳感器。其優(yōu)點(diǎn)是:超小型、高精度、低功耗的模擬溫度傳感器。而缺點(diǎn)是:接觸式的溫度傳感器,測體表溫度存在一定誤差。但是考慮到溫度測量的精度以及測量方便,最終選擇LMT70作為測溫傳感器,同時(shí)選擇采用ADS1118具有PGA、電壓基準(zhǔn)、16位的高精度ADC對(duì)LMT70數(shù)據(jù)的溫度模擬量進(jìn)行采集。

  • 系統(tǒng)不帶屏幕的外觀
  • 二、GUI的設(shè)計(jì)

    本系統(tǒng)為了更好的人機(jī)交互,采用4.3寸觸摸屏搭載開源圖形庫LVGL,一方面將顯示波形和數(shù)據(jù)與心電信號(hào)的采集和處理隔離開,另一方面是為了交互的方便和美觀,系統(tǒng)運(yùn)行界面如下圖所示。整體界面主要有菜單、返回、圖表、數(shù)據(jù)欄、導(dǎo)聯(lián)狀態(tài)燈以及開啟心電采集按鈕

    系統(tǒng)的菜單是通過LVGL的roller控件繪制的,roller里面選項(xiàng)的事件則是通過回調(diào)函數(shù)的形式調(diào)用。由于選中roller的選項(xiàng),LVGL就會(huì)返回選項(xiàng)的值,因此我自己設(shè)計(jì)了函數(shù)指針數(shù)組來注冊(cè)回調(diào)函數(shù),并且將這個(gè)選中的序號(hào)通過數(shù)組方式調(diào)用函數(shù),代碼如下所示:

    void (*oper_fuc[4])();//函數(shù)指針數(shù)組 void Menuitem_Init(void) {oper_fuc[0]=send_type_server;oper_fuc[1]=Set_chart_div_line;oper_fuc[2]=clear_step;oper_fuc[3]=smooth_filter; } static void roller_event_handler(lv_obj_t * obj, lv_event_t event) {static unsigned char count=0;if(event==LV_EVENT_VALUE_CHANGED){count=lv_roller_get_selected(obj);}if(event==LV_EVENT_CLICKED){oper_fuc[count]();} }

    roller_event_handler是選中roller中的事件函數(shù),在事件函數(shù)里面來回調(diào)選項(xiàng)的處理函數(shù)。roller中總共寫了4個(gè)選項(xiàng),分別為
    send_type選擇發(fā)送類型(支持發(fā)送到本地顯示或者串口發(fā)送給上位機(jī))、set_div_line是否設(shè)置圖表的等分線、
    clear_step清除界面上的數(shù)據(jù)、
    smooth_filter是否進(jìn)行平滑濾波

    本系統(tǒng)還設(shè)計(jì)導(dǎo)聯(lián)狀態(tài)指示燈,前面討論過ADS1292R可以檢測電聯(lián)的脫落狀態(tài),因而這里用LVGL的led控件作為導(dǎo)聯(lián)的狀態(tài)指示,當(dāng)檢測到導(dǎo)聯(lián)接入人體,led控件就會(huì)點(diǎn)亮。設(shè)計(jì)了紅心周期性跳動(dòng),當(dāng)檢測到導(dǎo)聯(lián)接入人體后,紅心就會(huì)周期性跳動(dòng),當(dāng)心電數(shù)據(jù)采樣開始后,紅心隨著心率值的改變而跳動(dòng)著。同時(shí)還設(shè)計(jì)了采樣開始/停止按鈕,可以隨時(shí)暫停和開始采樣心電信號(hào)。
    除了以上看得見的設(shè)計(jì)之外,還創(chuàng)建了四個(gè)周期性的任務(wù),任務(wù)優(yōu)先級(jí)從高到低分別為:更新數(shù)據(jù)欄里的數(shù)據(jù)、更新導(dǎo)聯(lián)狀態(tài)、檢查心電信號(hào)的縱軸范圍、系統(tǒng)狀態(tài)的檢查。

    三、導(dǎo)聯(lián)體系的選擇

    心電信號(hào)本質(zhì)上是測量人體體表的電信號(hào),將電極通過一定的導(dǎo)聯(lián)體系就可以記錄到心電圖,因而選擇合適的電極是觀察心電圖至關(guān)重要的選擇。在醫(yī)學(xué)上常見的導(dǎo)聯(lián)體系分別為標(biāo)準(zhǔn)12導(dǎo)聯(lián)體系、Lewis導(dǎo)聯(lián)、Fontaine導(dǎo)聯(lián)、Cabrera導(dǎo)聯(lián)、Nehb導(dǎo)聯(lián)、frank導(dǎo)聯(lián)、Mason-Likar導(dǎo)聯(lián)等。標(biāo)準(zhǔn)12導(dǎo)聯(lián)體系是醫(yī)院所使用的,它由3個(gè)雙極肢體導(dǎo)聯(lián)、6個(gè)單極胸前導(dǎo)聯(lián)、3個(gè)單極加壓肢體導(dǎo)聯(lián)所組成。
    該系統(tǒng)的主要目的是實(shí)時(shí)檢測心率和QRS寬度,因此選擇的導(dǎo)聯(lián)應(yīng)該基于能觀察心電中R波較大的原則。因而選擇標(biāo)準(zhǔn)12導(dǎo)聯(lián)中標(biāo)準(zhǔn)肢體導(dǎo)聯(lián)I(見圖左),或者M(jìn)ason-Likar導(dǎo)聯(lián)(見圖右)。

    四、心電電極選擇

    人體的內(nèi)阻很高,因而心電信號(hào)是一個(gè)高內(nèi)阻且幅度很低的信號(hào),如果處理不好就會(huì)造成心電信號(hào)的衰減,因此就需要從兩方面解決:
    (1)降低與電極的接觸阻抗(2)提高采集電路的輸入阻抗。

    目前,市面上有三種電極,分別為濕電極、干電極和非接觸式電極,這三種電極中濕電極的接觸電阻最小,因而對(duì)于模擬前端的輸入電阻不需要太大。濕電極主要由電極片、Ag/AgCl 涂層、導(dǎo)電膠等物質(zhì)組成。 醫(yī)學(xué)電極貼片與身體接觸的是水凝膠(親水化合物),“黑色”部分為Ag/AgCl,使用導(dǎo)電金屬和導(dǎo)線與儀器連接,實(shí)物如圖所示。

    五、心電信號(hào)時(shí)域和頻域特征

    人體的心電信號(hào)是一種非平穩(wěn)、非線性、隨機(jī)性比較強(qiáng)的微弱生理信號(hào),幅值約為毫伏(mV)級(jí),頻率在0.05-100Hz之間。心電信號(hào)的每一個(gè)心跳循環(huán)由一系列有規(guī)律的波形組成,它們分別是P波、QRS復(fù)合波和T波,而這些波形的起點(diǎn)、終點(diǎn)、波峰、波谷、以及間期分別記錄著心臟活動(dòng)狀態(tài)的詳細(xì)信息

    心電信號(hào)各個(gè)波段的詳細(xì)說明如下:

    心電各個(gè)波段的功率譜如下:

    心電信號(hào)的噪聲分析如下:

    讀者想對(duì)心電信號(hào)進(jìn)一步了解可以參考如下鏈接:http://www.mythbird.com/ecgxin-hao-te-zheng/。

    六、軟件設(shè)計(jì)

    6.1、系統(tǒng)總體設(shè)計(jì)

    系統(tǒng)先從硬件初始化開始,其中包括串口初始化、觸摸屏初始化、外部SRAM初始化、ADS1292R初始化、LMT70初始化、LVGL心跳定時(shí)器初始化。
    其次就是LVGL初始化,主要是一些主題和變量的初始化。然后創(chuàng)建系統(tǒng)的UI界面和一些定時(shí)的任務(wù)。
    最后初始化心電數(shù)據(jù)緩存、 數(shù)字低通濾波器初始化、心率數(shù)據(jù)緩存初始化。
    完成以上的初始化,系統(tǒng)便進(jìn)入主循環(huán),等待心電數(shù)據(jù)輸入緩存中出現(xiàn)數(shù)據(jù),隨后開始濾波,將濾波之后的數(shù)據(jù)寫入心電輸出緩存中,然后輪詢LVGL的任務(wù)和觸摸屏掃描。就這樣不停地循環(huán)。其中心電輸入緩存中的數(shù)據(jù)是通過中斷從ADS1292R的輸出引腳中讀取,而心電輸出緩存則是原始數(shù)據(jù)經(jīng)過低通處理后的數(shù)據(jù),等待LVGL顯示任務(wù)的到來并顯示在觸摸屏上。系統(tǒng)總體框圖和軟件框圖如下所示

    6.2、系統(tǒng)總體設(shè)計(jì)

    在前面討論過心電信號(hào)頻譜和噪聲,因而要對(duì)心電信號(hào)進(jìn)行濾波,為了同時(shí)實(shí)現(xiàn)心電信號(hào)的實(shí)時(shí)濾波和心電波形實(shí)時(shí)顯示,所以有必要設(shè)計(jì)一個(gè)緩存區(qū)來解決這個(gè)難題。這里我打算用我自己設(shè)計(jì)的兩個(gè)循環(huán)隊(duì)列解決這個(gè)難題。

    為了使得在濾波的時(shí)候,心電數(shù)據(jù)依然能夠采集,設(shè)計(jì)兩個(gè)循環(huán)隊(duì)列,如上圖所示,其中IN_Buffer和OUT_Buffer的每個(gè)矩形框表示25x4個(gè)字節(jié)的空間,這取決一次需要多少字節(jié)的數(shù)據(jù)濾波。這里一次濾波需要25個(gè)int型的數(shù)據(jù),因而每個(gè)緩存需要25x4字節(jié)。圖中的藍(lán)色填充表示緩存區(qū)中填滿了數(shù)據(jù),每次讀完數(shù)據(jù)之后都需要切換緩存區(qū),且IN_Buffer和OUT_Buffer的讀寫操作相反,即IN_Buffer的讀操作是OUT_Buffer的寫操作,程序框圖如下圖所示。

    圖上所示的三個(gè)程序均是并行處理的,
    程序1是通過外部中斷的服務(wù)函數(shù)調(diào)用的
    程序2則是在UI畫圖程序里面通過定時(shí)器周期性的調(diào)用
    程序3則是在主程序中的濾波函數(shù)里面調(diào)用
    程序1代碼如下(ADS1292R采用中斷方式讀取數(shù)據(jù)):

    void EXTI9_5_IRQHandler(void) {if(EXTI->IMR&EXTI_Line5 && ADS_DRDY==0)//數(shù)據(jù)接收中斷{ADS1292_Read_Data(ads1292_Cache);//數(shù)據(jù)存到9字節(jié)緩沖區(qū)Update_ECG_Data(ads1292_Cache);Cheack_lead_stata(ads1292_Cache);if(state_pcb.SampleStartFlag==true)WriteAdsInBuffer(ecg_info.ecg_data);//數(shù)據(jù)寫入緩存區(qū)} EXTI_ClearITPendingBit(EXTI_Line5); }

    程序2代碼如下(LVGL的心跳在定時(shí)器中周期調(diào)用,同時(shí)程序2也在其中運(yùn)行,主要從濾波后的數(shù)據(jù)緩存中取出數(shù)據(jù)進(jìn)行波形顯示):

    void Wave_show(void) {int value=0;if(ReadEcgOutBuffer(&value)!=0) {if(ecg_graph.send_type==GRAPH) {ecg_graph.y_pose=Transf_EcgData_To_Vert(value,ecg_graph.sacle);chart_add_data(ecg_graph.y_pose);set_data_into_heart_buff(ecg_graph.y_pose);} else if(ecg_graph.send_type==USART) {//EcgSendByUart(value);printf("%d\r\n",(int)alg(value/200));}} } //定時(shí)器3中斷服務(wù)程序 void TIM3_IRQHandler(void) { static u8 show_cnt=0; if(TIM3->SR&TIM_IT_Update)//溢出中斷{ show_cnt++;lv_tick_inc(1);//lvgl的1ms心跳if(show_cnt==3){show_cnt=0;Wave_show();}} TIM3->SR = (uint16_t)~TIM_IT_Update; }

    程序3代碼如下(在濾波函數(shù)中調(diào)用,用于承上啟下,即從IN緩存中取出數(shù)據(jù),濾波之后寫入OUT緩存中):

    void arm_fir_f32_lp(void) {float32_t *inputf32, *outputf32;if(ReadAdsInBuffer() && WriterEcgOutBuffer()){//指針定位成功/* 初始化輸入輸出緩存指針 */inputf32 = (float32_t *)InFifoDev.rp;outputf32 =(float32_t *)OutFifoDev.wp;/* 實(shí)現(xiàn)FIR濾波 */arm_fir_f32(&S, inputf32, outputf32, BLOCK_SIZE);//my_memcpy(OutFifoDev.wp,InFifoDev.rp,BLOCK_SIZE*4);InFifoDev.state[InFifoDev.read_front]=Empty;InFifoDev.read_front=(InFifoDev.read_front+1)%PACK_NUM;//切換讀緩存塊OutFifoDev.state[OutFifoDev.writer_rear]=Full;OutFifoDev.writer_rear=(OutFifoDev.writer_rear+1)%PACK_NUM;//切換寫緩存塊}}

    關(guān)于緩存切換代碼如下:

    static void WriteAdsInBuffer(int date) {static u8 cnt=0;if(InFifoDev.state[InFifoDev.writer_rear]==Empty){//緩存塊可寫InFifoDev.wp=&AdsInBuffer[InFifoDev.writer_rear*(BLOCK_SIZE)];//將寫指針定位寫緩存塊InFifoDev.wp[cnt++]=date;if(cnt==BLOCK_SIZE){cnt=0;InFifoDev.state[InFifoDev.writer_rear]=Full;InFifoDev.writer_rear=(InFifoDev.writer_rear+1)%PACK_NUM;//切換寫緩存塊}} }//定位讀指針 //成功則返回1,不成功則返回0 u8 ReadAdsInBuffer(void) {if(InFifoDev.state[InFifoDev.read_front]==Full){//緩存塊可讀InFifoDev.rp=&AdsInBuffer[InFifoDev.read_front*(BLOCK_SIZE)];//將讀指針定位讀緩存塊return 1;}return 0; }//定位讀指針 u8 WriterEcgOutBuffer(void) {if(OutFifoDev.state[OutFifoDev.writer_rear]==Empty){//緩存塊可寫OutFifoDev.wp=&EcgOutBuffer[OutFifoDev.writer_rear*(BLOCK_SIZE)];//將讀指針定位讀緩存塊return 1;}return 0; }//成功則返回1,不成功則返回0 u8 ReadEcgOutBuffer(int32_t *p) {static u8 cnt=0;if(OutFifoDev.state[OutFifoDev.read_front]==Full){//緩存塊可讀OutFifoDev.rp=&EcgOutBuffer[OutFifoDev.read_front*(BLOCK_SIZE)];//將寫指針定位讀緩存塊*p=OutFifoDev.rp[cnt++];if(cnt==BLOCK_SIZE){cnt=0;OutFifoDev.state[OutFifoDev.read_front]=Empty;OutFifoDev.read_front=(OutFifoDev.read_front+1)%PACK_NUM;//切換寫讀緩存塊}return 1;}return 0; }

    6.3、心電信號(hào)濾波

  • 工頻噪聲濾除
  • 濾除工頻噪聲的數(shù)字濾波算法主要有經(jīng)典濾波器、小波變換、自適應(yīng)濾波。小波變換能將心電信號(hào)進(jìn)行多層分解,可以使得心電信號(hào)與工頻噪聲分離,但是計(jì)算量大,所占用的中間變量也比較多,對(duì)于單片機(jī)來說,處理的速度也不夠快,因而對(duì)于系統(tǒng)的實(shí)時(shí)性這一指標(biāo)很難實(shí)現(xiàn)。自適應(yīng)濾波能夠自動(dòng)跟蹤工頻噪聲的改變,但是需要增加一個(gè)輸入信號(hào)作為參考,因而增加了系統(tǒng)的復(fù)雜性。在前面也討論過心電信號(hào)95%的能量都是集中在0~40Hz,而工頻噪聲則在50Hz左右,過渡帶比較寬,因而可以選擇截止頻率為40Hz的低通濾波器。
    該低通濾波器利用MATLAB的FDATOOL生成,只需要選擇低通濾波器是FIR結(jié)構(gòu),選擇Blackman-Harris窗函數(shù),濾波器的階數(shù)定為50,選擇采樣頻率為250Hz,截止頻率為40Hz,參數(shù)如下圖所示:

    然后利用FDATOOL生成的沖激響應(yīng)的數(shù)組,選擇ARM官方的DSP庫,調(diào)用arm_fir_f32函數(shù),既可以完成一次濾波。但是在這之前,需要調(diào)用arm_fir_init_f32進(jìn)行初始化。
    濾波器系數(shù)如下:

    const float32_t fir32LP[NUM_TAPS] = {-7.484454468902e-22,-3.269336712398e-06,-1.365915864079e-05,-5.014073980636e-06,6.804735231975e-05,0.0001662336497003,7.965197426322e-05,-0.0003784662837741,-0.0008928563387901,-0.0005280588787408, 0.001284875839485, 0.003225662215767,0.0022425431358,-0.003157084585057,-0.009028737319977,-0.007219934929014,0.006057868257093, 0.02144319498633, 0.01971312591228,-0.009448071870685,-0.04806332586811, -0.05291973061693, 0.01224382260678, 0.1388254178822,0.2663085232723, 0.3199984843521, 0.2663085232723, 0.1388254178822,0.01224382260678, -0.05291973061693, -0.04806332586811,-0.009448071870685,0.01971312591228, 0.02144319498633, 0.006057868257093,-0.007219934929014,-0.009028737319977,-0.003157084585057, 0.0022425431358, 0.003225662215767,0.001284875839485,-0.0005280588787408,-0.0008928563387901,-0.0003784662837741,7.965197426322e-05,0.0001662336497003,6.804735231975e-05,-5.014073980636e-06,-1.365915864079e-05,-3.269336712399e-06,-7.484454468902e-22 };static float32_t firStateF32[BLOCK_SIZE + NUM_TAPS - 1]; arm_fir_instance_f32 S; void arm_fir_Init(void) {arm_fir_init_f32(&S, NUM_TAPS, (float32_t *)&fir32LP[0], &firStateF32[0], BLOCK_SIZE); }

    濾波函數(shù)見程序3(往上找)

  • 基線漂移
  • 基線漂移與工頻噪聲不同,它是由于呼吸和電極滑動(dòng)變化所異致的,其頻率一般低于1Hz左右。常見對(duì)于基線漂移濾除的數(shù)字算法有高通濾波器、中值濾波、小波變換、形態(tài)學(xué)濾波、曲線擬合等,其中高通濾波器可能會(huì)對(duì)心電信號(hào)的ST波段產(chǎn)生影響,畢竟基線漂移的頻率也在ST波段里面。曲線擬合對(duì)較大的基線漂移處理能力較弱,處理的效果與處理數(shù)據(jù)的長度成正相關(guān),因而不適用實(shí)時(shí)處理的系統(tǒng)。小波變換計(jì)算量大,也不適用實(shí)時(shí)處理的系統(tǒng)。相比之下,形態(tài)學(xué)濾波對(duì)心電信號(hào)的基線漂移濾除效果更好,計(jì)算量也比中值濾波小。但是形態(tài)學(xué)濾波要求數(shù)據(jù)長度足夠長,因而會(huì)改變前面的緩存結(jié)構(gòu),并且在本系統(tǒng)中并未太嚴(yán)重的基線漂移,系統(tǒng)的任務(wù)也比較多,多方面權(quán)衡之下,選擇不處理基線漂移。

  • 肌電噪聲的抑制
  • 肌電噪聲主要是由于人體肌肉顫抖導(dǎo)致體表的電位發(fā)生變化,這種噪聲通過電極貼傳導(dǎo)至心電模擬前端,并且這種噪聲持續(xù)時(shí)間較短,使得ECG信號(hào)波形產(chǎn)生細(xì)小的波紋,這種噪聲頻率分布比較廣,前面已經(jīng)將心電信號(hào)通過截止頻率為40Hz的低通濾波器,因而需要5點(diǎn)平滑濾波將細(xì)小的波紋濾除,為了不影響心電信號(hào)的實(shí)時(shí)處理,因而改進(jìn)版的平滑濾波器代碼如下:

    /** 滑動(dòng)平均值濾波。* 每調(diào)用一次,就加入一個(gè)新數(shù)據(jù),并得到當(dāng)前的濾波值。*/ float alg(float new_val) {/* 用一個(gè)減法,就做了"丟棄最舊的數(shù)據(jù),加入最新的數(shù)據(jù)"這一操作 */sum += (new_val - buf[pos]);buf[pos] = new_val;pos = (pos + 1) % MAX_COUNT;/* 個(gè)數(shù)不足時(shí),cnt是實(shí)際個(gè)數(shù),個(gè)數(shù)足夠時(shí),cnt最多也只是MAX_COUNT */pcnt += (pcnt < MAX_COUNT);return sum / MAX_COUNT; }

    6.4、心率和QRS寬度檢測

    心率和QRS寬度檢測作為本系統(tǒng)的算法核心,有了心率值和QRS寬度值才能進(jìn)一步判斷常見的心律失常。心率基本上都是檢測兩個(gè)R波之間的時(shí)隙來計(jì)算的,常見檢測R的算法主要有閾值法、模板法和語句描述法。
    而本系統(tǒng)的心率和QRS寬度檢測算法是在一起檢測的,所采用的算法是幅度閾值檢測和差分檢測相結(jié)合,因?yàn)橛^察心電信號(hào)的R波,發(fā)現(xiàn)R波是具有窄的脈沖,且脈沖的幅度是心電信號(hào)最高的,因而采用幅度和一階差分共同約束找到R波,同時(shí)在找R波的同時(shí)還可以估計(jì)出QRS的寬度,算法的框圖如圖

    心率檢測和QRS寬度檢測算法是采用狀態(tài)機(jī)的編程思想,通過R波幅度大且從Q到R一直遞增,并且R波到S波的一階差分值很大,從而將R波定位出來,檢測兩個(gè)R波之前的時(shí)間,然后通過如下公式就可以計(jì)算出心率:
    HR=(60?SampleRate)/countHR=(60*SampleRate) /count HR=(60?SampleRate)/count

    而QRS寬度則是由
    QRS=QRScnt?2.2?1000/(SampleRate)QRS=QRScnt*2.2* 1000/(SampleRate) QRS=QRScnt?2.2?1000/(SampleRate)

    上式中的2.2是估計(jì)值,因?yàn)镼RS_cnt是在檢測到R波之后才開始計(jì)數(shù),并且未到S波谷停止計(jì)數(shù),觀察QRS波,發(fā)現(xiàn)Q到R與R到S近似對(duì)稱,因而采用2.2這個(gè)估計(jì)值,這也是實(shí)時(shí)檢測的缺陷,檢測的樣本不多。
    心率算法和QRS寬度檢測代碼如下:

    /*** @Brief 測量心率* @Call* @Param* @Note* @Retval*/ void ecg_heart_rate(int data) {int Signal=data;if(Signal>hr.vmax)hr.vmax=Signal;if(Signal<hr.vmin)hr.vmin=Signal;thresh=hr.vmax-(hr.vmax-hr.vmin)/5;for( uint16_t i = 0; i <= DATA_NUM_CAL_HR - 2; i++ ){DataArrayCalHR[i] = DataArrayCalHR[i + 1];}DataArrayCalHR[DATA_NUM_CAL_HR - 1] = Signal;Diff_Arrray( DiffDataArrayCalHR, DataArrayCalHR, DATA_NUM_CAL_HR ); //差分if(hr.flag==StartDetected){uint8_t FlagAllDiffRise = true;for( uint16_t i = 0; i <= DATA_NUM_CAL_HR - 2; i++ ) //判斷波形是否一直上升{if( DiffDataArrayCalHR[i] <= 0 ){FlagAllDiffRise = false;break;}}if(FlagAllDiffRise==true){hr.flag=QWave;}}else if(hr.flag==QWave)//已經(jīng)找Q波{if(DataArrayCalHR[DATA_NUM_CAL_HR-1]>thresh){if(hr.count>125){if( hr.firstBeat==true )//如果已經(jīng)找到 過R波{hr.rate=(float)60*SAMPLE_RATE/(hr.count);hr.count=0;//清除計(jì)數(shù)hr.flag=RWave;QRScntflag=true;} else if(hr.firstBeat==false) {hr.firstBeat=true;hr.count=0;//清除計(jì)數(shù)hr.flag=RWave;QRScntflag=true;}} }}else if(hr.flag==RWave ){if(DiffDataArrayCalHR[0]<-(hr.vmax-hr.vmin)/5){hr.flag=SWave;}}else if(hr.flag==SWave){if(hr.QRS_cnt<15){hr.flag=StartDetected;hr.QRS=hr.QRS_cnt*22*100/SAMPLE_RATE;hr.QRS_cnt=0;QRScntflag=false;}else {hr.flag=StartDetected;hr.QRS=0;hr.QRS_cnt=0;QRScntflag=false;}}if(hr.count>420){hr.firstBeat=false;hr.flag=StartDetected;hr.vmax=Heart_MIN;hr.vmin=Heart_MAX;hr.rate=0;thresh=0;hr.count=0;//清除計(jì)數(shù)} }

    七、實(shí)機(jī)演示

    實(shí)機(jī)演示

    八、總結(jié)與展望

    本系統(tǒng)因?yàn)闆]有加入操作系統(tǒng)的管理,造成實(shí)現(xiàn)的功能較為少,并且數(shù)據(jù)分析功能因?yàn)槿狈?qiáng)大處理器造成數(shù)據(jù)分析功能所需要的指標(biāo)太少,要想對(duì)心電信號(hào)實(shí)現(xiàn)自動(dòng)化分析,必須對(duì)心電信號(hào)更多的信息進(jìn)行提前,而且由于處理器的限制使得一些強(qiáng)大的數(shù)字算法是用不了,而且將采集—濾波—顯示集成一體化本身就顯得笨重,會(huì)讓每個(gè)處理單元相互牽制,嚴(yán)重的會(huì)影響系統(tǒng)的采樣率,造成一些不必要的誤差。所以日后會(huì)有針對(duì)選擇更為強(qiáng)大的處理器,會(huì)將采集、濾波、顯示分開來。同時(shí)為了減少外界噪聲,應(yīng)該選擇更為干凈的電源和屏蔽外殼,系統(tǒng)也不能以這種模塊化的方式拼接在一起,日后會(huì)選擇畫PCB,將所有模塊集成在PCB上,在套上屏蔽殼,這樣能夠最大程度減少外界噪聲干擾。并且無線通信模塊保留著,但是上位機(jī)并未實(shí)現(xiàn),因而日后需要增加這一項(xiàng)功能。總結(jié)以上的不足如下:

  • 使用更為強(qiáng)大的處理器,將采集、濾波、顯示分開來。
  • 所有模塊應(yīng)該集成在PCB上,在增加屏蔽殼。
  • 開發(fā)上位機(jī)軟件,實(shí)現(xiàn)心電數(shù)據(jù)的無線通信的功能。
  • 代碼我會(huì)放在github上,鏈接如下:
    https://github.com/lvzhe-speed/STM32_ECG
    后面我去考研了,希望能夠考上,以后會(huì)每一年至少寫一篇技術(shù)博客,謝謝各位大佬前來斧正,歡迎探討,一起技術(shù)進(jìn)步。其實(shí)我也想借此說一下,不能因?yàn)橐淮问【头穸ㄗ约褐暗呐?#xff0c;100-1=0這也許是別人對(duì)你的評(píng)價(jià),但自己不能認(rèn)同這個(gè)錯(cuò)誤的式子,人生不僅有加法,也有減法。也希望對(duì)別人多一點(diǎn)諒解,每個(gè)人都不容易,也許今日之菜鳥,明日之大鵬,總會(huì)翱翔九天。

    總結(jié)

    以上是生活随笔為你收集整理的基于STM32F4的心电监护仪的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。