2. 医疗设备数据采集接口与协议

医疗设备数据采集的第一道工程问题不是“怎么解析数据”,而是“数据从哪条物理链路进来、以什么协议封装、由谁负责拆包”。同一台监护仪可能同时提供 RS232 串口、USB 转串口、以太网和蓝牙四种出口,而它们承载的上层协议又可能是 HL7、DICOM 或 IEEE 11073。理解接口与协议的对应关系,是后续实时处理管线设计的前提。

一、四类物理接口的工程特征

RS232 是最传统的医疗设备接口,常见于监护仪、输液泵、血气分析仪。它采用点对点异步串行通信,工程上必须显式约定波特率、数据位、停止位、校验位和流控。例如某型号监护仪输出参数为 9600 bps、8 数据位、1 停止位、无校验、无流控,数据以 ASCII 文本行发送,每行以 \r\n 结束。RS232 的电气特性决定了传输距离通常不超过 15 米,且需要电平转换芯片(如 MAX232)才能与 MCU 的 TTL 电平对接。

USB 在医疗设备中多以两种形态出现:一是 USB CDC(通信设备类),设备枚举为虚拟串口,操作系统分配 COM 口,应用层仍按串口读写;二是 USB HID 或厂商自定义批量端点,需要 libusb 或厂商 SDK 直接操作端点。USB 的优势是即插即用和供电一体,但热插拔时的设备重枚举会导致句柄失效,采集程序必须监听设备到达/移除事件并重新打开。

以太网 是当前高端监护、影像和检验设备的主流接口。它提供高带宽和网络寻址能力,上层可承载 HL7 over MLLP、DICOM、IEEE 11073-20701 等。工程上需要关注 IP 分配方式(静态或 DHCP)、端口号、TCP 还是 UDP。例如 DICOM 存储服务通常监听 104 或 11112 端口,HL7 MLLP 常用 2575 端口。

蓝牙 在便携式血氧仪、血糖仪、动态心电贴中广泛使用。医疗场景多采用 BLE(低功耗蓝牙),通过 GATT 服务与特征值传输数据。IEEE 11073-20601 定义了 BLE 上的个人健康设备通信模型,设备以标准服务暴露测量值。蓝牙采集的难点在于配对、连接参数协商和断线重连,且不同厂商的 GATT 特征 UUID 可能不同,需要按设备型号维护映射表。

医疗设备接口 → 协议 → 采集通道映射 医疗设备 监护仪 多参数 / 波形 输液泵 速率 / 报警 血氧仪 SpO₂ / 脉率 CT / MR 影像 / 元数据 动态心电贴 ECG 片段 物理接口 RS232 9600-8-N-1 USB CDC / HID 虚拟串口 / 端点 以太网 TCP / UDP 蓝牙 BLE GATT 服务 上层协议 HL7 v2.x MLLP 封装 DICOM C-STORE / C-FIND IEEE 11073 PHD / MIB 对象 厂商私有 ASCII / 二进制 采集通道 串口读取线程 行缓冲 / 超时 USB 事件监听 重枚举恢复 TCP 服务端 MLLP 拆帧 BLE 订阅 Notify 回调 同一设备可同时提供多种接口;协议与接口并非一一对应,需按设备型号确认实际组合

二、三大协议的核心差异

HL7 v2.x 是临床信息系统之间交换患者、医嘱、检验结果的主流标准。它采用竖线分隔的段结构,例如 MSH|^~\&|MONITOR|ICU|HIS|HOSP|202405121030||ORU^R01|MSG001|P|2.4,其中 MSH 段定义消息头,OBX 段承载观察结果。HL7 本身不规定传输层,医疗设备常通过 MLLP(最小下层协议)封装:以 0x0B 起始、0x1C 0x0D 结束,在 TCP 上传输。采集程序必须按这两个边界符拆帧,不能假设一次 recv 就是一条完整消息。

DICOM 面向医学影像,定义了影像对象、服务类和数据编码。设备通过 DIMSE 服务(如 C-STORE 发送影像、C-FIND 查询)交互。DICOM 文件由文件头和数据集组成,数据集使用显式 VR 小端或隐式 VR 小端编码。采集影像时,通常由设备主动向 PACS 或采集网关发起 C-STORE,网关作为 SCP 接收并落盘。DICOM 的标签(Tag)以组号和元素号表示,如 (0010,0010) 为患者姓名,(0008,0060) 为模态。

