心率传感器是一种用于测量人体心跳率的传感器。它可以通过监测心脏的电活动或血流来提供实时的心率数据,并将心率数据转换为电信号或数字信号。心率是指心脏每分钟跳动的次数,通常以“bpm”(每分钟跳动次数)为单位。

图1:max30102光电式心率血氧传感器、XD-58C Pulse Sensor脉冲传感器

心率传感器的工作原理可以分为两种常见的方法:光电传感和电生理传感。

光学心率传感器

光电传感:这是最常见的心率传感器工作原理。它使用了光敏元件(例如光电二极管或光敏电阻)来测量皮肤上的血流变化,从而推导出心率数据。有些设备也可以估计血液中的氧气水平。

光学心率传感器是是智能穿戴设备中最为普及的用于心率检测的传感器之一。它采用电光溶剂脉搏波描记法(PPG)来测量心率及其他生物计量指标。

PPG测量原理:通过电容灯光射向皮肤,透过皮肤组织反射回的光被光敏传感器接受并转换成电信号,再经过电信号转换成数字信号,再根据血液的吸光率算出心率。简化测量过程就是:发射光——转换成电信号——转换成数字信号。

图2:光学心率传感器的基本结构与运行

光学心率传感器使用四个主要技术元件来测量心率:

  • 光发射器 - 通常至少由两个光发射二极管(LED)构成,它们会将光波照进皮肤内部。
  • 光电二极管和模拟前端(AFE) - 这些元件捕获穿戴者折射的光,并将这些模拟信号转换成数字信号用于计算可实际应用的心率数据。
  • 加速计 - 加速计可测量运动,与光信号结合运用,作为PPG算法的输入。
  • 算法 - 算法能够处理来自AFE和加速计的信号,然后将处理后的信号叠加到PPG波形上,由此可生成持续的、运动容错心率数据和其他生物计量数据。

光学心率传感器可生成测量心率的PPG波形并将该心率数据作为基础生物计量值,但是利用PPG波形可以测量的对象远不止于此。图3是经过简化的PPG信号,该信号代表了多个生物计量的测量结果。

图 3:典型的PPG波形

下面我们进一步详细解读某些光学心率传感器可以测得的结果:

  • 呼吸率 - 休息时的呼吸率越低,通常这表明身体状况越好。
  • 最大摄氧量(VO2max)– VO2测量人体可以摄入的最大氧气量,是人们广泛使用的有氧耐力指标。
  • 血氧水平(SpO2) - 是指血液中的氧气浓度。
  • R-R间期(心率变异率)- R-R间期是血脉冲的间隔时间;一般而言,心跳间隔时间越长越好。R-R间期分析,可用作压力水平和不同心脏问题的指标。
  • 血压 - 通过PPG传感器信号,无需使用血压计即可测量血压。
  • 血液灌注 - 灌注是指人体推动血液流经循环系统的能力,特别是在濒于死亡时流经全身毛细血管床的能力。因为PPG传感器可跟踪血液流动,所以可以测量血流相对灌注率及血液灌注水平的变化。
  • 心效率 - 这是心脑血管健康和身体状况的另一个指标,一般来说,它测量的是心脏每搏的做功效率。
光学心率传感器选择绿光作为光源的原因

图 4:光谱

选择绿光作为测量光源是考虑到以下几个特点:

  1. 皮肤的黑色素会吸收大量波长较短的波
  2. 皮肤上的水份也会吸收大量的UV(紫外)和IR(红外)部分的光
  3. 进入皮肤组织的绿光(500nm)– 黄光(600nm)大部分会被红细胞吸收
  4. 红光和接近IR的光相比其他波长的光更容易穿过皮肤组织
  5. 血液要比其他组织吸收更多的光
  6. 相比红光,绿(绿-黄)光能被氧合血红蛋白和脱氧血红蛋白吸收
  7. 虽然现在大部分智能穿戴设备采用绿光作为光源,但是字考虑到皮肤情况的不同(肤色、汗水),高端产品会根据情况自动使用绿光、红光和红外光等多种光源进行心率测量。

图 5: 光电式心率传感电路

电极式心率传感器

电生理传感:这种传感器利用人体的生物电活动来测量心率。即心脏在每次心跳时都会产生一个小电流,具有电检测功能的心率监测器通过检测和跟踪该电流,实现心率的测量。 常用的电生理传感器是心电图(ECG)传感器,通过测量心脏产生的电信号来确定心率。

