칼만 필터

내비게이션 서비스에서 GPS 노이즈를 제거하고 부드러운 위치 추적을 구현하기 위한 칼만 필터 학습 문서

1. GPS 노이즈란?

GPS가 알려주는 위치는 정확한 내 위치가 아니다. 항상 오차가 포함되어 있다.

가만히 서 있어도 GPS 좌표는 튄다

실제 위치: (37.5665, 126.9780)  ← 고정

GPS 측정값 (1초 간격):
  1초: (37.5667, 126.9782)  ← 2m 북동쪽으로 튐
  2초: (37.5663, 126.9778)  ← 3m 남서쪽으로 튐
  3초: (37.5666, 126.9781)  ← 1m 정도 튐
  4초: (37.5660, 126.9785)  ← 6m나 튐!

이걸 그대로 지도에 표시하면 마커가 덜덜 떨리면서 이리저리 움직이는 것처럼 보인다.

오차가 생기는 이유

  • 대기(전리층/대류층) 통과하면서 신호 지연
  • 건물 반사(멀티패스) — 도심에서 특히 심함, 빌딩에 반사된 신호가 섞임
  • 위성 배치 — 위성이 한쪽에 몰려있으면 정확도 하락
  • 실내/터널 — 신호 차단

일반 스마트폰 GPS 오차 범위: 보통 3~15m, 도심 빌딩 사이에서는 20~50m까지 벌어질 수 있음.

GPS 노이즈 필터링이란?

튀는 값(노이즈)을 걸러내서 실제 위치에 가깝게 보정하는 과정이다.


2. 칼만 필터란?

1960년 루돌프 칼만(Rudolf Kálmán)이 발표한 알고리즘으로, NASA 아폴로 우주선 항법 시스템에 처음 실전 적용되었다.

핵심 아이디어

“불확실한 두 가지 정보를 합쳐서, 각각보다 더 정확한 추정을 만든다”

직관적 비유

눈을 감고 걷고 있다고 상상하자. 내 위치를 알 방법이 두 가지 있다:

방법 1: 내 감각 (예측)
  "나는 1초에 한 걸음(1m) 앞으로 가니까,
   지금쯤 출발점에서 5m 왔겠지"

방법 2: 친구가 알려줌 (GPS 측정)
  "야, 너 지금 4.5m 지점에 있어!"
  (근데 이 친구 눈이 좀 나빠서 정확하진 않음)

칼만 필터는 매초마다 이 두 방법을 번갈아 사용한다.

핵심 공식

최종 추정 = 예측 × (1-K) + GPS 측정 × K
  • K = 칼만 이득 (Kalman Gain): GPS 측정값에 주는 가중치 (0~1 사이)
  • (1-K): 예측값에 주는 가중치
  • K + (1-K) = 1: 두 가중치의 합은 항상 1 (= 100%)

(1-K)를 하는 이유

두 정보의 가중치 합이 항상 1(=100%)이 되어야 결과값이 두 값 사이의 합리적인 지점에 오기 때문이다.

K = 0.3일 때 (GPS를 30% 신뢰):
  최종 = 예측 × 0.7 + GPS × 0.3 → 예측 쪽에 가까운 값

K = 0.8일 때 (GPS를 80% 신뢰):
  최종 = 예측 × 0.2 + GPS × 0.8 → GPS 쪽에 가까운 값

K = 0일 때: 예측 그대로 사용
K = 1일 때: GPS 그대로 사용

수식 변환 (실제 코드에서 쓰이는 형태)

최종 = 예측 × (1-K) + GPS × K
     = 예측 + K × (GPS - 예측)
                   ─────────
                   "잔차" (두 값의 차이)

“예측값에서 출발해서, GPS와의 차이를 K 비율만큼만 보정한다”


3. 칼만 필터 2단계 사이클

칼만 필터는 매 GPS 측정이 들어올 때마다 예측 → 보정 두 단계를 반복한다.

3-1. 1단계: 예측 (Predict) — “내 감각으로 추측하기”

GPS가 오기 전에, 내가 아는 정보만으로 지금 위치를 추측한다.

하는 일

이전에 내가 있던 곳: 10m 지점
내 속도: 초당 2m, 북쪽으로

→ 1초 지났으니까, 지금은 12m 지점이겠지!

정말 단순한 산수: 이전 위치 + 속도 × 시간 = 예측 위치

하지만 자신은 없음

  • 바람이 불어서 살짝 밀렸을 수도 있고
  • 속도가 정확히 2m/s가 아닐 수도 있고
  • 도로가 살짝 커브였을 수도 있고

