From cd3efc5f2425fd009eb81acc609f2f15ec29254c Mon Sep 17 00:00:00 2001 From: jjangddu Date: Wed, 1 Jul 2026 11:18:57 +0900 Subject: [PATCH] =?UTF-8?q?feat(bv):=20=EB=8D=B0=EB=AA=A8=20lr=5Fratio=5Fo?= =?UTF-8?q?verride=3D1.0=20default=20=E2=80=94=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=EC=95=B1=20(1add642)=20=EB=8F=99=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit algorithm 팀 최신 표준 (piezophantomtest 4830e7c) 반영. - GreenZoneConstants.lrRatioOverride: Double? = 1.0 추가 (default 1.0) - estimateBladderVolume6ch — override 있으면 computeLrRatio 스킵 - Dev panel toggle "lr=1.0 fixed" — ON/OFF 로 fixed vs computed 전환 Phantom 검증 (2533 scans, 150 mL): - APP (기존): 147.6 mL (-1.6%) ✓ - Config F (Python NEW lib + lr=1.0): 147.3 mL (-1.8%) ← 완전 동일 Co-Authored-By: Claude Opus 4.7 --- .../managers/GreenZoneConstants.kt | 11 +++++++++++ .../managers/PiezoBVEstimator.kt | 5 ++++- .../ui/views/monitoring/PiezoMonitoringView.kt | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/example/medilightv2android/managers/GreenZoneConstants.kt b/app/src/main/java/com/example/medilightv2android/managers/GreenZoneConstants.kt index e5376eb..282ea23 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/GreenZoneConstants.kt +++ b/app/src/main/java/com/example/medilightv2android/managers/GreenZoneConstants.kt @@ -41,6 +41,17 @@ object GreenZoneConstants { @Volatile var detectionMethod: DetectionMethod = DetectionMethod.METHOD_C @Volatile var bvMethod: BvMethod = BvMethod.V41 + + /** + * lr_ratio 강제 override (algorithm 팀 최신 표준: piezophantomtest 4830e7c). + * - null : computed (기존 Python `compute_lr_ratio` 알고리즘) + * - Double : 강제 값 (algorithm 팀 default = 1.0) + * + * Phantom 실측 검증: computed lr=0.68 → BV -38%. lr=1.0 fixed → -1.6% (APP 일치). + * 6채널 hardware LR 분해능 한계로 computed lr 신뢰도 낮음. Dev toggle 전환 가능. + */ + @Volatile var lrRatioOverride: Double? = 1.0 + @Volatile var placementGuideMode: PlacementGuideMode = PlacementGuideMode.SIMPLE @Volatile var alignmentAlgo: AlignmentAlgo = AlignmentAlgo.V1 // default V1 (일반 사용자). V2 (Method D) 는 clinical alignment session 전용. diff --git a/app/src/main/java/com/example/medilightv2android/managers/PiezoBVEstimator.kt b/app/src/main/java/com/example/medilightv2android/managers/PiezoBVEstimator.kt index 3c173ac..9bc385d 100644 --- a/app/src/main/java/com/example/medilightv2android/managers/PiezoBVEstimator.kt +++ b/app/src/main/java/com/example/medilightv2android/managers/PiezoBVEstimator.kt @@ -398,7 +398,10 @@ fun estimateBladderVolume6ch( var centerWalls = PiezoHW.centerCh.map { if (it < allWalls.size) allWalls[it] else null } centerWalls = repairCenterWallsFor6ch(centerWalls) val lateralWalls = PiezoHW.lateralCh.map { if (it < allWalls.size) allWalls[it] else null } - val lrRatio = computeLrRatio(centerWalls, lateralWalls, sensorZMm = PiezoHW.sensorZMmAll) + // 2026-07-01: algorithm 팀 최신 표준 (piezophantomtest 4830e7c) — lr_ratio_override=1.0 + // Phantom 검증: computed lr 은 6채널 HW 한계로 -38% 오차. Dev panel 로 전환 가능. + val lrRatio = com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride + ?: computeLrRatio(centerWalls, lateralWalls, sensorZMm = PiezoHW.sensorZMmAll) return estimateBladderVolume( walls = centerWalls, lrRatio = lrRatio, diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt index ee32b4d..3f637d2 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt +++ b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt @@ -1905,6 +1905,24 @@ fun PiezoMonitoringView(appState: AppState) { HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) + // 2026-07-01: lr_ratio override (algorithm 팀 4830e7c 표준) + var lrFixed by remember { + mutableStateOf(com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride != null) + } + Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { + Text("lr=1.0 fixed", fontSize = labelSize, fontWeight = FontWeight.SemiBold) + Spacer(modifier = Modifier.weight(1f)) + Switch(checked = lrFixed, + onCheckedChange = { + lrFixed = it + com.example.medilightv2android.managers.GreenZoneConstants.lrRatioOverride = + if (it) 1.0 else null + }, + colors = SwitchDefaults.colors(checkedTrackColor = MlPrimary)) + } + + HorizontalDivider(modifier = Modifier.padding(vertical = dividerPadding)) + // SG Filter var sgEnabled by remember { mutableStateOf(analyzer.useSgFilter) } Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {