feat: Method C (V4.1 CharlesKWON) 통합 + Placement 설정 패널
Method C (walldetect/ 패키지, 38파일): - V41Detector: OS-CFAR threshold + wavelet denoise + anatomical gate + B-mode score - Multi-method BV dispatch: frustum(≥2ch) / Verathon(1ch) / sphere fit(cross-check) - Kasa→LM sphere fitting, sub-sample parabolic refinement - 패키지 이동: com.medithings.charleskwonslaw → com.example.medilightv2android 통합: - 설정 UI: A/B 스위치 → A/B/C 버튼 그룹 (A=보라, B=파랑, C=주황) - Monitoring: Method C 선택 시 V41Detector.detect() → BV dispatch 결과 사용 - Placement: 선택된 Method(A/B/C) 반영 + 톱니바퀴 설정 패널 추가 Placement 그래프 개선: - Threshold 수평선 (주황 점선) - Y축 눈금 (0, 1k, 2k) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Medithings Co., Ltd.
|
||||
* Author: Charles KWON OhJun <charleskwon@medithings.co.kr>
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
*
|
||||
* Multi-channel BV estimation result (4-layer dispatch — see
|
||||
* docs/BV-CALCULATION-DESIGN.md). Replaces the sphere-only `v41Sphere.bvMl`
|
||||
* for the primary "BV" metric while sphere fit stays for cross-check.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect.dto
|
||||
|
||||
|
||||
data class BvDispatchResult(
|
||||
val bvMl: Float?, // null = no estimate
|
||||
val rMm: Float?, // equivalent sphere radius (sphere or chord-derived)
|
||||
val method: String, // FrustumLR | FrustumNoLR | SphereLM | ConeFallback | Verathon | None
|
||||
val confidence: Float, // 0..1
|
||||
val nCenter: Int, // gated center channels (CH0..CH3)
|
||||
val nLateral: Int, // gated lateral channels (CH4, CH5)
|
||||
val lrRatio: Float, // applied LR/AP ratio (1.0 if no lateral)
|
||||
val warnings: List<String> = emptyList(),
|
||||
val sphereCrossCheckBvMl: Float? = null,
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Medithings Co., Ltd.
|
||||
* Author: Charles KWON OhJun <charleskwon@medithings.co.kr>
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
*
|
||||
* Per-channel detector result. Schema is identical for V2 and V4.1.
|
||||
* V2 결과는 v41Diag 가 항상 null.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect.dto
|
||||
|
||||
|
||||
data class ChannelResult(
|
||||
val ch: Int,
|
||||
val sg: List<Float>,
|
||||
val threshold: List<Float>,
|
||||
val antIdx: Int?,
|
||||
val postIdx: Int?,
|
||||
val antRefined: Float?,
|
||||
val postRefined: Float?,
|
||||
val antMm: Float?,
|
||||
val postMm: Float?,
|
||||
val lumenStart: Int?,
|
||||
val lumenEnd: Int?,
|
||||
val chordMm: Float?,
|
||||
val clipping: Boolean? = null,
|
||||
val v41Diag: V41Diagnostics? = null
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Medithings Co., Ltd.
|
||||
* Author: Charles KWON OhJun <charleskwon@medithings.co.kr>
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
*
|
||||
* Top-level detector output. Identical schema for V2 and V4.1.
|
||||
* Only `algorithm` / `algorithmVersion` differ; all other field names match.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect.dto
|
||||
|
||||
|
||||
data class DetectionResult(
|
||||
val requestId: String,
|
||||
val timestampMs: Long,
|
||||
val algorithm: String,
|
||||
val algorithmVersion: String,
|
||||
val processingMs: Double,
|
||||
val perChannel: List<ChannelResult>,
|
||||
val summary: DetectionSummary
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Medithings Co., Ltd.
|
||||
* Author: Charles KWON OhJun <charleskwon@medithings.co.kr>
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
*
|
||||
* Sweep-level summary. Schema identical for V2 and V4.1.
|
||||
* V4.1-only fields are null in V2 results.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect.dto
|
||||
|
||||
|
||||
data class DetectionSummary(
|
||||
val matchCount: Int,
|
||||
val chordMmMean: Float?,
|
||||
val chordMmStd: Float?,
|
||||
val tier: String? = null,
|
||||
val scoreMean: Float? = null,
|
||||
val scoreMin: Float? = null,
|
||||
val scoreMax: Float? = null,
|
||||
val gatedCount: Int? = null,
|
||||
val v41Sphere: V41SphereFit? = null,
|
||||
/** Multi-channel BV dispatch (PR-13). Replaces sphere-only BV as primary value. */
|
||||
val bvDispatch: BvDispatchResult? = null,
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Medithings Co., Ltd.
|
||||
* Author: Charles KWON OhJun <charleskwon@medithings.co.kr>
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
*
|
||||
* Common input DTO for both V2 and V4.1 detectors.
|
||||
* 두 detector 가 동일 입력을 받는다는 drift-zero 보장의 단일 source.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect.dto
|
||||
|
||||
|
||||
data class SweepInput(
|
||||
val requestId: String,
|
||||
val timestampMs: Long,
|
||||
val deviceId: String,
|
||||
val sweepSeq: Int,
|
||||
val probe: ProbeProfileDto,
|
||||
val adc: List<List<Int>>,
|
||||
val gainDb: Int = 0
|
||||
)
|
||||
|
||||
data class ProbeProfileDto(
|
||||
val name: String,
|
||||
val rMm: Double,
|
||||
val anteriorAnchorMm: Double,
|
||||
val fsHz: Long,
|
||||
val cMmPerUs: Double,
|
||||
val anglesDeg: List<Double>
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Medithings Co., Ltd.
|
||||
* Author: Charles KWON OhJun <charleskwon@medithings.co.kr>
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
*
|
||||
* V4.1-only per-channel diagnostics carrier.
|
||||
* V2 결과에서는 ChannelResult.v41Diag = null. 스키마 자체는 양쪽 동일.
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect.dto
|
||||
|
||||
|
||||
data class V41Diagnostics(
|
||||
val waveletDenoised: List<Float>,
|
||||
val waveletEnergyRatio: WaveletEnergyRatio,
|
||||
val waveletCoefs: WaveletCoefs,
|
||||
val peaksAll: List<Int>,
|
||||
val spans: List<IntRange2>,
|
||||
val score: Float,
|
||||
val scoreSub: ScoreSubscores,
|
||||
val gated: Boolean,
|
||||
val tier: String,
|
||||
val sContrast: Float,
|
||||
val sContrastTier: String,
|
||||
val singleChannelBvMl: Float?
|
||||
)
|
||||
|
||||
data class WaveletEnergyRatio(val l1: Float, val l2: Float, val l3: Float)
|
||||
|
||||
data class WaveletCoefs(
|
||||
val l1: List<Float>,
|
||||
val l2: List<Float>,
|
||||
val l3: List<Float>,
|
||||
val a3: List<Float>
|
||||
)
|
||||
|
||||
data class ScoreSubscores(
|
||||
val uFarPost: Float,
|
||||
val uLumDark: Float,
|
||||
val uAntGrad: Float,
|
||||
val uPostGrad: Float
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Medithings Co., Ltd.
|
||||
* Author: Charles KWON OhJun <charleskwon@medithings.co.kr>
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
*
|
||||
* V4.1-only sweep-level sphere fit + BV result.
|
||||
* Q5: gated < 4 인 sweep 에서는 null (JS sphere_fit_2step.js 와 동일).
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect.dto
|
||||
|
||||
|
||||
data class V41SphereFit(
|
||||
val mode: String,
|
||||
val center: Vec3,
|
||||
val radiusMm: Float,
|
||||
val bvMl: Float,
|
||||
val residualStdMm: Float,
|
||||
val wallPoints: List<Vec3>,
|
||||
val deltaRMm: Float? = null,
|
||||
val deltaBvMl: Float? = null,
|
||||
val nPoints: Int
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Medithings Co., Ltd.
|
||||
* Author: Charles KWON OhJun <charleskwon@medithings.co.kr>
|
||||
* Project: CharlesKWONsLaw — wall-detect live compare
|
||||
*/
|
||||
package com.example.medilightv2android.walldetect.dto
|
||||
|
||||
|
||||
data class Vec3(val x: Float, val y: Float, val z: Float)
|
||||
|
||||
data class IntRange2(val start: Int, val end: Int)
|
||||
Reference in New Issue
Block a user