全部文章

【TECH】一个稳定心率测量流程背后的状态机

为什么 MonoPump 把测量设计成分阶段状态机,而不是简单的开始和停止相机动作。

状态机用户体验SwiftUIPPG
【TECH】一个稳定心率测量流程背后的状态机

摄像头心率 App 里最难的 bug 不一定在数学里。很多问题藏在用户动作和算法时序之间。用户把手指抬起半秒,相机还在预热,结果出现又消失,界面写着测量中,但信号已经明显不在了。

一台正在测量脉搏的手机旁边放着状态机草图笔记
用户体验应该由稳定状态驱动,而不是由单帧直接驱动。

解决办法不是再加一个 if,而是停止把测量当成一个按钮动作。它应该是一台状态机。

State diagram Preparing diagram
View diagram source
stateDiagram-v2
    [*] --> initial
    initial --> preparing: startDetection
    preparing --> detectingFinger: 相机就绪
    detectingFinger --> measuring: 覆盖良好并稳定
    measuring --> calculating: 时长和质量达标
    calculating --> completed: 接受结果
    calculating --> failed: 拒绝结果
    measuring --> detectingFinger: 超过宽限期仍丢失手指
    failed --> initial: reset
    completed --> initial: 停止或重新测量

准备中是一个真实状态

相机权限、会话配置、闪光灯预热、曝光稳定都不是瞬间完成的。如果界面直接进入测量,最开始几秒会被准备过程污染。MonoPump 保留 preparing 阶段,等相机链路就绪后才进入手指检测。

手指检测需要耐心

一帧好画面不代表手指放好了。MonoPump 会等待覆盖良好持续一段时间后才开始计时。这样可以保护测量窗口的开头,避免早期噪声在后面制造坏峰值。

Flow diagram Preparing diagram
View diagram source
flowchart TD
    A[覆盖变好] --> B[启动稳定计时]
    B --> C{延迟后仍然良好吗}
    C -- 否 --> D[继续引导]
    C -- 是 --> E[重置分析器并开始测量]

测量开始时重置分析器也是刻意的。找手指阶段的帧对 UI 有用,但不适合作为测量样本。

宽限期比立刻重置更像人

早期版本在手指移动时重置太快。技术上没错,体验上很烦。真实用户会调整握持,一个短宽限期可以让 App 容忍短暂坏片段,而不是假装整个测量都作废。

Sequence diagram Preparing diagram
View diagram source
sequenceDiagram
    participant F as 帧分析器
    participant D as Detector
    participant UI as UI
    F-->>D: 覆盖变差
    D->>D: 启动宽限计时器
    D-->>UI: 保持测量上下文
    F-->>D: 覆盖恢复
    D->>D: 取消宽限计时器
    D-->>UI: 继续测量

延长采集比快速失败更友好

如果计划时长结束,但置信度或质量还不够,MonoPump 可以在最大时长内继续采集。用户不用马上重来,App 也有硬上限,不会无限拖延。

Flow diagram Preparing diagram
View diagram source
flowchart LR
    A[达到计划测量时长] --> B{质量和置信度达标吗}
    B -- 是 --> C[完成]
    B -- 否 --> D{还没超过最大时长吗}
    D -- 是 --> E[延长采集]
    D -- 否 --> F[明确失败原因]

测量状态机不只是内部代码整洁。它决定用户看到什么、什么时候震动、什么时候关闪光灯、什么时候保存结果、什么时候诚实地失败。不要让单帧直接控制用户体验。帧输入状态,状态驱动 App。

来自 MonoWare

MonoPump 背后还有更多上下文。

打开产品网站,或继续阅读按 MonoPump 筛选的笔记。

通讯

隐私与产品工程笔记,偶尔发送。