Commit Graph

320 Commits

Author SHA1 Message Date
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
dw.jang 0b06acea2b fix: Placement 스캔 전 mpa(piezo power on) 전송 — ADC 미수신 해결
기기가 piezo power off 상태에서 maa 보내면 reb 없이 raa만 옴
→ performScan()에서 sendPiezoPowerOn() 호출 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 18:04:38 +09:00
dw.jang 737eaa1a32 fix: mcs 명령 제거 (avg=10이 echo detection 방해 가능성 — 기기 기본값 사용)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:58:26 +09:00
dw.jang 26d5ae20fd fix: mcs avg=10으로 설정 (freq=2, cycles=5, avg=10, delay=20, samples=140)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:53:52 +09:00
dw.jang 4045ae5198 fix: 연결 시 mcs avg=3 복원 (이전 avg=10 설정이 기기에 남아있음)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:45:37 +09:00
dw.jang fff465f6f6 fix: detachment 비활성화 + incomplete retry 제거 (c3eba58 기반 안정화)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 17:39:44 +09:00
dw.jang 01637ce503 feat: 6채널 미만 수신 시 자동 retry (패킷 드랍 대응)
onMultiChannelComplete에서 receivedCount < 6이면:
- 자동 retry (collector reset + 재전송)
- 최대 2회 재시도 (maxMeasureRetries)
- INCOMPLETE_SCAN 로그 기록
- 6채널 온전히 수신된 경우만 BV 파이프라인 진행

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 16:04:22 +09:00
dw.jang 1c5707ebf7 fix: Placement 재진입 시 상태 리셋 (Step 1부터 시작)
LaunchedEffect(Unit)으로 진입 시 모든 상태 초기화:
phase→VERTICAL, isLocked→false, scanCount→0,
channelDetected→false, urineLen→0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:50:52 +09:00
dw.jang 9b92f09e88 feat: Placement Guide 2단계 순차 탐색으로 전면 교체 (대표님 요구사항)
[1단계: 상하 탐색 (VERTICAL)]
- 안내: "센서를 아래에서 위로 천천히 이동하세요"
- CH3,2,1,0 low echo 검출, 3개 이상 필요
- 크기 패턴: 3≥2≥1≥0 또는 유사(변동 <50%) → PASS
- 미달 시: CH0 약하면 "위로", CH3 약하면 "아래로"
- PASS → 2단계(LATERAL)로 자동 전환

[2단계: 좌우 탐색 (LATERAL)]
- 안내: "센서를 좌우로 천천히 이동하세요"
- CH4,CH5 대칭성: |len4-len5|/max < 0.3 → PASS
- 상하 벗어나면 1단계로 복귀
- PASS → 3단계(GREEN)로 전환

[3단계: 최종 Green (CV 확인)]
- CV = std(depths)/mean(depths)
- CV ≤ threshold + LR dev OK → Green (LED 6, Lock)
- CV 미달 → 1단계부터 다시

UI: "Step 1/3", "Step 2/3", "Step 3/3" 상단 표시
LED: 4(미부착) → 5(탐색중) → 6(Green)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:13:26 +09:00
dw.jang e9c5e4536b fix: 도넛차트 캐릭터 옆 ml을 max volume으로 변경
lastVolumeMl (마지막 측정) → maxVolumeMl (최대 측정값)
세션 중 가장 높은 측정값을 표시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 15:07:13 +09:00
dw.jang fb8204994f feat: CSV에 threshold, dps, sg_filter 컬럼 추가
scan_id,timestamp,volume_ml,lr_ratio,threshold,dps,sg_filter,channel,s0,...
1,14:30:12,305.2,1.20,1150,1.771,ON,CH0,1823,...

매 측정 시점의 설정값이 ADC와 함께 기록되어
추후 분석 시 어떤 파라미터로 측정했는지 추적 가능

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 12:17:59 +09:00
dw.jang fecb02dfde fix: Endian 감지 간헐적 실패 수정 (19회 중 5회 ADC 값 폭발)
근본 원인: CH0 첫 샘플이 LE/BE 둘 다 4095 이하일 때
  감지 불가 → LE로 잘못 판정 → 전체 채널 값 폭발 (30000~65000)

수정:
- 확실한 경우: 기존 로직 유지 (LE>4095→BE, BE>4095→LE)
- 애매한 경우: forceBigEndian 기본값 사용
- VBT* 기기: forceBigEndian=true (기기 연결 시 자동 설정)
- 2025MEDIP: forceBigEndian=false
- Endian 결정 로그 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 12:09:57 +09:00
dw.jang 7125e79fb9 feat: scan_id를 BLE 로그에도 추가 (CSV와 대조 가능)
- MEASUREMENT scan=3 vol=305.2ml lr=1.20 valid=4/6
- BV_SKIP scan=4 center=2/4 total=2/6
- BV_FAIL scan=5 no valid channels

AdcCsvLogger.lastScanId 공개 → BleDebugLogger에서 참조

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 11:24:57 +09:00