Commit Graph

8 Commits

Author SHA1 Message Date
dw.jang 5373723864 feat(align): 부착 오프셋 0 — best 자리에서 바로 좌우 밸런스 (이번 임상부터 모든 자세에서 정렬)
임상팀 결정(2026-10-01, e.yu · kai.han): 모든 자세에서 정렬을 하므로 "best + 1cm 올리고
거기서 좌우" 단계를 빼고, 확인 측정한 best 자리에서 바로 좌우를 맞추고 그대로 붙인다.

  · AnchorConfig.FINAL_OFFSET_CM = 1 → 0. anchor_cm = best_cm. 2026-10-01 이전 세션
    (final_offset_cm: 1)과 대조할 때는 Python select_supine_anchor(offset_cm=0).
  · 지시문: 확인 측정 뒤 "치골 위 N cm 그대로 — 좌우 맞추기 / 옮기지 말고". 오프셋이
    0 이 아닐 때의 "N+offset cm 에 붙이세요" 는 남겨 둔다(상수만 되돌리면 그대로 동작).
  · AnchorGuide STOP 문구도 "이 자리(N cm)에 그대로 부착합니다".
  · 재부착 확인의 기준(좌우 확인 창)은 이제 확인 측정과 같은 높이 — "떼기 직전" 이라 그대로 둔다.

시험 AlignInstructionTest 오프셋 0 문구 1건 추가 — 전체 192건 · failures 0.
문서: CLINICAL_ALGORITHM §3.5/3.6/상수표, LABDB_DATATYPES final_offset_cm/anchor_cm, README.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-01 09:53:09 +09:00
dw.jang 6f118f3ee4 feat(hospital): 정렬을 자세마다 — 부착 위치·재부착 확인·정렬 폴더·labdb 세션을 자세별로
임상 프로토콜은 자세마다 정렬을 처음부터 다시 한다(2026-10-01 확인): Supine 정렬 →
Supine 0~100% → Sitting 정렬 → Sitting 0~100% …. 앱은 환자당 한 번이었다 — Sitting 에서
다시 정렬하면 같은 `align/` 의 원시 파일이 덮이고 labdb 세션 ID 도 같아 섞였다.

  · AppState: 부착 위치·근거·기준 채널·재부착 결과를 자세별 맵(AnchorState)으로. 기존
    접근자(anchorCm 등)는 지금 자세의 항목을 읽고 쓴다. 환자·프로브가 바뀌면 전 자세를
    비운다(clearAllAnchors).
  · 저장: `align/` → `align_{자세}/`. 업로드 대상 탐색은 옛 `align` 과 `align_*` 전부.
    labdb 601 세션 이름에 자세 꼬리(`…_align_sitting_HHmm`), 요약에 `posture`.
  · 정렬 화면: 자세 칩은 첫 위치를 재고 나면 잠근다(폴더·세션의 조건이다). 바꾸려면
    [처음부터 다시 정렬].
  · 병원 화면: 환자명 → 자세 → 정렬 카드 순(자세가 정렬보다 위). 카드가 그 자세의 상태를
    보인다 — "Sitting 부착 위치 미정렬" / "✓ Sitting 부착 위치 3cm 확정".

시험: 자세별 폴더 대상 탐색 · 세션 이름 자세 꼬리. 전체 190건 · failures 0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-01 09:32:23 +09:00
dw.jang 8ef7c64ba6 feat(hospital): 재부착 확인 단계 · 좌우 스트리밍 전체 기록 · 정렬 파형을 위로 (2026-09-29 임상 후속)
임상에서 정렬 → 위치 마킹 → 프로브 떼기 → 크래들로 다시 붙이기 사이에 CH2 가 사라진 채
18조합을 다 쟀다. 좌우는 실시간 판정만 하고 아무것도 남기지 않아 "그 전에는 있었나"를
대조할 수도 없었다. 세 가지를 넣는다.

1. 재부착 확인 (병원 화면 정렬 카드 아래, ReattachCheckCard)
   · 부착 위치에서 정렬 조건(2.3MHz·c3·20 cycle)으로 재고, 정렬 확인 측정에서 잡힌
     채널(AppState.anchorRefChannels ← 확인 측정의 walls)과 CH0~3 을 채널별로 대조
     + 탈착 감시. 판정은 ReattachCheck.judge (순수 함수, 시험 6건).
   · 막지 않는다 — 측정 시작 아래 경고, 측정 중 한 줄 요약에 "재부착 ⚠", run 매니페스트
     `anchor_reattach`, align_result.json `reattach`, 601 에 phase=reattach 로 파형·IMU.
   · AppState.clearAnchor() — 부착 위치와 딸린 것(근거·기준 채널·재부착)을 한꺼번에 비운다.