IEEE 11073 是个人健康设备通信标准族。11073-20601 定义抽象通信模型,11073-104xx 定义具体设备(如 10407 血压、10408 体温、10404 血氧)。设备以 MIB 对象形式暴露测量值,每个对象有属性(如 MDC_ATTR_NU_VAL_OBS 数值观察值)和单位代码。在 BLE 上,11073 通过 GATT 特征值传输,采集端需先发现服务、订阅 Notify,再按 ASN.1 或厂商编码解析字节流。

三、采集实战:从串口到结构化数据

以一台通过 RS232 输出 HL7 消息的监护仪为例,完整采集链路如下。物理层使用 USB 转 RS232 线缆,操作系统识别为 /dev/ttyUSB0(Linux)或 COM3(Windows)。串口参数设为 9600-8-N-1,无流控。应用层读取时不能按固定长度读,而应按行或按 MLLP 边界读取。

import serial

ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1.0)
buffer = b''

while True:
    chunk = ser.read(256)
    if not chunk:
        continue
    buffer += chunk
    # MLLP 拆帧:0x0B ... 0x1C 0x0D
    while b'\x0b' in buffer and b'\x1c\x0d' in buffer:
        start = buffer.index(b'\x0b')
        end = buffer.index(b'\x1c\x0d', start)
        frame = buffer[start+1:end]
        buffer = buffer[end+2:]
        text = frame.decode('ascii', errors='replace')
        # 按段解析
        for seg in text.split('\r'):
            fields = seg.split('|')
            if fields[0] == 'OBX':
                print('观察值:', fields[5], fields[6])

上述代码的关键点有三:一是 timeout=1.0 避免阻塞导致无法退出;二是缓冲区累积,因为一次 read 可能只收到半条消息;三是按 0x0B 和 0x1C 0x0D 定位帧边界,而不是按行分割,因为 HL7 段内可能包含 \r。解析出的 OBX 段中,fields[5] 是观察标识,fields[6] 是测量值,实际工程中还需结合 fields[2] 的值类型和 fields[3] 的标识符做映射。

串口采集常见故障:收到乱码通常是波特率或数据位不匹配;收到半条消息后卡住,往往是流控设置错误或对端未发送结束符;设备重启后端口号变化,需在程序中按 USB 序列号而非 COM 口号绑定。

四、以太网与蓝牙采集的差异处理

以太网采集 HL7 时,采集端通常作为 TCP 服务端监听 2575 端口,设备作为客户端连接。每个连接对应一台设备,需维护连接表。MLLP 拆帧逻辑与串口一致,但 TCP 是流式协议,必须处理粘包和半包。DICOM 采集则需引入 DCMTK 或 pydicom 等库,实现 C-STORE SCP,接收后按 SOP Instance UID 命名文件并写入数据库索引。

蓝牙 BLE 采集的流程不同:先扫描广播,按设备名称或服务 UUID 过滤;连接后调用 discoverServices,找到 11073 标准服务;对测量特征值使能 Notify,注册回调;在回调中按 11073 编码解析字节。BLE 的 MTU 通常为 23 字节,长数据需分包重组。断线后需重新扫描连接,不能复用旧句柄。

五、接口与协议选型对照

接口典型协议传输方向采集端角色关键参数
RS232HL7 / 私有 ASCII设备 → 采集端客户端(读串口)9600-8-N-1
USB CDCHL7 / 私有设备 → 采集端虚拟串口客户端COM 口号 / 序列号
以太网HL7 MLLP双向TCP 服务端2575 端口
以太网DICOM设备 → 采集端C-STORE SCP104 / 11112 端口
蓝牙 BLEIEEE 11073设备 → 采集端GATT 客户端服务 UUID / Notify

实际项目中,一台设备可能同时开启多种接口。例如监护仪通过 RS232 输出实时波形,通过以太网向中央站发送 HL7 报警,通过 USB 导出历史趋势。采集系统应优先选择带宽足够、协议标准化程度高的通道,并为每条通道独立维护连接状态和重连策略。接口决定“怎么连”,协议决定“怎么解”,两者共同决定采集程序的线程模型、缓冲策略和异常恢复方式。