docs(algo): ALGO-04 demo-final vs feature/cloud-mvp 브랜치 비교 문서

3축 (Alignment / Detection / BV) 로직 상세 비교.

핵심 정리:
  · demo-final = phantom (구) 시연 전용 · V=4/3πr³ · dps=1.968 · METHOD_D_PHANTOM
  · cloud-mvp   = 인체 (타원) 실사용 · Halir+adaptive · dps=1.936 · METHOD_D
  · 두 브랜치 값이 다른 것이 정상 설계 (기하가 다름).

각 축별 default 표 · 로직 diff 요약 · 관련 파일 경로 (line 번호 포함).
브랜치 전용 파일 (demo: AlignmentAdvisorV3 · estimateBvPhantomSphere ·
cloud: StreamingBladderEstimator · VDIP post recovery · audit-logger).
향후 유지 원칙 (무분별 이식 금지 · phantom 재현성 우선).

Docmost 업로드: https://docmost.medithings.net/s/vesiscan/p/IZyb46bKVH
This commit is contained in:
2026-08-11 16:42:12 +09:00
parent 6dfe5e6281
commit e414a41a6d
+214
View File
@@ -0,0 +1,214 @@
# demo-final vs feature/cloud-mvp 알고리즘 브랜치 비교
_마지막 업데이트: 2026-08-11 · 대상: Alignment · Detection · BV Estimation_
## 배경
VesiScan-Basic Android 앱은 두 개의 활성 브랜치로 관리됨.
| 브랜치 | 용도 | 대상 방광 | 상태 |
|---|---|---|---|
| **demo-final** | 시연/데모 전용 · 안정판 | phantom (구 모형 방광) | 동결 시연 |
| **feature/cloud-mvp** | 실사용/개발 · 인체 임상 | 실제 인체 (타원 방광) | 활성 개발 |
**핵심 원칙**: 두 브랜치 알고리즘 결과가 서로 다른 것이 **정상 설계**. phantom (구) 과 인체 (비대칭 타원) 은 기하가 근본 다르므로 · 같은 코드로 두 상황 모두 정확 계산 불가.
- demo-final = 데모 시 팬텀에서 300ml 근처 값이 안정적으로 나오는 것이 목표. 구 공식 (V = 4/3πr³) 사용.
- cloud-mvp = 인체 정확도 (Halir-Flusser + adaptive_large_bladder_relax + b_si_floor 등 Python parity).
또한 cloud-mvp 는 **패키지 domain-driven 재배치**를 완료: `managers/*` → `piezo/*` · `alignment/*` · `common/util/*`. 두 브랜치 동일 파일이 경로만 다르고 로직은 대부분 동일한 경우가 많음.
---
## 1. Alignment (정렬 · placement guide)
### 1-1. 기본 설정값
| 항목 | demo-final | feature/cloud-mvp |
|---|---|---|
| `alignmentAlgo` (default) | **V1** | **V1** |
| `placementGuideMode` (default) | **SIMPLE** (표시명 "Gradient") | **SIMPLE** |
| V2 진입 조건 | clinical alignment session 만 | clinical alignment session 만 |
| `verticalHitRequired` (V2) | 3 | 3 |
| `VERTICAL_HIT_WINDOW / _MAJORITY` | 6 / 3 | 6 / 3 |
| `STABILIZE_LOST_WINDOW / _MAJORITY` | 4 / 3 | 4 / 3 |
| **V3 CenterAligner** (2-Pass batch) | ✅ 있음 | ❌ 없음 |
### 1-2. 로직 차이
- **V1/V2 state machine 은 두 브랜치 100% 동일** (phase 진입 · hysteresis · CV 계산 · MOVE_UP/DOWN 방향 판정).
- **RollingAligner의 `detectMultichannel` 호출부**:
- demo-final: `applyCross = false` (piezophantomtest ea3f15c 이식 · 2026-07-06)
→ 정렬 위치 선택은 base 검출로만 수행 · 교차채널 보정이 nch 를 흔들지 못하게 격리 · BV 산출은 별도 경로에서 `applyCross=true`.
- cloud-mvp: `applyCross` 파라미터 자체 제거 → 정렬 위치 판정에도 cross-channel 보정 결과 사용.
- **V3 CenterAligner (demo-final 전용)**: Pass 1 = 5 위치 각 20 cycle 스캔 → Rule A (ch3 필수 · 검출률 ≥ 80% · max nch · min bv_cv) 로 최적 위치 선택. Pass 2 = 재측정 검증. cloud-mvp 는 이 배치 알고리즘 자체가 없음.
### 1-3. 관련 파일
| 파일 | demo-final | cloud-mvp |
|---|---|---|
| PlacementGuideView | `ui/views/monitoring/PlacementGuideView.kt` (2317 L) | `alignment/ui/PlacementGuideView.kt` (2187 L) |
| AlignmentAdvisorV2 (+ RollingAligner) | `managers/AlignmentAdvisorV2.kt:677` (`applyCross=false`) | `alignment/AlignmentAdvisorV2.kt:680` (파라미터 제거) |
| AlignmentAdvisorV3 | `managers/AlignmentAdvisorV3.kt` (신규) | — |
| ImuAnalysis / ImuPostureClassifier | `managers/` | `alignment/` |
---
## 2. Detection (벽 검출)
### 2-1. 기본 설정값
| 항목 | demo-final | feature/cloud-mvp |
|---|---|---|
| `detectionMethod` (default) | **METHOD_C** (V4.1 SphereFit walls) | **METHOD_D** (Python for_app_share 1:1) |
| `MethodDParams.otsuRatio` | 0.88 | 0.88 |
| `MethodDParams.oscfarWin` | 9 | 9 |
| `MethodDParams.promGamma / shoulderPromGamma` | 1.5 / 1.5 | 1.5 / 1.5 |
| `MethodDParams.minWallLumenRatio` | 1.16 | 1.16 |
| `MethodDParams.minPostRawRatio` | 1.08 | 1.08 |
| `MethodDParams.antDMax / dMax` | 18 / 10 | 18 / 10 |
| Cross-channel stage 순서 | ①→②→③ (3-stage) | ①→**①.5**→②→③ (4-stage) |
| `VDIP_POST_RECOVERY` | ❌ 없음 | ✅ **true** (DIP_TOL=8.0mm · REACH_MARGIN=15.0mm) |
| `NEIGHBOR_TOP_VALIDATE` / `INWARD_POST_SEARCH` | true / true | true / true |
| `applyCross` 파라미터 | ✅ 있음 (default true) | ❌ 제거 (항상 적용) |
| `topRecoverWallRatio` 파라미터 | ❌ 없음 | ✅ 있음 (streaming relaxed pass 용) |
### 2-2. 로직 차이
- `MethodDParams` 는 모든 필드 100% 동일 (임계값 · 필터 파라미터 전부).
- `MethodDRunner` 는 105 lines 차이 (443L vs 548L). 실질 로직 차이 3가지:
1. **`applyVdipPostRecovery` (cloud-mvp only · stage ①.5)**
- V-dip 심부후벽 복구. 중간 center 채널 후벽 z 가 양 이웃 모두보다 `VDIP_DIP_TOL=8.0mm` 얕고, 두 이웃이 서로 8.0mm 이내 일치 (=under-detected 심부후벽) 이면 consensus 깊이로 재탐색.
- Gate (wall/lumen ratio + post_raw_ratio) 통과한 심부 peak 만 채택.
- 원본: piezophantomtest c800f5d (2026-08-06).
2. **`applyCross` 파라미터**
- demo-final: `detectMultichannel(..., applyCross: Boolean = true)` 유지 → 정렬 / BV 경로 분리 가능.
- cloud-mvp: 제거됨 → 두 경로 모두 cross-channel 적용된 결과 사용.
3. **`topRecoverWallRatio` 파라미터 (cloud-mvp only)**
- `applyNeighborTopValidate` Rule A (FN 복원) 재탐색 시 `minWallLumenRatio` gate override.
- `StreamingBladderEstimator` relaxed pass (게이트 1.16 → 1.13) 용 hook.
- **detection default 가 다른 것 자체가 브랜치 성격의 표현**: demo-final = phantom-검증된 V4.1 (안정 · 시연 유효), cloud-mvp = 임상용 METHOD_D (Python for_app_share 1:1).
### 2-3. 관련 파일
| 파일 | demo-final | cloud-mvp |
|---|---|---|
| MethodDRunner | `walldetect/MethodDRunner.kt` (443 L) | `piezo/walldetect/MethodDRunner.kt` (548 L) |
| MethodDParams | `walldetect/algo/methodd/MethodDParams.kt` | `piezo/walldetect/algo/methodd/MethodDParams.kt` (동일) |
| VDIP 신설 함수 | — | `MethodDRunner.kt:214-306` (`vdipDeepCandidate` + `applyVdipPostRecovery`) |
---
## 3. BV Estimation (부피 계산)
### 3-1. 기본 설정값
| 항목 | demo-final | feature/cloud-mvp |
|---|---|---|
| `bvMethod` (default) | **METHOD_D_PHANTOM** (2026-08-11 신설 · 구 공식) | **METHOD_D** (Halir + adaptive) |
| `BvMethod` enum | `{FRUSTUM, V41, METHOD_D, METHOD_D_PHANTOM}` (4개) | `{FRUSTUM, V41, METHOD_D}` (3개) |
| `distancePerSample` (dps) | **1.968 mm/sample** (2026-08-11 phantom rollback) | **1.936 mm/sample** (Python config_6ch.py:90) |
| `lrRatioOverride` (default) | 1.0 | 1.0 |
| `lrRatioMin / lrRatioMax` clip | ❌ 없음 | ✅ **0.5 / 1.5** (해부학적 clip) |
| `estimateBv(walls, adaptive=true)` 구현 | ✅ 있음 (동일) | ✅ 있음 (동일) |
| `estimateBvPhantomSphere(walls)` | ✅ **있음** (신규 · 구 공식) | ❌ 없음 |
| Halíř–Flusser (`EllipseFitSpecific`) | ✅ 있음 (로직 완전 동일) | ✅ 있음 |
| `adaptive_large_bladder_relax` (low_wide_endpoint) | ✅ 있음 (동일) | ✅ 있음 |
| `b_si_floor_ratio` / `_edge_min` | ✅ 있음 (동일) | ✅ 있음 |
| Subsample refined (Double ant/post) | ✅ 있음 | ✅ 있음 |
| `StreamingBladderEstimator` | ❌ 없음 | ✅ **있음** (age-based strict/relaxed 병합) |
| `useStreamingBv` dev toggle | ❌ 없음 | ✅ 있음 |
### 3-2. 로직 차이
- **`estimateBv(walls)` 본체는 두 브랜치 100% 동일**
- `evalOnce()` → `applyLumenInsetOne(0.15)` → `estimateBladderVolume6ch` → Halíř–Flusser 타원 fit → 결과 검사 (`capFrac < 0.20 && edge ≥ 0.48 && (edge ≥ 0.70 && hRel < 0.42)`) → low_wide_endpoint 이면 `urineInsetFrac=0.05 + bSiFloorRatio=0.85` 로 재계산.
- Python `runners.estimate_bv` 1:1.
- **`estimateBvPhantomSphere(walls)` — demo-final 전용 (2026-08-11 신설)**
- 위치: `PiezoBVEstimator.kt:600`
- 로직: center CH0~3 각 채널의 `(post − ant) × dps` 를 지름으로 보고 평균 → `V = 4/3·π·r³` (r = D/2). Halíř · adaptive · b_si_floor · lr_ratio 전부 우회.
- 검증: D = 42 samples × 1.968 dps = 82.7 mm → r = 41.35 mm → V ≈ 296 ml (300 ml phantom 시연에서 재현 성공).
- **인체 방광 (비대칭 타원) 에는 부적합** · phantom 전용.
- **`distancePerSample` 편차 (1.968 vs 1.936)**
- 두 브랜치 계산 결과가 다른 결정적 원인 중 하나.
- dps 는 `WdConfig.DPS_DEFAULT` 도 함께 동기화 (V41 · Geometry · AnatomicalGate 모두 이 상수 사용) → 한 값만 바꾸면 두 경로 (6ch estimate vs V41/gate) dps 불일치 방지.
- **`StreamingBladderEstimator` (cloud-mvp only)**
- 파일: `piezo/StreamingBladderEstimator.kt` (신규).
- 각 채널별 `age` (마지막 strict 검출 이후 trace 수) 유지 → strict 실패 채널을 최근 K trace 내 strict 이력 있으면 relaxed (게이트 1.13) 로만 복구 · 이력 없으면 완화 안 함 → 게이트 경계 flicker 억제.
- `MethodDRunner.detectMultichannel(topRecoverWallRatio=…)` 로 게이트 override.
- `PiezoMonitoringView:406` 에서 dev toggle 로 라우팅. 배뇨/탈착 시 `reset()`.
- **`lrRatioMin/Max` clip [0.5, 1.5]**
- cloud-mvp 만 도입 (`PiezoHW:164-165` · `computeLrRatio` 반환값 clip).
- demo-final 은 computed lr 그대로 (실제로는 `lrRatioOverride=1.0` 강제 사용해서 clip 무의미).
### 3-3. 관련 파일
| 파일 | demo-final | cloud-mvp |
|---|---|---|
| PiezoBVEstimator | `managers/PiezoBVEstimator.kt` (1174 L) | `piezo/PiezoBVEstimator.kt` (1124 L) |
| EllipseFitSpecific | `managers/EllipseFitSpecific.kt` | `piezo/EllipseFitSpecific.kt` (package 다름) |
| GreenZoneConstants | `managers/GreenZoneConstants.kt:38, :59` | `common/util/GreenZoneConstants.kt:38, :69` |
| BV 신설 함수 (sphere) | `PiezoBVEstimator.kt:600` `estimateBvPhantomSphere` | — |
| Streaming BV | — | `piezo/StreamingBladderEstimator.kt` (신규) |
| BV 분기점 | `ui/views/monitoring/PiezoMonitoringView.kt:487-491` (`METHOD_D_PHANTOM → estimateBvPhantomSphere`) | `piezo/ui/PiezoMonitoringView.kt:406-418` (`useStreamingBv → streamingBv.update(signals)`) |
---
## 4. 브랜치 전용 파일/기능 요약
### demo-final only
- `managers/AlignmentAdvisorV3.kt` (CenterAligner · Rule A + bvcv batch scan-select)
- `BvMethod.METHOD_D_PHANTOM` enum value
- `fun estimateBvPhantomSphere(walls)` (구 공식 · phantom 시연 전용)
- `MethodDRunner.detectMultichannel(..., applyCross = false)` API 보존
### cloud-mvp only
- `piezo/StreamingBladderEstimator.kt` (age-based strict/relaxed 병합)
- `GreenZoneConstants.useStreamingBv` dev toggle + custom-setter audit logging
- `PiezoHW.lrRatioMin / lrRatioMax` clip + `coerceIn` in `computeLrRatio`
- `MethodDRunner.applyVdipPostRecovery` + `vdipDeepCandidate` (V-dip 심부후벽 복구)
- `MethodDRunner.detectMultichannel(..., topRecoverWallRatio: Double?)` API
- `PiezoHW.autoDetectPreset` PhiRedactor 마스킹 (cybersecurity DC-02)
- Custom-setter audit-logger wrappers on `_detectionMethod` / `_bvMethod` / `_lrRatioOverride` / `_placementGuideMode` / `_alignmentAlgo` / `_useStreamingBv` (cybersecurity UC-04)
- `piezo/ui/PiezoPersonalizationView.kt` streaming BV dev toggle UI
### 공통 (구현 동일 · 위치만 다름)
- Halíř–Flusser `EllipseFitSpecific` · `estimateBv(walls)` 본체 · `adaptive_large_bladder_relax` · `b_si_floor` · subsample refined · `MethodDParams` 전 필드 · V1/V2 alignment state machine 임계
---
## 5. 브랜치 default 조합 종합
| 축 | demo-final | cloud-mvp |
|---|---|---|
| 정렬 | V1 · Gradient (SIMPLE) | V1 · Gradient (SIMPLE) |
| 검출 | **METHOD_C** (V4.1 SphereFit walls) | **METHOD_D** (Python for_app_share) |
| BV | **METHOD_D_PHANTOM** (구 공식 · V=4/3πr³) | **METHOD_D** (Halir + adaptive) |
| dps | **1.968** mm/sample | **1.936** mm/sample |
| Streaming BV | — | dev toggle |
| Audit logging | — | 활성 |
## 6. 브랜치별 의사결정 기록 (핵심 커밋)
| 커밋 | 날짜 | 브랜치 | 변경 |
|---|---|---|---|
| `bcbc7b4` | 2026-07-02 | demo-final | 패키지 통일 (`com.example` → `com.medithings`) · BV 로직 안정판 |
| `d732150` | 2026-07-20 | demo-final | Halíř-Flusser ellipse fit 이식 (BV Δ 43→13mL) |
| `3152783` | 2026-07-20 | demo-final | estimateBv wrapper + adaptive_large_bladder_relax + b_si_floor |
| `430d9ad` | 2026-07-30 | demo-final | feature-folder refactor (147 파일 이동) |
| `1c3748b` | 2026-08-07 | demo-final | vdip_post_recovery 이식 (MethodDRunner) |
| `8cab1d0` | 2026-08-10 | demo-final | rollback 후 재조정 · detection=C + bv=METHOD_D |
| `d054b3b` | 2026-08-11 | demo-final | dps 1.936 → 1.968 (phantom 스케일 재현) |
| `d1d17f8` | 2026-08-11 | demo-final | METHOD_D_PHANTOM (구 공식) 신설 · demo default |
| `6dfe5e6` | 2026-08-11 | demo-final | `BleManager.disconnect()` 즉시 UI 반영 fix |
## 7. 향후 유지 원칙
1. **cloud-mvp 의 알고리즘 개선을 demo-final 로 무분별 이식하지 않기**
- Halir · adaptive 등은 인체 정확도 개선이지만 phantom 에서는 오히려 값 왜곡.
2. **demo-final 은 phantom 시연 재현성 최우선**
- 알고리즘 변경 시 300 ml phantom 결과가 296 ml 근처를 유지하는지 확인.
3. **동시 이식이 필요한 fix (예: BLE 안정성 · UI 버그) 는 두 브랜치 각각 별도 커밋**
- cherry-pick 대신 각 브랜치에서 명시적으로 적용 후 커밋 메시지에 "demo-final 이식" / "cloud-mvp 이식" 명시.