From fcdce12503393738a60d8691e48455a1a958dfaf Mon Sep 17 00:00:00 2001 From: jjangddu Date: Wed, 15 Jul 2026 14:47:27 +0900 Subject: [PATCH] =?UTF-8?q?fix(alignment):=20V3=20buildRecord=20BV=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=95=84=ED=84=B0=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20=E2=80=94=20Python=201:1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Python `position_records:151` 는 `if bv is not None: bvs.append(float(bv.volume_ml))` 으로 nan/0 필터 없이 그대로 추가. nan 발생 시 std/mean 모두 nan → bv_cv=nan 이 되어 `selectCm` tie 정렬에서 +inf 로 취급 (뒷순위). 기존 Kotlin 은 `if (volumeMl.isFinite() && volumeMl > 0)` 필터가 있어 nan/0 케이스에서 Python 과 다른 bv_cv 산출. cm=0 (BV 발산) 처럼 일부 trace 만 이상값일 때 값 오차 발생. Rule A 최종 선택 결과는 동일하지만 line-by-line 대조에서 유일하게 차이나는 지점이라 Python 과 완전 일치하도록 제거. BV null (검출 실패) 은 여전히 skip (Python 도 동일). mean/std 결과가 nan/inf 이면 bvCv=null 로 정규화 (Python nan 표현 = Kotlin null). --- .../vesiscan/managers/AlignmentAdvisorV3.kt | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/medithings/vesiscan/managers/AlignmentAdvisorV3.kt b/app/src/main/java/com/medithings/vesiscan/managers/AlignmentAdvisorV3.kt index 3a369b3..05d6ca1 100644 --- a/app/src/main/java/com/medithings/vesiscan/managers/AlignmentAdvisorV3.kt +++ b/app/src/main/java/com/medithings/vesiscan/managers/AlignmentAdvisorV3.kt @@ -197,16 +197,25 @@ class CenterAligner( r?.let { Pair(it.ant, it.post) } } val bv = estimateBladderVolume6ch(allWalls) - bv?.volumeMl?.let { if (it.isFinite() && it > 0) bvs.add(it) } + // Python `position_records`: `if bv is not None: bvs.append(float(bv.volume_ml))` + // nan/0 필터 없이 그대로 추가. nan 발생 시 std/mean 모두 nan → bv_cv=null → + // `selectCm` tie 정렬에서 +inf 로 취급되어 뒷순위로 밀림 (Python 과 동일 동작). + bv?.let { bvs.add(it.volumeMl) } } + // Python: `float(np.std(bvs) / np.mean(bvs)) if len(bvs)>=2 and np.mean(bvs) else nan` + // nan 이 하나라도 있으면 std/mean 모두 nan → 결과 nan (Kotlin: null). val bvCv: Double? = if (bvs.size >= 2) { val m = bvs.average() - if (m != 0.0) { + if (m != 0.0 && m.isFinite()) { val sd = sqrt(bvs.map { (it - m) * (it - m) }.average()) - sd / m + val cv = sd / m + if (cv.isFinite()) cv else null } else null } else null - val meanBv = if (bvs.isNotEmpty()) bvs.average() else null + val meanBv = if (bvs.isNotEmpty()) { + val m = bvs.average() + if (m.isFinite()) m else null + } else null return AlignPositionRecord( alignCm = cm, nch = nch, ch3Detected = ch3Detected,