Commit Graph

6 Commits

Author SHA1 Message Date
dw.jang 6bf399c7b9 fix(walking): chained failure — acc gate fail 시 walking 잃던 버그
증상: 로그캣 분석 — 활발히 걷는 중 (accMag > 1.2g) 일수록 화면에 안 보임.
  11:24:03 NON_LYING → WALKING 성공
  11:24:04 accMag=1.80 → UNKNOWN, walking 도 grace 들어감
  11:24:05 grace 2초 초과 → walking 종료
  → 활발 보행 = 가장 위험한 순간에 알람 사라짐 (정반대)

원인 두 가지:
  1) Classifier 가 acc gate fail 시 pitch=0 반환
     → WalkingDetector 가 pitch=0 받아서 pitchOk=false → grace 진입
  2) Composite 로직: r.posture==UNKNOWN 이면 WALKING 무시하고 UNKNOWN 표시

수정:
  1) ImuPostureClassifier: pitch 계산을 acc gate 이전으로 옮김
     → UNKNOWN Result 에도 실제 pitch 값 포함
     → WalkingDetector 가 정확한 pitch 로 grace 판단 가능

  2) PiezoMonitoringView composite 순서 변경:
     when {
       isWalkingNow -> WALKING          // 우선 (자체 게이트 신뢰)
       r.posture==UNKNOWN -> UNKNOWN
       else -> r.posture
     }
     walking detector 가 walking 이라고 하면 acc gate 실패해도 표시.
     walking 자체에 시간/wmean/wstd 게이트 있어 false-positive 거의 없음.

테스트 시나리오:
  정지 lying → 흔들면서 걷기 (pitch>45°) → walking 검출 → 격하게 흔들기
  (accMag>1.2g) 도 → "Walking" 계속 표시 + 빨간 팝업 유지.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-24 11:27:58 +09:00
dw.jang ecdec7c97c feat(posture): Walking detector (flowchart Path B) + 2단계 알람
새 flowchart 의 walking 검출 추가:

1) Posture enum: UNKNOWN/LYING/NON_LYING + **WALKING** (4-state)

2) WalkingDetector.kt 신규 (flowchart Path B 구현)
   - Sliding window (default 1.5초) buffer 에 gyro magnitude 누적
   - 매 cycle 마다 wmean (이동평균) + wstd (이동표준편차) 계산
   - State machine:
     IDLE → WALKING:
       |pitch| > 45° AND wmean > 4 AND wstd > 2
       → 1초 이상 연속 만족 시 전이
     WALKING → IDLE:
       |pitch| > 45° AND wmean > 2
       → 미달 후 2초 grace 지나면 전이

3) GreenZoneConstants 에 walking 임계 7개 추가 (모두 dev 조정 가능):
   - walkingMinPitchDeg=45, walkingStartWmean=4, walkingStartWstd=2,
     walkingStartHoldMs=1000, walkingKeepWmean=2, walkingKeepHoldMs=2000,
     walkingWindowMs=1500

4) PiezoMonitoring:
   - walkingDetector 인스턴스
   - imuCollector.onComplete: classifier + detector 동시 호출,
     composite posture (WALKING > NON_LYING > LYING) 결정
   - NON_WALKING → WALKING 전이 시 critical 알람 trigger

5) UI:
   - 상단 status bar: Walking 아이콘 (DirectionsWalk, 빨강) 추가
   - 기존 wakeup 팝업 색: 빨강 → 주황 (warning level)
   - 신규 walking 팝업: 빨강 + DirectionsWalk + "환자가 걷고 있습니다 — fall risk"

6) Dev settings: walking 임계 슬라이더 4개 추가
   (Min Pitch / Start Wmean / Start Wstd / Keep Wmean)
   sliding window / hold 시간은 default 유지 (필요 시 추가)

2단계 알람 체계 (의료적):
  - 주황 (warning): LYING N초 → NON_LYING/WALKING 전이 (일어남 감지)
  - 빨강 (critical): NON_WALKING → WALKING 전이 (보행 시작 — fall risk 최고)

