test(align): labdb 원시 파형을 앱 판정에 다시 넣는 진단 덤프 — 시도별 nch·CH3 trace 수
요약은 같은 cm 의 마지막 시도만 남겨(재측정은 최신값) 첫 측정 때 본 CH3 가 몇 trace 였는지 알 수 없다. LABDB_CYCLES_DIR 의 cycle CSV(scratch 스크립트가 labdb 601 JSON 에서 뽑는다)를 AnchorGuide.measure 에 넣어 파일마다 nch · ch3Mean · hit/traces · cap_frac 을 찍는다. 환경변수가 없으면 건너뛴다 — CI 와 무관. 2026-10-14 P9 sitting "1·2cm 에서 ch2·ch3" 질의에 처음 썼다. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
package com.medithings.vesiscan.managers
|
||||
|
||||
import org.junit.Assume.assumeTrue
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* 진단용 — labdb 601 원시 파형을 앱과 **똑같은 판정**([AnchorGuide.measure])에 다시 넣어
|
||||
* 시도별 nch · CH3 · 검출 trace 수를 찍는다. 요약(`positions`)은 같은 cm 의 **마지막 시도**만
|
||||
* 남기므로(재측정은 최신값), 첫 측정 때 화면에서 본 CH3 가 실제로 몇 trace 였는지는 이걸로만
|
||||
* 알 수 있다(2026-10-14, P9 sitting "1·2cm 에서 ch2·ch3 보였다" 질의).
|
||||
*
|
||||
* 입력: 환경변수 `LABDB_CYCLES_DIR` 의 `*.csv` (cycle,channel,s0.. · 헤더 없음 —
|
||||
* scratchpad/labdb_export_cycles.py 가 만든다). 파일명 `…__{cm}cm_{phase}_a{attempt}.csv`.
|
||||
* HW 프리셋은 `LABDB_HW_PRESET`(기본 R300). 환경변수가 없으면 건너뛴다 — CI 와 무관하다.
|
||||
*/
|
||||
class LabdbTraceDumpTest {
|
||||
|
||||
private fun loadCycles(f: File): List<List<DoubleArray>> {
|
||||
val byCycle = sortedMapOf<Int, MutableMap<Int, DoubleArray>>()
|
||||
f.readLines().filter { it.isNotBlank() }.forEach { line ->
|
||||
val p = line.split(',')
|
||||
byCycle.getOrPut(p[0].toInt()) { sortedMapOf() }[p[1].toInt()] =
|
||||
DoubleArray(p.size - 2) { p[it + 2].toDouble() }
|
||||
}
|
||||
return byCycle.values.map { chans -> chans.toSortedMap().values.toList() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dumpPerAttemptTraces() {
|
||||
val dir = System.getenv("LABDB_CYCLES_DIR")?.let(::File)
|
||||
assumeTrue("LABDB_CYCLES_DIR 없음 — 진단 전용", dir != null && dir.isDirectory)
|
||||
val presetName = System.getenv("LABDB_HW_PRESET") ?: "R300"
|
||||
val saved = PiezoHW.activePreset
|
||||
PiezoHW.activePreset = PiezoHW.DevicePreset.valueOf(presetName)
|
||||
try {
|
||||
val re = Regex("""__(-?\d+)cm_([a-z_]+)_a(\d+)\.csv$""")
|
||||
println("TRACEDUMP preset=$presetName")
|
||||
println("TRACEDUMP file | cycles | traces | nch | ch3Mean | ch3Hit/traces | ch3Rate | capFrac | nchTraceMean")
|
||||
dir!!.listFiles { f -> f.name.endsWith(".csv") }!!.sortedBy { it.name }.forEach { f ->
|
||||
val m = re.find(f.name) ?: return@forEach
|
||||
val cm = m.groupValues[1].toInt()
|
||||
val cycles = loadCycles(f)
|
||||
val rec = AnchorGuide().measure(cycles, cm)
|
||||
println(
|
||||
"TRACEDUMP ${f.name} | ${cycles.size} | ${rec.nTrace} | ${rec.nch} | ${if (rec.ch3Mean) "O" else "X"} | " +
|
||||
"${rec.ch3Hit}/${rec.nTrace} | ${"%.2f".format(rec.ch3Rate)} | ${"%.3f".format(rec.capFrac)} | ${"%.2f".format(rec.nchTrace)}",
|
||||
)
|
||||
}
|
||||
} finally {
|
||||
PiezoHW.activePreset = saved
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user