心率血氧传感器 - 从零开始认识各种传感器【第十三期】

news2024/11/13 12:47:03

1、什么是心率血氧传感器

心率传感器是一种用于测量人体心跳频率的设备或传感器。由于脉搏或者心率是生命体征的重要参数之一,所以心率测量是目前可穿戴产品必备的一个测量和健康监控功能。
而血氧传感器是一种用于测量人体血液中氧气饱和度的设备或传感器。血氧饱和度具体是指血液中与氧气结合的血红蛋白含量占比,即血液中血氧的浓度。一般而言,若血氧饱和度在94%以下,就会被视为供氧不足,因此血氧检测对于临床医学而言十分重要。

图1 血氧检测数值的参考性

在当前智能穿戴产品中,心率和血氧的检测几乎已经成了标配功能,通常由一颗集成了多种传感器和处理功能的芯片完成。

图2 智能穿戴设备配备心率血氧检测功能

2、心率血氧传感器是如何工作的

心率测量在医疗领域通常式使用心电图ECG来测量生理电信号来实现心率和心脏活动的检测。但是测量ECG信号,要在身体多个部位连接传感器电极,很不方便,目前普遍应用在智能设备上的测试方法是光电容积脉搏波描记法PPG,简单说就是利用光测量脉搏的一种技术,通过发射一定波长的光波射向皮肤,比如绿光,由于血管组织在脉搏跳动过程中对于光线的吸收率不同,那么透过皮肤组织反射回的光被光敏传感器接受并转换成电信号并数字化后,根据血液的吸光率即可算出心率。

图3 光电容积脉搏波描记法PPG原理

而随着临床医学的发展,在血氧测量方面也普遍采用无创式血氧测量,只要为患者佩戴一个指压式光电传感器,就能实现连续性的血氧检测。

图4 指压式光电传感器测量血氧

其工作原理是利用人体中含氧血红蛋白HBO2以及血红蛋白HB对红光和红外光的吸收率不同的特点,使用波长660nm的红光和940nm的近红外光作为光源,测定通过测定人体组织的光传导强度,来计算血氧浓度及血氧饱和度。

图5 HBO2及HB对红光和红外光的吸收率

用智能手表及其他智能设备测血氧的原理类似于指压式测量,但不同的是,手表发射光源所照射的部分是手腕,并不像手指那样“透明”,可见光与红外光无法穿透,并且设备佩戴在手腕的位置也常常不固定,有时会受到外来光源以及汗水等因素的干扰,所以目前的智能穿戴的心率和血氧检测常常设计一个发射极,多个接收级的方式来增加接收数据的稳定性和可靠性。

图6 发射极(紫色)和接收级(绿色)数量对比

3、常见的心率血氧传感器的种类

由于心率和血氧在测量方式上的相似性以及两个参数的紧密相关,目前大多数的解决方案都是将血氧和心率功能测量集成在一块集成电路中提供出来。

图7 MAX86140 心率和血氧传感器芯片

这是一款由 ADI 提供的 MAX86140,专门为穿戴设备设计的心率和血氧传感器芯片。它的外形非常小巧,采用了紧凑的WLP封装,尺寸只有2乘1.8毫米。我们来看下它的原理框图。

图8 MAX86140 原理框图

在框图左侧是光学输出输入部分,它具备了三个独立的 8bit DAC 以及LED驱动模块,通过复用,可以驱动高达12个LED光源。其接收端采用了高分辨率的 19bit ADC 模块,在执行每秒25个采样的情况下,典型功耗只有不到10微安。

4、心率血氧传感器实验演示 

我们来演示使用 MCU 读取显示心率血氧传感器的数据。实验使用测试模块中采用的是 ADI 的 MAX30102 心率血氧集成模块。
将手指贴在传感器上,经过一段时间,可以看到屏幕上的心率和血氧数据开始更新为当前测试数值。
这里需要注意手指要和测试点紧密贴合,如果手指和模块贴合不到位,会出现血氧测试数据偏低的可能,当前血氧SpO2的数值掉到了46%。
将手指紧贴模块一段时间,可以帮助传感器更准确的测量血氧,可以看到血氧测试数据开始升高,最终达到了稳定的96%左右,也就是身体正常血氧饱和度数值。

图9 树莓派读取心率血氧传感器展示

main.py:

