鸿蒙跨端心率异常预警系统开发指南 原创

进修的泡芙
发布于 2025-6-23 13:02
浏览
0收藏

鸿蒙跨端心率异常预警系统开发指南

一、项目概述

本文基于HarmonyOS的生物传感器能力和分布式技术,开发一套心率异常预警程序。该系统整合PPG传感器降噪技术、实时心率变异性(HRV)分析和低电量简化算法,并借鉴《鸿蒙跨端U同步》中的多设备同步技术,实现心率数据的精准采集、实时分析和多终端预警。

二、系统架构

±--------------------+ ±--------------------+ ±--------------------+
穿戴设备 <-----> 分布式数据总线 <-----> 监控终端
(智能手表/手环) (Distributed Bus) (手机/平板/医护端)
±---------±---------+ ±---------±---------+ ±---------±---------+

±---------v----------+ ±---------v----------+ ±---------v----------+
PPG信号处理模块 心率分析模块 预警同步模块
(降噪/特征提取) (HRV/异常检测) (多设备预警/通知)

±--------------------+ ±--------------------+ ±--------------------+

三、核心代码实现
心率监测服务实现

// src/main/ets/service/HeartRateService.ts
import { distributedData } from ‘@ohos.data.distributedData’;
import { BusinessError } from ‘@ohos.base’;
import { sensor } from ‘@ohos.sensor’;
import { power } from ‘@ohos.power’;
import { notification } from ‘@ohos.notification’;
import { taskpool } from ‘@ohos.taskpool’;
import { fileIo } from ‘@ohos.fileio’;
import { zlib } from ‘@ohos.zlib’;