2. 좌우 스트리밍 전체 기록 (HospitalRunStore.LateralStreamWriter)
   · 프레임마다 6채널 + 그 프레임의 판정(u4·u5·imbalance·action·ch3)을
     align_{n}cm_lateral_stream.csv 에 덧붙여 쓴다(앱이 죽어도 그때까지 남음).
     `attempt` 열로 [처음부터 다시 정렬] 시도를 가른다 — 앞 시도의 비동기 업로드가 파일을
     읽고 있을 수 있어 지우지 않는다. 601 에 phase=lateral_stream + `lateral{…}`.
3. 정렬 화면 파형 1차 개편 — 파형을 용적·접촉보다 위에 더 크게(170dp), 그 위에 채널별
   벽 검출 띠(CH0~3 ✓/✗, CH4·5 는 좌우용 회색). "CH2 없음"이 파형보다 먼저 보인다.

시험 88건 통과(전체 174 · skipped 3 · failures 0). 실기(프로브 필요)는 다음 임상에서.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-30 14:39:25 +09:00
dw.jang 9665216aad ui(align): 지시문 카드의 방향 화살표(↑↓●)를 뺀다
"치골 위 N cm" 하나만 말하기로 한 마당에 화살표가 남아 있으면 다시 방향을, 그러면
"얼마나"를 세게 된다(2026-09-29 현장 의견). AlignInstruction 에서 arrow 를 없앤다 —
좌우 정렬 단계의 ←/→/■ 는 좌우로 얼마나 움직일지 알려 주는 다른 것이라 그대로다.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-29 17:59:04 +09:00
dw.jang 57b8779110 ui(align): 지시문을 "치골 위 N cm 에 붙이고 측정" 하나로 — 상대 이동(올리고/내리고)을 뺀다
현장 의견(2026-09-29): 판정 뒤 "최적 N cm" 옆에 "아래로 2cm 내리세요" 가 붙어 나와
어디에 붙이라는 건지 헷갈린다. 2026-09-09 에 "최적 위치/부착 위치" 두 숫자가 헷갈려
상대 이동으로 바꿨는데, 상대 이동도 판정 숫자와 나란히 보이면 다시 숫자가 둘이 된다.

치골은 손으로 짚는 기준점이라 **치골 위 절대 위치 하나**만 말한다. 버튼의 숫자
("N cm 측정하기")와 같아 서로를 확인해 주고, 셀 것도 비교할 것도 없다.

  수집      치골 위 N cm 에 붙이고 측정
  확인 측정 치골 위 N cm 에 다시 붙이고 측정  (이미 그 자리면 "에서 한 번 더 측정")
  확정      치골 위 N+1 cm 에 붙이세요 — 재지 말고 좌우로
  재부착    더 아래에 다시 붙이세요  (갈 자리가 없어 이것만 상대적)

화살표(↑↓●)는 남긴다 — 글에는 방향을 쓰지 않고 눈으로만 거든다. 좌우 단계 안내도
"1cm 올린 자리" 대신 "치골 위 N cm 에 붙인 그대로" 로.

시험: AlignInstructionTest 문구 갱신 + "재부착 말고는 상대 이동을 말하지 않는다" 추가.
docs/CLINICAL_ALGORITHM.md §3.6 흐름을 새 문구로.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-29 17:23:46 +09:00
dw.jang c01da3512e feat(clinical): 정렬 판정을 **잰 위치 전부**로 — 0~4cm 다 재고 판단
알고리즘 설계자가 물었다 — "0cm·1cm 만 쟀는데 0cm 가 최적으로 나왔다. 3cm 가 최적이면?"
앞 커밋은 전수 측정만 하고 판정은 단일 pass 로 뒀는데, 원래 의도는 **다 재고 판단**이었다.

