모든 글

【TECH】차분한 심박 측정을 만드는 상태 머신

MonoPump가 측정을 단순한 카메라 시작/중지가 아니라 단계별 상태 머신으로 다루는 이유입니다.

상태 머신UXSwiftUIPPG
【TECH】차분한 심박 측정을 만드는 상태 머신

카메라 심박 앱에서 어려운 버그가 항상 수학 안에 있지는 않습니다. 많은 문제는 사용자 행동과 알고리즘 타이밍 사이에 있습니다. 사용자가 손가락을 반초 들어 올립니다. 카메라는 아직 안정화 중입니다. 결과가 보였다가 사라집니다.

맥박 측정 중인 스마트폰 옆에 상태 머신 스케치 노트가 놓인 모습
사용자 경험은 단일 원시 프레임이 아니라 안정된 상태에 의해 움직입니다.

해결책은 if를 더 붙이는 것이 아니었습니다. 측정을 버튼 동작이 아니라 상태 머신으로 보는 것입니다.

State diagram Preparing diagram
View diagram source
stateDiagram-v2
    [*] --> initial
    initial --> preparing: startDetection
    preparing --> detectingFinger: camera ready
    detectingFinger --> measuring: good coverage stays stable
    measuring --> calculating: duration and quality pass
    calculating --> completed: result accepted
    calculating --> failed: result rejected
    measuring --> detectingFinger: finger lost beyond grace period
    failed --> initial: reset
    completed --> initial: stop or new measurement

preparing은 실제 상태다

카메라 권한, 세션 구성, 플래시 워밍업, 노출 안정화는 즉시 끝나지 않습니다. UI가 바로 측정에 들어가면 처음 몇 초가 준비 과정으로 오염됩니다.

손가락 감지는 기다려야 한다

좋은 한 프레임만으로 손가락이 잘 놓였다고 할 수 없습니다. MonoPump는 좋은 덮임이 일정 시간 유지될 때까지 측정을 시작하지 않습니다.

Flow diagram Preparing diagram
View diagram source
flowchart TD
    A[덮임이 좋아짐] --> B[안정 타이머 시작]
    B --> C{지연 후에도 좋은가}
    C -- no --> D[계속 안내]
    C -- yes --> E[분석기 리셋 후 측정 시작]

유예 시간은 즉시 리셋보다 자연스럽다

초기 버전은 손가락이 움직이면 너무 빨리 리셋했습니다. 기술적으로는 맞지만 실제 사용에는 불편했습니다. 사람은 잡는 방식을 조정합니다. 짧은 유예 시간은 일시적인 나쁜 구간을 견디게 합니다.

Sequence diagram Preparing diagram
View diagram source
sequenceDiagram
    participant F as Frame analyzer
    participant D as Detector
    participant UI as UI
    F-->>D: coverage becomes bad
    D->>D: start grace timer
    D-->>UI: keep measurement context
    F-->>D: coverage recovers
    D->>D: cancel grace timer
    D-->>UI: continue measuring

빠른 실패보다 연장 측정이 낫다

계획된 시간이 끝났는데 품질이나 신뢰도가 부족하면 MonoPump는 최대 시간까지 측정을 연장할 수 있습니다. 사용자가 바로 다시 시작하지 않아도 되고, 동시에 흐름이 끝없이 늘어나지도 않습니다.

Flow diagram Preparing diagram
View diagram source
flowchart LR
    A[계획된 측정 시간 도달] --> B{품질과 신뢰도 통과?}
    B -- yes --> C[완료]
    B -- no --> D{최대 시간 미만?}
    D -- yes --> E[수집 연장]
    D -- no --> F[명확한 이유와 실패]

상태 머신은 내부 정리만이 아닙니다. 무엇을 보여 줄지, 언제 진동할지, 언제 플래시를 끌지, 언제 저장할지, 언제 실패를 말할지 결정합니다. 원시 프레임이 직접 UX를 움직이게 하지 않는다. 프레임은 상태로 들어가고, 상태가 앱을 움직입니다.

MonoWare에서

MonoPump에는 이 노트의 더 많은 맥락이 있습니다.

제품 사이트를 열거나 MonoPump로 필터된 노트를 계속 읽으세요.

뉴스레터

개인정보와 제품 엔지니어링 노트를 가끔 보내드립니다.