보폭 지표를 판정에서 빼야 하는 이유
지금 mmWave 보폭 지표(stride_length, stride_cv)는 걸음 수를 센 측정 69개 창 중 32개(46%)에서 값을 내지 못했고, 정답 ±10% 안에 든 값은 5개(7%)뿐이었습니다. 그래서 두 지표를 낙상 위험 판정에서 빼고, 값은 계속 기록하면서 새 측정 방법을 검증할 것을 제안합니다.
1. 보폭 지표는 어떻게 계산되는가
보폭은 직접 재는 값이 아니라, 레이더 속도 신호에서 걸음 리듬을 찾아낼 수 있다는 전제 위에서 계산하는 값입니다.
| 단계 | 내용 | 코드 위치 |
|---|---|---|
| 1 | 6초마다 환자 트랙의 펌웨어 속도를 모음 | mmWave/send_mmw.py:64, :481 |
| 2 | 속도 신호를 FFT해서 0.5~3Hz의 가장 큰 피크를 걸음 주파수로 봄 | send_mmw.py:303-321 |
| 3 | 보폭 = 평균 속도 ÷ 걸음 주파수 | send_mmw.py:324 |
| 4 | stride_cv는 3단계 값을 바탕으로 계산 | send_mmw.py:326 이후 |
2. 정답과 비교한 결과
낙상 위험 신호로 가장 중요한 종종걸음에서 10개 창 중 9개가 계산에 실패했습니다. 측정자가 걸음 수를 직접 세면서 걸었고, 지금 리더 함수를 그대로 돌려 비교했습니다.
| 측정 | 정답 | 6초 창 | 계산 실패 | 정답 ±10% 안 |
|---|---|---|---|---|
| 직선 3.3m, 2.9m 왕복 | 걸음 길이 0.36~0.58m | 22 | 14 (64%) | 0 |
| 원 모양 평소 60초 | 86걸음, 0.52m | 19 | 5 (26%) | 2 |
| 원 모양 천천히 60초 | 62걸음, 0.47m | 18 | 4 (22%) | 3 |
| 원 모양 종종걸음 60초 | 93걸음 | 10 | 9 (90%) | 0 |
| 합계 | 69 | 32 (46%) | 5 (7%) |
값이 나온 경우에도 오차가 −17%에서 +100%까지 컸습니다. 측정 날짜는 2026-11-05입니다.
3. 왜 틀리는가
가장 큰 원인은 계산에 쓰는 펌웨어 속도에 걸음 리듬이 없다는 점입니다. 다른 알고리즘을 써도 이 신호로는 맞지 않았습니다.
| 원인 | 근거 |
|---|---|
| 신호에 걸음 리듬이 없음 | 펌웨어 속도는 레이더 안의 추적 필터가 매끄럽게 다듬은 값입니다. 60초 동안 이어서 걸은 데이터에서도 걸음 리듬이 한 번도 나타나지 않았습니다. |
| 6초가 너무 짧음 | 6초 안에는 걸음이 6~8개뿐이라, 주파수 해상도(약 0.17Hz)가 평소와 천천히 걷기의 차이(약 0.3~0.4Hz)를 가르기에 부족합니다. |
| 시간 계산 버그 | send_mmw.py:627이 한 번에 읽은 프레임 여러 개에 같은 시각을 붙여서, 샘플링 주파수를 실제(18.2Hz)보다 약 5배 크게 계산합니다. 이 버그를 고쳐도 첫 번째 원인 때문에 정답률은 0%였습니다. |
엔벨로프 FFT, ACF, 힐베르트 변환, 피크 간격, 창 10~20초도 시험했지만, 펌웨어 속도로는 어떤 방법도 맞지 않았습니다.
4. 판정에 넣으면 생기는 문제
틀린 보폭 값을 판정에 넣으면 헛알람은 늘고 진짜 변화는 묻힙니다. 지금 판정은 지표 6개의 |z|를 더해서 문턱 3/6/9와 비교합니다(server/mmw_logic.py:37, :47).
- 헛알람: 틀린 보폭 값이 크게 튀면 환자 상태가 그대로여도 합계가 문턱을 넘습니다. Pi 기존 기록으로 시험했을 때 정상 구간의 73%가 "주의" 이상으로 판정됐습니다.
- 진짜 변화가 묻힘: 합성 저하를 넣은 시험에서 6개 지표 합계는 저하를 거의 구분하지 못했고(AUC 0.47~0.49), 속도 하나만 본 방식(AUC 0.57~0.72)보다 나빴습니다.
- 알람 신뢰 저하: 알람이 자주 틀리면 보호자와 간호 인력이 알람을 무시하게 되고, 그러면 진짜 위험도 놓칩니다.
5. 보폭을 빼도 이상을 잡는가
보폭 없이 속도만으로도 천천히 걷기와 종종걸음을 헛알람 없이 모두 잡았습니다. 원 모양 평소 걷기를 기준선으로 두고, 남은 지표 4개(속도, 속도 변동, 흔들림, 멈춤 비율)로 6초 창을 판정한 결과입니다.
| 판정 방법 | 평소 (헛알람) | 천천히 | 종종걸음 |
|---|---|---|---|
| 지금 방식, 4개 |z| 합 ≥ 3 | 42% | 100% | 100% |
| 속도만, 느려짐 z ≥ 2 | 0% | 100% | 100% |
보폭이 짧아지면 대부분 속도도 함께 떨어집니다(종종걸음 속도 −57%). 다만 이 측정은 변화가 크고(속도 −34%, −57%), 측정자 한 명의 데이터입니다. 실제 환자의 작고 느린 변화는 여러 날을 누적해서 봐야 합니다.
6. 빼서 잃는 것과 메우는 방법
보폭을 빼서 새로 잃는 정보는 사실상 없습니다. 지금 보폭 지표가 원래 놓치는 변화를 빼고 나면, 나머지는 속도로 잡히기 때문입니다.
| 변화 | 보폭 없이 잡히는가 |
|---|---|
| 보폭이 줄면서 느려짐 | 잡힘 (속도) |
| 전체적으로 느려짐 | 잡힘 (속도) |
| 보폭이 줄고 걸음이 빨라져 속도는 그대로 (가속 보행 등) | 놓침. 단, 지금 보폭 지표로도 잡지 못함 |
이 빈틈을 메울 후보 방법도 찾았습니다. 레이더 점의 도플러 크기(몸통 도플러 절댓값)를 6초 창마다 스펙트럼으로 만들고, 하루 동안 여러 창을 합친 뒤 환자의 평소 리듬 근처에서 피크를 찾는 방식입니다.
| 경우 | 정답률 (6초 창 5개 합산) |
|---|---|
| 평소 → 평소 | 98% |
| 평소 → 천천히 | 100% |
| 평소 → 종종걸음 | 94% (1.59Hz, 정답 1.55Hz) |
| 천천히 → 평소 (좋아지는 변화) | 0% |
| 2~5초 짧은 직선 걷기 | 대부분 틀림 |
아직 측정자 한 명의 데이터이고 짧은 걷기에서 약하므로, 이 방법은 판정에 넣지 않고 기록부터 시작합니다.
7. 제안 (C안)
두 지표는 판정에서만 빼고, 계산과 기록은 그대로 둡니다.
| 항목 | 변경 |
|---|---|
| 리더의 보폭 계산과 전송 | 그대로 유지 |
| DB 기록 | 그대로 유지 |
z-score 합계 판정 (server/mmw_logic.py:37) | 두 지표 제외, 지표 6개 → 4개 |
문턱 (server/mmw_logic.py:47, 3/6/9) | 지표 수에 맞게 다시 조정 |
추세 분석 (server/gait_trend.py:34) | 보폭 추세 제외 |
다시 넣는 기준: 걸음 수를 센 측정에서 값이 나오는 비율 80% 이상, 오차 ±10% 이내. 새 측정 방법이 이 기준을 넘으면 판정에 다시 넣습니다.
8. 예상 질문과 답
Q. 보폭은 낙상 위험의 중요한 지표 아닌가요?
맞습니다. 그래서 버리지 않고 기록은 계속합니다. 문제는 지표가 아니라 지금 측정값입니다. 잡아야 할 변화(예: 0.58m → 0.50m, −14%)보다 측정 오차(−17% ~ +100%)가 커서, 값이 낮게 나와도 실제 변화인지 측정 오류인지 구분할 수 없습니다.
Q. 14일 웜업 동안 데이터가 쌓이면 정확해지지 않나요?
지금 DB에는 창마다 숫자 7개만 남고(server/db.py:161-167), 보폭을 다시 계산할 원본 신호는 버려집니다. 또 오류가 한쪽으로 치우쳐 있어서(탐색 범위 끝에 붙음), 데이터를 늘려도 같은 쪽으로 틀립니다.
Q. 다른 알고리즘을 쓰면 되지 않나요?
엔벨로프 FFT, ACF, 힐베르트 변환, 피크 간격, 창 길이 10~20초를 모두 시험했습니다. 펌웨어 속도로는 어떤 방법도 맞지 않았습니다. 레이더 점 데이터를 쓰는 새 방법만 가능성을 보였고, 그 방법은 6장처럼 기록부터 검증합니다.
Q. 빼면 위험을 놓치지 않나요?
보폭이 줄어드는 변화는 대부분 속도 저하로 함께 나타나고, 속도로 잡혔습니다(5장). 속도가 그대로인 경우는 지금 보폭 지표로도 잡지 못하므로, 빼서 새로 잃는 것은 없습니다.
한계: 모든 측정은 측정자 한 명이 2026-11-05에 한 것입니다. Pi 기존 기록 시험은 여러 사람이 섞인 데이터에 합성 저하를 넣은 결과입니다. 다른 사람과 실제 환자 데이터로 다시 확인할 예정입니다.