칼만 필터

내비게이션 서비스에서 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 옆 인도 위
            │
            ▼
      맵 매칭 알고리즘
  "이 위치에서 가장 가까운 도로 위 지점은?"
            │
            ▼
  최종 표시 위치: 도로 위에 정확히 스냅

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