import uos
import st7789_c as st7789
from fonts import vga2_8x8 as font1
from fonts import vga1_16x32 as font2
import random
import framebuf
from machine import Pin, SPI, ADC,PWM,I2C,SoftI2C,Timer
import time, math,array
from utime import sleep_ms,ticks_diff, ticks_us
import struct
###############################################
from MAX30102 import MAX30102, MAX30105_PULSE_AMP_MEDIUM
from spo2cal import calc_hr_and_spo2
###############################################
st7789_res = 0
st7789_dc  = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
spi_sck=Pin(2)
spi_tx=Pin(3)
spi0=SPI(0,baudrate=40000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
display = st7789.ST7789(spi0, disp_width, disp_width,
                          reset=Pin(st7789_res, Pin.OUT),
                          dc=Pin(st7789_dc, Pin.OUT),
                          xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
display.text(font2, "EETREE", 10, 10)
display.text(font2, "www.eetree.cn", 10, 40)

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

SPO2 = 0  # 存储血氧
TEMPERATURE = 0  # 存储温度

def display_info(t):
    # 如果没有检测到手指,那么就不显示
    if FINGER_FLAG is False:
        return
    display.text(font1, "Heart Rate=", 10, 100)
    display.text(font2, str(BEATS), 100, 90)
    display.text(font1, "SpO2=", 10, 140)
    display.text(font2, str(SPO2), 50, 130)
def main():
    global BEATS, FINGER_FLAG, SPO2, TEMPERATURE  # 如果需要对全局变量修改,则需要global声明

    # 创建I2C对象(检测MAX30102)
    i2c = SoftI2C(sda=Pin(20), scl=Pin(21), 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("传感器已识别到")

    # 配置
    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
    
    beats_history = []
    beat = False

    red_list = []
    ir_list = []
    history = []
    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

            # 计算血氧
            red_list.append(red_reading)
            ir_list.append(ir_reading)
            # 最多 只保留最新的100个
            red_list = red_list[-100:]
            ir_list = ir_list[-100:]
            # 计算血氧值
            if len(red_list) == 100 and len(ir_list) == 100:
                hr, hrb, sp, spb = calc_hr_and_spo2(red_list, ir_list)
                if hrb is True and spb is True:
                    if sp != -999:
                        SPO2 = int(sp)

            # 计算温度
            TEMPERATURE = sensor.read_temperature()

if __name__ == '__main__':

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

    main()

屏幕显示和MAX30102心率血氧传感器驱动可以点此查看。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1945414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

c# 端口监控 Helper 以及写一个端口监控工具

c# 端口监控 Helper 以及写一个端口监控工具 介绍核心代码&#xff1a;工具完整编码&#xff1a;1、编写界面2、打开定时控件的属性设置。3、编写定时控件的 Tick 事件结果&#xff08;运行效果&#xff09; 介绍 由于最近做上架比较多&#xff0c;会经常来确保服务器的服务&a…

分享从零开始学习网络设备配置--任务6.1 实现计算机的安全接入

项目描述 随着网络技术的发展和应用范围的不断扩大&#xff0c;网络已经成为人们日常生活中必不可少的一部分。园区网作为给终端用户提供网络接入和基础服务的应用环境&#xff0c;其存在的网络安全隐患不断显现出来&#xff0c;如非人为的或自然力造成的故障、事故&#xff1b…

第八讲:Sysmac Studio控制器设置

控制器设置 一、控制器设定-操作设置 1、启动模式(运行模式/编程模式) 控制器上电后,希望程序运行还是不运行。如果说希望程序运行,那么就选择运行模式。如果说希望上电后程序不运行就选择编程模式。 通常情况下选运行模式可能会比较多一些。 2、SD内存卡设置 当控制…

科研绘图系列:R语言和弦图 (Chord diagram)

介绍 和弦图(Chord Diagram)是一种用于展示多个实体之间相互关系的数据可视化方法。它通常用于表示网络或系统中不同节点(实体)之间的连接强度或流量。和弦图由一个圆形布局组成,每个节点在圆周上占据一个扇形区域,节点之间的连接通过圆内的线条(和弦)来表示。 特点:…

获取本地时间(Linux下,C语言)

一、函数 #include <time.h> time_t time(time_t *tloc);函数功能&#xff1a;获取本机时间&#xff08;以秒数存储&#xff0c;从1970年1月1日0:0:0开始到现在&#xff09;。返回值&#xff1a;获得的秒数&#xff0c;如果形参非空&#xff0c;返回值也可以通过传址调用…

判断字符串,数组方法

判断字符串方法 在JavaScript中&#xff0c;可以使用typeof操作符来判断一个变量是否为字符串。 function isString(value) {return typeof value string; } 判断数组 在JavaScript中&#xff0c;typeof操作符并不足以准确判断一个变量是否为数组&#xff0c;因为typeof会…

Soul App创始人张璐团队参与公益活动,帮助年轻人正视并管理情绪需求

最近,“脆皮年轻人”在社交平台上持续走红。该词指年轻人常因别人一些无意的动作而导致身体或心理创伤,反映出“Z世代”年轻人面临着心理健康挑战。在此背景下,Soul APP创始人张璐团队携手上海市精神卫生中心(宛平南路600号),共同发起了一场别开生面的青年心理健康公益活动,旨在…

JDBC操作MySQL数据

一准备、 1、首先在IDEA中导入导入包&#xff1a;mysql-connector-java-8.0.23 2、写初始化语句 &#xff08;1&#xff09;在目录下找到driver类 &#xff08;2&#xff09;在JDBCUtil函数中把驱动器的类路径改掉 ①打开driver类 ②按住类名 Driver用快捷键 CtrlAltshiftC …

学懂C语言(十八):C语言中数组及其应用

目录 一、数组的概念 二、数组的声明、初始化及访问 1、声明 2、初始化 3、访问数组元素 三、数组的应用 1. 存储和处理数据 2. 字符串处理 3. 多维数组 4. 函数参数 5、注意事项 一、数组的概念 C语言中的数组是一种数据结构&#xff0c;用于存储一…

开源邮箱套件介绍系列1:SOGo

项目网站&#xff1a;SOGo | Free Open Source Webmail 提示&#xff1a;如下内容大部分来自官方网站&#xff0c;通过AI智能翻译而来。 1. SOGo功能概述 SOGo提供了多种访问日历和消息数据的方式。您的用户可以使用网页浏览器、Microsoft Outlook、Mozilla Thunderbird、Ap…

连接hive库增加相关包

连接hive库增加相关包 例如&#xff1a;java.lang.NoClassDefFoundError: com/ctc/wstx/io/InputBootstrapper org.apache.hadoop.hive.common.auth.HiveAuthUtils java.lang.NoClassDefFoundError: org/codehaus/stax2/XMLInputFactory2

Windows系统上Git详细图文安装及使用教程

Git 是一种高效、分布式的版本控制系统&#xff0c;用于代码的跟踪、分支管理和协同工作&#xff0c;支持快速提交、合并和回滚操作。它是开发者工具箱中必不可少的工具之一&#xff0c;广泛应用于软件开发和其他需要版本控制的领域。 1. Git的安装 1.1 Git下载 可以通过以下…

ESXi 虚拟机迁移,版本不兼容问题处理

背景描述 已知要被迁移的虚拟机的兼容性版本较高&#xff0c;如下图所示&#xff1a; 这个兼容性版本&#xff0c;是在创建虚拟机的时候&#xff0c;我们手工选择的&#xff0c;如下图所示&#xff1a; 当我们需要将一个虚拟机迁移到另外一个 ESXi 主机时&#xff0c;能否正常…

【计算机网络】三次握手、四次挥手

问&#xff1a;三次握手 四次挥手 TCP 连接过程是 3 次握手&#xff0c;终止过程是 4 次挥手 3次握手 第一步&#xff1a;客户端向服务器发送一个带有 SYN&#xff08;同步&#xff09;标志的包&#xff0c;指示客户端要建立连接。 第二步&#xff1a;服务器收到客户端的请求…

Shiro安全框架(上)

目录 第一章 权限概述 1、什么是权限 2、身份认证概念-Authentication 【1】什么是认证 【2】对象 2、用户授权概念-Authorization 【1】什么是授权 【2】授权流程 第二章 Shiro概述 1、Shiro简介 【1】什么是Shiro? 【2】Shiro 的特点 2、核心组件 第三章 Shiro…

【CSharp】VisualStudio2019进行Windows窗体编程时关于AnyCPU的说明

【CSharp】VisualStudio2019进行Windows窗体编程时关于AnyCPU的说明 1.背景2.说明3.修改1.背景 IDE:Visual Studio 2019 通过VS2019编写windows窗体应用程序时,在VS2019界面可以看到Any CPU,如下: 2.说明 在Visual Studio 2019中进行Windows窗体编程时, AnyCPU是一个平…

wefwefwe

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

微前端--qiankun

qiankun qiankun分为accpication和parcel模式。 aplication模式基于路由工作&#xff0c;将应用分为两类&#xff0c;基座应用和子应用&#xff0c;基座应用维护路由注册表&#xff0c;根据路由的变化来切换子应用。子应用是一个独立的应用&#xff0c;需要提供生命周期方法供…

AI智能名片小程序在内容营销中的创新应用:以“48小时够你玩”系列为例

摘要&#xff1a;在数字化时代&#xff0c;内容营销已成为企业连接消费者、塑造品牌形象、推动销售增长的关键策略。AI智能名片小程序&#xff0c;作为新兴技术的集大成者&#xff0c;以其智能化、个性化、便捷化的特点&#xff0c;为内容营销注入了新的活力。本文深入探讨了AI…

[C++][STL源码剖析] 详解AVL树的实现

1.概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。 因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年 发明了一种解决上…