工作过程如下:

  1. 心电图(ECG)测量:电生理心率传感器通过皮肤表面的电极与人体接触,检测和记录心脏的电信号。这些电信号反映了心脏在每个心搏周期中的电活动,可以用于分析心脏的功能状态和心率。
  2. 电极配置:电生理心率传感器通常采用多个电极,例如,常见的配置是将一个电极放置在胸前、另一个电极放置在手腕或手指上。这样的配置可以捕捉到心脏电活动的变化并生成心电图。
  3. 感应电位差:当心脏肌肉收缩和放松时,产生的电势差会在身体表面生成微弱的电流。电生理心率传感器的电极通过接触皮肤,能够感知和测量这些微弱的电势差,形成心电图信号。
  4. 信号放大和处理:电生理心率传感器会将感测到的微弱电信号放大,以便进行准确的记录和测量。信号处理器会对心电图信号进行滤波、放大和去除干扰等操作,以获取清晰的心电图波形数据。
  5. 心率计算:通过分析心电图信号中的R波,电生理心率传感器能够确定心脏每分钟跳动的次数,从而计算出心率值。
电极式心率传感器与传统医院获取心电图仪器的区别
  • 测量原理:电极式心率传感器使用表面电极与皮肤接触,通过检测心脏电活动来获取心率信息。它主要测量心电图中的R波峰值,并根据R-R间期计算心率。而传统医院使用的心电图仪器则是通过多个电极贴附在身体不同的位置,记录心脏电信号在不同导联下的变化,以获取更为详细和全面的心电图。
  • 使用场景:电极式心率传感器通常用于便携式设备和可穿戴设备中,如智能手环、智能手表等。它主要用于日常健康监测和运动追踪,提供用户的即时心率信息。传统医院使用的心电图仪器通常用于医疗机构,由专业医务人员操作,用于临床诊断和监测心脏疾病,可以提供更全面的心电图分析。
  • 数据输出:电极式心率传感器通常以数字形式输出心率数据,可以通过无线连接或数据线与手机、电脑等设备进行数据传输和分析。传统医院使用的心电图仪器可以输出心电图波形,通常以打印纸或数字文件的形式提供。
  • 精确度和准确性:传统医院使用的心电图仪器通常具有更高的精确度和准确性,能够提供更细致的心脏电信号分析。而电极式心率传感器由于采用简化的测量原理和设计,相对较低的成本和尺寸限制,可能在某些情况下存在一定的误差。

无论是光电传感还是电生理传感,心率传感器通常会将采集到的数据发送给处理器或设备进行分析和显示。这样,用户就可以实时了解自己的心率情况。

需要注意的是,不同型号的心率传感器可能采用不同的工作原理和技术细节,但基本原理是类似的:通过测量血流变化或心脏电信号来推导心率数据。

  • 胸带装置。这些设备使用电检测来跟踪您的心率。它们通过缠绕在胸部的带子检测电活动。为了使大多数这些设备按设计工作,表带必须是湿的,或者您需要在传感器接触皮肤的地方使用导电凝胶。水或导电凝胶可改善导电,因此设备更容易检测心脏的电流。
  • 腕部或前臂佩戴的可穿戴设备:前臂和手腕有两条主要动脉。桡动脉向拇指延伸,尺动脉向小指和无名指延伸。这两条动脉为手腕和前臂表面的皮肤提供充足的血液流动。这些可穿戴设备具有发光二极管(LED)和传感器,它们靠在该区域的皮肤上。该传感器使用LED光来检测皮肤表面下血管的微小扩张。
  • 智能戒指:这些是您像珠宝一样戴在一根手指上的设备。他们还使用光学检测来跟踪您的心率和其他生命体征。这些设备仍然非常新,关于其准确性的数据有限。
  • 脉搏血氧仪。这些设备,其中许多夹在手指上,也使用光学检测方法。这些跟踪脉搏率和血氧水平。它们在医院环境中很常见,但您也可以获得这些设备的便携式电池供电版本供个人使用。
  • 智能手机:跨不同平台的各种智能手机应用程序提供了测量脉搏率的能力。其中一些使用光学检测,通过将手指放在相机镜头上来找到您的脉搏率,相机的闪光灯用于照亮皮肤下的血管。其他人使用相机本身,对准你的脸,根据你皮肤的可见变化来检测你的脉搏率,但你的眼睛无法检测到。
  • Maxim Integrated:Maxim Integrated是一家知名的集成电路设计和生产公司,提供多种心率传感器芯片和模块。其中,MAX30102是一款常见的心率传感器模块,集成了红外LED、红光LED和光电传感器,适用于便携设备和健康监测设备等应用。
  • Texas Instruments(TI):TI是一家全球领先的半导体公司,提供多款生物传感器芯片和模块。AFE4404是TI的一款心率监测芯片,集成了红外LED、绿光LED、光电传感器和ADC等功能,可实现高精度的心率和血氧浓度测量。
  • ROHM Semiconductor:ROHM Semiconductor是一家领先的半导体制造商,其心率传感器芯片和模块在市场上得到广泛应用。BH1790GLC是ROHM的一款红外心率传感器芯片,具备运动伪影抑制和高精度测量特性。
  • Analog Devices(ADI):Analog Devices(ADI)是一家知名的模拟与数字混合信号处理技术供应商,提供多种生物传感器芯片和模块。AD8232是ADI的一款心率传感器芯片,专为心电图(ECG)采集设计,具备高性能和低功耗特点。
  • PixArt Imaging:PixArt Imaging是一家专注于光学传感器和图像处理技术的公司,其产品被广泛应用于健康监测和运动追踪等领域。PAH8011是PixArt的一款生物传感器模块,集成了红外和绿光LED、光电传感器以及信号处理电路,适用于心率和血氧浓度等生物参数测量。

