fix(posture): 걷기 초반 감지중 flash 제거 — UNKNOWN 시 tilt fallback

## 증상
걷기 시작 → 몇 초간 chip "감지중" 유지 → 그 후 "걷는중" 으로 전이.

## 원인
1. 걷기 발 임팩트로 순간 acc mag > 1.2g → classifier acc gate 실패 → UNKNOWN
2. Composite = UNKNOWN → 3연속 후 chip "감지중" 로 넘어감
3. Walking detector 는 6초 hold 진행 중이라 아직 IDLE
4. 6초 뒤 walking 발화 → chip "걷는중"

즉 6초 walking build-up 내내 chip "감지중" 이 뜨고 갑자기 "걷는중" 으로 점프.

## 수정
Composite 로직에서 UNKNOWN 발생 시 tilt(=r.pitchDeg) 로 fallback 판정.
- tilt > 25° (pitchLyingThreshold) → NON_LYING (upright 로 판정)
- tilt ≤ 25° → LYING

이유: tilt 는 acc gate 와 무관하게 항상 계산됨. 걷는 중 avg tilt 는 유효
(각 걸음의 upright 자세 반영). 정확한 pitch 는 어렵지만 lying vs upright
정도는 확신 가능.

## 결과 (예상)
걷기 시작 → chip 즉시 "일어서 있음" (NON_LYING) → 6초 walking hold 완료
후 "걷는중" 으로 전이. 감지중 flash 없음.

정지 자세 + 실제 오류 (acc mag 극단값 etc) 는 여전히 tilt 로 커버되므로
chip 은 최소한 LYING 또는 NON_LYING 을 표시. "감지중" 은 실질적으로 초기
1-2 cycle (buffer 부족) 에만 등장.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-07-03 11:13:23 +09:00
parent cd8b48a811
commit edece0ed14
@@ -779,9 +779,19 @@ fun PiezoMonitoringView(appState: AppState) {
val isWalkingNow = walkSnap.isWalking
// Composite posture — WALKING 이 UNKNOWN/NON_LYING 보다 우선 (자체 게이트 신뢰)
// 2026-07-03: acc gate 실패 (UNKNOWN) 시 tilt 로 tentative LYING/NON_LYING 결정.
// 왜: 걷기 임팩트로 acc mag > 1.2g → UNKNOWN → 걷는 초반 6초 (walking hold)
// 내내 "감지중" chip 이 뜨고, 그 후 갑자기 "걷는중" 으로 점프.
// tilt(=r.pitchDeg) 는 acc gate 와 무관하게 항상 계산되며, 걷기 중에도
// 평균 tilt 는 유효 → 최소한 upright 여부 (NON_LYING vs LYING) 는 신뢰 가능.
// Walking 6초 build-up 동안 chip 은 "일어서 있음" (NON_LYING) → 6초 뒤 "걷는중"
// 으로 자연스럽게 전이 (감지중 flash 제거).
val tiltFallback = if (kotlin.math.abs(r.pitchDeg) > com.medithings.vesiscan.managers.GreenZoneConstants.pitchLyingThreshold)
com.medithings.vesiscan.managers.Posture.NON_LYING
else com.medithings.vesiscan.managers.Posture.LYING
val composite = when {
isWalkingNow -> com.medithings.vesiscan.managers.Posture.WALKING
r.posture == com.medithings.vesiscan.managers.Posture.UNKNOWN -> com.medithings.vesiscan.managers.Posture.UNKNOWN
r.posture == com.medithings.vesiscan.managers.Posture.UNKNOWN -> tiltFallback
else -> r.posture // LYING or NON_LYING
}