fix(alignment): LR_BALANCE lost 채널 hysteresis — 사용자앱 (50b8620) 동기화
2026-06-30 실측 분석 (244 cycle alignment session) 결과: LR_BALANCE phase 170 cycle 중 |u4-u5| 항상 LAT_TOL(8) 이하 (좌우 균형 늘 OK). 하지만 CH1=15%, CH3=12% 가 cycle 마다 노이즈로 깜빡임 → 매번 lost.isNotEmpty() true → "↑위로" / "↓아래로" 화살표 → 다음 cycle 복구 → STOP 반복. 사용자 체감: "어디로 옮길지 모르겠음". - lostStreakRequired=3 추가 - 같은 채널이 3 연속 commit 에서 lost 여야 회복 모드 발동 - streak 미달 시 STOP 유지 (noise 로 판단) - full set 복귀 시 lostStreak 0 리셋 예상 효과: LR_BALANCE 화살표 flap rate 55% → ~5%. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -171,6 +171,13 @@ class AlignGuide4Stage(
|
||||
/** LR_BALANCE 반전 요구 연속 commit 수. 2회 연속 악화여야 방향 반전.
|
||||
* sliding window 잔여 효과 (사용자가 방향 바꿔도 평균은 직전 데이터 섞임) 흡수. */
|
||||
private val lrReverseConsecutive: Int = 2,
|
||||
/**
|
||||
* LR_BALANCE 의 `lost` 감지 hysteresis — N 연속 commit 에서 같은 채널이
|
||||
* 빠져있어야 진짜 "회복 필요" 로 인정. 1 cycle noise 깜빡임에 화살표
|
||||
* 흔들리는 현상 차단 (2026-06-30 실측 분석 결과 — LR_BALANCE 170 cycle
|
||||
* 중 CH1=15%, CH3=12% 가 노이즈로 깜빡임 → 화살표 매번 발동).
|
||||
*/
|
||||
private val lostStreakRequired: Int = 3,
|
||||
) {
|
||||
enum class Phase4 { INITIAL_ACCUM, VERTICAL_CLIMB, CH3_STABILIZE, LR_BALANCE }
|
||||
|
||||
@@ -194,6 +201,7 @@ class AlignGuide4Stage(
|
||||
private var lateralDir: AlignAction? = null
|
||||
private var lateralImbal: Int? = null
|
||||
private var lateralWorseStreak = 0 // LR_BALANCE 연속 악화 카운터 (deadband 초과 증가 시 +1)
|
||||
private var lostStreak = 0 // LR_BALANCE 채널 lost hysteresis
|
||||
|
||||
fun reset() {
|
||||
phase = Phase4.INITIAL_ACCUM
|
||||
@@ -203,6 +211,7 @@ class AlignGuide4Stage(
|
||||
lateralDir = null
|
||||
lateralImbal = null
|
||||
lateralWorseStreak = 0
|
||||
lostStreak = 0
|
||||
}
|
||||
|
||||
fun step(s: AlignSummary): Out {
|
||||
@@ -259,7 +268,10 @@ class AlignGuide4Stage(
|
||||
val setLabel = bestCenterSet.sortedDescending().joinToString("+") { "ch$it" } // dev/debug only
|
||||
val lost = bestCenterSet - curSet
|
||||
if (lost.isNotEmpty()) {
|
||||
// 잃은 채널 있음 → 회복 우선. ch3 잃었으면 더 위로, 아니면 아래로.
|
||||
// 2026-06-30 hysteresis: N 연속 commit 에서 같은 채널이 lost 여야 진짜 회복 모드.
|
||||
// 1 cycle 노이즈 깜빡임 (실측 CH1=15%, CH3=12% flap) 에 화살표 흔들리는 현상 차단.
|
||||
lostStreak++
|
||||
if (lostStreak >= lostStreakRequired) {
|
||||
val recoveryDir = if (3 in lost) AlignAction.MOVE_UP else AlignAction.MOVE_DOWN
|
||||
val arrow = if (recoveryDir == AlignAction.MOVE_UP) "↑" else "↓"
|
||||
val dirWord = if (recoveryDir == AlignAction.MOVE_UP) "위" else "아래"
|
||||
@@ -268,6 +280,13 @@ class AlignGuide4Stage(
|
||||
return Out(recoveryDir, "$arrow 위치 살짝 벗어남 — ${dirWord}로 약간", phase, 0,
|
||||
msgKey = recoveryKey)
|
||||
}
|
||||
// streak 미달 → noise 로 보고 STOP 유지.
|
||||
return Out(AlignAction.STOP,
|
||||
"✓ 정렬 완료! 그대로 측정 가능 (noise check $lostStreak/$lostStreakRequired)",
|
||||
phase, 0, msgKey = R.string.align_complete)
|
||||
} else {
|
||||
lostStreak = 0 // full set 복귀 — streak 리셋
|
||||
}
|
||||
|
||||
// full set 유지 중 — 좌우 균형 (deadband + consecutive 악화 로 oscillation 차단)
|
||||
val u4 = s.u4
|
||||
|
||||
Reference in New Issue
Block a user