Commit Graph

132 Commits

Author SHA1 Message Date
dw.jang 72ccbdf102 fix: Thread→coroutine, PlacementGuideView 메인스레드 보장
- #2: PiezoMonitoringView raw Thread → measureScope.launch + Dispatchers.Default
  withContext(Main)으로 state 변경 보장, composable 떠나면 자동 취소
- #22: PlacementGuideView onMultiChannelComplete 콜백 → handler.post 감싸기
  BLE Binder 스레드에서 Compose state 직접 변경 → 메인 스레드 보장
- nested handler.post 제거, throttle 시 직접 state 리셋

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 16:30:19 +09:00
dw.jang 758930796f fix: critical code review — thread safety, state management
CRITICAL fixes:
- #1: lastMultiChannelResult 변경을 handler.post로 (메인 스레드 보장)
- #3: measureDoneSignal var=remember → val mutableStateOf (recomposition 안전)
- #34,35: BleManager bluetoothGatt/tx/rxCharacteristic/lastRxTimestamp @Volatile
- #66: GreenZoneConstants 모든 mutable var @Volatile
- #56: PiezoHW.distancePerSample @Volatile
- nested handler.post 제거 (불필요한 프레임 지연)
- maa throttle deadlock 방지 (Boolean 반환 + state 리셋)
- Plot/Log 불일치 수정 (channelLogs를 allWalls 기준으로 통일)
- Placement 센서 위치/화살표 조정, gradient dead zone, CV relaxation
- 개발자 모드 CV 표시, 가이드 상자 항상 표시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 16:25:06 +09:00
dw.jang 0e0e04b6f5 fix: cross-channel outlier 제거 + placement 강화 + UI 수정
- Cross-channel urine length outlier: median의 1.35x 초과 또는 0.5x 미만 → 제거
  (CH3 바닥반사 urine=50 vs 정상 ~35 → 480ml↔223ml 편차 해결)
- Placement CV: V0=0.07, V1/V2=0.10 (기기별 분기)
- Placement 기준 강화: LR dev 0.20, gradient 0.3, lenVariation 0.35
- "방향OK→무조건GREEN" 제거, CV 미달시 "Fine-tune position"
- GREEN CV가이드/Hold steady 제거, ch별 len 분석 방향 안내
- 가이드 텍스트 상자 항상 표시
- 센서 이미지 topview 교체 (240×150dp)
- 앱 버전 VBTAND0101
- Plot/Log allWalls 통일 (선택 Method 기준)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 15:36:38 +09:00
dw.jang 6dd0ec5058 UI: 피드백 반영 — Placement/Donut/뒤로가기/토스트
[Placement]
- 복부 높이: 500dp→weight(1f) 유동, 스크롤 제거
- 화살표 크기: 50→70, head 20→28, stroke 7→9
- 6/6, 60% 비개발자 모드에서 제거
- Step indicator를 이미지 위로 이동

[Donut]
- Bladdy 크기: 80/110dp→120/150dp (비개발자)
- 도넛 크기: 260/320dp→300/360dp (비개발자)
- 볼륨 텍스트 배경 제거 (투명)
- 원 내부 흰색 반투명 배경 추가
- measuring 메시지 제거 (Auto 대기 중 표시 안 함)
- 배터리 옆 초록 connection dot 제거
- Volume 카드 제거, Fill/Level만 유지 (maxVolumeMl 기준)
- "빠른 저장"→"Quick Save" 영어 통일
- 측정 부족/미감지 토스트 제거

[기타]
- HOME 뒤로가기 → "Exit App?" 확인 다이얼로그

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 12:36:41 +09:00
dw.jang 414ce940a2 fix: maa 1초 throttle — BLE 계층에서 이중 전송 물리 차단
handler.post로 isMeasuring 갱신해도 Compose state 레이스 해결 안 됨.
BleManager에서 lastMaaSentMs 타임스탬프로 1초 이내 재전송 무조건 차단.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 12:27:58 +09:00
dw.jang 54bca199af fix: maa 이중 전송 방지 (BV_FAIL 근본 원인)
- isMeasuring=false를 handler.post로 메인 스레드 갱신
  (Thread 내 설정 → Compose state 지연 → 다음 measure() 통과 → maa 이중 전송)