interface HeartRateData {
timestamp: number;
heartRate: number; // 心率值 (bpm)
hrv: number; // 心率变异性 (ms)
confidence: number; // 数据置信度 0-1
deviceId: string;
isSynced: boolean;
interface HealthAlert {

timestamp: number;
type: ‘high_hr’ ‘low_hr’ ‘abnormal_hrv’
‘arrhythmia’;
heartRate?: number;
hrv?: number;
message: string;
isSynced: boolean;
interface DeviceStatus {

batteryLevel: number;
isLowPowerMode: boolean;
lastSyncTime: number;
syncInterval: number; // 同步间隔(秒)
export class HeartRateService {

private static instance: HeartRateService;
private kvStore: distributedData.KVStore | null = null;
private readonly STORE_ID = ‘heart_rate_store’;
private heartRateSensorId: number = -1;
private ppgSensorId: number = -1;
private hrData: HeartRateData[] = [];
private alerts: HealthAlert[] = [];
private deviceStatus: DeviceStatus = {
batteryLevel: 100,
isLowPowerMode: false,
lastSyncTime: 0,
syncInterval: 300 // 默认5分钟同步一次
};
private rawPPGData: number[] = [];
private readonly MAX_STORAGE_HOURS = 24; // 本地最多存储24小时数据

private constructor() {
this.initKVStore();
this.loadLocalData();
this.checkBatteryStatus();
public static getInstance(): HeartRateService {

if (!HeartRateService.instance) {
  HeartRateService.instance = new HeartRateService();

return HeartRateService.instance;

private async initKVStore(): Promise<void> {

try {
  const options: distributedData.KVManagerConfig = {
    bundleName: 'com.example.heartrate',
    userInfo: {
      userId: '0',
      userType: distributedData.UserType.SAME_USER_ID

};

  const kvManager = distributedData.createKVManager(options);
  this.kvStore = await kvManager.getKVStore({
    storeId: this.STORE_ID,
    options: {
      createIfMissing: true,
      encrypt: false,
      backup: false,
      autoSync: true,
      kvStoreType: distributedData.KVStoreType.SINGLE_VERSION

});

  this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (data) => {
    this.handleRemoteDataChange(data);
  });

catch (e) {

  console.error(Failed to initialize KVStore. Code: {e.code}, message: {e.message});

}

private async loadLocalData(): Promise<void> {
try {
// 加载心率数据
const hrFile = await fileIo.open(‘data/heart_rate_data.bin’, 0o666);
const hrData = await fileIo.read(hrFile.fd, new ArrayBuffer(0));
await fileIo.close(hrFile.fd);

  if (hrData) {
    const decompressed = await zlib.deflateSync(hrData);
    this.hrData = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(decompressed)));

// 加载报警记录

  const alertFile = await fileIo.open('data/health_alerts.bin', 0o666);
  const alertData = await fileIo.read(alertFile.fd, new ArrayBuffer(0));
  await fileIo.close(alertFile.fd);
  
  if (alertData) {
    const decompressed = await zlib.deflateSync(alertData);
    this.alerts = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(decompressed)));

// 加载设备状态

  const statusFile = await fileIo.open('data/device_status.bin', 0o666);
  const statusData = await fileIo.read(statusFile.fd, new ArrayBuffer(0));
  await fileIo.close(statusFile.fd);
  
  if (statusData) {
    const decompressed = await zlib.deflateSync(statusData);
    this.deviceStatus = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(decompressed)));

} catch (e) {

  console.log('No local data found or error reading file');

// 清理过期数据

this.cleanupOldData();

private cleanupOldData(): void {

const now = Date.now();
const cutoff = now - this.MAX_STORAGE_HOURS  60  60 * 1000;

this.hrData = this.hrData.filter(d => d.timestamp >= cutoff);
this.alerts = this.alerts.filter(a => a.timestamp >= cutoff);

private async saveLocalData(): Promise<void> {

try {
  // 确保目录存在
  await fileIo.mkdir('data');
  
  // 保存心率数据
  const hrStr = JSON.stringify(this.hrData);
  const hrCompressed = await zlib.inflateSync(new Uint8Array(hrStr.split('').map(c => c.charCodeAt(0))));
  
  const hrFile = await fileIo.open('data/heart_rate_data.bin', 0o666 | fileIo.OpenMode.CREATE);
  await fileIo.write(hrFile.fd, hrCompressed.buffer);
  await fileIo.close(hrFile.fd);
  
  // 保存报警记录
  const alertStr = JSON.stringify(this.alerts);
  const alertCompressed = await zlib.inflateSync(new Uint8Array(alertStr.split('').map(c => c.charCodeAt(0))));
  
  const alertFile = await fileIo.open('data/health_alerts.bin', 0o666 | fileIo.OpenMode.CREATE);
  await fileIo.write(alertFile.fd, alertCompressed.buffer);
  await fileIo.close(alertFile.fd);
  
  // 保存设备状态
  const statusStr = JSON.stringify(this.deviceStatus);
  const statusCompressed = await zlib.inflateSync(new Uint8Array(statusStr.split('').map(c => c.charCodeAt(0))));
  
  const statusFile = await fileIo.open('data/device_status.bin', 0o666 | fileIo.OpenMode.CREATE);
  await fileIo.write(statusFile.fd, statusCompressed.buffer);
  await fileIo.close(statusFile.fd);

catch (e) {

  console.error(Failed to save local data. Code: {e.code}, message: {e.message});

}

private async checkBatteryStatus(): Promise<void> {
try {
const batteryInfo = await power.getBatteryInfo();
this.deviceStatus.batteryLevel = batteryInfo.batterySoc;

  // 低电量模式切换
  const shouldLowPower = batteryInfo.batterySoc < 20;
  if (shouldLowPower !== this.deviceStatus.isLowPowerMode) {
    this.deviceStatus.isLowPowerMode = shouldLowPower;
    this.adjustMonitoringStrategy();

// 低电量时延长同步间隔

  this.deviceStatus.syncInterval = shouldLowPower ? 600 : 300;

catch (e) {

  console.error(Failed to get battery info. Code: {e.code}, message: {e.message});

}

private adjustMonitoringStrategy(): void {
if (this.deviceStatus.isLowPowerMode) {
// 低电量模式: 降低采样频率,简化算法
if (this.heartRateSensorId !== -1) {
sensor.off(this.heartRateSensorId);
this.heartRateSensorId = -1;
if (this.ppgSensorId !== -1) {

    sensor.off(this.ppgSensorId);
    this.ppgSensorId = -1;

this.startLowPowerMonitoring();

else {

  // 正常模式: 高精度监测
  if (this.heartRateSensorId !== -1) {
    sensor.off(this.heartRateSensorId);
    this.heartRateSensorId = -1;

if (this.ppgSensorId !== -1) {

    sensor.off(this.ppgSensorId);
    this.ppgSensorId = -1;

this.startHighAccuracyMonitoring();

}

public async startHighAccuracyMonitoring(): Promise<boolean> {
try {
// 启用高精度心率传感器
this.heartRateSensorId = await sensor.on(sensor.SensorId.HEART_RATE, {
interval: sensor.SensorFrequency.SENSOR_DELAY_FASTEST,
callback: (data) => {
this.handleHeartRateData(data);
});

  // 启用PPG传感器进行原始信号采集
  this.ppgSensorId = await sensor.on(sensor.SensorId.PPG, {
    interval: sensor.SensorFrequency.SENSOR_DELAY_GAME,
    callback: (data) => {
      this.handlePPGData(data);

});

  // 启用高性能模式
  await power.enablePowerMode(power.PowerMode.HIGH_PERFORMANCE, 'Heart rate monitoring');
  
  return true;

catch (e) {

  console.error(Failed to start high accuracy monitoring. Code: {e.code}, message: {e.message});
  return false;

}

public async startLowPowerMonitoring(): Promise<boolean> {
try {
// 低电量模式仅使用心率传感器,降低采样频率
this.heartRateSensorId = await sensor.on(sensor.SensorId.HEART_RATE, {
interval: sensor.SensorFrequency.SENSOR_DELAY_NORMAL,
callback: (data) => {
this.handleHeartRateData(data);
});

  // 启用低功耗模式
  await power.enablePowerMode(power.PowerMode.LOW_POWER, 'Low power heart rate monitoring');
  
  return true;

catch (e) {

  console.error(Failed to start low power monitoring. Code: {e.code}, message: {e.message});
  return false;

}

private async handleHeartRateData(data: sensor.HeartRateResponse): Promise<void> {
const now = Date.now();

// 简单滤波 - 去除异常值
if (data.heartRate < 30 || data.heartRate > 220) {
  return; // 忽略明显不合理的心率值

// 计算HRV (简化版)

let hrv = 0;
if (this.hrData.length > 0) {
  const lastHR = this.hrData[this.hrData.length - 1];
  const interval = now - lastHR.timestamp;
  hrv = Math.abs(interval - 60000 / data.heartRate); // 计算与预期间隔的差值

const newData: HeartRateData = {

  timestamp: now,
  heartRate: data.heartRate,
  hrv,
  confidence: data.confidence,
  deviceId: this.getDeviceId(),
  isSynced: false
};

this.hrData.push(newData);

// 心率异常检测
this.checkForAbnormalities(newData);

// 保存并同步数据
await this.saveLocalData();

if (now - this.deviceStatus.lastSyncTime > this.deviceStatus.syncInterval * 1000) {
  await this.syncData();
  this.deviceStatus.lastSyncTime = now;

}

private async handlePPGData(data: sensor.PPGResponse): Promise<void> {
// 保存原始PPG数据用于降噪处理
this.rawPPGData.push(…data.samples);

// 当积累足够数据时进行处理
if (this.rawPPGData.length >= 500) { // 约5秒数据(假设100Hz采样率)
  // 使用任务池并行处理PPG信号
  const task = new taskpool.Task(this.processPPGDataTask, this.rawPPGData.slice(-500));
  const processedData = await taskpool.execute(task) as { heartRate: number, hrv: number };
  
  // 如果高精度模式且PPG分析结果可信,更新心率数据
  if (!this.deviceStatus.isLowPowerMode && processedData.heartRate > 0) {
    const now = Date.now();
    const newData: HeartRateData = {
      timestamp: now,
      heartRate: processedData.heartRate,
      hrv: processedData.hrv,
      confidence: 0.9, // PPG分析通常有较高置信度
      deviceId: this.getDeviceId(),
      isSynced: false
    };
    
    this.hrData.push(newData);
    this.checkForAbnormalities(newData);

// 保留最近100个样本作为重叠

  this.rawPPGData = this.rawPPGData.slice(-100);

}

private processPPGDataTask(rawData: number[]): { heartRate: number, hrv: number } {
// PPG信号处理算法 (简化版)
// 实际应用中应实现完整的降噪和特征提取算法

// 1. 降噪处理 - 移动平均滤波
const windowSize = 5;
const smoothedData = [];
for (let i = 0; i < rawData.length - windowSize; i++) {
  let sum = 0;
  for (let j = 0; j < windowSize; j++) {
    sum += rawData[i + j];

smoothedData.push(sum / windowSize);

// 2. 峰值检测

const peaks = [];
for (let i = 1; i < smoothedData.length - 1; i++) {
  if (smoothedData[i] > smoothedData[i - 1] && smoothedData[i] > smoothedData[i + 1]) {
    peaks.push(i);

}

// 3. 计算心率和HRV
if (peaks.length >= 2) {
  const intervals = [];
  for (let i = 1; i < peaks.length; i++) {
    intervals.push(peaks[i] - peaks[i - 1]);

const avgInterval = intervals.reduce((sum, val) => sum + val, 0) / intervals.length;

  const heartRate = 60000 / (avgInterval * 10); // 假设100Hz采样率
  
  // 计算HRV (RR间期标准差)
  const squaredDiffs = intervals.map(i => Math.pow(i - avgInterval, 2));
  const variance = squaredDiffs.reduce((sum, val) => sum + val, 0) / intervals.length;
  const hrv = Math.sqrt(variance);
  
  return { heartRate, hrv };

return { heartRate: 0, hrv: 0 };

private checkForAbnormalities(data: HeartRateData): void {

// 心率异常检测规则
const now = new Date(data.timestamp);
const timeStr = now.toLocaleTimeString();

// 1. 高心率检测 (>100 bpm)
if (data.heartRate > 100) {
  const alert: HealthAlert = {
    timestamp: data.timestamp,
    type: 'high_hr',
    heartRate: data.heartRate,
    message: 高心率预警: {data.heartRate} bpm ({timeStr}),
    isSynced: false
  };
  this.alerts.push(alert);
  this.triggerAlert(alert);

// 2. 低心率检测 (<50 bpm)

else if (data.heartRate < 50) {
  const alert: HealthAlert = {
    timestamp: data.timestamp,
    type: 'low_hr',
    heartRate: data.heartRate,
    message: 低心率预警: {data.heartRate} bpm ({timeStr}),
    isSynced: false
  };
  this.alerts.push(alert);
  this.triggerAlert(alert);

// 3. 异常HRV检测 (>50ms 或 <10ms)

if (data.hrv > 50 || (data.hrv > 0 && data.hrv < 10)) {
  const alert: HealthAlert = {
    timestamp: data.timestamp,
    type: 'abnormal_hrv',
    hrv: data.hrv,
    message: 心率变异性异常: {data.hrv.toFixed(1)} ms ({timeStr}),
    isSynced: false
  };
  this.alerts.push(alert);
  this.triggerAlert(alert);

// 4. 心律失常检测 (简化版)

if (this.hrData.length >= 3) {
  const last3 = this.hrData.slice(-3);
  const diffs = [];
  for (let i = 1; i < last3.length; i++) {
    diffs.push(Math.abs(last3[i].heartRate - last3[i - 1].heartRate));

const avgDiff = diffs.reduce((sum, val) => sum + val, 0) / diffs.length;

  if (avgDiff > 15) { // 相邻心率差值平均超过15 bpm
    const alert: HealthAlert = {
      timestamp: data.timestamp,
      type: 'arrhythmia',
      message: 疑似心律失常 (${timeStr}),
      isSynced: false
    };
    this.alerts.push(alert);
    this.triggerAlert(alert);

}

private async triggerAlert(alert: HealthAlert): Promise<void> {

// 发送本地通知
try {
  await notification.publish({
    id: 1,
    contentType: notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
    normal: {
      title: '心率异常预警',
      text: alert.message,
      additionalText: new Date(alert.timestamp).toLocaleTimeString()

});

catch (e) {

  console.error(Failed to publish notification. Code: {e.code}, message: {e.message});

// 同步报警信息

await this.syncData();

private getDeviceId(): string {

// 实际应用中应获取真实设备ID
return 'hr_monitor_' + Math.random().toString(36).substr(2, 9);

private async syncData(): Promise<void> {

if (!this.kvStore) return;

try {
  // 同步心率数据
  const unsyncedHR = this.hrData.filter(d => !d.isSynced);
  if (unsyncedHR.length > 0) {
    await this.kvStore.put('heart_rate_data', { value: unsyncedHR });
    this.hrData.forEach(d => {
      if (!d.isSynced) d.isSynced = true;
    });

// 同步报警记录

  const unsyncedAlerts = this.alerts.filter(a => !a.isSynced);
  if (unsyncedAlerts.length > 0) {
    await this.kvStore.put('health_alerts', { value: unsyncedAlerts });
    this.alerts.forEach(a => {
      if (!a.isSynced) a.isSynced = true;
    });

// 同步设备状态

  await this.kvStore.put('device_status', { value: this.deviceStatus });

catch (e) {

  console.error(Failed to sync data. Code: {e.code}, message: {e.message});

}

private handleRemoteDataChange(data: distributedData.ChangeData): void {
data.insertEntries.forEach((entry: distributedData.Entry) => {
if (entry.key === ‘heart_rate_data’) {
const remoteHR = entry.value.value as HeartRateData[];
this.mergeHeartRateData(remoteHR);
else if (entry.key === ‘health_alerts’) {

    const remoteAlerts = entry.value.value as HealthAlert[];
    this.mergeHealthAlerts(remoteAlerts);

else if (entry.key === ‘device_status’) {

    const remoteStatus = entry.value.value as DeviceStatus;
    this.mergeDeviceStatus(remoteStatus);

});

private mergeHeartRateData(remoteData: HeartRateData[]): void {

remoteData.forEach(remote => {
  const existing = this.hrData.find(local => 
    local.timestamp === remote.timestamp && 
    local.deviceId === remote.deviceId
  );
  
  if (!existing) {
    this.hrData.push(remote);

else {

    // 合并策略:保留更高置信度的数据
    if (remote.confidence > existing.confidence) {
      existing.heartRate = remote.heartRate;
      existing.hrv = remote.hrv;
      existing.confidence = remote.confidence;

}

});

// 按时间排序
this.hrData.sort((a, b) => a.timestamp - b.timestamp);

private mergeHealthAlerts(remoteAlerts: HealthAlert[]): void {

remoteAlerts.forEach(remote => {
  const existing = this.alerts.find(local => 
    local.timestamp === remote.timestamp && 
    local.type === remote.type
  );
  
  if (!existing) {
    this.alerts.push(remote);

});

// 按时间排序
this.alerts.sort((a, b) => a.timestamp - b.timestamp);

private mergeDeviceStatus(remoteStatus: DeviceStatus): void {

// 采用更保守的低电量模式
if (remoteStatus.isLowPowerMode && !this.deviceStatus.isLowPowerMode) {
  this.deviceStatus.isLowPowerMode = true;
  this.adjustMonitoringStrategy();

// 采用更短的同步间隔

this.deviceStatus.syncInterval = Math.min(
  this.deviceStatus.syncInterval,
  remoteStatus.syncInterval
);

public getRecentHeartRate(count: number = 10): HeartRateData[] {

return this.hrData.slice(-count).reverse();

public getRecentAlerts(count: number = 5): HealthAlert[] {

return this.alerts.slice(-count).reverse();

public getCurrentStatus(): DeviceStatus {

return this.deviceStatus;

public async stopMonitoring(): Promise<void> {

if (this.heartRateSensorId !== -1) {
  await sensor.off(this.heartRateSensorId);
  this.heartRateSensorId = -1;

if (this.ppgSensorId !== -1) {

  await sensor.off(this.ppgSensorId);
  this.ppgSensorId = -1;

await power.disablePowerMode(power.PowerMode.HIGH_PERFORMANCE);

await power.disablePowerMode(power.PowerMode.LOW_POWER);

await this.saveLocalData();
await this.syncData();

public async destroy(): Promise<void> {

await this.stopMonitoring();

if (this.kvStore) {
  this.kvStore.off('dataChange');

}

心率监控组件实现

// src/main/ets/components/HeartRateMonitor.ets
@Component
export struct HeartRateMonitor {
private hrService = HeartRateService.getInstance();
@State heartRateData: HeartRateData[] = [];
@State healthAlerts: HealthAlert[] = [];
@State deviceStatus: DeviceStatus = {
batteryLevel: 100,
isLowPowerMode: false,
lastSyncTime: 0,
syncInterval: 300
};
@State isMonitoring: boolean = false;
private timer: number = 0;

aboutToAppear(): void {
this.loadData();
this.startMonitoring();
this.startAutoRefresh();
aboutToDisappear(): void {

this.stopAutoRefresh();

private loadData(): void {

this.heartRateData = this.hrService.getRecentHeartRate();
this.healthAlerts = this.hrService.getRecentAlerts();
this.deviceStatus = this.hrService.getCurrentStatus();

private async startMonitoring(): Promise<void> {

this.isMonitoring = await this.hrService.startHighAccuracyMonitoring();

private startAutoRefresh(): void {

this.timer = setInterval(() => {
  this.loadData();
}, 10000); // 每10秒刷新一次

private stopAutoRefresh(): void {

if (this.timer) {
  clearInterval(this.timer);
  this.timer = 0;

}

build() {
Column() {
// 标题
Text(‘心率异常预警系统’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  // 状态卡片
  this.buildStatusCard();
  
  // 心率图表
  Text('实时心率趋势')
    .fontSize(18)
    .fontWeight(FontWeight.Bold)
    .margin({ top: 20, bottom: 10 });
  
  this.buildHeartRateChart();
  
  // 报警记录
  Text('健康预警记录')
    .fontSize(18)
    .fontWeight(FontWeight.Bold)
    .margin({ top: 20, bottom: 10 });
  
  if (this.healthAlerts.length > 0) {
    this.buildAlertList();

else {

    Text('暂无预警记录')
      .fontSize(14)
      .fontColor('#666666');

}

.width('100%')
.height('100%')
.padding(20);

@Builder

private buildStatusCard() {
Column() {
// 当前心率
Row() {
Image($r(‘app.media.ic_heart’))
.width(24)
.height(24)
.margin({ right: 10 });

    Column() {
      Text('当前心率')
        .fontSize(14)
        .fontColor('#666666');
      
      if (this.heartRateData.length > 0) {
        Text(${this.heartRateData[0].heartRate} bpm)
          .fontSize(24)
          .fontWeight(FontWeight.Bold)
          .fontColor(this.getHeartRateColor(this.heartRateData[0].heartRate));
        
        Text(HRV: ${this.heartRateData[0].hrv.toFixed(1)} ms)
          .fontSize(14)
          .fontColor('#666666');

else {

        Text('-- bpm')
          .fontSize(24)
          .fontWeight(FontWeight.Bold);

}

    .layoutWeight(1);

.margin({ bottom: 15 });

  // 设备状态
  Row() {
    Image($r('app.media.ic_battery'))
      .width(24)
      .height(24)
      .margin({ right: 10 });
    
    Column() {
      Text('设备状态')
        .fontSize(14)
        .fontColor('#666666');
      
      Row() {
        Text(电量: ${this.deviceStatus.batteryLevel}%)
          .fontSize(16);
        
        Text(this.deviceStatus.isLowPowerMode ? ' (低电量模式)' : '')
          .fontSize(16)
          .fontColor('#FF9800');

}

    .layoutWeight(1);

}

.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(10)
.shadow({ radius: 5, color: '#E0E0E0', offsetX: 0, offsetY: 2 });

private getHeartRateColor(hr: number): string {

if (hr < 50) return '#2196F3';  // 低心率 - 蓝色
if (hr <= 100) return '#4CAF50'; // 正常 - 绿色
return '#F44336';               // 高心率 - 红色

@Builder

private buildHeartRateChart() {
// 获取最近5分钟数据
const now = Date.now();
const fiveMinutesAgo = now - 5 60 1000;
const recentData = this.heartRateData.filter(d => d.timestamp >= fiveMinutesAgo);

if (recentData.length === 0) {
  return Text('暂无心率数据')
    .fontSize(14)
    .fontColor('#666666');

// 计算图表参数

const minHR = Math.max(40, Math.min(...recentData.map(d => d.heartRate)) - 10);
const maxHR = Math.min(120, Math.max(...recentData.map(d => d.heartRate)) + 10);
const hrRange = maxHR - minHR;

Column() {
  // 图表区域
  Stack() {
    // 网格线
    ForEach(Array.from({ length: 5 }), (_, i) => {
      Line()
        .width('100%')
        .height(1)
        .backgroundColor('#E0E0E0')
        .position({ x: 0, y: i * 40 });
    });
    
    // 心率曲线
    Polyline()
      .width('100%')
      .height(160)
      .fillOpacity(0)
      .stroke('#E91E63')
      .strokeWidth(2)
      .points(this.getChartPoints(recentData, minHR, hrRange));
    
    // 数据点
    ForEach(recentData, (data, i) => {
      if (i % 5 === 0) { // 每5个数据显示一个点
        Circle()
          .width(8)
          .height(8)
          .fill('#E91E63')
          .position({
            x: i * (100 / (recentData.length - 1)) + '%',
            y: (maxHR - data.heartRate) * (160 / hrRange) + '%'
          });

});

.width(‘100%’)

  .height(160);
  
  // X轴标签
  Row() {
    Text(new Date(recentData[0].timestamp).toLocaleTimeString())
      .fontSize(10);
    
    Text(new Date(recentData[recentData.length - 1].timestamp).toLocaleTimeString())
      .fontSize(10)
      .margin({ left: '80%' });

.width(‘100%’)

  .margin({ top: 5 });
  
  // Y轴标签
  Row() {
    Text(${maxHR} bpm)
      .fontSize(10);
    
    Text(${minHR} bpm)
      .fontSize(10)
      .margin({ left: '85%' });

.width(‘100%’);

}

private getChartPoints(data: HeartRateData[], minHR: number, hrRange: number): Point[] {
return data.map((d, i) => ({
x: i * (100 / (data.length - 1)),
y: (minHR + hrRange - d.heartRate) * (160 / hrRange)
}));
@Builder

private buildAlertList() {
List({ space: 10 }) {
ForEach(this.healthAlerts, (alert) => {
ListItem() {
Column() {
Row() {
Text(this.getAlertTypeText(alert.type))
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor(this.getAlertColor(alert.type))
.layoutWeight(1);

          Text(new Date(alert.timestamp).toLocaleTimeString())
            .fontSize(14)
            .fontColor('#666666');

Text(alert.message)

          .fontSize(14)
          .fontColor('#666666')
          .margin({ top: 5 });

.width(‘100%’)

      .padding(10)

.borderRadius(10)

    .backgroundColor('#FFFFFF')
    .shadow({ radius: 3, color: '#E0E0E0', offsetX: 0, offsetY: 1 });
  })

.width(‘100%’)

.height('30%')

private getAlertTypeText(type: string): string {

switch (type) {
  case 'high_hr': return '⚠️ 高心率';
  case 'low_hr': return '⚠️ 低心率';
  case 'abnormal_hrv': return '⚠️ HRV异常';
  case 'arrhythmia': return '⚠️ 心律失常';
  default: return '⚠️ 健康预警';

}

private getAlertColor(type: string): string {
switch (type) {
case ‘high_hr’: return ‘#F44336’;
case ‘low_hr’: return ‘#2196F3’;
case ‘abnormal_hrv’: return ‘#FF9800’;
case ‘arrhythmia’: return ‘#9C27B0’;
default: return ‘#607D8B’;
}

private async toggleMonitoring(): Promise<void> {
if (this.isMonitoring) {
await this.hrService.stopMonitoring();
this.isMonitoring = false;
else {

  this.isMonitoring = await this.hrService.startHighAccuracyMonitoring();

}

主界面实现

// src/main/ets/pages/HealthPage.ets
import { HeartRateService } from ‘…/service/HeartRateService’;
import { HeartRateMonitor } from ‘…/components/HeartRateMonitor’;

@Entry
@Component
struct HealthPage {
@State activeTab: number = 0;
private hrService = HeartRateService.getInstance();

build() {
Column() {
// 标题
Text(‘健康监测系统’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  // 标签页
  Tabs({ barPosition: BarPosition.Start }) {
    TabContent() {
      // 心率监测标签页
      HeartRateMonitor()

.tabBar(‘心率监测’);

    TabContent() {
      // 健康报告标签页
      this.buildReportTab()

.tabBar(‘健康报告’);

.barWidth(‘100%’)

  .barHeight(50)
  .width('100%')
  .height('80%')

.width(‘100%’)

.height('100%')
.padding(20);

@Builder

private buildReportTab() {
Column() {
Text(‘心率健康报告’)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  // 今日统计数据
  this.buildDailyStats();
  
  // 心率变异性分析
  Text('心率变异性(HRV)分析')
    .fontSize(18)
    .fontWeight(FontWeight.Bold)
    .margin({ top: 30, bottom: 10 });
  
  this.buildHRVChart();

.width(‘100%’)

.height('100%')
.padding(20);

@Builder

private buildDailyStats() {
const now = Date.now();
const todayStart = new Date();
todayStart.setHours(0, 0, 0, 0);

const todayData = this.hrService.getRecentHeartRate(1000).filter(d => 
  d.timestamp >= todayStart.getTime()
);

if (todayData.length === 0) {
  return Text('今日暂无心率数据')
    .fontSize(14)
    .fontColor('#666666');

const avgHR = todayData.reduce((sum, d) => sum + d.heartRate, 0) / todayData.length;

const minHR = Math.min(...todayData.map(d => d.heartRate));
const maxHR = Math.max(...todayData.map(d => d.heartRate));
const avgHRV = todayData.reduce((sum, d) => sum + d.hrv, 0) / todayData.length;

Column() {
  Row() {
    Column() {
      Text('平均心率')
        .fontSize(14)
        .fontColor('#666666');
      
      Text(${avgHR.toFixed(0)} bpm)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor(this.getHeartRateColor(avgHR));

.width(‘33%’)

    Column() {
      Text('最低心率')
        .fontSize(14)
        .fontColor('#666666');
      
      Text(${minHR} bpm)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#2196F3');

.width(‘33%’)

    Column() {
      Text('最高心率')
        .fontSize(14)
        .fontColor('#666666');
      
      Text(${maxHR} bpm)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#F44336');

.width(‘33%’)

.margin({ bottom: 20 });

  Row() {
    Column() {
      Text('平均HRV')
        .fontSize(14)
        .fontColor('#666666');
      
      Text(${avgHRV.toFixed(1)} ms)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor(avgHRV > 50 || avgHRV < 10 ? '#FF9800' : '#4CAF50');

Column() {

      Text('预警次数')
        .fontSize(14)
        .fontColor('#666666');
      
      Text(${this.hrService.getRecentAlerts(1000).filter(a => 
        a.timestamp >= todayStart.getTime()
      ).length})
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor('#F44336');

.margin({ left: 20 });

}

.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(10)
.shadow({ radius: 5, color: '#E0E0E0', offsetX: 0, offsetY: 2 });

private getHeartRateColor(hr: number): string {

if (hr < 50) return '#2196F3';  // 低心率 - 蓝色
if (hr <= 100) return '#4CAF50'; // 正常 - 绿色
return '#F44336';               // 高心率 - 红色

@Builder

private buildHRVChart() {
// 获取最近24小时数据 (每小时一个点)
const now = Date.now();
const twentyFourHoursAgo = now - 24 60 60 * 1000;
const allData = this.hrService.getRecentHeartRate(1000).filter(d =>
d.timestamp >= twentyFourHoursAgo
);

if (allData.length === 0) {
  return Text('暂无HRV数据')
    .fontSize(14)
    .fontColor('#666666');

// 按小时分组计算平均HRV

const hourlyData: Record<string, number[]> = {};
allData.forEach(data => {
  const hour = new Date(data.timestamp).getHours();
  const key = ${hour}:00;
  if (!hourlyData[key]) {
    hourlyData[key] = [];

hourlyData[key].push(data.hrv);

});

const chartData = Object.entries(hourlyData).map(([hour, hrvValues]) => ({
  hour,
  avgHRV: hrvValues.reduce((sum, val) => sum + val, 0) / hrvValues.length
}));

// 构建柱状图
Row({ space: 15 }) {
  ForEach(chartData, (data) => {
    Column() {
      // HRV柱状图
      Column() {
        Blank()
          .height(data.avgHRV * 2) // 放大显示
          .width(20)
          .backgroundColor(data.avgHRV > 50 || data.avgHRV < 10 ? '#FF9800' : '#4CAF50')

.height(100)

      .justifyContent(FlexAlign.End);
      
      // 时间标签
      Text(data.hour)
        .fontSize(10)
        .margin({ top: 5 });

})

.width(‘100%’)

.height(150)
.margin({ top: 10 });

}

四、与游戏同步技术的结合点
实时状态同步:借鉴游戏中玩家状态实时同步机制,优化心率数据的跨设备同步

事件广播机制:类似游戏中的事件广播,实现心率异常预警的快速扩散

数据压缩传输:使用类似游戏中的网络优化技术,对PPG数据进行高效压缩传输

设备角色分配:参考游戏中的主机/客户端模式,确定主监测设备和从属设备

状态一致性保障:借鉴游戏中的状态同步机制,确保多设备间预警状态一致

五、关键特性实现
PPG传感器降噪处理:

  private processPPGDataTask(rawData: number[]): { heartRate: number, hrv: number } {
 // 1. 降噪处理 - 移动平均滤波
 const windowSize = 5;
 const smoothedData = [];
 for (let i = 0; i < rawData.length - windowSize; i++) {
   let sum = 0;
   for (let j = 0; j < windowSize; j++) {
     sum += rawData[i + j];

smoothedData.push(sum / windowSize);

// 2. 峰值检测

 const peaks = [];
 for (let i = 1; i < smoothedData.length - 1; i++) {
   if (smoothedData[i] > smoothedData[i - 1] && smoothedData[i] > smoothedData[i + 1]) {
     peaks.push(i);

}

 // 3. 计算心率和HRV
 if (peaks.length >= 2) {
   const intervals = [];
   for (let i = 1; i < peaks.length; i++) {
     intervals.push(peaks[i] - peaks[i - 1]);

const avgInterval = intervals.reduce((sum, val) => sum + val, 0) / intervals.length;

   const heartRate = 60000 / (avgInterval * 10); // 假设100Hz采样率
   
   // 计算HRV (RR间期标准差)
   const squaredDiffs = intervals.map(i => Math.pow(i - avgInterval, 2));
   const variance = squaredDiffs.reduce((sum, val) => sum + val, 0) / intervals.length;
   const hrv = Math.sqrt(variance);
   
   return { heartRate, hrv };

return { heartRate: 0, hrv: 0 };

实时心率变异性分析:

  private async handleHeartRateData(data: sensor.HeartRateResponse): Promise<void> {
 const now = Date.now();
 
 // 计算HRV (简化版)
 let hrv = 0;
 if (this.hrData.length > 0) {
   const lastHR = this.hrData[this.hrData.length - 1];
   const interval = now - lastHR.timestamp;
   hrv = Math.abs(interval - 60000 / data.heartRate); // 计算与预期间隔的差值

const newData: HeartRateData = {

   timestamp: now,
   heartRate: data.heartRate,
   hrv,
   confidence: data.confidence,
   deviceId: this.getDeviceId(),
   isSynced: false
 };
 
 this.hrData.push(newData);
 
 // 心率异常检测
 this.checkForAbnormalities(newData);

低电量简化算法:

  public async startLowPowerMonitoring(): Promise<boolean> {
 try {
   // 低电量模式仅使用心率传感器,降低采样频率
   this.heartRateSensorId = await sensor.on(sensor.SensorId.HEART_RATE, {
     interval: sensor.SensorFrequency.SENSOR_DELAY_NORMAL,
     callback: (data) => {
       this.handleHeartRateData(data);

});

   // 启用低功耗模式
   await power.enablePowerMode(power.PowerMode.LOW_POWER, 'Low power heart rate monitoring');
   
   return true;

catch (e) {

   console.error(Failed to start low power monitoring. Code: {e.code}, message: {e.message});
   return false;

}

异常心率检测:

  private checkForAbnormalities(data: HeartRateData): void {
 // 心率异常检测规则
 const now = new Date(data.timestamp);
 const timeStr = now.toLocaleTimeString();
 
 // 1. 高心率检测 (>100 bpm)
 if (data.heartRate > 100) {
   const alert: HealthAlert = {
     timestamp: data.timestamp,
     type: 'high_hr',
     heartRate: data.heartRate,
     message: 高心率预警: {data.heartRate} bpm ({timeStr}),
     isSynced: false
   };
   this.alerts.push(alert);
   this.triggerAlert(alert);

// 2. 低心率检测 (<50 bpm)

 else if (data.heartRate < 50) {
   const alert: HealthAlert = {
     timestamp: data.timestamp,
     type: 'low_hr',
     heartRate: data.heartRate,
     message: 低心率预警: {data.heartRate} bpm ({timeStr}),
     isSynced: false
   };
   this.alerts.push(alert);
   this.triggerAlert(alert);

// 3. 异常HRV检测 (>50ms 或 <10ms)

 if (data.hrv > 50 || (data.hrv > 0 && data.hrv < 10)) {
   const alert: HealthAlert = {
     timestamp: data.timestamp,
     type: 'abnormal_hrv',
     hrv: data.hrv,
     message: 心率变异性异常: {data.hrv.toFixed(1)} ms ({timeStr}),
     isSynced: false
   };
   this.alerts.push(alert);
   this.triggerAlert(alert);

}

六、性能优化策略
智能数据同步:

  // 只有新数据时才触发同步

if (now - this.deviceStatus.lastSyncTime > this.deviceStatus.syncInterval * 1000) {
await this.syncData();
this.deviceStatus.lastSyncTime = now;

本地缓存优先:

  public getRecentHeartRate(count: number = 10): HeartRateData[] {
 // 先从内存缓存读取
 return this.hrData.slice(-count).reverse();

并行计算优化:

  // 使用任务池并行处理PPG信号

const task = new taskpool.Task(this.processPPGDataTask, this.rawPPGData.slice(-500));
const processedData = await taskpool.execute(task) as { heartRate: number, hrv: number };

资源释放管理:

  public async destroy(): Promise<void> {
 await this.stopMonitoring();
 
 if (this.kvStore) {
   this.kvStore.off('dataChange');

}

七、项目扩展方向
ECG心电图集成:增加心电图监测功能,提供更全面的心脏健康分析

血压估算:基于PPG信号实现无创血压估算

睡眠分析:结合心率变异性进行睡眠质量评估

云端健康档案:建立个人健康档案,长期跟踪心率变化趋势

紧急联系人通知:在检测到严重心律失常时自动通知紧急联系人

八、总结

本文实现的心率异常预警系统具有以下特点:
采用先进的PPG信号降噪技术,提高心率监测精度

实时分析心率变异性,早期发现心脏健康问题

智能低电量模式切换,平衡性能与续航

基于分布式数据同步,实现多终端实时预警

提供直观的数据可视化和完整的健康报告功能

该应用展示了HarmonyOS在健康监测领域的强大能力,特别是在生物信号处理、低功耗控制和多设备协同方面的优势。通过借鉴游戏同步技术,实现了高效可靠的健康预警机制,为个人健康监护提供了完整的解决方案。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