From 8eee3550f345d72b261990559ce1d4174d0b6942 Mon Sep 17 00:00:00 2001 From: jjangddu Date: Wed, 14 Oct 2026 10:14:19 +0900 Subject: [PATCH] =?UTF-8?q?test(align):=20labdb=20=EC=9B=90=EC=8B=9C=20?= =?UTF-8?q?=ED=8C=8C=ED=98=95=EC=9D=84=20=EC=95=B1=20=ED=8C=90=EC=A0=95?= =?UTF-8?q?=EC=97=90=20=EB=8B=A4=EC=8B=9C=20=EB=84=A3=EB=8A=94=20=EC=A7=84?= =?UTF-8?q?=EB=8B=A8=20=EB=8D=A4=ED=94=84=20=E2=80=94=20=EC=8B=9C=EB=8F=84?= =?UTF-8?q?=EB=B3=84=20nch=C2=B7CH3=20trace=20=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 요약은 같은 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 --- .../vesiscan/managers/LabdbTraceDumpTest.kt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 app/src/test/java/com/medithings/vesiscan/managers/LabdbTraceDumpTest.kt diff --git a/app/src/test/java/com/medithings/vesiscan/managers/LabdbTraceDumpTest.kt b/app/src/test/java/com/medithings/vesiscan/managers/LabdbTraceDumpTest.kt new file mode 100644 index 0000000..bba313d --- /dev/null +++ b/app/src/test/java/com/medithings/vesiscan/managers/LabdbTraceDumpTest.kt @@ -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> { + val byCycle = sortedMapOf>() + 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 + } + } +}