- measure() 진입 시 isMeasuring 가드 추가 (중복 호출 방어)
- 채널 수신 로그 추가 (RECEIVED N channels)
- MTU 247 negotiation 추가 (reb: 208B 분할 전송 최소화)
- Spot 6ch 필터 추가 (allChannelsReceived)
- Auto Stop 시 값 유지 (재계산 안 함)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 11:59:13 +09:00
dw.jang c819d615d0 fix: LR 방향 수정 + Almost there 제거 + postMaxIdx 슬라이더
- 좌우 방향 전면 수정: ch4(왼쪽)길다→←, ch5(오른쪽)길다→→
  ch4만 감지→← (기기 오른쪽 치우침), ch5만→→
- Almost there 제거: 방향OK+CV미달 → 그냥 GREEN 통과
- postMaxIdx 런타임 슬라이더 (개발자 설정, 기본 80, 범위 50-95)
  Method A/B 공통 적용 — 바닥반사 peak 무시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 09:41:44 +09:00
dw.jang b1ca5bfd66 fix: Auto Stop 최종 trimmedMean 반영 + Placement 채널소실 멘트
- Auto Stop 시 윈도우 전체 trimmed mean 계산 후 표시
- LATERAL/GREEN 중 center 채널 소실 → "Start over from above the pubic bone"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-07 18:04:24 +09:00
dw.jang e5b252b314 feat: Detection/BV 분리 설정 + Spot 5회 trimmedMean + UI 여유
- Detection(A/B/C)과 BV(Frustum/V41) 독립 설정 (개발자 모드)
  기본값: Detection=C, BV=V41
- Spot: 3회 median → 5회 1.5초간격 trimmed mean (Auto와 동일)
  최대 8회 재시도, 최소 유효 3개
- 일반 모드 도넛 320dp, 간격 28dp, 버튼 62dp (화면 여유)
- Placement mm 표시 제거 — 방향만 안내

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-07 17:28:04 +09:00
dw.jang 1b70ec809d fix: preset 감지 오류 (BV 2배 차이 근본원인) + 도넛 비율 + placement 자동통과
- autoDetectPreset: 기기이름 뒤에서 3번째 글자로 각도타입 판별
  VBT26050301 → '3' → V2 (기존: VBT2604 매칭 실패 → V0 → 각도 0° → BV 절반)
