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