半年,1萬(wàn)行代碼,1447個(gè)焊盤(pán),做了一個(gè)心電儀,開(kāi)源了
半年,1萬(wàn)行代碼,1447個(gè)焊盤(pán),做了一個(gè)心電儀,開(kāi)源了
我想,優(yōu)秀的心電監護儀,一定能一邊進(jìn)行高精度檢測,一邊直接打印檢測數據!
本文引用地址:http://dyxdggzs.com/article/202412/465451.htm抱著(zhù)這樣的想法,我做了這個(gè)心電儀,順便被電視臺報導了……
這個(gè)心電儀厲害在哪里?
下面,就介紹一下我做的心電監護儀,順便分享一下——功能亮點(diǎn)、硬件設計、數據處理原理、軟件說(shuō)明、成本說(shuō)明。
參考開(kāi)源資料:
https://oshwhub.com/lmppbba/ecg-monitoring-defibrillator-with-12-leads
項目簡(jiǎn)介
這是一個(gè)擁有12導聯(lián)的心電監護儀
作者用半年時(shí)間,寫(xiě)出一萬(wàn)行代碼,放置1447個(gè)焊盤(pán),連3310條導線(xiàn),最終開(kāi)源出來(lái)了這個(gè)項目!
一、功能/亮點(diǎn)
1.心電監護功能
一鍵10s快照功能
一鍵凍結
血壓測量
實(shí)時(shí)分析計算
實(shí)時(shí)時(shí)鐘顯示
2.十二導聯(lián)心電圖功能
實(shí)時(shí)快速心律分析
一鍵凍結
一鍵10s記錄
自動(dòng)分析標注
一鍵快速打印
3.5個(gè)巧思
將心電監護儀與十二導聯(lián)心電圖相結合, 功能強大
減輕了整機重量,整機A4紙大小,若運用于急救系統,可減輕急救人員負重壓力,可讓急救員輕松穿過(guò)狹窄區域
集成8寸(A4)熱敏打印機芯,可隨時(shí)快速打印長(cháng)度固定為30cm的記錄
記錄紙打印裝訂參考線(xiàn),內置RTC時(shí)鐘同步時(shí)間,便于快速整理數據,提高工作效率
打印模板數據欄簡(jiǎn)潔易懂,排列整齊,可快速查找重要數據
4.7個(gè)亮點(diǎn)
全站首個(gè)12導聯(lián)心電圖采集電路
全站首套心電圖基線(xiàn)修正與心電圖(實(shí)時(shí))詳細分析標定算法
全站首套完整基礎患者監護系統
全站首套呼吸波分析算法
全站首套血壓計系統(首套血壓計示波法算法)
全站首次熱敏打印機控制器實(shí)際專(zhuān)項應用項目,數組合并,實(shí)時(shí)計算算法
全站首個(gè)應用CLUT低RAM點(diǎn)亮大屏項目
二、硬件設計
1.電路設計
主控部分
電源部分
12導聯(lián)模塊
心電監護及PANDLE
除顫器部分
控制面板
參考資料頁(yè)
PCB圖
2.硬件說(shuō)明
設計軟件:嘉立創(chuàng )EDA
主控芯片:GD32F470ZIT6
生物電采集前端設計使用:TI ads129x
電池管理:IP5310(英集芯)
心電圖前端:ADS1298(TI)
呼吸測量前端:ADS1292R (TI) ADS1294R缺貨被迫選擇
電壓基準源:REF3433IDBVR(TI)95uA低功耗
打印頭機芯:JX-8R-LXS(QJ) 目前搜到成本最低
參加開(kāi)源活動(dòng):星火計劃
[星火計劃]提供了:PCB-550;SMT-3000;元器件-200;3D外殼-400等開(kāi)發(fā)耗材;具體心電儀成本見(jiàn)【第5章】
三、數據處理原理
1.血氧飽和度脈搏波的獲取
怎么獲取更精準的數值?原理是什么?
下面圖示是需要獲取的PPG數據(類(lèi)似)。
如果我們單純設置一個(gè)閾值來(lái)“一刀切”,那么不在范圍內的信號就會(huì )被斬于馬下,呈在屏幕上呈現出滿(mǎn)量程的假象。每一個(gè)人的脈搏波測量后所反饋所得數值都不一樣,且該波形易受到意外影響,如:亂動(dòng)血氧夾子,二度房室傳導阻滯,窒息或其他原因的血氧跌落,肢體活動(dòng)等導致血流受阻。
因此,我們必須使用特殊算法來(lái)適應。思路如下:
讀取窗:
我們設置顯示窗為0~1000范圍,要在顯示窗內顯示完整圖形,首先要標記出數值的最值,標記出最大值和最小值就為將圖形全部放到顯示窗內提供了可能。
但,傳感器所反饋回來(lái)的數值非常大,并不能直接放到顯示窗內,所以我們要進(jìn)行下一步的必要處理。
處理窗:
脈搏波所反饋的信息很多,我們?yōu)榱吮A裘}搏波跌落,上升,以及圖形更多細節,采用分段取最值的方式,并沒(méi)有采用中值濾波,現在設置一個(gè)周期,每1000周期取一次最值(紅線(xiàn)標記相關(guān)代碼,下同)
然后,我們將數值減去最小值,我們將小于最小值的數字直接略去,但分段取值的缺點(diǎn)因此顯現,所以我們在略去的同時(shí)告訴取值部分需要重新取值(最大值同理)
這樣不是又出現了滿(mǎn)量程現象嗎?
其實(shí),這是對于顯示趨勢時(shí)的必要犧牲,在下一周期會(huì )重新被感應,而且一個(gè)周期持續只有2秒
處理窗:
然后,我們截取數據,將圖形繪制到顯示窗上,為了減少超量程現象,我們?yōu)樽钪翟黾?00的寬限
PPG顯示窗:
但是,在調光后幾秒,脈搏波的最值取值不正確,或者患者發(fā)生心律失常時(shí)脈搏減弱,這個(gè)過(guò)程中,脈搏數據均未突破最值,但是波形異常小,難以閱讀 甚至為一條直線(xiàn)不能閱讀。
出現波形 “難以閱讀 ”的現象,怎么破?
此時(shí),我們要檢測波形振幅,當振幅低于設定值,發(fā)送需要重新取最值請求
PPG顯示窗(異常):
這樣,當PPG信號出現振幅異常時(shí),程序才會(huì )將波形”伸開(kāi)“,至此,解決了PPG的搜索,以及意外處理
PPG顯示窗(運行時(shí)):
PPG顯示窗(實(shí)際運行),可以很清楚看到各個(gè)周期的處理:
*PPG與ECG不同,不能代替ECG診斷復雜情況,但PPG也有自己的用武之地,如:發(fā)現房顫,早搏或傳導阻滯,過(guò)速或過(guò)緩,但只起到發(fā)現作用,還需要ECG確認和定性
2.心電信號解算
如何基于A(yíng)DS1298讀取心電信號解算?如何實(shí)時(shí)基線(xiàn)修正呢?
首先吐槽一下ADS1298的奇葩輸出方式,在0到正滿(mǎn)量程時(shí)輸出值位0 - 0x7FFFFF,但是在負滿(mǎn)量程到0時(shí)卻跟在了0x7FFFFF之后,為0x800000 - 0xFFFFFF
所以,畫(huà)出的數軸是這樣子的,需要進(jìn)一步處理將兩者連到一起,否則當數據卡在正負中間時(shí),解算的數據上上下下無(wú)法分析
怎么將兩者連到一起呢?
現在紅色為一組,藍色為一組,按照uint來(lái)看,藍色在前,紅色在后,現在我們把藍色放到后面,剩下的交給基線(xiàn)修正邏輯
為了把藍色放到后面,且防止溢出,我們分為三步走。
第一步,判斷數據應屬于0以上還是0以下
第二步,如果是0以下,讓數據減去0x800000,使得負滿(mǎn)量程為0
第三步,如果數據是0以上(含0),讓數據加上0x8000
這樣,讀取數據的時(shí)候就不會(huì )抽風(fēng)了,可以安心丟給基線(xiàn)修正邏輯
舊的問(wèn)題解決,新的問(wèn)題油然而生。
在用”12陣法“鎮住數據之后,我們發(fā)現數據上出現了很多毛刺,非常影響判讀和分析……
我們需要清理這些 “數據毛刺”!
我們發(fā)現,比較突兀的毛刺電壓為8mV,那么QRS電壓有可能超過(guò)8mV嗎?
正??隙ú粫?huì )的,但是情景是多變的,我開(kāi)始搜索病態(tài)心電圖查找線(xiàn)索。在搜索的病案中,QRS電壓在3mV左右, 沒(méi)有超過(guò)3.5mV的,保險起見(jiàn)我們將超過(guò)6mV的信號定為毛刺信號去除(最終最高QRS電壓為患有心力衰竭左心室擴張的親戚,R波電壓5mV)
現在,我們就和大毛刺say good bye了,小毛刺還需在電源努力。
怎么清除 “小毛刺?”
接下來(lái),就該處理喝醉酒一樣的基線(xiàn)了,我們可以看到基線(xiàn)一直在上下傾斜,這就是基線(xiàn)漂移現象。
基線(xiàn)漂移如何處理呢?
基線(xiàn)漂移的重中之重就是找到基線(xiàn)信號,緊接著(zhù)將原始數據減去基線(xiàn)信號就可以得到修正后的波形了。
要得到基線(xiàn)信號,我們需要去除QRS波,P波和T波。QRS波是最好去除的,只需要沿用毛刺去除代碼,將QRS判定為毛刺即可。
說(shuō)明一下,在定義的時(shí)候,I導聯(lián),aVR aVL aVF不做定義,因為這些導聯(lián)是算法推算的,后算即可(bsxx 即basexx為基線(xiàn)變量)
想象很美好,現實(shí)是殘酷的,因為高采樣率的緣故,QRS有上升時(shí)間,得到的基線(xiàn)標本(紫色)和原始數據(紅色)是差不多一樣的!解決這個(gè)僵局很簡(jiǎn)單,我們使用抽樣調查之后,再進(jìn)行接下來(lái)的處理:
就這樣,我們得到了抽樣調查后去掉QRS波的樣本,雖然采樣率被極致壓縮,但是這對于解算基線(xiàn)已經(jīng)綽綽有余了
聽(tīng)說(shuō)你要直接拿數據減去這個(gè)?不!這里面還有未除凈的p波和T波,有時(shí)候s波也混在其中!
此時(shí),請出我們的中值濾波器。
這樣我們在用“原始數據”減去“基線(xiàn)數據”就能得到“基線(xiàn)”和“最終波形”。
測試對象2:
*相關(guān)代碼存在變更,測試圖并不能反映最終結果
然后推算其他肢體導聯(lián)。
3.NIBP無(wú)創(chuàng )血壓數據處理
無(wú)創(chuàng )血壓(同NIBP)?怎么測量這個(gè)數據?
怎么獲取NIBP數值?一般是給袖帶充氣,當超過(guò)人體最高血壓值一定數值,再緩慢放氣,讀取放氣過(guò)程中袖帶壓(或管路壓力)的變化,并處理,得出NIBP數值。具體原理如下:
當袖帶充氣超過(guò)收縮壓之后,血流被阻斷,不會(huì )對袖帶產(chǎn)生作用力,在放氣時(shí),袖帶壓降低到收縮壓之后血流重新流通并產(chǎn)生波動(dòng),對袖帶產(chǎn)生作用力,引起袖帶內壓力值增高或暫時(shí)不變。繼續放氣低于舒張壓之后,有壓強差可得,袖帶對血管產(chǎn)生壓力與所受血管的支持力相等,合力為0,不產(chǎn)生形變,袖帶內壓強不再受血流沖擊變化,壓力值正常下降。
了解了原理,讓我們將目光放回本項目!
實(shí)際操作中,如何實(shí)現精準的NIBP數值測量呢?
首先,看一下理想情況下袖帶壓力變化。
圖表來(lái)自https://www.bilibili.com/video/BV1JV4y167AJ
然而,事實(shí)上,沒(méi)有什么事情是理想的,在實(shí)際對*0.1kPa數據前處理之后,讀出的波形成了這副模樣:
全貌:
泄氣部分:
如何處理這種 “波形泄氣 ”的情況?
由于之前處理運算轉換為mmHg int值時(shí),在*0.75過(guò)程中丟失了波形細節,所以我們在這個(gè)失真的波形上意外的讀出了(87/45)的奇怪NIBP值。
我們將int換為float得到以下圖形:
所蘊含的信息在哪里呢?我幫你指一下:
這里可以找到四個(gè)心搏點(diǎn),但是黃色標記的心搏太淺,單片機可能無(wú)法正常識別到,所以,可以認為僅存在三個(gè)有效點(diǎn)
接著(zhù),就要讓單片機認識這幾個(gè)心搏點(diǎn)
直接讓單片機處理是不可能的,因為前后都有平直線(xiàn)段,而且我們也不能標定閾值,由于數據讀取的特殊性,只要讀錯一個(gè),所得數據會(huì )造成極大誤差。
根據唐老師將電賽-電子血壓計電路指導,我使用一個(gè)0.3~3.5帶通濾波器協(xié)助調整。但在實(shí)際操作中,發(fā)現需要使用一個(gè)頻率為<3Hz的低通濾波器,不斷調整數值到最佳頻率。
億頓操作猛如虎,經(jīng)過(guò)濾波,提取,再濾波之后得到這樣的數據,可以輕松找到五個(gè)搏動(dòng)點(diǎn),但是仍然存在許多噪聲,無(wú)法滿(mǎn)足單片機的處理需要,單片機還是看不懂。
并且,左邊的大豎線(xiàn)需要在以后匯總時(shí)屏蔽掉。
怎么削弱 “波形噪聲 ”?
這里可使用閾值法。
首先,通過(guò)間隔取中值濾波,將圖形稍做優(yōu)化,看起來(lái)不那么雜亂無(wú)章了,就不為難單片機了。
通過(guò)平方削弱雜波成分后,再通過(guò)下降枝閾值法和干擾值排除確定出搏動(dòng)。
如圖,這是提取出來(lái)的脈搏點(diǎn)(未經(jīng)過(guò)排除),可以看到,重博波與過(guò)遠的無(wú)效波。
然后,再經(jīng)過(guò)隔值法與直接法處理并比較有效點(diǎn)個(gè)數,多者勝出,運用其方案計算
隔值法原理:
現有的數據: N N N N N N N(直接法算法)
第一次處理: N N N N N N(嘗試計算)
第二次處理: N N N N N N(嘗試計算)
第三次處理: N N N N N N(嘗試計算)
第四次處理: N N N N N N(嘗試計算)
第五次處理: N N N N N N(嘗試計算)
沒(méi)有第六次啦!不然比較不了間隔值!
排除干擾所得數據如圖,可以看到“原理數據”的值和兩個(gè)有效數據之間的“干擾值”被濾去:
第二次試驗:
看到先出現對應收縮壓,后出現對應舒張壓,就完畢啦!
4.呼吸波數據解析
首先要讀取到呼吸波形
我們使用了0.1 - 4 Hz低通濾波器,以及一個(gè)中值濾波進(jìn)行處理,得到初步波形,將其存入數組。
為保證分析和快照實(shí)時(shí)性,我們采取將數組左移,最后追加的方式存儲數據。
我們使用memmove方法安全且快速的移動(dòng)數據。
這是讀取出來(lái)的原始呼吸波性,被載入到緩存數組中,但是仍然有很多毛刺,雖然在顯示時(shí)無(wú)影響,但是對于數據處理是致命的
怎么處理這些毛刺?
于是我們對其進(jìn)行了一次帶通濾波(0.2 ~ 4 Hz)和寬窗中值濾波,讓波形變平滑,最后進(jìn)行下降沿檢測即可。
在實(shí)驗時(shí)發(fā)現總會(huì )有1的重復值,進(jìn)行矯正即可:
最后我們把識別呼吸波的個(gè)數乘以三 即可。
因為采樣率是10ms一次,傳入數組體量為2000,含20s數據,乘以三即可獲得60s數據。
5.多導聯(lián)心電圖聯(lián)合解析算法
這是一項艱巨的任務(wù),也是各個(gè)數字心電圖機開(kāi)發(fā)所面臨的挑戰。
R波識別
處理第一步,通過(guò)Pan-Tompkins算法濾波+平方運算削弱p、T等小波,提高R波斜率。
所得結果1:
所得結果2:
然后就可以通過(guò)“斜率識別”把R波的索引提取出來(lái)。
對于低電壓的情況,識別到無(wú)任何波形,可以降低閾值繼續檢測。
但是如結果1所示,II導聯(lián)處理的數據中間存在若干干擾,還需要引入III導聯(lián)進(jìn)行雙重校驗,得出純凈的數據。然后再將索引根據采樣率計算出RR間期以及心率。
緊接著(zhù)計算出QRS數據與QT數據。
QRS起點(diǎn)尋找
我們通過(guò)以上算法尋找的R波可能超過(guò)R波,也可能在Q與R之間,我們需要進(jìn)一步向左尋找QRS波起點(diǎn)。
對于起點(diǎn)尋找,就需要考慮多種情況了。
我們總結出這幾種情況:
1.無(wú)Q波,直接平直
2.有Q波,即存在轉折關(guān)系
這些是可能的情況,部分情況可以合并(正向波和負向波的同類(lèi)型情況可以合并,根據Q波的情況可以合并)
我們針對第一種情況設置低于4單位即為平直(別看很多,其實(shí)整個(gè)圖拉的很大),遇到平直數值停止查找,定義其對應索引值為起點(diǎn)。
斜率符號改變視為掉頭,針對第二種掉頭情況。我們設置掉頭次數不能超過(guò)三次(抵消干擾),并且遇到操作索引的前一個(gè)和后一個(gè)的差值不能小于3,否則立即停止查找,定義其對應索引值為起點(diǎn)。
在尋找起點(diǎn)的同時(shí),定義起點(diǎn)索引前 2單位的數值為零電位(要取平均值的)。接著(zhù)進(jìn)入下一步,心電軸計算。
QRS電軸計算
電軸也稱(chēng)平均電軸,是心臟電活動(dòng)的平均方向(向量),是心電圖檢測指標之一,指心臟除極和復極時(shí)額面最大綜合向量與水平軸形成的角度。
我們已經(jīng)記錄了QRS波,想要讓機器識別心電軸,就必須推導出計算方法。
想必學(xué)過(guò)心電圖的醫學(xué)生們一定對這張圖非常熟悉,這張是使用I,III導聯(lián)代數和進(jìn)行計算的,但是,這種方法對于機器來(lái)說(shuō)比較復雜,我們采取另一種方式,面積積分法。
這個(gè)方法因為人工計算麻煩而被拋棄,但是面積積分法是測量心電軸最標準的方法,也是機器計算最簡(jiǎn)單的方法。
在這幅圖中,顯示了振幅法和面積法的差距。
面積積分法是把I,III導聯(lián)相對于等電位線(xiàn)正向和負向面積代數和做圖在一個(gè)特殊坐標系上,其中-III與+I的夾角度數為60deg。
在計算時(shí)有四種情況:
SI <0 SIII<0 電軸不確定
SI <0 SIII>0 電軸左偏
SI >0 SIII<0 電軸右偏
SI >0 SIII>0 電軸不偏
我們選取有代表性的兩種做出幾何推理:
紅線(xiàn):SI SIII
黑線(xiàn):反向延長(cháng)線(xiàn)
綠線(xiàn):相交點(diǎn)與電偶中心連線(xiàn)
定義點(diǎn)I為A;點(diǎn)III為B。
情況A:電軸不偏
延長(cháng)P III 交直線(xiàn)I O 與點(diǎn)N
∵PB⊥ OB,∠NOB = ∠ = 60 deg
∴∠ONB = 30 deg
又∵∠NBO= 90 deg
∴NO = 2SIII
∴NA = 2SIII+SI
∵∠NAP = 90 deg,∠ONB = 30 deg
∴PA =
∵∠NAP = 90 deg
∴心電軸=
情況B:電軸左偏
延長(cháng)BP交支線(xiàn)I與點(diǎn)N
∵∠BON = 60 deg,∠OBN = 90 deg
∴∠BNO = 30 deg
∴在△NBN中 ON = 2SIII
在△PAN中 PA =NA/√3
∵NA = ON - OA = 2SIII-SI
∴PA=
∴在Rt△PAO中,∠PAO = 90 deg
心電軸=
對于另外兩種可情況,可以將兩個(gè)面積和取相反數,根據對頂角相等的數學(xué)思維即可轉化為以上兩種情況,是不是很有趣呢。
所對應的計算是這樣子的:
T波尋找與QTc計算
T波屬于小波成分,斜率較小,我們使用新的帶通濾波器(8-22.5Hz)提取出T波。
這樣P,T的成分就明顯了。
緊接著(zhù)把索引內小于100與大于1800的索引編號去除,防止搜索時(shí)越界。
然后計算出最大的QT間期(QTc按550ms記,再高就不可能了,就會(huì )有尖端扭轉室速)
然后跳過(guò)QRS波,并向后30s到最長(cháng)QT間期尋找最大最小值,最大最小值對應T波終點(diǎn)(對于這個(gè)濾波器處理后的數據)
然后求平均值算出QT間期:
然后根據QTc矯正公式算出QTc,在用QT-QRS算出T波時(shí)限:
胸導聯(lián)R/S波電壓分析
胸導聯(lián)R/S波電壓RV5+SV1和RV1+SV5是心電圖分析時(shí)重要的工具??梢苑治鲎笫液陀沂译妷旱拇笮?,對心肌梗死,高血壓心臟病,心室擴張,心室肥大,肺動(dòng)脈高壓的診斷有指導意義。
首先,根據QRS起點(diǎn)向左兩個(gè)單位算出等電位求平均值
然后求與等電位相對值的最大最小值:
最后求電壓值的平均值,然后取絕對值,將記錄的值(單位)轉化為電壓值(mV):
結束解算代碼。
四、軟件說(shuō)明
由于單片機片上資源極度有限,我們放棄了占用資源多的FreeRTOS與LVGL,使用裸機+LCD繪圖庫完成設計
軟件部分主要說(shuō)明什么呢?
已知,心電儀的應用設計,是兩個(gè)App以及多個(gè)界面切換。
那要如何保證切換不出錯??jì)x器按鍵不出錯?
我使用了將App或界面返回值代入決策的方式實(shí)現切換。
這樣,只需要在A(yíng)pp函數返回一串特征代碼,管理器即可切換到指定App或界面。
我們使用一個(gè)旋轉開(kāi)關(guān)來(lái)作為App切換,我們通過(guò)讀取開(kāi)關(guān),累計標識的方式銷(xiāo)毀當前App切換。
在讀取到App不一致時(shí)開(kāi)啟累計標識,達到一定數值后銷(xiāo)毀并切換,標識歸零。若檔位開(kāi)關(guān)回到當前App,標識歸零。
復雜的系統,機械按鍵是不允許出半點(diǎn)差錯的,我們對于機械按鍵處理,使用中斷調用管理器中的按鍵功能決策函數,根據App和頁(yè)面標識決策功能。
當然在A(yíng)pp/頁(yè)面被調用時(shí),需要設置標識:
這樣,整個(gè)調度系統才能有條不紊的運作下去,長(cháng)期保持穩定。而且,裸機相比于RTOS大幅提升了系統穩定性,保留更多資源。
五、成本說(shuō)明
個(gè)人制作一個(gè)心電監護儀的總成本約3100元。
你覺(jué)得這個(gè)儀器做得怎么樣呢?
參考開(kāi)源資料:
https://oshwhub.com/lmppbba/ecg-monitoring-defibrillator-with-12-leads
評論