From f3d3a9ce54fb09fcb94e2c5d489e9a1703be1004 Mon Sep 17 00:00:00 2001 From: jjangddu Date: Wed, 6 May 2026 12:13:10 +0900 Subject: [PATCH] =?UTF-8?q?feat:=206ch=20=ED=95=84=ED=84=B0=20+=20?= =?UTF-8?q?=EB=8F=84=EB=84=9B=20=ED=99=95=EB=8C=80=20+=20Fill/Level=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=20=EB=B3=80=EA=B2=BD=20+=20=EC=8A=AC?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=94=A9=20=EC=9C=88=EB=8F=84=EC=9A=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BV 계산: - 6채널 모두 수신(buffer>=20) 시에만 BV 계산 (불완전 데이터 제외) 도넛 차트: - 크기: compact 180→220dp, normal 240→280dp - 선 두께: 20→22, 28→30dp - 캐릭터: 70→80, 100→110dp - 볼륨 텍스트: 16→18sp, maxVolumeMl → lastVolumeMl 표시 Info Cards: - Fill: appState.fillPercentage → lastVolumeMl/maxVolume×100 (실측 기준) - Level: appState.bladderLevel → lastVolumeMl/maxVolume×MAX_LEVEL - 미측정 시 "—" 표시 Auto 측정: - 배치 윈도우 → 슬라이딩 윈도우 (최대 10개 유지, 오래된 것 제거) - 5개 이상이면 매 측정마다 trimmed mean 업데이트 - 이전: 10개 모이면 한 번에 업데이트 → clear - 변경: [1,2,3,4,5]→출력, [2,3,4,5,6]→출력 (실시간 반영) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../views/monitoring/PiezoMonitoringView.kt | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) 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 0a8923e..8987557 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 @@ -151,7 +151,8 @@ fun PiezoMonitoringView(appState: AppState) { var totalWallCount = 0 val validChannels = channels.filter { it.isValid } - if (validChannels.isNotEmpty()) { + val allChannelsReceived = channels.filter { it.buffer.size >= 20 }.size >= 6 + if (validChannels.isNotEmpty() && allChannelsReceived) { val method = com.example.medilightv2android.managers.GreenZoneConstants.detectionMethod val analyzerA = com.example.medilightv2android.managers.PiezoEchoAnalyzerA.shared @@ -287,18 +288,20 @@ fun PiezoMonitoringView(appState: AppState) { handler.post { if (finalRawVol != null && finalRawVol > 0) { if (isAutoMeasuring) { - if (finalTotalWalls >= 4) { + if (allChannelsReceived) { autoVolumeWindow.add(finalRawVol) - Log.d("PiezoMonitor", "AUTO window[${autoVolumeWindow.size}/$autoWindowSize] +${"%.1f".format(finalRawVol)}ml (valid=$finalTotalWalls)") + // 슬라이딩 윈도우: 오래된 값 제거 + while (autoVolumeWindow.size > autoWindowSize) autoVolumeWindow.removeAt(0) + Log.d("PiezoMonitor", "AUTO window[${autoVolumeWindow.size}/$autoWindowSize] +${"%.1f".format(finalRawVol)}ml") } else { - Log.d("PiezoMonitor", "AUTO skip ${"%.1f".format(finalRawVol)}ml (valid=$finalTotalWalls < 4)") + Log.d("PiezoMonitor", "AUTO skip ${"%.1f".format(finalRawVol)}ml (channels incomplete)") } - if (autoVolumeWindow.size >= autoWindowSize) { + // 윈도우에 5개 이상이면 매번 trimmed mean 업데이트 + if (autoVolumeWindow.size >= 5) { val displayVol = trimmedMean(autoVolumeWindow.toList()) lastVolumeMl = displayVol maxVolumeMl = maxOf(maxVolumeMl, displayVol) Log.d("PiezoMonitor", "AUTO trimmedMean=${"%.1f".format(displayVol)}ml from ${autoVolumeWindow.map { "%.0f".format(it) }}") - autoVolumeWindow.clear() } } else { lastVolumeMl = finalRawVol @@ -753,20 +756,20 @@ fun PiezoMonitoringView(appState: AppState) { ) // Donut chart with Bladdy - val donutSize = if (isCompact) 180.dp else 240.dp + val donutSize = if (isCompact) 220.dp else 280.dp Box(contentAlignment = Alignment.Center) { DonutChartView( progress = appState.bladderLevel.progress, urgency = urgency, - lineWidth = if (isCompact) 20.dp else 28.dp, + lineWidth = if (isCompact) 22.dp else 30.dp, size = donutSize ) Column(horizontalAlignment = Alignment.CenterHorizontally) { - BladdyRiveView(urgency = urgency, size = if (isCompact) 70.dp else 100.dp) + BladdyRiveView(urgency = urgency, size = if (isCompact) 80.dp else 110.dp) Spacer(modifier = Modifier.height(4.dp)) Text( - if (maxVolumeMl > 0) "${"%.0f".format(maxVolumeMl)} ml" else "${appState.estimatedVolume} ml", - fontSize = 16.sp, + if (lastVolumeMl > 0) "${"%.0f".format(lastVolumeMl)} ml" else "${appState.estimatedVolume} ml", + fontSize = 18.sp, fontWeight = FontWeight.Bold, color = urgency.accentColor, modifier = Modifier @@ -778,12 +781,15 @@ fun PiezoMonitoringView(appState: AppState) { } } - // Info cards + // Info cards (Fill/Level은 maxVolume 기준) + val maxVol = appState.piezoSettings.maxVolume.toDouble() + val fillPct = if (maxVol > 0 && lastVolumeMl > 0) (lastVolumeMl / maxVol * 100).coerceAtMost(100.0) else 0.0 + val levelVal = if (maxVol > 0 && lastVolumeMl > 0) ((lastVolumeMl / maxVol) * BladderLevel.MAX_LEVEL).toInt().coerceIn(0, BladderLevel.MAX_LEVEL) else 0 Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { - val displayVol = if (lastVolumeMl > 0) "%.0f".format(lastVolumeMl) else "${appState.estimatedVolume}" + val displayVol = if (lastVolumeMl > 0) "%.0f".format(lastVolumeMl) else "—" InfoCard("Volume", displayVol, "ml", urgency.accentColor, Modifier.weight(1f)) - InfoCard("Fill", String.format("%.0f", appState.fillPercentage), "%", urgency.accentColor, Modifier.weight(1f)) - InfoCard("Level", "${appState.bladderLevel.currentLevel}/${BladderLevel.MAX_LEVEL}", "", urgency.accentColor, Modifier.weight(1f)) + InfoCard("Fill", if (fillPct > 0) "%.0f".format(fillPct) else "—", "%", urgency.accentColor, Modifier.weight(1f)) + InfoCard("Level", if (levelVal > 0) "$levelVal/${BladderLevel.MAX_LEVEL}" else "—", "", urgency.accentColor, Modifier.weight(1f)) } // Control buttons: Void/Catheterize / Auto / Spot