## 무엇이 바뀌고 무엇이 그대로인가

    측정        종료 조건에서 중단      →  0~4cm 무조건 전부
    후보        종료까지의 위치         →  잰 위치 전부          ← 바뀜
    선택 규칙   자격→nch→cap→낮은 cm   →  그대로
    부착        best + 1cm 단순 덧셈   →  그대로
    종료 조건   판정을 끝냄            →  진단용 (decided_at_cm)

선택 규칙 `AnchorSelection.selectBest` 는 Python `select_supine_anchor` 와 1:1 이고 200
케이스로 대조돼 있다 — **손대지 않았다.** 바뀐 것은 후보 집합뿐이고, Python 의 회고 분석
경로가 이미 전 위치로 판정하므로 같은 방식으로 재현·대조할 수 있다. 다만 **최종 보고서의
"단일 pass" 기술은 갱신이 필요하다.**

## 왜

단일 pass 는 지표가 단봉이라고 가정해 나빠지는 순간 멈춘다. 장내 가스·접촉 불량·호흡으로
**한 위치만** 일시적으로 나빠져도 멈추므로 더 위를 놓친다. 실측에 징후가 있었다 —
2026-09-09 `kai` 는 0cm ch3=X → 1cm ch3=O 91% 로 지표가 **올라갔다.** 같은 날 `181128` 은
1cm 에서 nch 2→0, ch3 100%→0% 로 best=0cm 으로 끝나 2cm 이후를 몰랐다.

## 화면 단계를 화면이 직접 몰고 간다

종전에는 `AnchorGuide` 의 STOP(`last.done`)이 확정 신호였다. 이제 guide 의 단일 pass 답과
앱의 부착 위치가 다를 수 있어 그걸 쓸 수 없다. `confirmTarget`/`confirmDone` 으로 바꿨다:

    수집 중          → ↑ 1cm 올리고 측정 (판정보다 우선)
    수집 끝          → ↓/↑ N cm 로 이동해 확인 측정
    확인 측정 완료    → ↑ 1cm 올리세요 (초록) → 좌우
    후보 없음        → ↓ 더 아래에 다시 붙이세요

우선순위를 테스트로 고정했다 — 확정이 수집·재부착보다 먼저, 수집이 판정보다 먼저.
뒤바뀌면 4cm 까지 못 가거나 끝난 단계를 되돌린다.

## 감사 가능하게 둘 다 기록

    "selection_scope": "full_sweep"
    "best_cm": 3                    앱이 쓴 값 = 전 위치 판정
    "best_cm_single_pass": 0        옛 방식이 냈을 답
    "single_pass_disagrees": true
    "decided_at_cm": 1              종료 조건이 걸린 위치 (이제 진단값)

갈리면 화면에도 참고 문구가 뜬다. 이 빈도가 곧 "단봉 가정이 얼마나 깨지는가"의 지표다.

## 같이 정리

AnchorBasis 에 FULL_SWEEP 을 만들려다 **만들지 않았다** — 전 위치 판정이 이제 앱의 기본
규칙이므로 ALGORITHM 이 그 뜻이다. 항목을 늘리면 정확도 검증 모집단을 가르는 기준이
흐려진다.

테스트 143개 통과(AlignInstructionTest 13개 전면 재작성).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 12:21:59 +09:00
dw.jang b71a04374f feat(clinical): 전수 판정을 같이 계산해 기록 · 확인 측정이 판정 데이터를 덮지 않게
알고리즘 설계자가 물었다 — "0cm·1cm 만 쟀는데 0cm 가 최적으로 나왔다. 만약 3cm 가
최적이면?"

## 이건 버그가 아니라 설계 가정이다

단일 pass 는 **지표가 cm 에 대해 단봉**이라고 가정한다. 올라가다 나빠지면 봉우리를 지난
것으로 보고 멈춘다. Python 도 같다. 물리적 근거는 있다 — CH3 은 제일 기울어진 채널로
방광 아래쪽을 보므로 위로 가면 점점 벗어난다.

깨질 수 있는 경우는 **한 위치만** 일시적으로 나빠지는 것이다: 장내 가스가 CH3 을 가림,
접촉이 뜸, 호흡으로 방광이 움직임. 그러면 더 위가 진짜 좋았는데 조기 종료한다.

