diff --git a/app/src/main/java/com/example/medilightv2android/managers/ImuPostureClassifier.kt b/app/src/main/java/com/example/medilightv2android/managers/ImuPostureClassifier.kt index e66b1f2..a7b7f31 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/ImuPostureClassifier.kt +++ b/app/src/main/java/com/example/medilightv2android/managers/ImuPostureClassifier.kt @@ -24,10 +24,13 @@ enum class Posture { UNKNOWN, LYING, NON_LYING } object ImuPostureClassifier { - // 게이트 임계값 — flowchart 그대로 + // 게이트 임계값 private const val ACC_MAG_MIN = 0.8f private const val ACC_MAG_MAX = 1.2f - private const val GYRO_MAG_MAX_DPS = 9.16f + // Gyro gate 비활성화 — 일부 디바이스의 gyro calibration bias (-25 dps 등) 가 + // flowchart 임계(9.16) 보다 커서 정지 상태에서도 fail → 분류 영구 불가. + // accel magnitude gate (0.8-1.2g) 가 이미 큰 모션 거름. gyro 게이트 제거. + // 단 dev 모드 디버그 위해 magnitude 는 계속 계산해 로그/Result 에 노출. /** 자세 + 진단 정보 (UI/log용). */ data class Result( @@ -60,10 +63,7 @@ object ImuPostureClassifier { return Result(Posture.UNKNOWN, 0f, accMag, gyroMag, "acc mag out of range (%.2f)".format(accMag)) } - if (gyroMag > GYRO_MAG_MAX_DPS) { - return Result(Posture.UNKNOWN, 0f, accMag, gyroMag, - "moving (gyro %.1f dps)".format(gyroMag)) - } + // Gyro gate 제거 — bias 큰 디바이스에서 영구 fail 문제 (위 주석 참조) val pitch = (atan(ax / sqrt(ay * ay + az * az)) * 180.0 / Math.PI).toFloat() val absPitch = abs(pitch) diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt index 9ad1682..c937c49 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt +++ b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt @@ -665,13 +665,19 @@ fun PiezoMonitoringView(appState: AppState) { currentPosture = com.example.medilightv2android.managers.Posture.LYING return@LaunchedEffect } + var unknownStreak = 0 bleManager.imuCollector.onComplete = { samples -> val r = com.example.medilightv2android.managers.ImuPostureClassifier.classify(samples) if (r.posture != com.example.medilightv2android.managers.Posture.UNKNOWN) { currentPosture = r.posture wakeupDetector.update(r.posture) + unknownStreak = 0 + } else { + unknownStreak++ + // 3회 연속 UNKNOWN 이면 화면에 표시 (silent stuck 방지) + if (unknownStreak >= 3) currentPosture = com.example.medilightv2android.managers.Posture.UNKNOWN } - Log.d("ImuDbg", "POSTURE ${r.posture} pitch=${"%.1f".format(r.pitchDeg)}° accMag=${"%.2f".format(r.accMag)}g gyro=${"%.1f".format(r.gyroMagDps)}dps (${r.reason}) samples=${samples.size}") + Log.d("ImuDbg", "POSTURE ${r.posture} pitch=${"%.1f".format(r.pitchDeg)}° accMag=${"%.2f".format(r.accMag)}g gyro=${"%.1f".format(r.gyroMagDps)}dps (${r.reason}) samples=${samples.size} unknownStreak=$unknownStreak") } bleManager.imuCollector.onLog = { msg -> Log.d("ImuDbg", "imuCollector log: $msg")