Tag phase2-pre-walking (28a8769) 이전 상태로 복원 가능.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-24 10:28:43 +09:00
dw.jang a175540291 fix(posture): pitch 분류 invert + PiezoMonitoring 설정에도 기상 알람 토글
증상 1: 디바이스 평평하게 둠 → "Upright" / 세움 → "Lying" (또는 기존 빌드의
        "Sitting") 으로 사용자 직관과 반대.

진단: 사용자 raw 데이터 분석
  - 평평 (AZ dominant, AZ ≈ 1g): pitch ≈ 0° → 코드가 NON_LYING (Upright) 반환
  - 세움 (AX dominant, AX ≈ 1g): pitch ≈ 80~90° → 코드가 LYING 반환
  사용자 직관: 평평=Lying, 세움=Upright → 코드 inversion.

수정 1: ImuPostureClassifier 의 분류 조건 invert
  - 기존: |pitch| > threshold → LYING
  - 신규: |pitch| ≤ threshold → LYING (작은 pitch = AZ 가 중력 = 센서 평평)
  - dev slider hint 도 "|pitch|≤N°→Lying" 으로 동기화

수정 2: PiezoMonitoring 의 dev settings overlay 에도 기상 알람 토글 추가
  - 기존: PiezoPersonalizationView 에만 존재
  - 신규: dev settings panel (Pitch Threshold slider 아래) 에 동일 토글
  - 두 위치 모두 같은 WakeupAlarmPrefs 사용 — sync 됨
  - 사용자가 monitoring 페이지에서 바로 켜고 끌 수 있음

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-23 17:39:46 +09:00
dw.jang 9a5fa16f94 fix(posture): gyro gate 제거 + UNKNOWN streak 화면 표시
증상: 디바이스를 lying 상태로 둬도 "Upright" 표시가 안 바뀜.

진단 (raw 로그 분석):
  - 디바이스 정지 상태에서도 gyro y 축 ≈ -25 dps 일관 표시
  - 이는 IMU 칩의 **calibration bias** (정지 시 zero offset 안 됨)
  - flowchart 의 gyro gate (9.16 dps) 가 항상 fail → classifier 영구 UNKNOWN
  - currentPosture 가 UNKNOWN 시 업데이트 안 되는 로직 때문에 첫 valid
    값 (NON_LYING, 사용자가 손에 들고 진입한 순간) 으로 stuck
  - 사용자가 눕혀도 분류 자체가 안 되니 "Upright" 그대로

수정:
  1) ImuPostureClassifier: gyro gate 제거
     - accel magnitude gate (0.8-1.2g) 가 큰 모션은 이미 거름
     - gyro magnitude 는 Result/log 에 계속 노출 (디버그용)
     - flowchart 그대로 따르려면 gyro 도 활용해야 하지만, bias 큰
       디바이스에선 무용지물이라 실용성 우선

  2) PiezoMonitoringView: UNKNOWN streak 카운터
     - 3회 연속 UNKNOWN 이면 currentPosture = UNKNOWN 으로 강제 표시
     - silent stuck 상태 (잘못된 자세 계속 보여줌) 방지
     - 잠시 1-2 cycle 동안 motion artifact 로 UNKNOWN 떠도 직전
       자세 유지 (이전 동작 보존)

  3) Log: unknownStreak 도 출력 → 디버그 시 stuck 케이스 가시화

테스트:
  - lying → upright 전환 시 즉시 "Upright" 표시되어야 함
  - 정지 시 "Lying" 또는 "Upright" 안정적 유지
  - 큰 모션 (들어올림 등) 중에는 3 cycle 후 "—" 표시

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-23 17:25:58 +09:00
dw.jang af469558e6 feat(posture): Phase 2 — 기상 알람 (LYING/NON_LYING + Settings 토글 + 빨간 팝업)
요구사항: 설정 탭에서 알람 on/off → on 상태에서 일어남 감지 시 빨간 팝업.

변경:

1) ImuPostureClassifier 2-state 단순화
   - 기존: SUPINE/SITTING/STANDING (3 state)
   - 신규: LYING / NON_LYING (2 state) + UNKNOWN
   - sitting/standing 구분 불필요 (낙상 예방엔 "누웠나/일어났나" 만 중요)
   - 분류: |pitch| > threshold → LYING, ≤ → NON_LYING

