ux(alignment v2): hint 문구를 사용자 행동 중심으로 — ch 기술용어 제거
V2 algorithm hint 만 수정 (V1 그대로): - INITIAL_ACCUM: '측정 준비 중' → '잠시 그대로 두세요' - VERTICAL_CLIMB: '↑ 위로 (ch3 미검출)' → '↑ 위로 조금씩 올리세요' - CH3_STABILIZE hold: '✓ ch3 검출! 위치 유지' → '✓ 좋아요! 그 위치 유지' - CH3_STABILIZE lost: '↑ ch3 다시 잃음 — 위로' → '↑ 살짝 놓침 — 다시 위로' - LR_BALANCE lost: '↑ chN 잃음 — 위치 회복' → '↑ 위치 살짝 벗어남 — 위로 약간' - LR_BALANCE done: '■ 정렬 완료 (ch1+ch2..., |Δ|=N)' → '✓ 정렬 완료! 그대로 측정 가능' - LR_BALANCE LR: '← chN 유지 + 좌우 균형 (|Δ|=N)' → '← 왼쪽으로 살짝' (or 오른쪽) - LR_BALANCE probe: '↔ ch... 좌우 천천히 (lateral 미검출)' → '↔ 좌우로 천천히 움직여 보세요' PlacementGuideView 의 V2-only baseline 메시지: - waitingForStart V2 branch: '센서를 치골 위에 두고 Start 를 누르세요' 원본 ch/Δ/setLabel 같은 임상 메타는 dev debug log (ALIGN_V2 ...) 로만 유지. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -190,7 +190,7 @@ class AlignGuide4Stage(
|
|||||||
if (phase == Phase4.INITIAL_ACCUM) {
|
if (phase == Phase4.INITIAL_ACCUM) {
|
||||||
initialCount++
|
initialCount++
|
||||||
if (initialCount < initialTarget) {
|
if (initialCount < initialTarget) {
|
||||||
return Out(null, "측정 준비 중... (${initialCount}/${initialTarget})",
|
return Out(null, "잠시 그대로 두세요 (${initialCount}/${initialTarget})",
|
||||||
phase, initialCount)
|
phase, initialCount)
|
||||||
}
|
}
|
||||||
phase = Phase4.VERTICAL_CLIMB
|
phase = Phase4.VERTICAL_CLIMB
|
||||||
@@ -199,7 +199,7 @@ class AlignGuide4Stage(
|
|||||||
// === Phase 2: VERTICAL_CLIMB ===
|
// === Phase 2: VERTICAL_CLIMB ===
|
||||||
if (phase == Phase4.VERTICAL_CLIMB) {
|
if (phase == Phase4.VERTICAL_CLIMB) {
|
||||||
if (!s.ch3) {
|
if (!s.ch3) {
|
||||||
return Out(AlignAction.MOVE_UP, "↑ 위로 조금씩 올리세요 (ch3 미검출)",
|
return Out(AlignAction.MOVE_UP, "↑ 위로 조금씩 올리세요",
|
||||||
phase, 0)
|
phase, 0)
|
||||||
}
|
}
|
||||||
phase = Phase4.CH3_STABILIZE
|
phase = Phase4.CH3_STABILIZE
|
||||||
@@ -215,12 +215,12 @@ class AlignGuide4Stage(
|
|||||||
// ch3 잃었으면 → VERTICAL_CLIMB 회귀
|
// ch3 잃었으면 → VERTICAL_CLIMB 회귀
|
||||||
phase = Phase4.VERTICAL_CLIMB
|
phase = Phase4.VERTICAL_CLIMB
|
||||||
stabilizeCount = 0
|
stabilizeCount = 0
|
||||||
return Out(AlignAction.MOVE_UP, "↑ ch3 다시 잃음 — 위로",
|
return Out(AlignAction.MOVE_UP, "↑ 살짝 놓침 — 다시 위로",
|
||||||
phase, 0)
|
phase, 0)
|
||||||
}
|
}
|
||||||
if (stabilizeCount < stabilizeTarget) {
|
if (stabilizeCount < stabilizeTarget) {
|
||||||
return Out(AlignAction.STOP,
|
return Out(AlignAction.STOP,
|
||||||
"✓ ch3 검출! 위치 유지 (${stabilizeCount}/${stabilizeTarget})",
|
"✓ 좋아요! 그 위치 유지 (${stabilizeCount}/${stabilizeTarget})",
|
||||||
phase, stabilizeCount)
|
phase, stabilizeCount)
|
||||||
}
|
}
|
||||||
phase = Phase4.LR_BALANCE
|
phase = Phase4.LR_BALANCE
|
||||||
@@ -228,14 +228,14 @@ class AlignGuide4Stage(
|
|||||||
|
|
||||||
// === Phase 4: LR_BALANCE ===
|
// === Phase 4: LR_BALANCE ===
|
||||||
if (curSet.size > bestCenterSet.size) bestCenterSet = curSet
|
if (curSet.size > bestCenterSet.size) bestCenterSet = curSet
|
||||||
val setLabel = bestCenterSet.sortedDescending().joinToString("+") { "ch$it" }
|
val setLabel = bestCenterSet.sortedDescending().joinToString("+") { "ch$it" } // dev/debug only
|
||||||
val lost = bestCenterSet - curSet
|
val lost = bestCenterSet - curSet
|
||||||
if (lost.isNotEmpty()) {
|
if (lost.isNotEmpty()) {
|
||||||
// 잃은 채널 있음 → 회복 우선. ch3 잃었으면 더 위로, 아니면 아래로.
|
// 잃은 채널 있음 → 회복 우선. ch3 잃었으면 더 위로, 아니면 아래로.
|
||||||
val recoveryDir = if (3 in lost) AlignAction.MOVE_UP else AlignAction.MOVE_DOWN
|
val recoveryDir = if (3 in lost) AlignAction.MOVE_UP else AlignAction.MOVE_DOWN
|
||||||
val lostLabel = lost.sortedDescending().joinToString(",") { "ch$it" }
|
|
||||||
val arrow = if (recoveryDir == AlignAction.MOVE_UP) "↑" else "↓"
|
val arrow = if (recoveryDir == AlignAction.MOVE_UP) "↑" else "↓"
|
||||||
return Out(recoveryDir, "$arrow $lostLabel 잃음 — 위치 회복", phase, 0)
|
val dirWord = if (recoveryDir == AlignAction.MOVE_UP) "위" else "아래"
|
||||||
|
return Out(recoveryDir, "$arrow 위치 살짝 벗어남 — ${dirWord}로 약간", phase, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// full set 유지 중 — 좌우 균형 (deadband + consecutive 악화 로 oscillation 차단)
|
// full set 유지 중 — 좌우 균형 (deadband + consecutive 악화 로 oscillation 차단)
|
||||||
@@ -245,7 +245,7 @@ class AlignGuide4Stage(
|
|||||||
val imbal = kotlin.math.abs(u4 - u5)
|
val imbal = kotlin.math.abs(u4 - u5)
|
||||||
if (imbal <= latTol) {
|
if (imbal <= latTol) {
|
||||||
return Out(AlignAction.STOP,
|
return Out(AlignAction.STOP,
|
||||||
"■ 정렬 완료 ($setLabel 유지, |Δ|=$imbal)", phase, 0)
|
"✓ 정렬 완료! 그대로 측정 가능", phase, 0)
|
||||||
}
|
}
|
||||||
if (lateralDir == null) {
|
if (lateralDir == null) {
|
||||||
// 첫 진입 — u4/u5 비교로 방향 추정
|
// 첫 진입 — u4/u5 비교로 방향 추정
|
||||||
@@ -269,12 +269,11 @@ class AlignGuide4Stage(
|
|||||||
}
|
}
|
||||||
lateralImbal = imbal
|
lateralImbal = imbal
|
||||||
val arrow = if (lateralDir == AlignAction.MOVE_LEFT) "←" else "→"
|
val arrow = if (lateralDir == AlignAction.MOVE_LEFT) "←" else "→"
|
||||||
return Out(lateralDir!!, "$arrow $setLabel 유지 + 좌우 균형 (|Δ|=$imbal)",
|
val sideWord = if (lateralDir == AlignAction.MOVE_LEFT) "왼쪽" else "오른쪽"
|
||||||
phase, 0)
|
return Out(lateralDir!!, "$arrow ${sideWord}으로 살짝", phase, 0)
|
||||||
}
|
}
|
||||||
// u4/u5 미검출 → probe
|
// u4/u5 미검출 → probe
|
||||||
return Out(AlignAction.PROBE_LR, "↔ $setLabel 유지 + 좌우 천천히 (lateral 미검출)",
|
return Out(AlignAction.PROBE_LR, "↔ 좌우로 천천히 움직여 보세요", phase, 0)
|
||||||
phase, 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -351,8 +351,10 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
val rawHint = buildString {
|
val rawHint = buildString {
|
||||||
val hint = directionHint.ifEmpty { " " }
|
val hint = directionHint.ifEmpty { " " }
|
||||||
append(hint)
|
append(hint)
|
||||||
|
// 점 ... 애니메이션 — 알고리즘 진행 중인 메시지에 점 추가.
|
||||||
if (hint.startsWith("Slide") || hint.startsWith("Optimizing") ||
|
if (hint.startsWith("Slide") || hint.startsWith("Optimizing") ||
|
||||||
hint.startsWith("Checking") || hint.startsWith("Adjust")) {
|
hint.startsWith("Checking") || hint.startsWith("Adjust") ||
|
||||||
|
hint.contains("이동") || hint.contains("천천히") || hint.contains("그대로")) {
|
||||||
append(dots)
|
append(dots)
|
||||||
}
|
}
|
||||||
if (appState.isDevMode && !lastCv.isNaN()) {
|
if (appState.isDevMode && !lastCv.isNaN()) {
|
||||||
@@ -859,7 +861,7 @@ fun PlacementGuideView(appState: AppState) {
|
|||||||
// Clinical alignment session + waitingForStart 일 땐 알고리즘 skip —
|
// Clinical alignment session + waitingForStart 일 땐 알고리즘 skip —
|
||||||
// baseline cycles 만 누적 (Start 누르기 전 자동 phase 진행 차단).
|
// baseline cycles 만 누적 (Start 누르기 전 자동 phase 진행 차단).
|
||||||
if (waitingForStart) {
|
if (waitingForStart) {
|
||||||
directionHint = "Place sensor above pubic bone, then press Start"
|
directionHint = "센서를 치골 위에 두고 Start 를 누르세요"
|
||||||
directionIcon = ""
|
directionIcon = ""
|
||||||
placementScore = 0
|
placementScore = 0
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user