- 도넛차트: level 단계별 → maxVolumeMl/maxVolume 연속 비율로 변경
- Placement "Almost there" 3회 연속 → 자동 GREEN 통과

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-07 16:13:13 +09:00
dw.jang b73921eb2b fix: UX feedback + BV ellipse outlier (#22) + README v3 update
- #1 배터리 최적화 페이지 이동 제거 (ForegroundService+WakeLock만)
- #2 Auto 첫 측정 대기 시 "Measuring... (n/5)" loading 표시
- #3 Placement 멘트 정리 — 방향만 남기기 (CH 언급 제거)
- #4 CH0~CH5 dot row 개발자 모드 전용
- #5 Spot 재시도 로직 (최대 6회, 유효 3개 목표, 300ms 간격)
- LR 좌우 조건 완화: ±8mm, symmetry≥0.5, lrDev≤0.35
- |len4-len5|≤10 → LATERAL 건너뛰고 바로 GREEN
- GREEN 미달 시 CV만 간당간당하면 GREEN 유지 ("Almost there...")
- CV 기본 임계 0.08→0.12, 디바운스 3초→1.5초
- BV 타원 피팅 outlier 반복 제거 (appshare #22)
- README v3 업데이트 (3모드 placement, BV 파이프라인, 상태표)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-07 15:36:14 +09:00
dw.jang 139ebcbbb1 refactor: BV estimation — y-z/x-z ellipse fitting, wall repair, outlier removal
Port of appshare #21 merge (bv_estimation.py):
- repairCenterWallsFor6ch: gap=1 보간, gap>=2 top 그룹 제거
- computeLrRatio: chord 비율 → x-z 6점 타원 피팅 (b_lr/a_ap)
- Post-median outlier 제거 (median ±25%, ≥3ch)
- Cap 높이: ellipseCapHeights 삭제 → y-z 8점 타원 피팅 inline
- Top cap 상한: 미검출 상위 채널 빔 y좌표 기준 제한

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-07 12:06:41 +09:00
dw.jang 53a07195f8 feat: developer mode, SWEEP placement, gradient guide, spot flicker fix
- Developer mode: 캐릭터 3탭 토글, dev-only settings/graphs/logs
- SWEEP placement (CKLaw): BladderSphereSeek circle fit + RTracker
  + argmax + coronal lateral + R-peak gate GREEN lock
- Gradient placement: weighted center gradient 기반 상하 판정,
  방향 로직 수정 (ch0=위, ch3=아래), 초기 멘트 "치골 위에 배치"
- Spot 측정: isSpotInProgress 플래그로 중간값 화면 깜빡임 제거
- 좌우 애매한 ↔ 멘트 제거 → 구체적 방향 또는 상태 안내

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-07 11:32:03 +09:00
dw.jang 4b74b88f76 refactor: placement body PNG → Canvas 실루엣 (CKLaw Bezier torso)
placement_body.png 제거, CKLaw BladderSeekScreen의 해부학적
Canvas 실루엣으로 교체 (갈비뼈, 배꼽, 치골 아치, hourglass torso).
sensor_device.png는 유지. 센서 위치 방광 타원 안쪽으로 조정.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 16:38:44 +09:00
dw.jang 9d64faf8cf UX: Placement UI 대폭 개선 — 센서 사진, 영어 멘트, 화살표 강화
이미지:
- 센서 사진(vesiscanbasicimage.png) 오버레이 (200×125dp)
- 전체 영역 500dp로 확대
- 타원 높이 절반 + 위쪽 경계 고정
- 센서 위치 미세 조정 (x+5dp)

화살표:
- 타원 바깥 경계에 부착 (gap=12)
- 두께 5→7, 머리 18→20, 색상 #FF5722
- 상하좌우 타원 경계 기준 위치

텍스트:
- 전체 영어화 (Gradually raise/lower, Move right/left 등)
- "Sensor Placement" → "Sensor Alignment"
- "Placement Complete" → "Alignment Complete"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 14:12:04 +09:00
dw.jang b4e2b21306 fix: 배터리 최적화 제외 요청 (Doze 면제, 삼성 대응)
- BLE 연결 시 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 다이얼로그 표시
- 이미 제외 상태면 스킵
- Manifest에 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 권한 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 12:30:54 +09:00
dw.jang 4357cb359a fix: 도넛 차트 maxVolume 복원 (최대값 유지, Volume 카드는 실시간)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 12:22:07 +09:00
dw.jang f3d3a9ce54 feat: 6ch 필터 + 도넛 확대 + Fill/Level 기준 변경 + 슬라이딩 윈도우
BV 계산:
- 6채널 모두 수신(buffer>=20) 시에만 BV 계산 (불완전 데이터 제외)

도넛 차트:
- 크기: compact 180→220dp, normal 240→280dp
- 선 두께: 20→22, 28→30dp
- 캐릭터: 70→80, 100→110dp
- 볼륨 텍스트: 16→18sp, maxVolumeMl → lastVolumeMl 표시

Info Cards:
- Fill: appState.fillPercentage → lastVolumeMl/maxVolume×100 (실측 기준)
- Level: appState.bladderLevel → lastVolumeMl/maxVolume×MAX_LEVEL
- 미측정 시 "—" 표시

Auto 측정:
- 배치 윈도우 → 슬라이딩 윈도우 (최대 10개 유지, 오래된 것 제거)
- 5개 이상이면 매 측정마다 trimmed mean 업데이트
- 이전: 10개 모이면 한 번에 업데이트 → clear
- 변경: [1,2,3,4,5]→출력, [2,3,4,5,6]→출력 (실시간 반영)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 12:13:10 +09:00
dw.jang 802b9b1822 feat: Placement 하복부 일러스트 이미지 + UI 개선
Placement:
- Canvas 실루엣 → 하복부 일러스트 PNG 배경 (투명 배경 처리)
- 방광+센서+화살표는 Canvas 오버레이 유지
- GREEN 진입/이탈 즉시 반영 (디바운스 무시)
- 좌측 라벨(가슴/배꼽/치골) 제거

Spot 측정:
- 3회 측정 중 화면 깜빡임 방지 (이전 값 유지, 최종 median만 표시)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-06 11:52:32 +09:00
dw.jang 4dd8d5382f fix: BLE 로그 실시간 파일 기록 (화면 잠금/앱 종료에도 보존)
BleDebugLogger:
- 매 entry마다 즉시 Downloads/VesiScan_BLE_*.log에 append
- 새 BLE 연결 시 새 파일 생성 + 헤더 기록
- 기존 메모리 내 로그 + UI 표시는 동일 유지
- 화면 잠금/Doze/앱 종료에도 로그 보존

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 18:06:55 +09:00
dw.jang 231ae1bf6d fix: Placement GREEN CV 기준 strict화
- DEFAULT_CV_THR: 0.10 → 0.08
- 완화: 0.05/8회 → 0.03/10회 (max 0.14)
- 초기 0.08, 10회 후 0.11, 20회 후 0.14

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 17:51:29 +09:00
dw.jang 502151b967 feat: Spot 3회 median + Placement 가이드 딜레이 3초
Spot:
- 1회 즉시 → 3회 연속 측정(200ms 간격) → median 표시
- 측정 중 로딩 인디케이터
- 2회 이상 유효 시 median 적용

Placement:
- 가이드 텍스트 최소 유지시간 4초 → 3초

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 17:20:32 +09:00
dw.jang 82634c2107 feat: Method C (V4.1) 대규모 업데이트 — 2-pass pipeline + ChordConsensus
새 알고리즘 모듈 (7개):
- ImpulseReject: 2-pass Hampel filter (lumen 내 impulse 제거)
- MedianFilter: running-median pre-filter (window=7, speckle 제거)
- MorphClose: morphological closing on lumen mask (disabled)
- StaLta: STA/LTA impulse detector (Allen 1978, wall edge vs reverberation)
- ChordConsensus: Tukey MAD outlier + Fischler-Bolles pair test
- DetectionSanity: detection sanity checks
- SweepStabilizer: sweep temporal stability

변경된 모듈 (9개):
- V41Detector: 2-pass pipeline (ImpulseReject.detectWithLumenClean),
  BModeScore V41_WEIGHTS (wamp+stalta), ChordConsensus filtering
- BvEstimation: ChordConsensus filter → trusted channel only
- DetectLumenFirst: running-median pre-filter, V41_PARAMS,
  mergeGapMax=5, Kremkau half-amplitude ant fallback
- AnatomicalGate: antDepthMin 22→10mm, strict threshold 제거
- BModeScore: V41_WEIGHTS (far=0.15, dark=0.10, wamp=0.45, stalta=0.20)
- WallSelect: MAX_PEAK_CANDIDATES_POST=64
- SpanUtils, Otsu, BvDispatchResult 업데이트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 17:01:55 +09:00
dw.jang d6e981e1d2 feat: 채널별 빔 각도 보정 (Python PR#20 동기화)
Method B:
- 채널별 otsu_ratio = OTSU_RATIO × cos(θ) 보정
- 큰 각도 채널은 threshold 완화 → 약한 후위벽 감지 개선
- detectLowEcho에 otsuRatioOverride 파라미터 추가
- analyzeMultiChannelWithTgc: initial + rerun 모두 각도 보정 적용

Method A:
- 채널별 min_wall_contrast_ratio = 1.2 × cos(θ) 보정
- detectMethodA에 contrastRatioOverride 파라미터 추가
- analyzeChannel에서 PiezoHW.degreeAll 기반 자동 계산

Monitoring:
- Detachment LED: 상태 변경 시에만 전송 (wasDetached 추적)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 16:32:31 +09:00
dw.jang 258bad9a26 feat: Foreground Service + Detachment 개선 + Placement 가이드 모드
Foreground Service (BleForegroundService.kt):
- BLE 연결 시 자동 시작, 해제 시 자동 중단
- PARTIAL_WAKE_LOCK (최대 4시간)
- Notification: "VesiScan - BLE 기기 연결 중..."
- connectedDevice foregroundServiceType
- Doze 모드에서도 BLE 통신 유지
- keepScreenOn도 유지 (추가 안전장치)

Detachment 개선:
- THR_MEAN/STD 100→30 (완전 탈착만 감지, 거리 약화 무시)
- 6채널 모두 수신됐을 때만 체크 (BLE 거리 문제와 구분)
- Placement: if(false) 제거 → 활성화 + "센서가 부착되지 않았습니다"
- Monitoring: 정상 복귀 시 LED OFF

Placement 가이드 모드:
- Simple (기본): 3+채널 → 바로 좌우 (기존)
- Boundary: 올라갔다 내려오기 패턴 (경계 감지 → 최적점 복귀)
- 설정 톱니바퀴에 Simple/Boundary 스위치

BLE 로그:
- 역순 표시 (최신이 위) — 스크롤 위치 유지

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 16:09:54 +09:00
dw.jang 48df4370bc fix: Placement 그래프를 선택된 Method 결과로 통일
- 그래프 벽 표시: analyzer.analyzeChannel(B 고정) → lastWallResults(선택 Method)
- lastWallResults state 추가: 콜백에서 allWalls 저장 → 그래프에서 참조
- Method C 선택 시에도 V41Detector의 ant/post가 그래프에 정확히 표시
- dot 색상 + 그래프 벽 + depth mm 모두 동일 Method 결과 사용

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 18:04:01 +09:00
dw.jang 3370fd8087 fix: 후면반사 오판방지 수정 + 1채널 구 BV 추가
BackReflection.kt (Python 동기화):
- consensusIdx: min_votes=3 (후보 3개 미만이면 None)
- buildCandidate: post≈global_br이면 None 반환 (post를 BR로 판단 안함)
- isSuspiciousPostPeak: post>ant → post>ant×1.5 (amp_ratio=1.5)
- isReflectionOnlyMultichannel: post>ant → post>ant×1.5

BV Estimation:
- 1채널 구(sphere) 계산 추가 (Python _single_channel_bv)
  - V = (4/3)πR³, R = D/2 (cos 보정)
  - centerWallCount >= 1이면 BV 계산 (기존 3 → 1)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 17:42:30 +09:00
dw.jang 002a99d163 fix: Placement LED 단계별 1회만 + 화살표 확대 + 도넛뷰 detachment LED
Placement:
- LED 명령: 매 스캔 → 단계 변경 시 1회만 (lastLedMode 추적)
  - 5=SEARCHING, 6=COMPLETE, 화면 나갈 때 0=OFF
- 화살표 크기: arrowLen 40→60, arrowHead 12→18, strokeWidth 4→5

Monitoring (도넛뷰):
- 매 측정마다 DetachmentDetection.detect() 실행
- 미부착 감지 시 LED 4 (DETACH_WARNING) 전송 + 로그

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 17:29:37 +09:00
dw.jang 30c1d4d8db feat: Python 알고리즘 대규모 동기화 — 후면반사 재작성 + detect_core + wall selection
BackReflection.kt (신규):
- 합의 기반 다채널 BR 시스템 (Python pipeline.py 1:1)
- buildCandidate: post 뒤 strongest peak 또는 post 자체
- consensusIdx: outlier 제거 후 median
- isReflectionOnlyMultichannel: 조건A(shared_idx) + 조건B(post 클러스터)
- isSuspiciousPostPeak: post>ant 또는 shared 근접
- selectIdx + resolveIndices: 최종 BR/suppress 위치 결정
- chooseResult: rerun vs initial fallback 로직
- suppress: valley early-stop 50.0 (over-erasure 방지)

PiezoEchoAnalyzer.kt:
- Otsu: separability/fallback 제거, OTSU_RATIO 0.85→0.9, Otsu-only 단일 시도
- detectLowEchoCore: 비대칭 score (ant_reliability × ant_depth + post_depth)
  - FP: postProm < minPeakMargin reject
  - FP: sg[ant/post] < threshold reject
  - wallLowMeanMinRatio 제거
- selectWallByProminence: ANT=nearest outer peak, POST=edge_score
- findRightValley/findLeftValley: descending-first logic (Python 동일)
- refineRightEdge: 병합 span 우측 트리밍
- POST 먼저 찾고 ANT는 반사 fallback (post-e 거리 대칭)
- analyzeMultiChannelWithTgc: Python pipeline.py 전체 흐름
  - TGC 전체 채널 통합 (applyTgcMultichannel)
  - initial detect → BR candidate → consensus → reflection_only
  - resolve → suppress → rerun → choose
- LOW_ECHO_AMP: 1250 (config_6ch 동일)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 16:34:18 +09:00
dw.jang 0a8ae91409 UX: UI 정리 — 단위 배치, 버튼 텍스트, LED OFF, Delete Pairing
도넛차트:
- InfoCard: ml/% 단위를 숫자 오른쪽에 배치 (기존 아래 → 옆)
- Void/Catheterize: 글자 크기 통일 (11+13sp → 12sp 균일)
- Disconnect → "Delete Pairing" 텍스트 변경

Placement:
- 화면 벗어날 때 LED OFF (DisposableEffect onDispose → sendLedMode(0))
- LATERAL 디버그 로그 추가 (CH4/CH5 len + symmetry)
- 대칭 기준 0.7 유지

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 15:27:13 +09:00
dw.jang 288efaafc9 UX: Placement 자동스캔 + Stop/Resume 삭제 + Placement Complete
Placement:
- 화면 진입 시 자동 스캔 시작 (isContinuousMode=true)
- 초기 힌트: "센서를 부착해주세요"
- Stop/Resume Scanning 버튼 삭제
- Start Measurement → "Placement Complete" (Green 또는 4+ch 감지 시 활성화)
- Skip 버튼 TextButton으로 유지

Algorithm:
- LATERAL 조건: (ch4&&ch5) OR 제거 → lrSymmetry >= 0.7 필수

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 14:43:36 +09:00
dw.jang e528bc6761 fix: Python 대조 CRITICAL 10건 수정 (Method A/B 완전 동기화)
Method B:
- #1 Otsu: limit 제거 → 전체 신호로 계산
- #2 detectLowEcho: 2단계 fallback (Otsu→None이면 고정1250 재시도)
- #3 LOW_ECHO_AMP: 1150 → 1250
- #4 low mask: analysisLimit 제한 제거 → 전체 신호 마스킹
- #5 postH >= threshold 체크 제거 (Python에 없음)
- #6 merge gap < 3: 무조건 병합 (peak_check_min_gap=3)
- #7 TGC: raw fit → log 압축 후 fit (Python fit_attenuation_lines 동일)
- #8 Back reflection: 다채널 consensus → 채널별 개별 (Python pipeline.py 동일)

Method A:
- #9 sliding_scores_1d low quantile: floor index → np.quantile 선형 보간
- #10 score_thr: 중간값 근사 → np.quantile(0.5) 선형 보간
- npQuantile() 헬퍼 함수 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 14:33:58 +09:00
dw.jang 5affcde3c4 fix: 그래프 Method 동기화, Spot 쿨다운, 스캔 캐릭터 센터링
도넛차트:
- Developer Tools 그래프: 선택된 Method(A/B/C)로 분석 표시 (기존 B 고정 → 동기화)
- Spot 버튼: 1.5초 쿨다운 (연속 탭 방지, 기기 회복 시간 확보)

DeviceScan:
- 스캐닝 캐릭터 가운데 정렬 (.fillMaxWidth()) + 크기 140→180dp

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 12:31:20 +09:00
dw.jang 85162669e4 fix: BLE 패킷 수신 메인스레드 의존 제거 + Auto 간격 1.5초
BLE:
- onCharacteristicChanged에서 handler.post 제거
- processReceivedData를 Binder 스레드에서 직접 실행
- 메인 스레드 큐 대기로 인한 reb 패킷 유실 방지

Auto:
- 최소 간격 1000ms → 1500ms (기기 연속 maa 채널 드롭 방지)
- 10개 × 1.5초 = ~15초마다 trimmed mean 업데이트

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 10:37:14 +09:00
dw.jang 1a42fe6a07 fix: 분석 백그라운드 Thread, 그래프 빈칸 표시, CSV 세션별 분리
성능:
- 측정 콜백 분석(TGC/Otsu/BV)을 백그라운드 Thread로 이동
- UI 업데이트만 handler.post로 메인 스레드 복귀
- 메인 스레드 블로킹으로 인한 BLE 패킷 드롭 방지
- 분석 소요시간 로그 출력 (Analysis took Xms)
- Toast도 handler.post로 감싸서 Thread-safe

Placement:
- 6채널 그래프: 데이터 없는 채널도 "No data" 빈 칸 표시 (항상 6칸)

CSV:
- 일별 파일 → 세션별 파일 (YYYY-MM-DD_HHmmss.csv)
- BLE 연결 시 자동 newSession()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 10:04:03 +09:00
dw.jang 297d67b4d7 fix: Auto 측정 완료대기+최소1초 간격, 10개 trimmed mean, 토스트 억제
Auto 측정:
- 완료 대기 방식: isMeasuring polling (100ms) → 다음 측정
- 최소 1000ms 간격 강제 (기기 한계 0.6초 + 여유)
- 윈도우 5→10개, 최대/최소 제외 8개 평균 (~10초마다 업데이트)
- valid≥4만 윈도우에 추가, 나머지 skip (로그만)
- Auto 중 "접촉불량" 토스트 숨김 (Spot에서만 표시)

Placement:
- 그래프 ant/post 항상 표시 (감지 여부 무관)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 18:12:49 +09:00
dw.jang 6614e915d6 feat: Method B TGC+FP필터, Placement UI 리디자인, 네비게이션 개선
Method B 알고리즘 (Python 동기화):
- TGC 파이프라인: applyTgc (감쇠 보상, adaptive ratio)
- 후면반사 제거: findBackReflectionIdx + suppressBackReflection
- 멀티채널 합의: findBackReflectionMultichannel (median)
- FP 필터: wallMin/lowMean < 1.15, score < 3000
- peakMin: max(lowMean+margin, threshold)
- Otsu: separability 반환 + OTSU_RATIO(0.85) + fallback(sep<0.3)
- urineLen: post-ant → post-ant-1 (Python 동기화)
- ant fallback: span 시작 직전 (단조 감소 대응)

Placement UI 리디자인:
- 상반신 일러스트 (Canvas: 몸통+배꼽+치골+방광+센서+화살표)
- Green Zone: 배경 animateColorAsState 전환 + 체크마크
- 가이드 순서: 치골→위로→CH0 안잡히면 아래로→좌우 대칭
- 디바운스 4초 유지, 힌트 텍스트 Green시 초록
- 좌우 힌트: CH4/CH5 비교 기반 방향 제시
- 설정 톱니바퀴 + floating 패널 (Method A/B/C + Otsu)
- 채널 dot row 별도 배치
- Green score: CV 0.10, LR dev 0.25 (엄격화)

도넛차트 UI:
- Max Vol 카드 제거 (4→3칸), InfoCard 높이 통일
- Void/Catheterize 버튼 (2줄, 56dp)
- Quick Save: 실제 측정값 표시 + volume 0 리셋
- 기본 Method C

네비게이션:
- Placement 뒤로가기 → 연결중이면 Monitoring (Home 안감)
- Home Start → 연결중이면 바로 Monitoring (DeviceScan 스킵)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 16:56:51 +09:00
dw.jang c9cd3cb3ce 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>
2026-04-29 11:06:22 +09:00
dw.jang dc340608ee fix: Placement 오탐 개선 — MIN_URINE_LEN 12, 미감지 채널 벽 표시 제거
- MIN_URINE_LEN_PLACEMENT 10 → 12 (짧은 오탐 필터 강화)
- 미감지 채널(channelDetected=false)은 그래프에서 ant/post 선, depth mm, cyan 영역 미표시
- 파형 자체는 유지 (신호 확인용)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 08:58:56 +09:00
dw.jang 9e350d6d40 fix: Python 대조 검증 — CRITICAL 차이 7건 수정
Method A (PiezoEchoAnalyzerA.kt):
- sliding_scores_1d: edge padding 추가 (np.pad mode="edge" 동일)
- robust_z: 짝수 길이 시 두 중간값 평균 (np.median 동일)
- plateau threshold: 전체 배열 기반 quantile (잘린 배열 → 전체)
- urineLen: post-ant → post-ant-1 (Python 동일)
- score: ((ant+post)/2-lowMean)*len → sg[ant]+sg[post] (Python 동일)
- cross-validation: vals 미변경 + Math.round() (Python 동일)

BV Estimation (PiezoBVEstimator.kt):
- computeLrRatio maxRatio 기본값 3.0 → 1.0 (Python 동일)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 19:00:17 +09:00
dw.jang c849943b4e feat: Otsu adaptive threshold, Method A 포팅, BV ellipse cap, UI 정리
Algorithm:
- Otsu 1D adaptive threshold 포팅 (span_utils.py otsu_1d, 기본 ON)
- Method A 벽 검출 포팅 (PiezoEchoAnalyzerA.kt: plateau score + prominence)
- Method A cross-validation (채널간 중앙값/gradient 보정)
- BV cap 높이: parabolic → ellipse 피팅 (8점 축정렬 타원)
- Bottom cap: sphere, Top cap: cone (Python bv_estimation.py 동기화)
- 설정에 Method A/B 토글 (왼쪽=A, 오른쪽=B)

Logging:
- BLE 로그 + CSV에 otsu threshold 값 기록
- 측정 로그에 method label (A/B) 표시

UI:
- 설정 패널: floating overlay로 변경 + MaxVolume 슬라이더 추가
- Onboarding: 1페이지로 단순화 (Pager/indicator 제거)
- Registration: 한 페이지에 전체 입력 + Skip 버튼
- Placement: 로딩 인디케이터/스캔 텍스트 삭제

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 18:43:56 +09:00
dw.jang c6e84bd6c0 fix: watchdog heartbeat, 배터리 계산, placement 디바운스+방향 수정
BLE:
- watchdog idle heartbeat: 10초 무통신 시 IMU query로 keepalive
- 배터리: 3500-3700mV→0-5%, 3700-4100mV→5-100%, 증가 무시
- 배터리 표시: 아이콘→퍼센트 숫자 (색상 유지)

Placement:
- 힌트 디바운스: 같은 phase 2회 연속일 때만 변경 (깜빡임 방지)
- 방향 힌트 반전: CH3만 잡힘→아래로↓, CH0만 잡힘→위로↑

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 17:27:32 +09:00
dw.jang 5cdae8a86e fix+UX: BLE 중복수신 수정, peak detection 개선, UI 대폭 정리
BLE:
- GATT 다중연결 race condition 수정 (reconnectConnecting 플래그)
- onCharacteristicChanged API 레벨 분기 (dual callback 방지)
- DeviceScan: isConnected → isServiceReady 전환 (서비스 준비 후 화면전환)
- Placement: mpa/maa 500ms 딜레이 (power on 대기)
- Disconnect & Unbond 기능 추가 (msr? + removeBond + 저장정보 삭제)
- autoConnect 삭제 (HomeView)

Algorithm:
- 후위벽 피크 >= threshold 조건 추가 (false positive 차단)
- low-echo 분석범위 80샘플 제한 (뒤쪽 노이즈 무시)
- urineLen: post-ant-1 → post-ant 수정
- Placement: UrinAI fallback 제거 (PiezoEchoAnalyzer만 사용)
- 기기 프리셋 autoDetect index 7→8 수정 (VBT26040Nxx)
- dps 기본값 1.771 → 1.968

UI:
- 도넛차트: Home버튼 삭제, Auto/Catheter count/History 삭제
- 3버튼 레이아웃 (Catheterize/Auto/Spot)
- 배터리 아이콘 (60+초록/30+주황/빨강) + 설정 톱니바퀴 분리
- SensorSelect/Consent 페이지 스킵
- 온보딩: VesiScan-Basic, NIRS 페이지 삭제
- MaxVolume: Step 표시 삭제, mL 오른쪽 배치
- BackHandler 전체 재정리 (자연스러운 뒤로가기)
- BLE 신호 기준 완화 (Good≥-80, Fair≥-90)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 17:03:37 +09:00
dw.jang 227480af4b feat: UI 일괄 수정 (5,6,7,8번)
5. Onboarding 간소화: 4단계→1단계 (Max Volume만)
   Step 1(자세)/2(위치)/4(최적화) 제거, Continue 바로 완료

6. 자동 reconnect: 앱 시작 시 마지막 기기에 자동 연결
   SharedPreferences에 address+name 저장, HomeView에서 autoConnectLastDevice()

7. Demo 모드: DeviceScanView에서 Demo 버튼 제거

8. Android 뒤로가기: BackHandler로 화면별 네비게이션 매핑
   Placement→Home, Monitoring→Placement, History/Diary→Monitoring 등

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 11:41:22 +09:00
dw.jang cc00c25a66 feat: UI 일괄 수정 (9개 항목 중 1,2,3,4,9번)
1+2. Placement peak 감도: urineLen >= 10 필터 (짧은 false positive 방지)
3. Placement 센서 그림(SensorLayoutCanvas) 제거
4. 앱 이름: MediLight → VesiScan-Basic (홈화면 + strings.xml)
9. BLE 신호: Good+Excellent 통합 (rssi >= -65 → Green 4칸)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 11:30:45 +09:00
dw.jang 45e06d8aba fix: mpa 첫 스캔 시 1회만 전송 (매초 중복 전송 제거)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 10:12:42 +09:00
dw.jang 0ffac85f44 UX: Placement 스캔 간격 3초→1초
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 10:10:32 +09:00
dw.jang 6098047cef fix: Settings 스크롤 + Placement Green 후 가이드 복귀
1. Settings 열면 화면 맨 위로 자동 스크롤 (animateScrollTo)
2. Placement Green 후 조건 벗어나면 isLocked=false → 가이드 다시 표시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 10:02:35 +09:00
dw.jang 9d171f0e06 fix: 배터리 연결 시 1회만 측정 (반복 폴링 없음)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:25:18 +09:00
dw.jang 953e6b56aa fix: 배터리 폴링(5초 msn) 제거 — 측정 간섭 방지
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:24:27 +09:00