우리가 사는 세상은 불확실성으로 가득 차 있다. 우리가 만드는 시스템 모델은 현실을 완벽하게 반영하지 못하고, 우리가 사용하는 센서의 측정값에는 항상 노이즈가 섞여 있다.1 예를 들어, GPS 수신기는 현재 위치를 알려주지만 수 미터의 오차 범위를 가지며 5, 로켓의 움직임은 물리 법칙에 기반한 모델로 예측할 수 있지만, 예상치 못한 바람이나 대기 저항 같은 외부 요인 때문에 예측은 항상 빗나간다.6 칼만 필터는 바로 이러한 불확실성 속에서 시스템의 상태를 가장 정확하게 추정하기 위해 탄생한 알고리즘이다.
칼만 필터(Kalman Filter)는 시간에 따라 변하는 동적 시스템의 상태를 추정하는 재귀적(recursive) 알고리즘이다. 이 알고리즘은 불완전하고 노이즈가 포함된 일련의 측정값들을 사용하여, 그 어떤 단일 측정값보다도 더 정확한 상태 추정치를 계산해낸다.1
여기서 두 가지 핵심 단어에 주목해야 한다. 첫째, ‘필터(filter)’라는 단어는 이 알고리즘이 원하는 정보(시스템의 실제 상태)를 원하지 않는 노이즈로부터 걸러내는 역할을 한다는 의미다.3 둘째, ‘재귀적(recursive)’이라는 단어는 칼만 필터의 가장 중요한 특징 중 하나를 설명한다. 현재 상태를 추정하기 위해 과거의 모든 데이터를 저장하고 계산할 필요 없이, 오직 직전 시간 단계의 추정값과 현재 시간의 측정값만 있으면 된다.2 이러한 특성 덕분에 칼만 필터는 계산 효율성이 매우 높고 메모리 사용량이 적어, 아폴로 우주선의 유도 컴퓨터와 같은 제한된 자원을 가진 시스템부터 오늘날의 실시간 로봇, 드론, IoT 장치에 이르기까지 광범위하게 사용될 수 있었다.3
단순히 노이즈를 제거하여 데이터를 매끄럽게 만드는 것(smoothing)을 넘어, 칼만 필터의 본질은 두 가지 불완전한 정보 소스, 즉 ‘시스템 모델의 예측’과 ‘센서의 측정’을 융합하여 통계적으로 최적의 추정치를 만들어내는 데 있다. 이는 최소 평균 제곱 오차(Minimum Mean-Square Error, MMSE) 관점에서 최적의 해를 제공하는 추정기(estimator)이다.2
graph TD
subgraph "입력: 불완전한 정보 소스"
A["<b>시스템 모델의 예측</b><br/><i>'아마도 여기 있을 것이다'</i><br/>(예: 항해 계획, 물리 법칙)<br/>불확실성 포함 (프로세스 노이즈)"]
B["센서의 측정값"]
end
subgraph "처리"
C<b>칼만 필터</b><br/>(최적의 융합 엔진)
end
subgraph "출력: 개선된 정보"
D["<b>최적 상태 추정치</b><br/><i>'가장 가능성 높은 현재 상태'</i><br/>(어떤 단일 정보보다 정확함)"]
end
A -- "예측된 상태와 불확실성" --> C
B -- "측정된 상태와 불확실성" --> C
C -- "각 정보의 불확실성을<br/>가중치로 사용하여 융합" --> D
[그림] 칼만 필터는 불확실한 예측과 불확실한 측정을 현명하게 조합하여 최상의 추정치를 만들어내는 알고리즘이다.
graph TD
A("k-1 시점의 최종 추정치<br>x̂<sub>k-1|k-1</sub>") --> B{"칼만 필터 계산 루프"};
C("k 시점의 새로운 측정치<br>z<sub>k</sub>") --> B;
B --> D("k 시점의 최종 추정치<br>x̂<sub>k|k</sub>");
D -- "다음 계산을 위한 입력으로 사용" --> E(("k+1 시점의 루프"));
칼만 필터의 작동 원리를 직관적으로 이해하기 위해, 폭풍우가 몰아치는 바다 한가운데서 자신의 위치를 파악하려는 선장의 상황을 상상해 보자.10
칼만 필터는 이 과정을 수학적으로 정립하여, 각 정보의 불확실성을 정량화하고 이를 바탕으로 최적의 가중치를 계산하여 두 정보를 융합하는 알고리즘이다.
용어를 명확히 할 필요가 있다. 이 자습서에서는 주로 필터링에 초점을 맞추지만, 세 가지 개념은 미묘하게 다르다.11
이 자습서는 실시간 처리에 가장 널리 사용되는 필터링을 중심으로 칼만 필터의 세계를 탐험할 것이다.
gantt
title 필터링, 예측, 스무딩 개념 비교
dateFormat X
axisFormat %S
section 데이터<br>사용 범위
측정값 (z_1... z_k... z_{k+n}) : 0, 100
section 추정 시점
필터링 (현재 k 추정) : crit, 50, 1s
예측 (미래 k+n 추정) : 75, 25s
스무딩 (과거 k 재추정) : milestone, 50, 0s
section 사용 데이터<br>설명
필터링 (z_1... z_k 사용) : 0, 51s
예측 (z_1... z_k 사용) : 0, 51s
스무딩 (z_1... z_{k+n} 사용) : 0, 100s
칼만 필터 알고리즘의 심장은 ‘예측(Prediction)’과 ‘갱신(Update)’이라는 두 단계가 끊임없이 반복되는 루프에 있다.2 이 두 단계의 춤을 통해 필터는 불확실성을 길들이고 최적의 추정치에 점차 수렴해 나간다.
이 사후 추정치는 다시 다음 루프의 예측 단계를 위한 입력으로 사용되며, 이 과정이 재귀적으로 무한히 반복된다.
graph TD
subgraph "k-1 시점"
A["<b>사후 추정치 (k-1)</b><br><i>Posteriori Estimate</i><br><b>x̂<sub>k-1|k-1</sub>, P<sub>k-1|k-1</sub></b><br>이전 단계의 최종 결과"]
end
A -- "시스템 모델(F)을 통해<br>다음 상태를 추측" --> B
subgraph "k 시점: 예측 단계 (Time Update)"
B["<b>사전 추정치 (k)</b><br><i>A Priori Estimate</i><br><b>x̂<sub>k|k-1</sub>, P<sub>k|k-1</sub></b><br>측정값 없이 예측만 한 상태<br><i>불확실성 증가!</i>"]
end
C["<b>새로운 측정값 (k)</b><br><i>Measurement</i><br><b>z<sub>k</sub></b>"] -- "예측과 실제 측정의<br>차이(혁신) 계산" --> D
B --> D
subgraph "k 시점: 갱신 단계 (Measurement Update)"
D{"<b>칼만 이득(K) 계산 및<br>상태 갱신</b>"}
end
D -- "예측과 측정을 융합하여<br>추정치 보정" --> E
subgraph "k 시점"
E["<b>사후 추정치 (k)</b><br><i>Posteriori Estimate</i><br><b>x̂<sub>k|k</sub>, P<sub>k|k</sub></b><br>현재 단계의 최종 결과<br><i>불확실성 감소!</i>"]
end
E -- "다음 루프(k+1)의<br>입력으로 재귀" --> A
이 예측과 갱신의 춤을 추기 위해, 우리는 세상을 수학적으로 모델링해야 한다. 칼만 필터는 이를 ‘상태’와 ‘불확실성’이라는 두 가지 개념으로 표현한다.
상태(state)란 특정 시간에 시스템을 완벽하게 설명하는 데 필요한 변수들의 집합이다.2 이 변수들은 벡터 형태로 표현되며, 이를 상태 벡터라고 한다. 예를 들어, 1차원 공간을 움직이는 물체의 상태는 위치와 속도로 나타낼 수 있다. \(x = \begin{bmatrix} \text{위치} \\ \text{속도} \end{bmatrix}\) 만약 로켓의 고도를 추적한다면, 상태 벡터는 고도, 속도, 가속도를 포함할 수 있다.7 \(x = \begin{bmatrix} \text{고도} \\ \text{속도} \\ \text{가속도} \end{bmatrix}\) 칼만 필터의 궁극적인 목표는 바로 이 숨겨진 상태 벡터 $x$를 추정하는 것이다.
현실 세계에서 우리는 시스템의 상태를 단 하나의 값으로 완벽하게 알 수 없다. 항상 불확실성이 존재한다. 칼만 필터는 이러한 불확실성을 가우시안 분포(정규 분포)로 모델링한다.3 가우시안 분포는 두 개의 매개변수로 완벽하게 정의된다.
칼만 필터는 시스템에 존재하는 불확실성을 두 가지 주요 원인으로 나누어 모델링한다.
프로세스 노이즈 (Process Noise, $w$): 우리의 모델은 현실을 완벽하게 설명하지 못한다. 등속도로 움직인다고 가정한 자동차는 실제로는 운전자의 미세한 가속 페달 조작, 도로의 마찰 변화, 바람의 영향 등으로 인해 완벽한 등속도 운동을 하지 않는다.6 이처럼 시스템 모델 자체의 불완전함이나 예측 불가능한 외부 요인으로 인해 발생하는 오차를 프로세스 노이즈라고 한다. 이 노이즈는 평균이 0인 가우시안 분포를 따른다고 가정하며, 그 공분산 행렬을 $Q$로 표기한다.6
$Q$가 크다는 것은 우리의 시스템 모델을 별로 신뢰하지 않는다는 의미다.
측정 노이즈 (Measurement Noise, $v$): 센서는 완벽하지 않다. GPS는 대기 상태에 따라 오차를 내고, 레이더는 신호 반사 과정에서 노이즈가 발생한다.6 이처럼 센서 측정 과정에서 발생하는 오차를 측정 노이즈라고 한다. 이 노이즈 역시 평균이 0인 가우시안 분포를 따른다고 가정하며, 그 공분산 행렬을 $R$로 표기한다.19
$R$이 크다는 것은 센서 측정값을 별로 신뢰하지 않는다는 의미다.
graph TD
subgraph "시스템 동역학 (이상적 모델)"
X_km1(실제 상태<br>x<sub>k-1</sub>)
F_model["상태 전이 모델<br><b>x<sub>k</sub> = Fx<sub>k-1</sub></b>"]
X_k_ideal(이상적인 다음 상태)
X_km1 --> F_model --> X_k_ideal
end
subgraph "현실 세계"
Q_noise["<b>프로세스 노이즈 (w)</b><br><i>Process Noise</i><br>모델의 불완전성, 외부 교란<br>공분산: <b>Q</b>"]
X_k_real(실제 다음 상태<br>x<sub>k</sub>)
H_model["관측 모델<br><b>z<sub>k</sub> = Hx<sub>k</sub></b>"]
Z_k_ideal(이상적인 측정값)
R_noise("측정 노이즈 공분산<br><b>R<b>")
Z_k_meas(실제 측정값<br>z<sub>k</sub>)
X_k_ideal -- "현실의 불확실성" --> X_k_real
Q_noise -.-> X_k_real
X_k_real --> H_model --> Z_k_ideal
Z_k_ideal -- "센서의 불확실성" --> Z_k_meas
R_noise -.-> Z_k_meas
end
linkStyle 1,4 stroke-width:2px,stroke:blue,stroke-dasharray: 5 5;
linkStyle 2,5 stroke-width:2px,stroke:red,stroke-dasharray: 5 5;
이 예측-갱신 사이클은 사실 베이즈 정리(Bayes’ Theorem)의 재귀적 적용과 같다.5
| 예측 단계는 이전의 믿음(사후 확률)을 시스템 모델에 통과시켜 현재의 믿음(사전 확률, $P(H)$)을 만들어내는 과정이다. 갱신 단계는 이 사전 확률에 새로운 증거(측정값)의 가능도(likelihood, $P(E | H)$)를 결합하여 더 정제된 현재의 믿음(사후 확률, $P(H | E)$)을 계산하는 과정이다. 즉, 칼만 필터는 임의의 수식 집합이 아니라, 선형 시스템과 가우시안 노이즈라는 가정 하에서 베이즈 추론 문제를 푸는 최적의 해법인 것이다. |
이 과정에서 ‘혁신(innovation)’은 필터가 세상을 배우는 창구 역할을 한다. 혁신, 즉 예측과 측정의 차이는 모델이 예측하지 못한 ‘새로운 정보’를 의미한다. 혁신이 0에 가깝다면, 현실이 모델의 예측대로 움직였다는 뜻이므로 배울 것이 별로 없다. 혁신이 크다면, 모델이 현실을 제대로 예측하지 못했다는 신호이며, 필터는 이 차이를 통해 자신의 상태 추정치를 수정하며 ‘학습’한다. 칼만 이득은 이 학습의 강도를 조절하는 역할을 하며, 예측과 측정의 불확실성을 비교하여 혁신을 얼마나 신뢰할지 동적으로 결정한다.
칼만 필터의 방정식을 제대로 이해하려면, 그 바탕에 깔린 수학적 원리를 먼저 알아야 한다. 복잡해 보일 수 있지만, 핵심은 가우시안 분포의 두 가지 강력한 성질에 있다. 칼만 필터가 선형 시스템에서 최적의 성능을 보이는 이유는 바로 이 성질들 덕분이다.3
칼만 필터가 시스템의 상태와 노이즈가 모두 가우시안 분포를 따른다고 가정하는 데에는 중요한 이유가 있다.3
상태가 여러 변수(예: 위치와 속도)로 구성된 다차원 시스템에서, 공분산 행렬 $P$는 불확실성을 입체적으로 표현한다. \(P = \begin{bmatrix} P_{00} & P_{01} & P_{02} \\ P_{10} & P_{11} & P_{12} \\ P_{20} & P_{21} & P_{22} \\ \end{bmatrix}\)
예를 들어, 자동차의 위치와 속도를 추정하는 경우를 생각해 보자. 만약 자동차가 빠르게 움직이고 있다는 강한 믿음이 있다면, ‘높은 위치’ 추정치와 ‘높은 속도’ 추정치는 서로 강한 양의 상관관계를 가질 것이다. 이 관계가 공분산 행렬의 비대각 원소에 인코딩되며, 시각적으로는 기울어진 타원 형태로 나타난다.5 칼만 필터는 이 상관관계까지 고려하여 추정을 수행한다.
칼만 필터의 예측과 갱신 단계는 각각 가우시안 분포에 대한 두 가지 다른 연산으로 수학적으로 모델링된다. 이 두 연산을 이해하면 칼만 필터의 작동 방식이 명확해진다.21
예측 단계는 “현재 상태에 대한 믿음”에 “움직임에 대한 믿음”을 더하는 과정이다. 확률 분포의 덧셈은 합성곱 연산으로 정의된다.
두 가우시안 분포의 합성곱 결과는 놀랍게도 또 다른 가우시안 분포이며, 그 평균과 분산은 원래 두 분포의 평균과 분산을 단순히 더한 것과 같다.3 \(N(\mu_{k-1}, \sigma^2_{k-1}) * N(\mu_{motion}, \sigma^2_Q) = N(\mu_{k-1} + \mu_{motion}, \sigma^2_{k-1} + \sigma^2_Q)\) 여기서 가장 중요한 점은 예측 단계에서 불확실성(분산)이 항상 증가한다는 것이다 ($\sigma^2{k-1} + \sigma^2_Q > \sigma^2{k-1}$). 이는 매우 직관적이다. 미래를 예측하는 행위는 본질적으로 불확실성을 더하는 과정이기 때문이다. 시간이 지날수록 우리의 예측은 점점 더 불확실해진다.21
graph LR
subgraph "입력"
A["<b>이전 믿음 (k-1)</b><br><br>N(μ<sub>k-1</sub>, σ²<sub>k-1</sub>)<br><br> ^<br> / \\<br>/___\\<br><i>(상대적으로 좁은 분포)</i>"]
B["<b>움직임/프로세스 노이즈</b><br><br>N(μ<sub>motion</sub>, σ²<sub>Q</sub>)"]
end
subgraph "연산"
C{"<b>예측<br>(합성곱)</b>"}
end
subgraph "출력"
D["<b>예측된 믿음 (사전 추정치, k)</b><br><br>N(μ<sub>k-1</sub>+μ<sub>motion</sub>, σ²<sub>k-1</sub>+σ²<sub>Q</sub>)<br><br> ^<br> / \\<br> /_____\\<br><i>(더 넓어진 분포 = <b>불확실성 증가</b>)</i>"]
end
A -- " \+ " --> C
B -- " " --> C
C --> D
갱신 단계는 “예측된 상태에 대한 믿음(사전 확률)”과 “측정된 값에 대한 믿음(가능도)”을 결합하는 과정이다. 베이즈 정리에 따르면, 사후 확률은 사전 확률과 가능도의 곱에 비례한다. 따라서 이 결합 과정은 두 확률 밀도 함수의 곱으로 계산된다.
두 가우시안 분포의 곱 역시 놀랍게도 또 다른 가우시안 분포가 된다. 그 새로운 평균 $\mu_{new}$와 분산 $\sigma^2{new}$는 다음과 같이 계산된다.21 \(\mu_{new} = \frac{\sigma^2_{meas}\mu_{prior} + \sigma^2_{prior}\mu_{meas}}{\sigma^2_{prior} + \sigma^2_{meas}} \\ \sigma^2_{new} = \frac{\sigma^2_{prior}\sigma^2_{meas}}{\sigma^2_{prior} + \sigma^2_{meas}} \quad \text{또는} \quad \frac{1}{\sigma^2_{new}} = \frac{1}{\sigma^2_{prior}} + \frac{1}{\sigma^2_{meas}}\) 여기서 가장 중요한 점은 갱신 단계에서 불확실성(분산)이 항상 감소한다는 것이다 ($\sigma^2{new} < \sigma^2{prior}$ 이고 $\sigma^2{new} < \sigma^2_{meas}$). 두 개의 불확실한 정보를 융합하면, 각각의 정보보다 더 확실한 새로운 정보를 얻게 된다. 이는 우리의 직관과 완벽하게 일치한다.21
graph LR
subgraph "입력"
A["<b>예측된 믿음 (사전)</b><br><br>N(μ<sub>prior</sub>, σ²<sub>prior</sub>)<br><br> ^<br> / \\<br> /_____\\<br><i>(넓은 분포)</i>"]
B["<b>측정값의 믿음 (가능도)</b><br><br>N(μ<sub>meas</sub>, σ²<sub>meas</sub>)<br><br> ^<br> / \\<br> /_____\\<br><i>(넓은 분포)</i>"]
end
subgraph "연산"
C{"<b>갱신<br>(곱)</b>"}
end
subgraph "출력"
D["<b>갱신된 믿음 (사후 추정치)</b><br><br>N(μ<sub>new</sub>, σ²<sub>new</sub>)<br><br>^<br>/\\<br>/__\\<br><i>(더 좁아진 분포 = <b>불확실성 감소</b>)</i>"]
end
A -- " × " --> C
B -- " " --> C
C --> D
이처럼 가우시안 분포의 수학적 특성은 칼만 필터의 직관적인 원리를 완벽하게 뒷받침한다. 예측을 통해 불확실성이 커지고, 갱신을 통해 불확실성이 줄어드는 과정의 반복. 이것이 바로 칼만 필터가 불확실성 속에서 최적의 추정치를 찾아가는 여정의 수학적 표현이다. 하지만 이 우아한 해법은 가우시안과 선형성이라는 두 가지 가정에 깊이 의존하고 있다. 이 가정이 깨지는 순간, 칼만 필터의 최적성은 보장되지 않으며, 이것이 바로 확장 칼만 필터(EKF)나 무향 칼만 필터(UKF)와 같은 더 복잡한 필터들이 필요한 이유가 된다.
이제 칼만 필터의 심장부로 들어가, 알고리즘을 구성하는 5개의 핵심 방정식을 해부해 보자. 이 방정식들은 앞서 설명한 예측과 갱신이라는 두 단계를 수학적으로 구현한 것이다. 방정식을 이해하기 위해 먼저 시스템을 어떻게 수학적으로 표현하는지부터 정의해야 한다.
칼만 필터는 시스템을 상태 공간 모델이라는 표준적인 형식으로 기술한다. 이 모델은 두 개의 선형 방정식으로 구성된다.2
상태 방정식 (State Equation): 시스템의 상태가 시간이 지남에 따라 어떻게 변하는지를 설명한다. \(x_k = F_k x_{k-1} + B_k u_k + w_{k-1}\)
측정 방정식 (Measurement Equation): 시스템의 상태와 센서 측정값 사이의 관계를 설명한다. \(z_k = H_k x_k + v_k\)
이 상태 공간 모델을 바탕으로, 칼만 필터는 다음 5개의 방정식을 재귀적으로 계산한다.11
1. 상태 추정치 예측 (사전 추정치): \(\hat{x}_{k|k-1} = F_k \hat{x}_{k-1|k-1} + B_k u_k\) 이 방정식은 이전 시간 단계의 최종 추정치($\hat{x}_{k-1|k-1}$)를 사용하여 현재 시간 단계의 상태를 예측한다. 상태 전이 행렬 $F_k$를 곱하여 시스템의 동역학을 반영하고, 제어 입력 $u_k$의 효과를 더한다.
2. 오차 공분산 예측 (사전 추정치): \(P_{k|k-1} = F_k P_{k-1|k-1} F_k^T + Q_k\) 이 방정식은 추정치의 불확실성이 어떻게 변하는지를 예측한다. 이전 단계의 오차 공분산 $P_{k-1|k-1}$이 상태 전이 행렬 $F_k$를 통해 어떻게 전파되는지 계산하고($F_k P_{k-1|k-1} F_k^T$), 여기에 프로세스 노이즈의 불확실성 $Q_k$를 더한다. 이 과정에서 불확실성은 항상 증가하거나 유지된다.
3. 칼만 이득 계산: \(K_k = P_{k|k-1} H_k^T (H_k P_{k|k-1} H_k^T + R_k)^{-1}\) 칼만 이득 $K_k$는 칼만 필터의 ‘뇌’와 같다. 이 값은 예측된 상태와 실제 측정값 중 어느 쪽을 더 신뢰할지를 결정하는 가중치 역할을 한다.
| 분모 ($H_k P_{k | k-1} H_k^T + R_k$)는 혁신(innovation)의 총 불확실성을 나타낸다. 이는 예측의 불확실성($P_{k | k-1}$)이 측정 공간으로 변환된 것과 측정 자체의 불확실성($R_k$)을 합한 것이다. |
| 분자 ($P_{k | k-1} H_k^T$)는 예측의 불확실성과 관련된 항이다. |
| 반대로 예측 오차 공분산 $P_{k | k-1}$이 매우 크면(모델 예측이 불확실하면), $K_k$는 커진다. 이는 측정값을 더 많이 신뢰하겠다는 의미다.3 |
4. 상태 추정치 갱신 (사후 추정치): \(\hat{x}_{k|k} = \hat{x}_{k|k-1} + K_k (z_k - H_k \hat{x}_{k|k-1})\) 이 방정식은 실제 측정값 $z_k$를 사용하여 사전 추정치 $\hat{x}{k|k-1}$를 보정한다. 괄호 안의 $z_k - H_k \hat{x}{k|k-1}$ 항이 바로 혁신(innovation)이다. 즉, (실제 측정값) - (예측된 측정값)의 차이다. 이 혁신에 칼만 이득 $K_k$를 곱한 만큼 사전 추정치를 보정하여 최종 사후 추정치 $\hat{x}_{k|k}$를 얻는다.
5. 오차 공분산 갱신 (사후 추정치): \(P_{k|k} = (I - K_k H_k) P_{k|k-1}\) 마지막으로, 새로운 측정값을 반영하여 불확실성을 업데이트한다. 칼만 이득 $K_k$를 사용했기 때문에, 갱신된 오차 공분산 $P_{k|k}$는 예측된 공분산 $P_{k|k-1}$보다 항상 작아진다. 즉, 측정값을 통해 정보를 얻었으므로 불확실성이 감소하는 것이다.
이 5개의 방정식이 한 사이클을 이루며, 새로운 측정값이 들어올 때마다 반복적으로 실행되어 시스템의 상태를 지속적으로 추적하고 추정한다.
graph TD
%% Inputs
X_prev[("<b>x̂<sub>k-1|k-1</sub></b><br>이전 사후 상태")]
P_prev[("<b>P<sub>k-1|k-1</sub></b><br>이전 사후 공분산")]
Z_curr[("<b>z<sub>k</sub></b><br>현재 측정값")]
U_curr[("<b>u<sub>k</sub></b><br>현재 제어입력")]
subgraph "예측 단계 (Time Update)"
direction LR
%% Equation 1
X_pred_calc
X_prev --> X_pred_calc
U_curr --> X_pred_calc
X_pred_calc --> X_pred_out[("<b>x̂<sub>k|k-1</sub></b><br>사전 상태")]
%% Equation 2
P_pred_calc
P_prev --> P_pred_calc
P_pred_calc --> P_pred_out[("<b>P<sub>k|k-1</sub></b><br>사전 공분산")]
end
subgraph "갱신 단계 (Measurement Update)"
direction LR
%% Equation 3
K_calc
P_pred_out --> K_calc
K_calc --> K_out[("<b>K<sub>k</sub></b><br>칼만 이득")]
%% Equation 4
X_upd_calc["<b>4. 상태 갱신</b><br>x̂<sub>k|k</sub> = x̂<sub>k|k-1</sub> + K<sub>k</sub>(z<sub>k</sub>-Hx̂<sub>k|k-1</sub>)"]
X_pred_out --> X_upd_calc
K_out --> X_upd_calc
Z_curr --> X_upd_calc
X_upd_calc --> X_upd_out[("<b>x̂<sub>k|k</sub></b><br>사후 상태")]
%% Equation 5
P_upd_calc["<b>5. 공분산 갱신</b><br>P<sub>k|k</sub> = (I - K<sub>k</sub>H)P<sub>k|k-1</sub>"]
P_pred_out --> P_upd_calc
K_out --> P_upd_calc
P_upd_calc --> P_upd_out[("<b>P<sub>k|k</sub></b><br>사후 공분산")]
end
%% Loop back for recursion
X_upd_out -.-> X_prev
P_upd_out -.-> P_prev
칼만 필터 관련 자료들은 표기법이 조금씩 다를 수 있어 혼란을 유발할 수 있다. 다음 표는 이 자습서에서 사용하는 주요 변수와 행렬을 정리한 것이다.14
| 기호 | 이름 | 다른 이름 | 차원 | |
|---|---|---|---|---|
| $x$ | 상태 벡터 | 상태 | $n_x \times 1$ | |
| $\hat{x}_{k | k-1}$ | 사전 상태 추정치 | 예측된 상태 | $n_x \times 1$ |
| $\hat{x}_{k | k}$ | 사후 상태 추정치 | 갱신된 상태, 필터링된 상태 | $n_x \times 1$ |
| $P$ | 오차 공분산 행렬 | 상태 공분산, 추정 공분산 | $n_x \times n_x$ | |
| $F$ | 상태 전이 행렬 | 시스템 행렬, 동역학 행렬, $\Phi, A$ | $n_x \times n_x$ | |
| $B$ | 제어 입력 행렬 | 입력 행렬 | $n_x \times n_u$ | |
| $u$ | 제어 벡터 | 입력 벡터 | $n_u \times 1$ | |
| $Q$ | 프로세스 노이즈 공분산 | 시스템 노이즈 공분산 | $n_x \times n_x$ | |
| $z$ | 측정 벡터 | 관측 벡터, $y$ | $n_z \times 1$ | |
| $H$ | 관측 행렬 | 측정 행렬, $C$ | $n_z \times n_x$ | |
| $R$ | 측정 노이즈 공분산 | 관측 노이즈 공분산 | $n_z \times n_z$ | |
| $K$ | 칼만 이득 | 칼만 게인, 가중치 행렬 | $n_x \times n_z$ | |
| $I$ | 단위 행렬 | - | - | |
| $n_x, n_u, n_z$ | 상태, 입력, 측정 벡터의 차원 | - | - |
추상적인 방정식만으로는 감을 잡기 어렵다. 이제 간단한 1차원 예제를 통해 5개의 방정식이 실제로 어떻게 작동하는지 단계별로 따라가 보자.23
직선 철로 위를 대략 일정한 속도로 움직이는 기차가 있다고 가정하자. 우리는 이 기차의 정확한 위치와 속도를 알고 싶지만, 가지고 있는 센서는 노이즈가 섞인 위치 정보만 제공한다.
상태 벡터 ($x$): 기차의 상태는 위치($p$)와 속도($v$)로 정의한다. \(x = \begin{bmatrix} p \\ v \end{bmatrix}\) 상태 전이 행렬 ($F$): 기본 물리 법칙에 따라 다음 상태를 모델링한다. 시간 간격을 $\Delta t$라고 할 때,
새로운 위치 = 이전 위치 + (이전 속도 $\times \Delta t$)
새로운 속도 = 이전 속도 (등속도 가정이므로)
이를 행렬로 표현하면 다음과 같다.
관측 행렬 ($H$): 센서는 위치만 측정하므로, 상태 벡터에서 위치 성분만 골라내는 역할을 한다. \(H = \begin{bmatrix} 1 & 0 \end{bmatrix}\) 프로세스 노이즈 공분산 ($Q$): 기차가 완벽한 등속도 운동을 하지 않을 수 있다(미세한 가감속). 이 불확실성을 모델링하기 위해 작은 프로세스 노이즈를 추가한다. 여기서는 간단한 값을 가정한다. \(Q = \begin{bmatrix} 0.0001 & 0 \\ 0 & 0.0001 \end{bmatrix}\) 측정 노이즈 공분산 ($R$): 위치 센서의 노이즈 분산을 나타낸다. 센서의 표준편차가 1m라고 가정하면, 분산은 $1^2 = 1$이다. 측정값은 스칼라이므로 $R$도 스칼라다. \(R = [1]\)
시간 간격 $\Delta t = 1$초라고 가정하고 계산을 시작해 보자.
필터를 시작하기 위해 초기 상태와 불확실성을 가정해야 한다. 보통 초기값은 불확실하므로, 공분산 $P$를 큰 값으로 설정하여 필터가 초기 측정값에 더 큰 가중치를 두도록 한다.4
1. 예측 (Time Update)
상태 예측 $\hat{x}_{1|0}$: \(\hat{x}_{1|0} = F \hat{x}_{0|0} = \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 0 \\ 0 \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \end{bmatrix}\) (이전 상태가 정지였으므로, 예측도 정지 상태다.)
공분산 예측 $P_{1|0}$: \(\begin{align} P_{1|0} &= F P_{0|0} F^T + Q = \begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 100 & 0 \\ 0 & 100 \end{bmatrix} \begin{bmatrix} 1 & 0 \\ 1 & 1 \end{bmatrix} + Q \\ &= \begin{bmatrix} 200 & 100 \\ 100 & 100 \end{bmatrix} + \begin{bmatrix} 0.0001 & 0 \\ 0 & 0.0001 \end{bmatrix}\\ &= \begin{bmatrix} 200.0001 & 100 \\ 100 & 100.0001 \end{bmatrix} \end{align}\) (예측 단계를 거치면서 불확실성(공분산 값들)이 증가했다.)
2. 갱신 (Measurement Update)
이제 첫 번째 측정값이 들어왔다고 가정하자. $z_1 = 0.9$m.
칼만 이득 $K_1$ 계산: \(\begin{align} H P_{1|0} H^T + R &= \begin{bmatrix} 1 & 0 \end{bmatrix} \begin{bmatrix} 200.0001 & 100 \\ 100 & 100.0001 \end{bmatrix} \begin{bmatrix} 1 \\ 0 \end{bmatrix} + 1 \\ &= 200.0001 + 1 \\ &= 201.0001 \\ \\ K_1 &= P_{1|0} H^T (H P_{1|0} H^T + R)^{-1} \\ &= \begin{bmatrix} 200.0001 & 100 \\ 100 & 100.0001 \end{bmatrix} \begin{bmatrix} 1 \\ 0 \end{bmatrix} (201.0001)^{-1} \\ \\ &= \begin{bmatrix} 200.0001 \\ 100 \end{bmatrix} \times 0.004975 \\ &= \begin{bmatrix} 0.995 \\ 0.497 \end{bmatrix} \end{align}\) 상태 갱신 $\hat{x}_{1|1}$: \(\begin{align} \text{혁신} &= z_1 - H \hat{x}_{1|0} \\ &= 0.9 - \begin{bmatrix} 1 & 0 \end{bmatrix} \begin{bmatrix} 0 \\ 0 \end{bmatrix} \\ &= 0.9 \\ \\ \hat{x}_{1|1} &= \hat{x}_{1|0} + K_1 (\text{혁신}) \\ &= \begin{bmatrix} 0 \\ 0 \end{bmatrix} + \begin{bmatrix} 0.995 \\ 0.497 \end{bmatrix} \times 0.9 \\ &= \begin{bmatrix} 0.8955 \\ 0.4473 \end{bmatrix} \end{align}\)
(위치 추정치는 0.8955m, 속도 추정치는 0.4473m/s로 갱신되었다.)
공분산 갱신 $P_{1|1}$: \(P_{1|1} = (I - K_1 H) P_{1|0} = \left( \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} - \begin{bmatrix} 0.995 \\ 0.497 \end{bmatrix} \begin{bmatrix} 1 & 0 \end{bmatrix} \right) P_{1|0} \\ = \begin{bmatrix} 0.005 & 0 \\ -0.497 & 1 \end{bmatrix} \begin{bmatrix} 200.0001 & 100 \\ 100 & 100.0001 \end{bmatrix} = \begin{bmatrix} 1.00 & 0.5 \\ 0.5 & 50.25 \end{bmatrix}\)
(근사값)
(갱신 후 위치의 불확실성($P_{11}$)이 200에서 1로 크게 줄었다.)
| 이제 갱신된 $\hat{x}_{1 | 1}$과 $P_{1 | 1}$을 가지고 두 번째 사이클을 시작한다. |
1. 예측 (Time Update)
2. 갱신 (Measurement Update)
두 번째 측정값이 들어왔다고 가정하자. $z_2 = 1.5$m.
| 이전과 동일한 방식으로 칼만 이득 $K_2$를 계산하고, $\hat{x}_{2 | 1}$과 $P_{2 | 1}$을 갱신하여 $\hat{x}_{2 | 2}$와 $P_{2 | 2}$를 얻는다. |
이 간단한 예제는 몇 가지 중요한 사실을 보여준다.
| 초기값의 영향: 처음에는 매우 불확실한 초기값($P_{0 | 0}$이 큼)으로 시작했지만, 필터는 들어오는 측정값을 바탕으로 빠르게 자신의 추정치를 수정해나간다. 이는 칼만 필터가 초기 추측이 부정확하더라도 스스로 보정해나가는 능력이 있음을 보여준다. |
이제 더 현실적인 2차원(2D) 객체 추적 문제를 Python 코드로 직접 구현해 보자. 이 예제를 통해 이론이 실제 코드로 어떻게 변환되는지 명확하게 이해할 수 있을 것이다. numpy 라이브러리를 사용하여 행렬 연산을 수행하고, matplotlib으로 결과를 시각화할 것이다.27
2차원 평면 위를 움직이는 물체(예: 드론, 자동차)를 추적하는 시나리오를 가정한다. 물체는 대략 일정한 속도로 움직이지만 약간의 무작위적인 가속이 있을 수 있다. 센서는 노이즈가 포함된 물체의 $(x, y)$ 위치 좌표를 주기적으로 제공한다.
상태 벡터 ($x$): 2D 위치($p_x, p_y$)와 2D 속도($v_x, v_y$)를 포함한다. \(x = \begin{bmatrix} p_x \\ p_y \\ v_x \\ v_y \end{bmatrix}\) 상태 전이 행렬 ($F$): 1D 예제와 동일한 등속도 운동 모델을 각 축에 독립적으로 적용한다. \(F = \begin{bmatrix} 1 & 0 & \Delta t & 0 \\ 0 & 1 & 0 & \Delta t \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} $\) 이 행렬의 구조는 물리 법칙을 직접적으로 반영한다. 첫 번째 행은 $p_{x, k} = p_{x, k-1} + v_{x, k-1} \cdot \Delta t$를, 두 번째 행은 $p_{y, k} = p_{y, k-1} + v_{y, k-1} \cdot \Delta t$를 나타낸다.
관측 행렬 ($H$): 센서가 $(x, y)$ 위치만 측정하므로, 4차원 상태 벡터에서 두 개의 위치 성분만 선택한다. \(H = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \end{bmatrix}\) 프로세스 노이즈 공분산 ($Q$): 물체의 움직임이 완벽한 등속도가 아니라는 사실을 모델링한다. 짧은 시간 동안의 무작위 가속이 위치와 속도에 미치는 영향을 공분산 행렬로 표현한다. 이 행렬은 물리 모델로부터 유도될 수 있으며, 가속도의 분산 $\sigma_a^2$에 의존한다.27 \(Q = \begin{bmatrix} \frac{\Delta t^4}{4} & 0 & \frac{\Delta t^3}{2} & 0 \\ 0 & \frac{\Delta t^4}{4} & 0 & \frac{\Delta t^3}{2} \\ \frac{\Delta t^3}{2} & 0 & \Delta t^2 & 0 \\ 0 & \frac{\Delta t^3}{2} & 0 & \Delta t^2 \end{bmatrix} \sigma_a^2\) 측정 노이즈 공분산 ($R$): $x$축과 $y$축의 측정 노이즈가 독립적이라고 가정하고, 각각의 분산을 $\sigma_x^2$와 $\sigma_y^2$라고 하면 다음과 같다. \(R = \begin{bmatrix} \sigma_x^2 & 0 \\ 0 & \sigma_y^2 \end{bmatrix}\)
구현의 핵심은 앞서 배운 5개의 방정식을 코드로 그대로 옮기는 것이다. 각 행렬 연산은 numpy의 @ 연산자(행렬 곱) 또는 np.dot() 함수를 사용하여 간결하게 표현할 수 있다. 코드는 KalmanFilter 클래스로 구조화하여 재사용성을 높인다.27
import numpy as np
class KalmanFilter2D:
def __init__(self, dt, std_acc, std_meas_x, std_meas_y):
# 시간 간격
self.dt = dt
# 상태 전이 행렬 F (Constant Velocity Model)
self.F = np.array([[1, 0, self.dt, 0],
[0, 1, 0, self.dt],
[0, 0, 1, 0], # 3번째 행 추가
[0, 0, 0, 1]]) # 4번째 행 추가
# 관측 행렬 H
self.H = np.array([[1, 0, 0, 0], # 1번째 행 추가
[0, 1, 0, 0]]) # 2번째 행 추가
# 프로세스 노이즈 공분산 Q
# 가속도의 불확실성을 모델링
self.q_val = std_acc**2
self.Q = self.q_val * np.array([[(self.dt**4)/4, 0, (self.dt**3)/2, 0],
[0, (self.dt**4)/4, 0, (self.dt**3)/2],
[(self.dt**3)/2, 0, self.dt**2, 0],
[0, (self.dt**3)/2, 0, self.dt**2]])
# 측정 노이즈 공분산 R
self.R = np.array([[std_meas_x**2, 0],
[0, std_meas_y**2]])
# 초기 상태 벡터 [px, py, vx, vy]
self.x = np.zeros((4, 1))
# 초기 오차 공분산 P
self.P = np.eye(4) * 1000 # 큰 값으로 초기화하여 불확실성을 표현
def predict(self):
# 1. 상태 예측 (a priori)
# x_k|k-1 = F * x_k-1|k-1
self.x = self.F @ self.x
# 2. 오차 공분산 예측 (a priori)
# P_k|k-1 = F * P_k-1|k-1 * F^T + Q
self.P = self.F @ self.P @ self.F.T + self.Q
return self.x
def update(self, z):
# z: 측정값 [px, py]
z = np.array(z).reshape(2, 1)
# 3. 칼만 이득 계산
# S = H * P_k|k-1 * H^T + R
S = self.H @ self.P @ self.H.T + self.R
# K_k = P_k|k-1 * H^T * S^-1
K = self.P @ self.H.T @ np.linalg.inv(S)
# 4. 상태 갱신 (a posteriori)
# x_k|k = x_k|k-1 + K * (z - H * x_k|k-1)
self.x = self.x + K @ (z - self.H @ self.x)
# 5. 오차 공분산 갱신 (a posteriori)
# P_k|k = (I - K * H) * P_k|k-1
I = np.eye(4)
self.P = (I - K @ self.H) @ self.P
이제 이 클래스를 사용하여 가상의 물체를 추적하고, 그 결과를 시각화해 보자.
import matplotlib.pyplot as plt
# 시뮬레이션 설정
dt = 0.1
total_time = 10
steps = int(total_time / dt)
# 실제 물체 궤적 생성 (예: 등속도 운동)
true_x = np.linspace(0, 10, steps)
true_y = np.linspace(0, 5, steps)
true_states = np.vstack((true_x, true_y))
# 측정값 생성 (실제 궤적 + 노이즈)
std_meas_x = 0.5
std_meas_y = 0.5
measurements = np.vstack((
true_x + np.random.randn(steps) * std_meas_x,
true_y + np.random.randn(steps) * std_meas_y
))
# 칼만 필터 생성 및 실행
std_acc = 0.2 # 프로세스 노이즈 표준편차 (튜닝 파라미터)
kf = KalmanFilter2D(dt, std_acc, std_meas_x, std_meas_y)
estimated_states = [] # 빈 리스트로 초기화
for i in range(steps):
kf.predict()
kf.update(measurements[:, i])
estimated_states.append(kf.x.flatten())
estimated_states = np.array(estimated_states)
# 결과 시각화
plt.figure(figsize=(12, 8))
plt.plot(true_states[0, :], true_states[1, :], 'g-', label='True Trajectory')
plt.plot(measurements[0, :], measurements[1, :], 'rx', label='Measurements')
plt.plot(estimated_states[:, 0], estimated_states[:, 1], 'b-', label='Kalman Filter Estimate')
plt.title('2D Object Tracking with Kalman Filter')
plt.xlabel('X Position')
plt.ylabel('Y Position')
plt.legend()
plt.grid(True)
plt.axis('equal')
plt.show()
이 코드를 실행하면, 노이즈가 심한 붉은색 ‘x’ 표시(측정값)들 사이로, 칼만 필터가 추정한 파란색 궤적이 실제 녹색 궤적을 부드럽게 따라가는 것을 확인할 수 있다. 이는 칼만 필터가 어떻게 노이즈를 효과적으로 걸러내고 시스템의 동역학 모델을 활용하여 더 정확한 추정치를 생성하는지를 시각적으로 보여준다. 이 코드는 칼만 필터의 5가지 핵심 방정식이 어떻게 실제 문제 해결에 직접적으로 적용되는지를 명확히 보여주는 사례이다.
칼만 필터를 실제 문제에 적용할 때 가장 어렵고 중요한 과정은 바로 프로세스 노이즈 공분산($Q$)과 측정 노이즈 공분산($R$) 행렬을 결정하는 것이다. 이 두 행렬을 어떻게 설정하느냐에 따라 필터의 성능이 극적으로 달라지기 때문에, 이를 ‘튜닝(tuning)’이라고 부른다. 튜닝은 때로는 과학적 분석에 기반하지만, 때로는 경험과 직관이 필요한 예술의 영역이기도 하다.32
필터의 동작을 지배하는 것은 $Q$와 $R$의 절대적인 크기보다는 그 둘 사이의 비율이다.35 이 비율은 칼만 이득($K$)의 크기를 결정하며, 필터가 모델 예측과 센서 측정 중 어느 쪽을 더 신뢰할지를 조절한다.
graph TD
subgraph "Q >> R : 모델 불신, 측정 신뢰"
direction TB
A1
A2{"칼만 이득 (K)가 커짐"}
A3["필터가 측정값(z)을 더 많이 신뢰"]
A4["<b>결과:</b> 측정값의 노이즈까지 따라가<br>추정치가 거칠고 불안정함"]
A5["<b>장점:</b> 응답성이 빠름 (상태 급변에 잘 추종)<br><b>단점:</b> 노이즈 제거 성능 저하"]
A1 --> A2 --> A3 --> A4 --> A5
end
subgraph "R >> Q : 모델 신뢰, 측정 불신"
direction TB
B1
B2{"칼만 이득 (K)가 작아짐"}
B3["필터가 모델 예측(Fx)을 더 많이 신뢰"]
B4["<b>결과:</b> 측정값의 노이즈를 무시하여<br>추정치가 매우 부드러움"]
B5["<b>장점:</b> 노이즈 제거 성능 탁월<br><b>단점:</b> 응답성이 느림 (상태 급변 시 지연 발생)"]
B1 --> B2 --> B3 --> B4 --> B5
end
$R$ 행렬은 비교적 튜닝하기 쉽다. 이는 센서의 물리적 특성과 직접적으로 관련이 있기 때문이다.
$R$과 달리 $Q$는 튜닝하기가 훨씬 까다롭다. $Q$는 눈에 보이지 않는 ‘모델의 불확실성’을 나타내기 때문이다.32 실제로 $Q$는 종종 우리가 사용하는 시스템 모델이 현실을 얼마나 잘 반영하지 못하는지를 보상하는 ‘조절 손잡이(tuning knob)’ 역할을 한다.34
예를 들어, 우리는 자동차를 ‘등속도 모델’로 가정했지만 실제 자동차는 가속하고 회전한다. 이처럼 모델이 현실을 따라가지 못할 때 발생하는 오차를 $Q$가 흡수해주는 것이다. $Q$를 크게 설정하는 것은 필터에게 “내 모델은 단순해서 현실의 모든 움직임을 설명하지 못하니, 측정값이 모델과 크게 다르더라도 너무 놀라지 말고 유연하게 받아들여라”라고 말해주는 것과 같다.
체계적인 튜닝을 위해 다음 전략을 따를 수 있다.35
| 혁신(Innovation) 분석: 필터 튜닝에서 가장 강력한 진단 도구는 혁신(innovation), 즉 잔차($z_k - H\hat{x}_{k | k-1}$)를 분석하는 것이다. 만약 필터가 최적으로 튜닝되었다면, 혁신 시퀀스는 평균이 0이고 자기상관이 없는 백색 잡음(white noise)의 특성을 보여야 한다. |
결론적으로, $R$은 센서의 물리적 특성에 대한 우리의 지식을 반영하는 ‘과학’에 가깝고, $Q$는 모델의 한계를 인정하고 보상하는 ‘예술’에 가깝다. 이 둘의 균형을 잘 맞추는 것이 칼만 필터링 성공의 핵심 열쇠이다.
지금까지 다룬 표준 칼만 필터는 강력하지만 치명적인 한계를 가지고 있다. 바로 시스템이 선형(linear)이라고 가정한다는 점이다. 상태 전이와 관측 과정이 행렬 곱으로 표현되는 선형 관계여야만 한다. 하지만 로봇의 회전 운동, 레이더의 거리/각도 측정, 위성의 궤도 등 현실 세계의 많은 시스템은 본질적으로 비선형(non-linear)이다.3
비선형 시스템에 표준 칼만 필터를 적용하면 왜 문제가 될까? 핵심은 가우시안 분포의 성질에 있다. 선형 변환을 거친 가우시안 분포는 여전히 가우시안 분포를 유지하지만, 비선형 함수를 통과한 가우시안 분포는 더 이상 가우시안 분포가 아니게 된다. 모양이 왜곡되고 찌그러져 더 이상 평균과 공분산만으로는 분포를 제대로 표현할 수 없게 된다. 이렇게 칼만 필터의 기본 가정이 무너지면, 필터의 성능은 급격히 저하되고 심지어 발산(diverge)해버릴 수도 있다.38
이 문제를 해결하기 위해 여러 비선형 필터가 개발되었으며, 그중 가장 대표적인 두 가지가 확장 칼만 필터(EKF)와 무향 칼만 필터(UKF)이다.
EKF는 비선형 문제를 풀기 위한 가장 고전적이고 직관적인 접근법이다. 그 핵심 아이디어는 “비선형 함수를 국소적으로 선형 함수로 근사하자”는 것이다.39
핵심 원리: 선형화 (Linearization)
EKF는 각 시간 단계에서 현재의 상태 추정치 지점에서 비선형 함수를 1차 테일러 급수(Taylor series)로 전개하여 선형적으로 근사한다. 미적분학에서 곡선의 특정 지점에서의 접선이 그 지점 근방에서 곡선을 잘 근사하는 것과 같은 원리다.38 이 선형화된 모델에 표준 칼만 필터의 방정식을 그대로 적용한다.
자코비안 행렬 (Jacobian Matrix)
다변수 함수를 선형으로 근사하는 데 사용되는 도구가 바로 자코비안 행렬이다. 자코비안 행렬은 함수의 모든 1차 편도함수를 모아놓은 행렬이다.38
| 비선형 상태 전이 함수가 $x_k = f(x_{k-1}, u_k)$일 때, 표준 칼만 필터의 $F_k$ 행렬은 자코비안 행렬 $F_k = \frac{\partial f}{\partial x} \bigg | {\hat{x}{k-1 | k-1}}$로 대체된다. |
| 비선형 관측 함수가 $z_k = h(x_k)$일 때, 표준 칼만 필터의 $H_k$ 행렬은 자코비안 행렬 $H_k = \frac{\partial h}{\partial x} \bigg | {\hat{x}{k | k-1}}$로 대체된다. |
예제: 레이더 측정 모델
레이더는 보통 물체까지의 거리(range, $\rho$), 물체를 바라보는 각도(bearing, $\phi$), 그리고 거리 변화율(range rate, $\dot{\rho}$)을 측정한다. 필터의 상태 벡터가 데카르트 좌표계의 위치와 속도($p_x, p_y, v_x, v_y$)일 때, 상태를 측정값으로 변환하는 함수 $h(x)$는 다음과 같이 비선형이다. \(\rho = \sqrt{p_x^2 + p_y^2}\)
\[\phi = \operatorname{atan2}(p_y, p_x)\] \[\dot{\rho} = \frac{p_x v_x + p_y v_y}{\sqrt{p_x^2 + p_y^2}}\]이 함수 $h(x)$를 상태 벡터 $x$의 각 성분으로 편미분하여 자코비안 행렬 $H_k$를 구하고, 이를 갱신 단계에 사용한다.43
장단점:
UKF는 EKF와는 다른 철학에서 출발한다. “비선형 함수를 근사하는 대신, 확률 분포 자체를 더 잘 근사하자”는 것이다.41
핵심 원리: 무향 변환 (Unscented Transform, UT)
UKF는 현재 상태의 가우시안 분포를 대표하는 소수의 샘플 포인트, 이른바 시그마 포인트(sigma points)를 결정론적으로 선택한다. 이 시그마 포인트들은 원래 분포의 평균과 공분산을 정확하게 포착하도록 설계된다. 그런 다음, 이 시그마 포인트들을 비선형 함수에 직접 통과시킨다. 마지막으로, 변환된 시그마 포인트들의 가중 평균과 가중 공분산을 계산하여 변환 후의 새로운 가우시안 분포를 재구성한다.48
이 과정은 마치 몬테카를로 시뮬레이션과 유사하지만, 무작위 샘플링 대신 통계적 특성을 보존하는 소수의 지점을 전략적으로 선택한다는 점에서 훨씬 효율적이다. “함수를 근사하는 것보다 분포를 근사하는 것이 더 쉽다”는 통찰에 기반한다.41
장단점:
graph LR
subgraph "확장 칼만 필터 (EKF: Extended Kalman Filter)"
direction LR
A1["<b>접근법: 함수를 선형으로 근사</b>"]
A2["비선형 함수 f(x)를<br>현재 추정치 지점에서<br>1차 테일러 급수로 전개 (접선)"]
A3["<b>f(x) ≈ f(x̂) + J(x-x̂)</b><br>여기서 J는 자코비안 행렬"]
A4["장점: 계산량 적음<br>단점: 비선형성이 강하면<br>근사 오차가 커져 발산 위험"]
A1 --> A2 --> A3 --> A4
end
subgraph "무향 칼만 필터 (UKF: Unscented Kalman Filter)"
direction LR
B1["<b>접근법: 확률 분포를 근사</b>"]
B2["가우시안 분포를 대표하는<br>소수의 시그마 포인트를 선택"]
B3["이 포인트들을 실제 비선형 함수 f(x)에<br>직접 통과시킨 후,<br>결과 분포를 재구성"]
B4["장점: EKF보다 정확함, 자코비안 불필요<br>단점: 계산량이 더 많음"]
B1 --> B2 --> B3 --> B4
end
| 특징 | 확장 칼만 필터 (EKF) | 무향 칼만 필터 (UKF) |
|---|---|---|
| 비선형성 접근법 | 비선형 함수를 선형으로 근사 (테일러 급수) | 확률 분포를 시그마 포인트로 근사 (무향 변환) |
| 정확도 | 1차 근사 정확도. 비선형성이 강하면 성능 저하. | 3차 근사 정확도(가우시안 가정 하). 일반적으로 EKF보다 우수. |
| 구현 복잡도 | 자코비안 행렬의 해석적 유도 및 구현이 필요. | 자코비안 불필요. 무향 변환 알고리즘 구현 필요. |
| 계산 비용 | 상대적으로 낮음. | EKF보다 높음. 상태 차원에 따라 증가. |
| 적합한 시스템 | 비선형성이 약하거나, 계산 자원이 매우 제한적인 경우. | 비선형성이 강하거나, 높은 정확도가 요구되는 경우. |
결론적으로, EKF와 UKF 사이의 선택은 공학적인 트레이드오프 문제이다. EKF는 “충분히 좋은” 성능을 더 적은 계산 비용으로 제공하는 경우가 많아 여전히 널리 쓰인다. 반면, UKF는 더 높은 정확성이 요구되고 추가적인 계산 비용을 감당할 수 있는 현대적인 시스템에서 강력한 대안으로 자리 잡고 있다. 이 선택은 결국 해결하고자 하는 문제의 특성과 사용 가능한 자원에 따라 달라진다.
칼만 필터는 이론적인 알고리즘을 넘어, 다양한 분야에서 현실 세계의 복잡한 문제들을 해결하는 데 핵심적인 역할을 수행하고 있다. 그 응용 분야는 광범위하며, 공통적으로 ‘시간에 따라 변하는 시스템의 상태를 불확실한 정보 속에서 추정한다’는 본질적인 문제를 다룬다.
칼만 필터가 가장 활발하게 사용되는 분야 중 하나는 단연 자율주행과 로보틱스다.2
graph TD
subgraph "입력 센서 데이터"
GPS
IMU
RADAR
end
subgraph "중앙 처리 장치"
KF_FUSION{"<b>센서 퓨전<br>(EKF / UKF)</b>"}
end
subgraph "최종 출력"
STATE["<b>통합된 최적 차량 상태</b><br>- 정확한 위치 (x, y)<br>- 속도 (vx, vy)<br>- 방향 (heading)"]
end
GPS -->|위치 정보| KF_FUSION
IMU -->|움직임 정보| KF_FUSION
RADAR -->|주변 환경 정보| KF_FUSION
KF_FUSION -->|강건하고 신뢰도 높은 추정치| STATE
불확실성이 지배하는 금융 시장 역시 칼만 필터의 중요한 응용 분야다.3
컴퓨터 비전 분야에서도 칼만 필터는 움직이는 객체를 추적하는 데 널리 사용된다.2
이 모든 응용 사례들의 공통점은 명확하다. 바로 ‘예측 모델’과 ‘노이즈 섞인 측정’이라는 두 가지 불완전한 정보를 시간에 따라 융합한다는 것이다. 자동차의 물리 모델과 GPS 데이터, 경제 모델과 시장 데이터, 등속도 모델과 영상 속 객체 탐지 결과 등 문제의 형태는 다르지만, 모두 상태 공간 표현으로 모델링될 수 있다. 이는 칼만 필터가 특정 분야에 국한되지 않고, 동적 시스템 추정이라는 광범위한 문제 클래스를 해결할 수 있는 일반적이고 강력한 수학적 프레임워크임을 보여준다. 특히, 직접 측정할 수 없는 속도, 가속도, 변동성, 시장 체제와 같은 ‘숨겨진 상태’를 추론해내는 능력이야말로 칼만 필터가 다양한 분야에서 귀중한 통찰력을 제공하는 핵심적인 이유다.18
이 자습서를 통해 우리는 칼만 필터의 근본적인 직관에서부터 수학적 원리, 실제 구현, 그리고 비선형 시스템을 위한 확장에 이르기까지 깊이 있는 여정을 함께했다. 이제 칼만 필터의 핵심적인 의의를 정리하고, 그 한계와 미래를 조망하며 마무리하고자 한다.
EKF와 UKF가 비선형성 문제를 해결했지만, 여전히 풀지 못한 숙제가 남아있다. 바로 비가우시안(non-Gaussian) 불확실성이다. 예를 들어, 로봇이 복도를 따라가다가 갈림길을 만났을 때, 로봇의 위치에 대한 확률 분포는 왼쪽 길과 오른쪽 길에 각각 봉우리가 있는 이중 봉우리(bimodal) 형태가 될 수 있다. 이는 단일 가우시안 분포로는 절대 표현할 수 없다.
이러한 문제를 해결하기 위해 등장한 것이 파티클 필터(Particle Filter)이다.59
결국, 어떤 필터를 선택할 것인지는 해결하려는 문제의 특성에 따라 결정되는 계층 구조를 형성한다.
graph TD
A{"시스템이<br>선형(Linear)<br>인가?"} --"Yes"--> B{"노이즈가<br>가우시안(Gaussian)<br>인가?"}
A --"No"--> C{"노이즈가<br>가우시안(Gaussian)<br>인가?"}
B --"Yes"--> KF(["<b>칼만 필터 (KF)</b><br>선형/가우시안 시스템의<br>최적 해법"])
B --"No"--> PF_Note1["(일반적으로 선형 시스템은<br>가우시안 노이즈를 가정함)"]
C --"Yes"--> EKF_UKF([<b>EKF / UKF</b><br>EKF: 비선형성이 약하거나 계산량이 중요할 때<br>UKF: 비선형성이 강하고 정확도가 중요할 때])
C --"No"--> PF(["<b>파티클 필터 (PF)</b><br>비선형 & 비가우시안 시스템을 위한<br>강력하지만 계산량이 많은 해법"])
| 칼만 필터와 그 확장들은 단순히 신호 처리 기법 중 하나가 아니다. 그것들은 불확실한 세상에 대한 우리의 ‘믿음(belief)’, 즉 사후 확률 분포($p(x_k | z_{1:k})$)를 어떻게 합리적으로 갱신해 나갈 것인가에 대한 수학적 프레임워크다. KF는 엄격한 가정 하에서 이 문제를 해석적으로 정확하게 풀고, EKF와 UKF는 비선형성을 다루기 위해 각기 다른 방식으로 근사해를 찾으며, PF는 가우시안 가정마저 버리고 수치적 근사를 통해 더 넓은 범위의 문제에 도전한다. |
루돌프 칼만이 1960년에 제시한 이 우아한 아이디어는 반세기가 넘는 시간 동안 수많은 공학과 과학 분야의 발전을 이끌어온 근간이 되었다. 불확실성 속에서 최적의 판단을 내리는 것은 인공지능 시대의 핵심 과제이며, 그 중심에는 여전히 칼만 필터의 깊은 통찰이 자리 잡고 있다. 이 자습서가 그 강력한 도구를 이해하고 활용하는 데 튼튼한 발판이 되기를 바란다.
| Extended Kalman Filters for Dummies | by Raúl Serrano - Medium, accessed July 29, 2025, https://medium.com/@serrano_223/extended-kalman-filters-for-dummies-4168c68e2117 |
| How to Tune a Kalman Filter: Step-by-Step Guide | JuliaHub, accessed July 29, 2025, https://juliahub.com/blog/how-to-tune-kalman-filter |
| How to Tune a Kalman Filter: Step-by-Step Guide | JuliaHub - juliabloggers.com, accessed July 29, 2025, https://www.juliabloggers.com/how-to-tune-a-kalman-filter-step-by-step-guide-juliahub/ |
| The math behind Extended Kalman Filtering | by Sasha Przybylski - Medium, accessed July 29, 2025, https://medium.com/@sasha_przybylski/the-math-behind-extended-kalman-filtering-0df981a87453 |
| EKF vs. UKF: Important Aspects in the Observation of Bioprocesses | Iris Publishers, accessed July 29, 2025, https://irispublishers.com/abba/fulltext/ekf-vs-ukf-important-aspects-in-the-observation.ID.000633.php |