Files
VesiscanClinicalAndroid/app/src/main/java/com/medithings/vesiscan/managers/AlgoMode.kt
T
dw.jang 441f249410 feat(algo): 미이식 3건 마저 이식 — post_tie_lock · sibeam · F83
레퍼런스에서 남겨 뒀던 세 가지를 옮겼다. 셋 다 레퍼런스 경로 전용이고 기존(현행
임상) 경로는 그대로다.

  · post_tie_lock  후벽 상위 두 후보의 score 가 구조적으로 붙는 구간(전 데이터
                   5773 결정 중 격차<10% 가 17.9%)에서 직전 trace 선택을 유지한다.
                   방향을 강제하지 않는다 — 깊은-peak 고정·인접 골 tie-break 은
                   전부 계통 편향을 낳았고, tie 밴드에서는 정의상 두 후보의 증거가
                   같기 때문이다. 상태기를 넘길 때만 동작하며, 레퍼런스도 streaming
                   strict pass 에서만 건다. streaming.py 이식 전까지 호출부는 없다.
  · _sibeam_cap_bounds  검출 채널이 정확히 2개일 때 미검출 이웃 빔까지의 SI 거리를
                   cap 상한으로. 2개뿐이면 끝 채널이 서로의 이웃이라 기존 top/bottom
                   clamp 가 성립하지 않아 cap 이 무제한 외삽된다. supine 은 건너뛴다.
  · F83            적도-밖 bottom cap 연속 보간(실리콘·supine). 전제인
                   mirror_bottom_cap 도 함께 옮겼다.

좌표계가 두 개라는 것을 확인했다

레퍼런스 cross_channel._z 는 sample_to_ap_depth 를 인자 없이 불러 교차채널 좌표가
언제나 모듈 기본값(1.936/6.85)으로 떨어진다. BV 는 프리셋 값을 명시로 넘긴다.
abs 는 두 값이 같아 표가 안 나지만 실리콘(1.897/7.651)에서는 갈린다 — 실측
f06/r1 단일 cycle 에서 CH0 전벽이 8 vs 14 로 갈려 439.88 vs 416.95 mL 이 됐다.
is_deep 판정이 34.209 > 34.042 처럼 아슬아슬한 자리라 작은 좌표 차가 선택을 뒤집는다.
의도인지 누락인지는 알고리즘팀 확인이 필요하다. 확인 전까지 레퍼런스와 같은 값을
내는 쪽을 택했고, 기존 경로는 프리셋 값을 그대로 쓴다.

missing_outside 의 null 과 빈 집합을 구분했다

null = 계산 안 함 → cap clamp 를 언제나 상한으로. 빈 집합 = 계산했고 '방광 밖'
채널이 없다 → 하한 쪽으로. ifEmpty { null } 로 뭉개면 "미검출이지만 span 은 있다"는
가장 흔한 경우에 si_floor 가 통째로 죽는다.

검증

  · 레퍼런스 대조 6종 전부 불일치 0 — tie 1568행(lock 24건) · 실데이터 BV 784행
    (nch=2 6건) · sibeam 120행(상한 102건) · 합성 BV 640행(mirror 226건) ·
    F83 blend 440행 · F83 apply 12행. 실데이터가 미러·nch=2 에 거의 안 닿아
    그 경로는 합성 입력으로 레퍼런스 함수를 직접 호출한 기대값으로 덮었다.
  · 기존 경로 무변경 — 44 cycle × CCC on/off 덤프가 HEAD 와 88행 전부 일치.
  · 전체 36개 통과 · demoDebug APK 빌드 성공.

LegacyEquivalenceDumpTest 가 PiezoHW.activePreset 을 명시로 고정하게 했다. 전역
가변 상태라 다른 테스트가 먼저 돌면 덤프가 통째로 달라진다 — 실제로 한 번 착시를
만들었다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 18:09:26 +09:00

52 lines
3.0 KiB
Kotlin

/*
* 알고리즘 경로 전환 — 기존(demo-final 현행) vs 레퍼런스(piezo-phantom-test 1:1).
*/
package com.medithings.vesiscan.managers
/**
* 검출·BV 알고리즘을 어느 쪽으로 돌릴지.
*
* ## 왜 두 경로를 유지하나
* demo-final 은 팬텀 시연과 임상 계측이 함께 도는 브랜치다. 여기서 "기존"이란
* **오늘 임상이 실제로 돌아간 코드**(커밋 `ebddc52`·`20a48ad` 시점의 검출·BV)를 말한다.
* 그 위에 신 저장소가 추가로 맞춘 레퍼런스 단계들은 값을 눈에 띄게 바꾸므로, 시연·계측이
* 모르는 사이 다른 알고리즘으로 도는 일이 없도록 **기본은 기존 경로**로 두고 레퍼런스
* 경로는 dev 패널에서 명시적으로 켤 때만 쓴다.
*
* ## 무엇이 갈리나
* 켜면 아래가 전부 레퍼런스 동작으로 바뀐다. 부분 적용은 없다 — 단계들이 서로를
* 전제하므로 섞으면 어느 쪽도 아닌 값이 나온다.
*
* · 교차채널 보정 3단계 → **7단계**
* (①.9 envelope · ① ant_tiebreak · ①.7 Λ-dip · ①.8 edge ·
* ①.95 lumen_return · ② NTV[Rule A 만] · ③ fp_gate,
* 기존의 `inward_post` 는 빠진다)
* · 파이프라인 `scale_recovery`(2) · `missing_outside` 증거 산출(4) ·
* `channel_confidence`→untrusted(5b) · `CONF_DEMOTE`(6)
* · 좌표계 교차채널 z 를 프리셋(실리콘 1.897/7.651) 대신 **전역 캘리브레이션**
* (1.936/6.85)으로 잰다 — 레퍼런스 `cross_channel._z` 가 그렇다.
* abs 는 값이 같아 표가 안 나고 실리콘에서만 갈린다.
* · nch=2 clamp `_sibeam_cap_bounds` — 채널이 2개뿐일 때 빔 기하로 cap 상한
* · 미러 · F83 `mirror_bottom_cap` + 적도-밖 bottom cap 연속 보간(실리콘·supine)
* · BV 극 cap 의 상한/하한을 관측 증거로 가르는 `si_floor`/`missing_outside`,
* bottom cap 제한 신설, 중앙 채널 보간 은행가 반올림,
* `adaptive_large_bladder_relax` 제거(cap 축 폴백을 가로막고 있었다)
*
* 검출 파라미터(`d_max` 15 · `inward_walk_win` 4)와 prominence 기준(`ANT_FLOOR_REF`),
* cap 축 폴백 · `ELLIPSE_CAP_R_MAX` · `TOP_CAP_EDGE_K` · `cap_d_adaptive`, 프리셋 유도
* dps/delay 는 **양쪽 공통**이다 — `ebddc52`/`20a48ad` 에서 이미 기존 경로에 들어갔고
* 오늘 임상이 그 위에서 돌았으므로 여기서 되돌리지 않는다.
*
* ## 상태 보관
* 프로세스 수명 동안만 유지한다(런타임 토글). 앱을 다시 켜면 기존 경로로 돌아간다.
*/
object AlgoMode {
/** true = 레퍼런스 1:1 경로. 기본은 false(기존 경로). */
@Volatile
var reference: Boolean = false
/** 화면에 표시할 이름. */
val label: String get() = if (reference) "레퍼런스 (Python 1:1)" else "기존 (현행 임상)"
}