그래서 예측할 때 “나 좀 불확실해”라는 표시도 같이 한다:

이전 불확실성: ±3m
         ↓
   시간이 지남 (1초)
         ↓
예측 불확실성: ±5m (시간 지나니까 더 불확실해졌어)

시간이 지나면 불확실성은 항상 커진다. 눈 감고 걷는데, 오래 걸을수록 내가 어디 있는지 점점 모르게 되는 것과 같다.

1단계 요약

📍 예측 위치 = 이전 위치 + 이동한 거리
❓ 불확실성 = 이전 불확실성 + 약간 더 (커짐!)
→ 아직 GPS는 안 봤음. 순전히 내 추측.

3-2. 2단계: 보정 (Update) — “친구 말도 듣고 합치기”

GPS 측정값이 도착했다!

상황

내 예측:  "나는 12m 지점에 있어" (불확실성 ±5m)
GPS 측정: "너는 10m 지점에 있어" (불확실성 ±8m)

Step A: 누구를 더 믿을지 결정 (칼만 이득 K)

내 불확실성이 작으면 → K 작음 → 내 예측을 더 믿음
GPS 불확실성이 작으면 → K 큼  → GPS를 더 믿음

Step B: 두 정보 합치기

최종 위치 = 내 예측 + K × (GPS - 내 예측)

숫자 예시:
  내 예측: 12m, GPS: 10m, K: 0.3

  최종 = 12 + 0.3 × (10 - 12)
       = 12 + 0.3 × (-2)
       = 11.4m  ← 최종 추정!

Step C: 불확실성이 줄어듦 (보물찾기 비유)

나:    "보물은 이 근처 어딘가야" (큰 원)
친구:  "보물은 저 근처 어딘가야" (큰 원)

두 원이 겹치는 부분 → 작은 영역 → 이게 보정 후 불확실성!
내 예측만 쓸 때:       ±5m
GPS만 쓸 때:          ±8m
둘 합친 후 (보정 후):  ±4.2m  ← 둘 다보다 작아졌다!

부정확한 정보 두 개를 합치면, 각각보다 더 정확해진다. 이게 칼만 필터의 마법.

2단계 요약

📡 GPS 측정값 도착!
⚖️ 누구를 더 믿을지 결정 (K 계산)
🎯 예측과 GPS를 적절히 섞어서 최종 위치 결정
📉 불확실성이 줄어듦!

3-3. 전체 사이클 예시

시작: 내가 5m 지점에 있다고 알고 있음 (불확실성 ±2m)

[1초 후]
  ① 예측: "1초 지났고 속도가 2m/s니까 7m 지점이겠지"
          불확실성 ±2m → ±4m (커짐)
  ② GPS 도착: "6.5m 지점이야" (불확실성 ±6m)
  ③ 합치기:  K = 작음 (내 예측이 더 확실하니까)
             최종 = 6.8m / 불확실성 ±3m (줄어듦)

[2초 후]
  ① 예측: "6.8m에서 2m 더 갔으니 8.8m이겠지"
          불확실성 ±3m → ±5m (또 커짐)
  ② GPS 도착: "9.2m 지점이야" (불확실성 ±4m)
  ③ 합치기:  K = 좀 큼 (이번엔 GPS가 좀 더 확실하니까)
             최종 = 9.0m / 불확실성 ±3m (또 줄어듦)

[3초 후]
  ① 예측 → ② GPS 도착 → ③ 합치기 ... 계속 반복!


4. 불확실성은 어떻게 구하는가?

4-1. “불확실성”이란

“실제 값이 이 범위 안에 있을 거야”라는 의미. 수학에서는 분산(variance)이라는 숫자로 표현한다.

"나는 10m 지점에 있어 (불확실성 ±3m)"
→ 실제로는 7m ~ 13m 사이 어딘가
→ 10m에 가까울 확률이 높고, 멀어질수록 확률이 낮아짐

4-2. 출발점: GPS의 accuracy 값

브라우저의 Geolocation API가 좌표와 함께 accuracy도 같이 준다:

navigator.geolocation.watchPosition((pos) => {
  console.log(pos.coords.latitude); // 37.5665
  console.log(pos.coords.longitude); // 126.9780
  console.log(pos.coords.accuracy); // 12  ← 불확실성 (미터)
});

accuracy = 12의 의미: “실제 위치가 이 좌표 중심으로 반경 12m 원 안에 있을 확률이 약 68%”

상황별 accuracy 값:

하늘 탁 트인 곳:    3~5m    (자신 있음)
일반 도심:          8~15m   (보통)
빌딩 사이 골목:     20~50m  (자신 없음)
실내/터널:          100m+   (거의 모름)

