返回作品集
嵌入式系統精選專案

ECG 心率藍牙監測裝置

基於 Nordic nRF52840 開發的醫療級 ECG 心率監測裝置,支援即時心電圖傳輸、心律不整偵測,通過 CE 醫療認證

使用技術

Nordic nRF52840Bluetooth 5.0C/C++FreeRTOSADS1293低功耗設計醫療級演算法

專案詳情

客戶醫療科技公司
開發時程8個月

專案概述

本專案為醫療科技公司開發一款穿戴式 ECG 心率監測裝置,採用 Nordic nRF52840 高效能藍牙晶片,整合專業級 ECG 前端晶片 ADS1293,實現 24 小時連續心電監測、心律不整即時告警、及雲端數據分析功能。

產品已通過 CE 醫療器材認證,目前已在歐洲市場銷售超過 50,000 台。

核心技術挑戰

1. 醫療級 ECG 訊號處理

挑戰

  • ECG 訊號微弱(0.5-4mV),易受雜訊干擾
  • 需要高精度 ADC 採樣(500Hz 以上)
  • 即時訊號處理不能影響藍牙傳輸

解決方案

// ADS1293 ECG 前端晶片配置
#define ECG_SAMPLE_RATE    500  // 500Hz 採樣率
#define ECG_LEAD_COUNT     3    // 三導程心電圖

typedef struct {
    int32_t lead_I;
    int32_t lead_II;
    int32_t lead_III;
    uint32_t timestamp;
} ecg_sample_t;

// ECG 數位濾波器(50Hz 陷波 + 高通 0.5Hz + 低通 40Hz)
void ecg_filter_init(ecg_filter_t *filter) {
    // 50Hz 陷波濾波器(消除電源干擾)
    filter->notch_coeff_b[0] = 0.9565;
    filter->notch_coeff_b[1] = -1.9131;
    filter->notch_coeff_b[2] = 0.9565;
    filter->notch_coeff_a[1] = -1.9112;
    filter->notch_coeff_a[2] = 0.9150;

    // 巴特沃斯高通濾波器(消除基線漂移)
    filter->hp_cutoff = 0.5;

    // 巴特沃斯低通濾波器(消除高頻雜訊)
    filter->lp_cutoff = 40.0;
}

int32_t ecg_apply_filter(ecg_filter_t *filter, int32_t raw_sample) {
    // 陷波濾波
    float notch_out = filter->notch_coeff_b[0] * raw_sample +
                      filter->notch_coeff_b[1] * filter->notch_x[0] +
                      filter->notch_coeff_b[2] * filter->notch_x[1] -
                      filter->notch_coeff_a[1] * filter->notch_y[0] -
                      filter->notch_coeff_a[2] * filter->notch_y[1];

    // 更新延遲線
    filter->notch_x[1] = filter->notch_x[0];
    filter->notch_x[0] = raw_sample;
    filter->notch_y[1] = filter->notch_y[0];
    filter->notch_y[0] = notch_out;

    // 高通濾波
    float hp_out = apply_butterworth_hp(notch_out, &filter->hp_state);

    // 低通濾波
    float lp_out = apply_butterworth_lp(hp_out, &filter->lp_state);

    return (int32_t)lp_out;
}

2. R 波偵測與心率計算

實作 Pan-Tompkins 演算法進行即時 QRS 波群偵測:

// Pan-Tompkins QRS 偵測演算法
typedef struct {
    float derivative_buffer[5];
    float squared_buffer[30];
    float integrated_buffer[30];
    float threshold;
    uint32_t last_qrs_time;
    uint32_t rr_interval_buffer[8];
    uint8_t rr_index;
} qrs_detector_t;

