すべての記事

【TECH】拍を数える:ピーク検出と BPM 推定

MonoPump がピーク間隔、タイムスタンプ、外れ値除去、EMA 平滑化で PPG 波形から BPM を推定する方法です。

BPMピーク検出PPGアルゴリズム
【TECH】拍を数える:ピーク検出と BPM 推定

きれいになった波形を見ると安心しますが、ユーザーが知りたいのは結局ひとつです。今の心拍数はいくつか。答えはピークの高さではなく、ピークとピークの距離にあります。

ヘルスアプリ画面上の脈波と強調されたピーク
BPM は波形の高さではなく、ピーク間の時間距離から得られます。

MonoPump の方法は控えめです。もっともらしいピークを見つけ、タイムスタンプで間隔を測り、怪しい間隔を外し、秒を BPM に変換し、最後に UI が暴れない程度に平滑化します。

Flow diagram Preparing diagram
View diagram source
flowchart LR
    A[整えた PPG 窓] --> B[適応的なしきい値]
    B --> C[局所最大値]
    C --> D[ピーク間隔リスト]
    D --> E[中央値ベースの外れ値除去]
    E --> F[BPM = 60 / 平均間隔]
    F --> G[EMA 平滑化]

最初から FFT にしなかった理由

FFT は分かりやすく、脈拍帯域の強い周波数を見つければ BPM にできます。ただ、スマートフォンカメラの短く汚い窓では、その美しさが必ずしも勝ちません。動き、フレーム落ち、接触不良があると、間違った周波数が強く見えることがあります。

ピーク検出は派手ではありませんが、デバッグしやすい。推定が外れたら、ピークと間隔を見れば理由を追えます。

ピークは時間の目印

MonoPump は適応的なしきい値を超える局所最大値を探します。同時に、1 つの拍が複数の小さなピークに分かれないよう、ピーク間の最小距離を設けます。

minPeakDistance = sampleRate * 60 / maxBPM
threshold = mean + 0.5 * standardDeviation

固定しきい値は振幅が安定している場合にだけ強いです。カメラ PPG の振幅はそこまで素直ではないため、窓ごとにしきい値を動かします。

Flow diagram Preparing diagram
View diagram source
flowchart TD
    P1[t1 のピーク] --> I1[t2 - t1]
    P2[t2 のピーク] --> I2[t3 - t2]
    P3[t3 のピーク] --> I3[t4 - t3]
    I1 --> M[中央値間隔]
    I2 --> M
    I3 --> M
    M --> F[離れすぎた間隔を除外]

数字を落ち着かせる

生の BPM は更新ごとに揺れます。全部見せるとアプリが落ち着きません。逆に固定しすぎると不自然です。MonoPump は EMA を使い、さらに更新ごとの変化幅に上限を設けます。

smoothed = 0.35 * current + 0.65 * previous
smoothed = clamp(smoothed, previous - maxDelta, previous + maxDelta)

信頼度は飾りではありません。使えるピーク間隔の数と、最近の信号変動が最終結果の門番になります。数字を出すのは簡単です。出さない判断の方が難しいのです。

MonoWare より

MonoPump にはこのノートの背景があります。

製品サイトを開くか、MonoPump のノートを続けて読めます。

ニュースレター

プライバシーと製品技術ノートを、ときどき送信します。