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>
This commit is contained in:
@@ -69,7 +69,10 @@ object ImuPostureClassifier {
|
|||||||
val absPitch = abs(pitch)
|
val absPitch = abs(pitch)
|
||||||
val thr = GreenZoneConstants.pitchLyingThreshold
|
val thr = GreenZoneConstants.pitchLyingThreshold
|
||||||
|
|
||||||
val posture = if (absPitch > thr) Posture.LYING else Posture.NON_LYING
|
// Pitch 의미: AX 가 중력과 일치할수록 큰 값 (≈90°), AZ 가 중력과 일치하면 작은 값 (≈0°).
|
||||||
|
// 사용자 직관: 센서 평평하게 둠 (AZ up) = LYING, 세움 (AX up) = NON_LYING (upright).
|
||||||
|
// → 작은 pitch → LYING, 큰 pitch → NON_LYING
|
||||||
|
val posture = if (absPitch <= thr) Posture.LYING else Posture.NON_LYING
|
||||||
return Result(posture, pitch, accMag, gyroMag, "ok")
|
return Result(posture, pitch, accMag, gyroMag, "ok")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-1
@@ -1791,7 +1791,7 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Text("${pitchThrVal.toInt()}°", fontSize = 13.sp, fontWeight = FontWeight.Bold, color = MlPrimary)
|
Text("${pitchThrVal.toInt()}°", fontSize = 13.sp, fontWeight = FontWeight.Bold, color = MlPrimary)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Text("|pitch|>${pitchThrVal.toInt()}°→Lying", fontSize = 11.sp, color = MlSecondaryText)
|
Text("|pitch|≤${pitchThrVal.toInt()}°→Lying", fontSize = 11.sp, color = MlSecondaryText)
|
||||||
}
|
}
|
||||||
Slider(
|
Slider(
|
||||||
value = pitchThrVal,
|
value = pitchThrVal,
|
||||||
@@ -1800,6 +1800,29 @@ fun PiezoMonitoringView(appState: AppState) {
|
|||||||
steps = 11,
|
steps = 11,
|
||||||
colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)
|
colors = SliderDefaults.colors(thumbColor = MlPrimary, activeTrackColor = MlPrimary)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
||||||
|
|
||||||
|
// Wakeup Alarm toggle (Personalization 페이지 와 동일 prefs)
|
||||||
|
var wakeupEnabled by remember {
|
||||||
|
mutableStateOf(com.example.medilightv2android.services.WakeupAlarmPrefs.isEnabled(context))
|
||||||
|
}
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text("기상 알람", fontSize = labelSize, fontWeight = FontWeight.SemiBold)
|
||||||
|
Text("일어남 감지 시 빨간 팝업",
|
||||||
|
fontSize = 11.sp, color = MlSecondaryText)
|
||||||
|
}
|
||||||
|
Switch(
|
||||||
|
checked = wakeupEnabled,
|
||||||
|
onCheckedChange = {
|
||||||
|
wakeupEnabled = it
|
||||||
|
com.example.medilightv2android.services.WakeupAlarmPrefs.setEnabled(context, it)
|
||||||
|
},
|
||||||
|
colors = SwitchDefaults.colors(checkedTrackColor = Color(0xFFD32F2F))
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding))
|
||||||
|
|||||||
Reference in New Issue
Block a user