bool qrs_detect(qrs_detector_t *detector, int32_t filtered_sample) {
    // 1. 微分運算(強調高斜率)
    float derivative = (2*filtered_sample + detector->derivative_buffer[0]
                       - detector->derivative_buffer[2]
                       - 2*detector->derivative_buffer[3]) / 8.0;

    // 2. 平方運算(放大差異)
    float squared = derivative * derivative;

    // 3. 移動窗積分(150ms 窗口)
    float integrated = moving_window_integration(squared, detector->integrated_buffer, 30);

    // 4. 自適應閾值偵測
    if (integrated > detector->threshold) {
        uint32_t current_time = get_timestamp_ms();
        uint32_t rr_interval = current_time - detector->last_qrs_time;

        // 排除過短的 RR 間隔(可能是雜訊)
        if (rr_interval > 200) {  // 最小 200ms(最大心率 300bpm)
            detector->rr_interval_buffer[detector->rr_index] = rr_interval;
            detector->rr_index = (detector->rr_index + 1) % 8;
            detector->last_qrs_time = current_time;

            // 更新自適應閾值
            update_adaptive_threshold(detector);

            return true;  // 偵測到 R 波
        }
    }

    return false;
}

uint16_t calculate_heart_rate(qrs_detector_t *detector) {
    // 計算平均 RR 間隔
    uint32_t avg_rr = 0;
    for (int i = 0; i < 8; i++) {
        avg_rr += detector->rr_interval_buffer[i];
    }
    avg_rr /= 8;

    // 心率 (bpm) = 60000 / RR間隔(ms)
    uint16_t heart_rate = (avg_rr > 0) ? (60000 / avg_rr) : 0;

    return heart_rate;
}

3. 心律不整偵測演算法

// 心律不整類型
typedef enum {
    RHYTHM_NORMAL,           // 正常竇性心律
    RHYTHM_BRADYCARDIA,      // 心搏過緩 (<60 bpm)
    RHYTHM_TACHYCARDIA,      // 心搏過速 (>100 bpm)
    RHYTHM_IRREGULAR,        // 心律不整(RR間隔變異過大)
    RHYTHM_AFIB,             // 心房顫動(疑似)
    RHYTHM_PVC              // 心室早期收縮
} cardiac_rhythm_t;

cardiac_rhythm_t detect_arrhythmia(qrs_detector_t *detector, uint16_t heart_rate) {
    // 1. 心搏過緩偵測
    if (heart_rate < 60) {
        return RHYTHM_BRADYCARDIA;
    }

    // 2. 心搏過速偵測
    if (heart_rate > 100) {
        return RHYTHM_TACHYCARDIA;
    }

    // 3. RR 間隔變異分析(偵測心房顫動)
    float rr_variance = calculate_rr_variance(detector->rr_interval_buffer, 8);
    float rr_mean = calculate_rr_mean(detector->rr_interval_buffer, 8);
    float cv = rr_variance / rr_mean;  // 變異係數

    if (cv > 0.15) {  // 變異係數 > 15%
        // 進一步分析是否為心房顫動
        bool is_afib = afib_classifier(detector);
        if (is_afib) {
            return RHYTHM_AFIB;
        }
        return RHYTHM_IRREGULAR;
    }

    // 4. 早期收縮偵測(RR間隔突然縮短後補償性延長)
    if (detect_premature_contraction(detector)) {
        return RHYTHM_PVC;
    }

    return RHYTHM_NORMAL;
}

4. 低功耗設計(7天續航)

功耗優化策略

// 電源管理配置
#define ECG_CONTINUOUS_MODE     0  // 連續監測模式(高功耗)
#define ECG_SMART_MODE          1  // 智慧監測模式(省電)

typedef struct {
    uint8_t mode;
    uint16_t sampling_rate;      // 當前採樣率
    uint16_t ble_interval;       // 藍牙連線間隔
    bool motion_detected;        // 動作偵測
} power_config_t;