실측에 징후가 있다. 2026-09-09 `kai` 는 **0cm ch3=X → 1cm ch3=O 91%** 로 지표가
올라갔다. 시작 쪽은 종료 조건이 "앞에 eligible 이 있어야" 걸리게 막혀 있지만 **중간에서는
한 칸만 나빠도 끝난다.** 같은 날 `181128` 이 정확히 그 경우다 — 1cm 에서 nch 2→0,
ch3 100%→0% 로 두 조건이 동시에 걸려 best=0cm, 2cm 이후는 모른다.

## 판정은 바꾸지 않고 **측정 가능하게** 만든다

규칙을 바꾸면 레퍼런스 대조(단일 pass 기준)를 다시 해야 한다. 그건 알고리즘 팀이 숫자를
보고 정할 일이다. 그래서 전 위치로 고르면 어디가 뽑히는지 **같이 계산해 기록한다**:

    "best_cm": 0,                  앱이 쓰는 값 (단일 pass · 레퍼런스)
    "best_cm_full_sweep": 3,       잰 위치 전부로 고르면
    "sweep_disagrees": true

갈리면 화면에도 참고 문구가 뜬다 — 그 자리에서 "더 위가 좋아 보인다"를 알면 다시 정렬을
택할 수 있다. 어제 전수 측정으로 바꾼 것이 이 답을 내는 전제였다(조기 종료하면 비교할
위치가 없다).

## 확인 측정이 판정 데이터를 덮고 있었다

부착 위치로 내려가 한 번 더 재면 `align_2cm.csv` 를 **덮어썼다.** 화면 판정은 먼저 잰 것
기준인데 파일은 나중 것이라, 파일로 재판정하면 앱과 답이 갈릴 수 있다. 조기 종료 시절에는
드물었지만 전수 측정으로 바꾼 뒤에는 **항상** 일어난다.

`align_2cm_confirm.csv` 로 분리했다. 판정 근거가 파일에 그대로 남는다.

테스트 139개 통과.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 12:05:16 +09:00
dw.jang 2ec874d7f8 docs: 병원 임상 알고리즘 상세 — BV · 그래프 필터 · 정렬 판정 · 벽 검출
docs/CLINICAL_ALGORITHM.md 신규. 네 항목을 코드에서 읽어 정리했고 각 주장에 파일·라인을
달았다.

## ① BV 계산
샘플→mm 변환(프리셋별 dps·delay) → 각도 보정 단면 지름 → 타원 단면적(lrRatio) →
y-z 타원 피팅 → 절두원뿔 적분 → 위/아래 모자. 공식과 상수를 그대로 적었다.

## ② 그래프 필터 — 제일 많이 오해할 지점
**화면 파형은 원신호다.** SG도 TGC도 안 들어간다(y축 0~4095 고정). 세로선만 SG·TGC·CCC 를
거친 결과다. 그래서 선이 봉우리에서 살짝 비켜 있는 것이 정상인데, 모르면 검출이 틀린
것으로 읽는다. SG(7,3) heavy/light 를 왜 둘 쓰는지, TGC 의 ratio 식도 적었다.

## ③ 정렬 판정
지표 넷(nch·ch3·ch3_rate·cap_frac)이 왜 CCC on/off 로 갈리는지, 종료 조건 셋의 우선순위,
3단 선택 규칙, 부착=best+1 을 왜 단순 덧셈으로 두는지(스냅은 회고 분석 전용),
2026-09-10 전수 측정으로 바꿨어도 판정이 안 바뀌는 이유.

## ④ 벽 검출
"벽보다 오줌을 먼저 찾는다"는 발상부터 5단계. Otsu 구간, 후보 점수식, 어깨 페널티가
데드밴드인 이유, 게이트 넷, 레퍼런스 경로의 CCC 단계가 기존과 다른 점.

## 문서에 꼭 넣은 세 가지 함정
  · 화면 세로선은 정수 ant/post, BV는 소수 antRefined/postRefined — 손으로 검산하면
    미세하게 안 맞는다
  · 프리셋이 틀리면 BV가 통째로 틀린다(실측 125 ↔ 490 mL)
  · 좌우 미검출이면 lrRatio=1.0, 즉 방광을 원으로 놓고 계산한다

마지막에 상수 표 한 장과 "기억할 것 다섯", 레퍼런스 대조 테스트 목록을 붙였다.
인용한 테스트 7개와 값(155.4257 mL, anchor_cases 200건)은 파일로 확인했다.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 11:14:24 +09:00