我想,优秀的心电监护仪,一定能一边进行高精度检测,一边直接打印检测数据!
下面,就介绍一下我做的心电监护仪,顺便分享一下——功能亮点、硬件设计、数据处理原理、软件说明、成本说明。
作者用半年时间,写出一万行代码,放置1447个焊盘,连3310条导线,最终开源出来了这个项目!
减轻了整机重量,整机A4纸大小,若运用于急救系统,可减轻急救人员负重压力,可让急救员轻松穿过狭窄区域
记录纸打印装订参考线,内置RTC时钟同步时间,便于快速整理数据,提升工作效率
[星火计划]提供了:PCB-550;SMT-3000;元器件-200;3D外壳-400等开发耗材;具体心电仪成本见【第5章】
如果我们单纯设置一个阈值来“一刀切”,那么不在范围内的信号就会被斩于马下,呈在屏幕上呈现出满量程的假象。每一个人的脉搏波测量后所反馈所得数值都不一样,且该波形易受到意外影响,如:乱动血氧夹子,二度房室传导阻滞,窒息或其他原因的血氧跌落,肢体活动等导致血流受阻。
我们设置显示窗为0~1000范围,要在显示窗内显示完整图形,首先要标记出数值的最值,标记出最大值和最小值就为将图形全部放到显示窗内提供了可能。
但,传感器所反馈回来的数值非常大,并不能直接放到显示窗内,所以我们要进行下一步的必要处理。
脉搏波所反馈的信息很多,我们为了保留脉搏波跌落,上升,以及图形更多细节,采用分段取最值的方式,并没有采用中值滤波,现在设置一个周期,每1000周期取一次最值(红线标记相关代码,下同)
然后,我们将数值减去最小值,我们将小于最小值的数字直接略去,但分段取值的缺点因此显现,所以我们在略去的同时告诉取值部分要重新取值(最大值同理)
其实,这是对于显示趋势时的必要牺牲,在下一周期会重新被感应,而且一个周期持续只有2秒
然后,我们截取数据,将图形绘制到显示窗上,为减少超量程现象,我们为最值增加300的宽限
但是,在调光后几秒,脉搏波的最值取值不正确,或者患者发生心律失常时脉搏减弱,这样的一个过程中,脉搏数据均未突破最值,但是波形异常小,难以阅读甚至为一条直线不能阅读。
这样,当PPG信号出现振幅异常时,程序才会将波形”伸开“,至此,解决了PPG的搜索,以及意外处理
*PPG与ECG不同,不能代替ECG诊断复杂情况,但PPG也有自己的用武之地,如:发现房颤,早搏或传导阻滞,过速或过缓,但只起到发现作用,还需要ECG确认和定性
所以,画出的数轴是这样子的,要进一步处理将两者连到一起,否则当数据卡在正负中间时,解算的数据上上下下无法分析
现在红色为一组,蓝色为一组,按照uint来看,蓝色在前,红色在后,现在我们把蓝色放到后面,剩下的交给基线修正逻辑
在用”12阵法“镇住数据之后,我们得知数据上出现了很多毛刺,非常影响判读和分析……
我们发现,比较突兀的毛刺电压为8mV,那么QRS电压有可能超过8mV吗?
正常必然不会的,但是情景是多变的,我开始搜索病态心电图查找线索。在搜索的病案中,QRS电压在3mV左右, 没有超过3.5mV的,保险起见我们将超过6mV的信号定为毛刺信号去除(最终最高QRS电压为患有心力衰竭左心室扩张的亲戚,R波电压5mV)
接下来,就该处理喝醉酒一样的基线了,我们大家可以看到基线一直在上下倾斜,这就是基线漂移现象。
基线漂移的重中之重就是找到基线信号,紧接着将原始数据减去基线信号就可以得到修正后的波形了。
要得到基线信号,我们需要去除QRS波,P波和T波。QRS波是最好去除的,只需要沿用毛刺去除代码,将QRS判定为毛刺即可。
说明一下,在定义的时候,I导联,aVR aVL aVF不做定义,因为这些导联是算法推算的,后算即可(bsxx 即basexx为基线变量)
想象很美好,现实是残酷的,因为高采样率的缘故,QRS有上升时间,得到的基线标本(紫色)和原始数据(红色)是差不多一样的!解决这个僵局很简单,我们使用抽样调查之后,再进行接下来的处理:
就这样,我们得到了抽样调查后去掉QRS波的样本,虽然采样率被极致压缩,但是这对于解算基线已经绰绰有余了
听说你要直接拿数据减去这个?不!这里面还有未除净的p波和T波,有时候s波也混在其中!
这样我们在用“原始数据”减去“基线数据”就能得到“基线”和“最终波形”。
怎么获取NIBP数值?一般是给袖带充气,当超过人体最高血压值一定数值,再缓慢放气,读取放气过程中袖带压(或管路压力)的变化,并处理,得出NIBP数值。具体原理如下:
当袖带充气超过收缩压之后,血流被阻断,不会对袖带产生作用力,在放气时,袖带压降低到收缩压之后血流重新流通并产生波动,对袖带产生作用力,引起袖带内压力值增高或暂时不变。继续放气低于舒张压之后,有压强差可得,袖带对血管产生压力与所受血管的支持力相等,合力为0,不产生形变,袖带内压强不再受血流冲击变化,压力值正常下降。
然而,事实上,没有什么事情是理想的,在实际对*0.1kPa数据前处理之后,读出的波形成了这副模样:
由于之前处理运算转换为mmHg int值时,在*0.75过程中丢失了波形细节,所以我们在这个失真的波形上意外的读出了(87/45)的奇怪NIBP值。
这里可以找到四个心搏点,但是黄色标记的心搏太浅,单片机可能无法正常识别到,所以,可以认为仅存在三个有效点
直接让单片机处理是不可能的,因为前后都有平直线段,而且我们也不能标定阈值,由于数据读取的特殊性,只要读错一个,所得数据会造成极大误差。
根据唐老师将电赛-电子血压计电路指导,我使用一个0.3~3.5带通滤波器协助调整。但在实际操作中,发现需要使用一个频率为3Hz的低通滤波器,不断调整数值到最佳频率。
亿顿操作猛如虎,经过滤波,提取,再滤波之后得到这样的数据,可以轻松找到五个搏动点,但是仍然存在许多噪声,无法满足单片机的处理需要,单片机还是看不懂。
首先,通过间隔取中值滤波,将图形稍做优化,看起来不那么杂乱无章了,就不为难单片机了。
如图,这是提取出来的脉搏点(未经过排除),能够正常的看到,重博波与过远的无效波。
然后,再经过隔值法与直接法处理并比较有效点个数,多者胜出,运用其方案计算
排除干扰所得数据如图,可以看到“原理数据”的值和两个有效数据之间的“干扰值”被滤去:
我们使用了0.1 - 4 Hz低通滤波器,以及一个中值滤波进行处理,得到初步波形,将其存入数组。
这是读取出来的原始呼吸波性,被载入到缓存数组中,但是仍然有很多毛刺,虽然在显示时无影响,但是对于数据处理是致命的
于是我们对其进行了一次带通滤波(0.2 ~ 4 Hz)和宽窗中值滤波,让波形变平滑,最后进行下降沿检测即可。
因为采样率是10ms一次,传入数组体量为2000,含20s数据,乘以三即可获得60s数据。
处理第一步,通过Pan-Tompkins算法滤波+平方运算削弱p、T等小波,提高R波斜率。
但是如结果1所示,II导联处理的数据中间存在若干干扰,还需要引入III导联进行双重校验,得出纯净的数据。然后再将索引根据采样率计算出RR间期以及心率。
我们通过以上算法寻找的R波可能超过R波,也可能在Q与R之间,我们应该进一步向左寻找QRS波起点。
这些是可能的情况,部分情况可以合并(正向波和负向波的同类型情况可以合并,根据Q波的情况可以合并)
我们针对第一种情况设置低于4单位即为平直(别看很多,其实整个图拉的很大),遇到平直数值停止查找,定义其对应索引值为起点。
斜率符号改变视为掉头,针对第二种掉头情况。我们设置掉头次数不能超过三次(抵消干扰),并且遇到操作索引的前一个和后一个的差值不能小于3,否则立即停止查找,定义其对应索引值为起点。
在寻找起点的同时,定义起点索引前 2单位的数值为零电位(要取平均值的)。接着进入下一步,心电轴计算。
电轴也称平均电轴,是心脏电活动的平均方向(向量),是心电图检测指标之一,指心脏除极和复极时额面最大综合向量与水平轴形成的角度。
想必学过心电图的医学生们一定对这张图非常熟悉,这张是使用I,III导联代数和进行计算的,但是,这种方法对于机器来说比较复杂,我们采取另一种方式,面积积分法。
这个方法因为人工计算麻烦而被抛弃,但是面积积分法是测量心电轴最标准的方法,也是机器计算最简单的方法。
面积积分法是把I,III导联相对于等电位线正向和负向面积代数和做图在一个特殊坐标系上,其中-III与+I的夹角度数为60deg。
对于另外两种可情况,可以将两个面积和取相反数,根据对顶角相等的数学思维即可转化为以上两种情况,是不是很有趣呢。
T波属于小波成分,斜率较小,个人会使用新的带通滤波器(8-22.5Hz)提取出T波。
然后计算出最大的QT间期(QTc按550ms记,再高就不可能了,就会有尖端扭转室速)
然后跳过QRS波,并向后30s到最长QT间期寻找最大最小值,最大最小值对应T波终点(对于这个滤波器处理后的数据)
胸导联R/S波电压RV5+SV1和RV1+SV5是心电图分析时重要的工具。可以分析左室和右室电压的大小,对心肌梗死,高血压心脏病,心室扩张,心室肥大,肺动脉高压的诊断有指导意义。
最后求电压值的平均值,然后取绝对值,将记录的值(单位)转化为电压值(mV):
由于单片机片上资源极度有限,我们放弃了占用资源多的FreeRTOS与LVGL,使用裸机+LCD绘图库完成设计
这样,只需要在App函数返回一串特征代码,管理器即可切换到指定App或界面。
个人会使用一个旋转开关来作为App切换,我们通过读取开关,累计标识的方式销毁当前App切换。
在读取到App不一致时开启累计标识,达到一定数值后销毁并切换,标识归零。若档位开关回到当前App,标识归零。
复杂的系统,机械按键是不允许出半点差错的,我们对于机械按键处理,使用中断调用管理器中的按键功能决策函数,根据App和页面标识决策功能。
这样,整个调度系统才能有条不紊的运作下去,长期保持稳定。而且,裸机相比于RTOS大幅度的提高了系统稳定性,保留更多资源。