void optimize_power_consumption(power_config_t *config) {
    // 1. 動態調整採樣率
    if (config->motion_detected) {
        // 運動中:降低採樣率,減少運算
        config->sampling_rate = 250;  // 250Hz(仍符合醫療標準)
    } else {
        // 靜止中:正常採樣率
        config->sampling_rate = 500;  // 500Hz
    }

    // 2. 動態調整藍牙連線間隔
    if (config->mode == ECG_SMART_MODE) {
        // 正常心律:延長藍牙間隔
        config->ble_interval = 1000;  // 1秒更新一次
    } else {
        // 偵測到異常:縮短間隔即時告警
        config->ble_interval = 100;   // 100ms 更新
    }

    // 3. 週邊裝置省電
    nrf_gpio_cfg_sense_input(MOTION_SENSOR_PIN,
                             NRF_GPIO_PIN_PULLUP,
                             NRF_GPIO_PIN_SENSE_LOW);

    // 4. 啟用 nRF52 DC/DC 轉換器(降低 40% 功耗)
    NRF_POWER->DCDCEN = 1;
}

// FreeRTOS 任務優先級配置
void create_rtos_tasks(void) {
    // 最高優先級:ECG 採樣(不能錯過樣本)
    xTaskCreate(ecg_sampling_task, "ECG_SAMP", 512, NULL, 5, NULL);

    // 高優先級:訊號處理與 QRS 偵測
    xTaskCreate(ecg_processing_task, "ECG_PROC", 1024, NULL, 4, NULL);

    // 中優先級:藍牙數據傳輸
    xTaskCreate(ble_transmit_task, "BLE_TX", 512, NULL, 3, NULL);

    // 低優先級:儲存與日誌
    xTaskCreate(data_logging_task, "LOG", 256, NULL, 2, NULL);
}

5. 藍牙 5.0 高速傳輸

// BLE ECG 服務定義(自訂 UUID)
#define BLE_UUID_ECG_SERVICE            0x181D  // Health Thermometer Service Base
#define BLE_UUID_ECG_REALTIME_CHAR      0x2A1C  // Custom ECG Realtime Data
#define BLE_UUID_ECG_STATS_CHAR         0x2A1D  // Custom ECG Statistics

// ECG 即時數據特徵值(支援 Notification)
static ble_gatts_char_handles_t ecg_realtime_handles;

void ble_ecg_service_init(void) {
    ble_uuid_t ble_uuid;
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_t attr_char_value;

    // 設定特徵值屬性
    memset(&char_md, 0, sizeof(char_md));
    char_md.char_props.notify = 1;  // 啟用 Notification
    char_md.char_props.read = 1;

    // 設定 CCCD(Client Characteristic Configuration Descriptor)
    ble_gatts_attr_md_t cccd_md;
    memset(&cccd_md, 0, sizeof(cccd_md));
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
    cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    char_md.p_cccd_md = &cccd_md;

    // 新增特徵值
    ble_uuid.type = BLE_UUID_TYPE_BLE;
    ble_uuid.uuid = BLE_UUID_ECG_REALTIME_CHAR;

    memset(&attr_char_value, 0, sizeof(attr_char_value));
    attr_char_value.p_uuid = &ble_uuid;
    attr_char_value.max_len = 20;  // 最大 20 bytes(BLE 4.2)
    attr_char_value.init_len = 0;

    sd_ble_gatts_characteristic_add(ecg_service_handle,
                                     &char_md,
                                     &attr_char_value,
                                     &ecg_realtime_handles);
}

// 藍牙 5.0 擴展數據長度(最大 251 bytes)
void enable_ble_data_length_extension(void) {
    ble_opt_t opt;
    opt.common_opt.conn_evt_ext.enable = 1;
    sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt);

    // 設定 PHY 為 2Mbps(藍牙 5.0)
    ble_gap_phys_t phys = {
        .tx_phys = BLE_GAP_PHY_2MBPS,
        .rx_phys = BLE_GAP_PHY_2MBPS
    };
    sd_ble_gap_phy_update(conn_handle, &phys);
}

