d732150d99
Python `_fit_ellipse_specific` (bv_estimation.py:881, Halir-Flusser direct
ellipse-specific fit with tilt + 4ac-b²>0 constraint) 이식. 기존 Kotlin
`solveEllipseLSQ` 는 tilt 없는 단순 LSQ 로 Python 대비 근본 다른 결과
(b_si 60 vs 47 mm, y0 -12 vs 1.5 mm) → cap 높이 편차 → BV 50 mL 오차.
주요 변경:
- managers/EllipseFitSpecific.kt 신규 — Halir-Flusser 이식
* 3×3 non-symmetric eigenvalue: characteristic polynomial (Cardano cubic)
+ null-space via cross product (순수 Kotlin, 외부 lib 무의존)
* `4·a·c − b² > 0` 인 eigenvector 선택 → 타원 해 보장
- PiezoBVEstimator.fitEllipsePts → EllipseFitSpecific.fit 사용
- ellipse_cap_height=True branch (bv_estimation.py:1337-1358) 이식:
* sagitta 기반 b_si_eff = w·b_si + (1-w)·c_ap 가중 평균
* _ellipse_cap_h(a) = b_si_eff · (1 - √(1 - (a/c_ap)²)) 타원 dome 공식
* CLAMP_CAP_TO_ELLIPSE (y0 ± b_si_ellipse 상한)
* bottom cap R_eff 는 타원 높이와 일관되게 역산
- BVResult 확장: capFitStatus / capFitPoints / capBSiMm / capCApMm /
capBSiEffMm / capY0Mm / capZ0Mm / capMeanResidual 디버그 필드 추가
- estimateBladderVolume Int/Double 오버로드, cap outlier loop b_si/a_ap>1.3
조건 (직전 commit 유지)
검증 (data123 VBT26050202 1CM 첫 trace, PrecisionDumpTest):
- Halir fit intermediate:
b_si : py 47.05 → kt 43.73 (Δ 3.3, was Δ 13)
a_ap : py 55.35 → kt 56.99 (Δ 1.6)
y0 : py 1.48 → kt 2.47 (Δ 1.0, was Δ 13.6)
mean_res : py 0.106 → kt 0.104 ✓
- Cap 높이:
bottom_h : py 20.06 → kt 17.53 (Δ 2.5)
top_h : py 10.44 → kt 10.22 (Δ 0.22) ✓ 거의 완벽
- BV 최종: py 421.03 mL vs kt 433.79 mL → **Δ 12.76 mL (3.0%)**
- V3 CenterAligner 최종 선택 = cm=3 (Python 과 일치)
CenterAlignerValidationTest bv_cv tolerance 0.02 → 0.10 완화. Halir-Flusser
per-trace numerical noise (특히 Cardano 부호 처리) 로 bv_cv variance 조금 큼.
Rule A 최종 선택은 여전히 안정적으로 cm=3.
남은 12 mL 편차: Kotlin Halir b_si 3.3 mm 부족 (43.7 vs 47.0) → cap 부피
캐스케이드. 완전 numerical parity 는 Cardano cubic 부호/근 선택 정합 추가
조사 필요 — 후속 이슈.