4-3. 불확실성이 변하는 3가지 순간

순간 1: 처음 시작할 때

아무 정보도 없으니, GPS accuracy를 그대로 쓴다.

this.variance = accuracy * accuracy; // 분산 = accuracy²

왜 제곱? → 수학에서 불확실성을 다룰 때 분산(variance) 단위를 쓰는데, 분산은 오차의 제곱이다. (수학의 약속/규칙)

accuracy = 10m → 분산 = 100 (m²)
다시 미터로: √100 = 10m

순간 2: 예측할 때 — 불확실성이 커짐

const Q = 3; // "1초마다 이만큼 불확실해진다"는 상수
this.variance += Q;
이전 분산: 9  (= ±3m)
Q를 더함: 9 + 3 = 12
새 불확실성: √12 ≈ ±3.46m (커졌다!)

Q 값은 개발자가 정하는 값 (실험으로 조절):

Q가 크면 (예: 10): GPS를 더 자주 믿게 됨. 반응 빠르지만 노이즈에 약함
Q가 작으면 (예: 1): 예측을 더 오래 믿음. 부드럽지만 실제 변화에 느림
GPS 내비게이션에서는 Q = 2~5 정도가 무난

순간 3: GPS로 보정할 때 — 불확실성이 줄어듦

const K = this.variance / (this.variance + accuracy * accuracy);
this.variance = (1 - K) * this.variance;

숫자 예시:

내 예측 분산: 25 (= ±5m)
GPS 분산:     64 (= ±8m)

K = 25 / (25 + 64) = 25/89 ≈ 0.28
보정 후 분산 = (1-0.28) × 25 = 18
보정 후 불확실성 = √18 ≈ ±4.2m

결과:
  내 예측만: ±5m  /  GPS만: ±8m  /  합친 후: ±4.2m ← 둘 다보다 작아짐!

4-4. 불확실성 변화 전체 흐름

[시작]
  분산 = GPS accuracy²

[매 사이클마다 반복]
  ① 예측 단계:  분산 = 분산 + Q           ← 커진다 (시간이 지나서)
  ② 보정 단계:  분산 = (1-K) × 분산       ← 작아진다 (정보가 합쳐져서)
  → 다음 사이클로...

불확실성은 예측하면 커지고, GPS로 보정하면 줄어드는 걸 계속 반복한다. 마치 풍선을 부풀렸다(예측) 눌렀다(보정) 반복하는 것과 같다.


5. 실제 코드

class KalmanFilter {
  private lat: number = 0;
  private lng: number = 0;
  private variance: number = -1; // 불확실성의 제곱 (분산)

  process(lat: number, lng: number, accuracy: number, timestamp: number) {
    if (this.variance < 0) {
      // 첫 측정: 아무 정보 없으니 GPS를 그대로 신뢰
      this.lat = lat;
      this.lng = lng;
      this.variance = accuracy * accuracy;
      return { lat, lng };
    }

    // ① 예측 단계: 불확실성 증가
    const Q = 3;
    this.variance += Q;

    // ② 보정 단계
    const K = this.variance / (this.variance + accuracy * accuracy);
    // K가 작으면 → GPS를 덜 믿음 (내 예측을 더 따름)
    // K가 크면 → GPS를 더 믿음

    this.lat += K * (lat - this.lat); // 위치 보정
    this.lng += K * (lng - this.lng);
    this.variance *= 1 - K; // 불확실성 감소

    return { lat: this.lat, lng: this.lng };
  }
}


6. 필터 적용 전 vs 후

필터 없이 (원시 GPS):
  - 마커가 1초마다 2~10m씩 튀어다님
  - 가만히 있어도 마커가 떨림
  - 주행 중 마커가 도로 밖으로 나갔다 들어왔다 반복

칼만 필터 적용 후:
  - 마커가 부드럽게 이동
  - 정지 시 거의 안 움직임
  - 주행 중 도로 위를 자연스럽게 따라감


7. 실제 서비스에서는? (칼만 필터 + 맵 매칭)

실제 내비게이션 앱은 칼만 필터에 추가로 맵 매칭(Map Matching)도 함께 사용한다:

칼만 필터 보정 위치: 도로에서 3m 옆 인도 위
            │
            ▼
      맵 매칭 알고리즘
  "이 위치에서 가장 가까운 도로 위 지점은?"
            │
            ▼
  최종 표시 위치: 도로 위에 정확히 스냅

칼만 필터(노이즈 제거) + 맵 매칭(도로 스냅) 조합으로 마커가 항상 도로 위를 매끄럽게 이동하는 것처럼 보이게 만든다.