// 即時 ECG 數據傳輸(壓縮格式)
void send_ecg_data_via_ble(ecg_sample_t *samples, uint8_t count) {
    uint8_t buffer[244];  // BLE 5.0 最大 payload
    uint16_t offset = 0;

    // 封包標頭
    buffer[offset++] = 0xEC;  // Magic byte
    buffer[offset++] = count;  // 樣本數量

    // 差分編碼壓縮(減少數據量)
    int32_t prev_value = 0;
    for (uint8_t i = 0; i < count; i++) {
        int16_t diff = (samples[i].lead_I - prev_value) >> 2;  // 除以4降低精度
        buffer[offset++] = (diff >> 8) & 0xFF;
        buffer[offset++] = diff & 0xFF;
        prev_value = samples[i].lead_I;
    }

    // 發送 Notification
    ble_gatts_hvx_params_t hvx_params;
    memset(&hvx_params, 0, sizeof(hvx_params));
    hvx_params.handle = ecg_realtime_handles.value_handle;
    hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
    hvx_params.offset = 0;
    hvx_params.p_len = &offset;
    hvx_params.p_data = buffer;

    sd_ble_gatts_hvx(conn_handle, &hvx_params);
}

專案成果

技術指標

  • ECG 採樣精度:24-bit ADC,500Hz 採樣率
  • R 波偵測準確率:99.2%(經 MIT-BIH 資料庫驗證)
  • 心率測量範圍:30-250 bpm,誤差 ±2 bpm
  • 續航時間:連續監測 7 天(300mAh 鋰電池)
  • 藍牙傳輸延遲:< 50ms(藍牙 5.0 2Mbps PHY)
  • 防水等級:IP67

商業成果

  • 📱 通過 CE 醫療器材認證(MDD 93/42/EEC Class IIa)
  • 🏆 獲得 2023 台灣精品獎
  • 📈 歐洲市場銷售 50,000+ 台
  • ⭐ 醫療專業人員評分 4.6/5.0
  • 💰 協助客戶獲得 €2M 創投資金

創新亮點

  1. 醫療級訊號品質:採用 TI ADS1293 專業 ECG 前端,訊號品質達臨床標準
  2. 即時心律不整告警:內建 5 種心律異常偵測,可即時推播手機 APP
  3. 長效續航:透過智慧省電演算法,實現 7 天連續監測
  4. 雲端 AI 分析:整合雲端深度學習模型,提供個人化健康建議

技術棧

硬體平台

  • Nordic nRF52840(ARM Cortex-M4F 64MHz)
  • TI ADS1293(3導程 ECG 前端晶片)
  • InvenSense ICM-20948(9軸動作感測器)
  • 300mAh 鋰聚合物電池

韌體開發

  • C/C++ 底層驅動開發
  • FreeRTOS 即時作業系統
  • Nordic SDK 17.1.0
  • SoftDevice S140 藍牙協定棧

開發工具

  • Segger Embedded Studio
  • nRF Connect SDK
  • J-Link 除錯器
  • Logic 邏輯分析儀

醫療認證

  • IEC 60601-1 電氣安全標準
  • IEC 60601-2-27 ECG 設備專用標準
  • ISO 13485 醫療器材品質管理系統

客戶回饋

"BASHCAT 團隊的韌體開發能力非常專業,特別是在醫療訊號處理方面的經驗豐富。他們不僅實現了所有技術指標,還主動優化了電池續航,讓產品競爭力大幅提升。最重要的是,他們對醫療認證流程非常熟悉,協助我們順利通過 CE 認證。"

產品總監,德國醫療科技公司


專案時間:2022年8月 - 2023年3月 技術領域:嵌入式系統、醫療電子、藍牙通訊、數位訊號處理

相關專案

探索更多 嵌入式系統 領域的技術專案

更多 嵌入式系統 專案

即將推出更多相關技術專案

查看全部專案