电路连接

程序代码

驱动文件包含三个.py文件。

  • init.py
  • circular_buffer.py
  • 检测心率.py

前面两个文件可在后面链接中下载:https://github.com/n-elia/MAX30102-MicroPython-driver/tree/main/max30102

检测心率.py程序如下

from machine import SoftI2C, Pin, Timer
from utime import ticks_diff, ticks_us
from max30102 import MAX30102, MAX30105_PULSE_AMP_MEDIUM

BEATS = 0  # 存储心率
FINGER_FLAG = False  # 默认表示未检测到手指


def display_info(t):
    # 如果没有检测到手指,那么就不显示
    if FINGER_FLAG is False:
        return

    print('心率: ', BEATS)


def main():
    global BEATS, FINGER_FLAG  # 如果需要对全局变量修改,则需要global声明
    
    # 创建I2C对象(检测MAX30102)
    i2c = SoftI2C(sda=Pin(16), scl=Pin(17), freq=400000)  # Fast: 400kHz, slow: 100kHz

    # 创建传感器对象
    sensor = MAX30102(i2c=i2c)

    # 检测是否有传感器
    if sensor.i2c_address not in i2c.scan():
        print("没有找到传感器")
        return
    elif not (sensor.check_part_id()):
        # 检查传感器是否兼容
        print("检测到的I2C设备不是MAX30102或者MAX30105")
        return
    else:
        print("传感器已识别到")

    print("使用默认配置设置传感器")
    sensor.setup_sensor()

    # 对传感器进行设定
    sensor.set_sample_rate(400)
    sensor.set_fifo_average(8)
    sensor.set_active_leds_amplitude(MAX30105_PULSE_AMP_MEDIUM)

    t_start = ticks_us()  # Starting time of the acquisition

    MAX_HISTORY = 32
    history = []
    beats_history = []
    beat = False

    while True:
        sensor.check()
        if sensor.available():
            # FIFO 先进先出,从队列中取数据。都是整形int
            red_reading = sensor.pop_red_from_storage()
            ir_reading = sensor.pop_ir_from_storage()
            
            if red_reading < 1000:
                print('No finger')
                FINGER_FLAG = False  # 表示没有放手指
                continue
            else:
                FINGER_FLAG = True  # 表示手指已放

            # 计算心率
            history.append(red_reading)
            
            # 为了防止列表过大,这里取列表的后32个元素
            history = history[-MAX_HISTORY:]
            
            # 提取必要数据
            minima, maxima = min(history), max(history)
            threshold_on = (minima + maxima * 3) // 4   # 3/4
            threshold_off = (minima + maxima) // 2      # 1/2
            
            if not beat and red_reading > threshold_on:
                beat = True                    
                t_us = ticks_diff(ticks_us(), t_start)
                t_s = t_us/1000000
                f = 1/t_s
                bpm = f * 60
                if bpm < 500:
                    t_start = ticks_us()
                    beats_history.append(bpm)                    
                    beats_history = beats_history[-MAX_HISTORY:]   # 只保留最大30个元素数据
                    BEATS = round(sum(beats_history)/len(beats_history), 2)  # 四舍五入
            if beat and red_reading < threshold_off:
                beat = False


if __name__ == '__main__':

    tim = Timer(period=1000, mode=Timer.PERIODIC, callback=display_info)
    
    main()

运行效果