Chapter 06

양방향 거리 측정: SS-TWR와 DS-TWR

휴대폰과 태그의 시계는 서로 맞춰져 있지 않다. 한쪽이 “지금 12시 0분 0.000000001초에 보냈어”라고 해도, 받는 쪽 시계로는 그게 언제인지 알 수 없다. 그래서 UWB는 한 번 보내고 받는 것으로는 거리를 잴 수 없고, 보내고, 답을 받고, 걸린 시간을 비교한다. 이것이 TWR(Two-Way Ranging)이다. 이 장의 공식은 공개 라이브러리 Decawave uwb-core의 rng_math.c를 그대로 옮겼고, 그 라이브러리의 자체 시험 값으로 검증했다.

단방향 TWR: 핑퐁 한 번

A(시작자, initiator)가 Poll을 보내고 송신 시각을 자기 시계로 찍는다. B(응답자, responder)는 받은 시각을 자기 시계로 찍고, 정해진 시간 뒤에 Response를 보낸다. A는 그 Response를 받은 시각을 찍는다. 이제 두 시간이 있다.

왕복에서 B가 기다린 시간을 빼면 신호가 두 번 날아간 시간이 남는다. 그래서 ToF = (Tround − Treply) ÷ 2. 각자 자기 시계 안에서의 차이만 쓰므로, 두 시계가 맞을 필요가 없다. 대신 5장에서 본 대로 시계의 빠르기가 다르면 Treply가 A의 단위로 틀리게 전달된다.

메아리와 답장 시간

산에서 “야호”를 외치고 메아리가 2초 뒤에 오면, 소리가 왕복한 시간이 2초라서 산까지 1초 거리다. 사람이 답한다면 답하기 전에 망설인 시간을 빼야 한다. TWR은 상대가 “나는 받고 나서 정확히 이만큼 있다가 답했다”고 알려 줘서 그 시간을 뺀다. 문제는 상대의 시계도 조금 틀리다는 것이다.

예측해 보기

두 기기의 시계가 서로 20 ppm 어긋나 있다. DS-TWR(메시지 셋)를 쓰면 이 오차는?

DS-TWR은 양쪽이 한 번씩 응답해 왕복을 두 번 잰다.

양쪽 왕복을 곱셈 꼴로 묶으면(비대칭 DS-TWR 식) 시계 오차 항이 서로 상쇄되어 남는 오차는 ppm × 비행시간 수준, 즉 mm 이하가 된다. 아래 타임라인에서 SS와 DS를 바꿔 보자.
SIMULATOR

타임라인으로 보는 SS-TWR와 DS-TWR

방식
SS-TWR (보정 없음)—
SS-TWR (반송파로 보정)—
DS-TWR—
그림: 위 = A, 아래 = B. 사선은 공중을 나는 프레임(비행시간을 아주 크게 과장했다), 괄호는 각자 자기 시계로 잰 구간. 해볼 것: ① A +10 ppm, B −10 ppm, 응답 500 µs면 보정 없는 SS-TWR가 1.5 m 틀린다. ② 반송파로 잰 시계 차이로 보정하면 거의 맞는다(보정 오차 0 가정). ③ DS-TWR는 보정 없이도 mm 아래로 맞는다. 모델: 시계 오차는 ppm만큼 빠르기 차이, 타임스탬프 잡음·안테나 지연 오차 없음. 계산 함수는 uwb-core의 calc_tof_ss()·calc_tof_ds()와 같다.
SS-TWR 오차 ≈ Treply × (eA − eB) ÷ 2   (e = 시계 빠르기 오차, ppm)
응답 시간이 길수록, 두 시계가 다를수록 커진다. 그래서 SS-TWR는 응답을 아주 빨리 하거나(수십~수백 µs), 시계 차이를 재서 보정한다.

uwb-core의 calc_tof_ss()는 마지막 인자 skew로 이 보정을 한다: ToF = (Tround − Treply × (1 − skew)) ÷ 2. A는 B가 보낸 Response의 반송파 주파수가 자기 반송파와 얼마나 다른지 재서(5장, 9번 채널에서 1 ppm ≈ 8 kHz) skew를 얻는다.

양방향 TWR: 핑퐁 두 번