2) GreenZoneConstants.pitchLyingThreshold (default 25°)
   - @Volatile var — runtime 변경 가능
   - dev 모드 설정에서 slider 로 조정 (10~70°, 11 steps)

3) WakeupAlarmPrefs — SharedPreferences 저장
   - isEnabled (default false)
   - lyingDurationSec (default 180 = 3분)

4) WakeupDetector — state machine
   - LYING 진입 시 timestamp 기록
   - LYING → NON_LYING 전이 시 elapsed 측정
   - elapsed ≥ lyingDurationSec 이면 onWakeup 콜백
   - 1회 발동 후 LYING 복귀까지 재무장 안 됨 (스팸 방지)
   - UNKNOWN 은 무시 (motion artifact 흔들림 영향 X)

5) PiezoMonitoringView
   - posture 아이콘 매핑 LYING (Hotel, 파랑) / NON_LYING (AccessibilityNew, 초록) / UNKNOWN
   - imuCollector.onComplete 콜백에서 wakeupDetector.update(posture) 호출
   - showWakeupAlarm Boolean state + 빨간 Dialog (Color 0xFFD32F2F)
     · Warning 아이콘 + "환자가 일어났습니다" 메세지
     · 누운 시간 표시
     · 확인 버튼 (사용자 dismiss 필수, 자동 닫힘 X)
     · dismissOnBackPress/ClickOutside = false (실수 dismiss 방지)
   - Demo 모드: posture LYING 고정 (BLE 없음)

6) PiezoPersonalizationView — WakeupAlarmCard 신규
   - 빨간 톤 카드 + Switch
   - "기상 알람 — 환자가 일어나면 빨간 팝업으로 알림 (낙상 예방)"
   - 토글 즉시 WakeupAlarmPrefs.setEnabled

7) Dev 설정 (PiezoMonitoringView 의 dev panel)
   - "Pitch Threshold" 슬라이더 추가 (10°~70°)
   - GreenZoneConstants.pitchLyingThreshold 직접 조정
   - 실시간 반영 — 다음 cycle 부터 적용

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-23 17:17:58 +09:00
dw.jang cf476971a5 feat(posture): Phase 1 — flowchart 기반 자세 분류 + 도넛 우상단 아이콘 (demo-final)
allignment flowchart "Posture classification" 알고리즘 적용. Phase 1
범위: 자세 분류 + 화면 표시만 (알람/감지 없음).

1) ImuPostureClassifier.kt 신규
   flowchart 단계 그대로:
   - Acc magnitude 게이트: 0.8 ≤ |a| ≤ 1.2 (motion/bad reject)
   - Gyro magnitude 게이트: |g| ≤ 9.16 dps (회전 reject)
   - Pitch = atan(ax / sqrt(ay² + az²)) × 180/π
   - 분류:
     · |pitch| < 25°  → SUPINE
     · 25-70°         → SITTING
     · > 70°          → STANDING
   - 게이트 실패 시 UNKNOWN + 사유 반환
   - 입력: ImuSample 리스트 (한 응답 15 sample 평균)
   ※ flowchart 의 "|pitch| > 25; supine" 는 typo 로 판단 → < 25 적용

2) PiezoMonitoringView IMU polling 추가
   - 5초 주기로 sendImuQuery() → rim: 응답 → classifier
   - UNKNOWN 결과 시 직전 자세 유지 (artifact 흔들림 방지)
   - demo mode: SUPINE 으로 fix (BLE 없음)

3) 도넛 차트 우상단 자세 아이콘 표시 (Battery 옆)
   - SUPINE   → Icons.Hotel (파랑)
   - SITTING  → Icons.AirlineSeatReclineNormal (주황)
   - STANDING → Icons.AccessibilityNew (초록)
   - UNKNOWN  → Icons.HelpOutline (회색)
   - 아이콘 + 텍스트 라벨 (Lying/Sitting/Standing/—)

Phase 2 (다음): Settings 토글 + wake-up state machine + 빨간 팝업.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-23 12:24:22 +09:00