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

해결책은 if를 더 붙이는 것이 아니었습니다. 측정을 버튼 동작이 아니라 상태 머신으로 보는 것입니다.
This diagram could not be rendered. Its source is still available below.
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는 좋은 덮임이 일정 시간 유지될 때까지 측정을 시작하지 않습니다.
This diagram could not be rendered. Its source is still available below.
View diagram source
flowchart TD
A[덮임이 좋아짐] --> B[안정 타이머 시작]
B --> C{지연 후에도 좋은가}
C -- no --> D[계속 안내]
C -- yes --> E[분석기 리셋 후 측정 시작]
유예 시간은 즉시 리셋보다 자연스럽다
초기 버전은 손가락이 움직이면 너무 빨리 리셋했습니다. 기술적으로는 맞지만 실제 사용에는 불편했습니다. 사람은 잡는 방식을 조정합니다. 짧은 유예 시간은 일시적인 나쁜 구간을 견디게 합니다.
This diagram could not be rendered. Its source is still available below.
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는 최대 시간까지 측정을 연장할 수 있습니다. 사용자가 바로 다시 시작하지 않아도 되고, 동시에 흐름이 끝없이 늘어나지도 않습니다.
This diagram could not be rendered. Its source is still available below.
View diagram source
flowchart LR
A[계획된 측정 시간 도달] --> B{품질과 신뢰도 통과?}
B -- yes --> C[완료]
B -- no --> D{최대 시간 미만?}
D -- yes --> E[수집 연장]
D -- no --> F[명확한 이유와 실패]
상태 머신은 내부 정리만이 아닙니다. 무엇을 보여 줄지, 언제 진동할지, 언제 플래시를 끌지, 언제 저장할지, 언제 실패를 말할지 결정합니다. 원시 프레임이 직접 UX를 움직이게 하지 않는다. 프레임은 상태로 들어가고, 상태가 앱을 움직입니다.