DS-TWR(Double-Sided TWR)는 핑퐁을 한 번 더 한다. A Poll → B Response → A Final. 이제 A와 B 모두 왕복 하나와 응답 하나씩을 갖는다(Tround1, Treply1은 첫 번째 핑퐁, Treply2, Tround2는 두 번째). 두 응답 시간이 같지 않아도 되는 비대칭 공식은 다음과 같다.

ToF = (Tround1 × Tround2 − Treply1 × Treply2) ÷ (Tround1 + Tround2 + Treply1 + Treply2)
오차는 대략 ToF × (eA + eB) ÷ 2. 비행시간(나노초) 자체에 ppm이 곱해지니 사실상 0이다. 응답 시간에 곱해지던 SS-TWR와 대조된다. 대가는 프레임 하나와 그만큼의 시간·전력, 그리고 마지막 타임스탬프를 누군가에게 알려 줄 프레임이 더 필요할 수 있다는 것(FiRa의 “deferred” 방식, 11장).

SS: calc_tof_ss(response, request, transmission, reception, skew) = ((응답 − 요청) − (송신 − 수신) & 0xFFFFFFFF × (1 − skew)) ÷ 2 · DS 비대칭: calc_tof_ds()(분모가 0이면 NaN) · DS 대칭 근사: calc_tof_sym_ds() = (T1R − T1r + T2R − T2r) ÷ 4 · 거리: uwb_rng_tof_to_meters() = ToF × (299,792,458 ÷ 1.000293) × (1 ÷ 499.2 MHz ÷ 128) — 모두 Decawave uwb-core lib/rng_math/src/rng_math.c · Android FiRa의 측정 방식 이름: RANGING_ROUND_USAGE_SS_TWR_*, DS_TWR_*(FiraParams.java)

공개 코드의 시험 값으로 계산하기

uwb-core에는 실제 측정에서 가져온 타임스탬프로 공식이 정확한 거리(정수 m)를 내는지 확인하는 자체 시험이 있다. 32비트 시계 넘침(0xFFFFFFFF 근처의 값)을 일부러 섞은 경우도 있다. 같은 값을 이 책의 계산 함수에 넣어 보자.

CALCULATOR

uwb-core 시험 타임스탬프

시험 경우
ToF(눈금)—
거리—
시험이 기대하는 값(정수 m)—
값은 uwb-core의 lib/rng_math/selftest/src/testcases/calc_tof_test.c에서 그대로 가져왔다. 시험은 결과를 정수로 자른 값(F64_TO_U64)이 기대값과 같은지 본다. “넘침”은 응답 − 요청이 32비트를 넘어가 0으로 돌아가는 값을 섞은 경우로, 빼기를 32비트에서 하고 마스크를 씌워야 맞는다(5장).

핵심 정리

  1. 시계가 맞지 않는 두 기기는 왕복으로 잰다. SS-TWR: ToF = (Tround − Treply) ÷ 2.
  2. SS-TWR 오차 ≈ Treply × (eA − eB) ÷ 2. 20 ppm 차이, 500 µs면 1.5 m. 반송파로 잰 시계 차이(skew)로 보정한다.
  3. DS-TWR(비대칭): ToF = (R1·R2 − P1·P2) ÷ (R1 + R2 + P1 + P2). 오차 ≈ ToF × ppm, 사실상 0. 대신 프레임이 하나 더.
  4. 타임스탬프 빼기는 넘침을 고려해 마스크를 씌운다. 공식은 uwb-core의 시험 값으로 검증된다.

확인 퀴즈

Tround = 1,000.0200 µs, Treply = 1,000.0000 µs(같은 시계 빠르기)면 거리는?

ToF = 20 ns ÷ 2 = 10 ns → 약 3 m.

SS-TWR의 오차를 키우는 두 가지는?

오차 ≈ Treply × Δppm ÷ 2.

DS-TWR가 시계 오차에 강한 이유는?

남는 오차는 ToF(나노초)에 ppm이 곱해진 크기뿐이다.

calc_tof_ss()의 skew 인자는 무엇을 보정하나?

Treply × (1 − skew)로 상대가 잰 응답 시간을 내 시계 단위로 고친다.