확장 칼만 필터의 기본 구조
확장 칼만 필터(EKF)는 두 가지 주요 단계로 나눌 수 있다: 예측 단계와 업데이트 단계. 이 과정에서 상태 변수와 측정값을 기반으로 시스템의 상태를 지속적으로 추정하게 된다.
1. 초기화
확장 칼만 필터에서 먼저 상태 벡터 \mathbf{x}와 공분산 행렬 \mathbf{P}를 초기화해야 한다. 여기서 \mathbf{x}는 시스템의 초기 상태를 나타내고, \mathbf{P}는 초기 상태에 대한 불확실성을 나타낸다.
초기 상태 벡터 \mathbf{x}_0는 다음과 같이 정의된다:
공분산 행렬 \mathbf{P}_0는 다음과 같이 대각 성분에 초기 불확실성을 반영한다:
2. 예측 단계
예측 단계에서는 상태 전이 함수 \mathbf{f}(\mathbf{x})를 통해 다음 상태를 예측한다. 이때, 시스템의 동역학을 나타내는 함수 \mathbf{f}(\mathbf{x})는 일반적으로 비선형이다. 상태 예측은 다음과 같이 이루어진다:
공분산 행렬의 예측은 야코비 행렬 \mathbf{F}를 사용하여 계산된다. 야코비 행렬은 상태 전이 함수 \mathbf{f}(\mathbf{x})의 편미분으로 구성되며 다음과 같이 정의된다:
예측된 공분산 행렬 \mathbf{P}_{k|k-1}는 다음과 같이 계산된다:
여기서 \mathbf{Q}는 시스템 노이즈 공분산 행렬이다.
3. 업데이트 단계
업데이트 단계에서는 측정값 \mathbf{z}_k를 통해 상태를 보정한다. 측정 함수 \mathbf{h}(\mathbf{x}) 역시 비선형일 수 있으며, 상태 벡터를 측정값 공간으로 사상하는 역할을 한다. 측정 예측은 다음과 같이 이루어진다:
측정 오차 \mathbf{y}_k는 실제 측정값과 예측 측정값의 차이로 정의된다:
측정 오차 공분산 행렬 \mathbf{S}_k는 야코비 행렬 \mathbf{H}_k와 측정 노이즈 공분산 행렬 \mathbf{R}_k를 사용하여 계산된다:
4. 칼만 이득 계산
칼만 이득 \mathbf{K}_k는 상태 업데이트에서 측정 오차를 얼마나 반영할지 결정하는 요소이다. 칼만 이득은 다음과 같이 계산된다:
5. 상태 및 공분산 업데이트
최종적으로 상태 벡터는 칼만 이득과 측정 오차를 사용하여 업데이트된다:
공분산 행렬은 다음과 같이 업데이트된다:
예제 코드: 확장 칼만 필터 구현
아래는 확장 칼만 필터(EKF)를 Python으로 구현한 예제 코드이다. 이 코드는 위에서 설명한 EKF의 예측 및 업데이트 단계를 포함하고 있다. 구체적인 수학적 알고리즘을 코드로 변환하여 직관적으로 이해할 수 있도록 작성되었다.
1. 상태 및 공분산 초기화
먼저, 상태 벡터와 공분산 행렬을 초기화한다.
import numpy as np
# 상태 벡터 초기화 (예: 위치와 속도)
x = np.array([0, 0, 0, 0]) # [x_position, y_position, x_velocity, y_velocity]
# 공분산 행렬 초기화
P = np.eye(4) * 1000 # 초기 불확실성이 크기 때문에 대각 성분을 크게 설정
# 시스템 노이즈 공분산 행렬 Q 초기화
Q = np.eye(4) * 0.1
# 측정 노이즈 공분산 행렬 R 초기화
R = np.eye(2) * 5 # 측정값은 위치만 포함한다고 가정
2. 예측 단계
다음은 상태 전이 함수와 공분산 행렬을 사용하여 예측을 수행하는 부분이다.
# 상태 전이 함수 정의 (여기서는 단순한 선형 이동 모델)
def f(x):
F = np.array([[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0],
[0, 0, 0, 1]])
return F @ x
# 예측 단계
def predict(x, P, Q):
# 상태 예측
x_pred = f(x)
# 상태 전이 함수의 야코비 행렬
F = np.array([[1, 0, 1, 0],
[0, 1, 0, 1],
[0, 0, 1, 0],
[0, 0, 0, 1]])
# 공분산 행렬 예측
P_pred = F @ P @ F.T + Q
return x_pred, P_pred
# 예측 수행
x_pred, P_pred = predict(x, P, Q)
3. 업데이트 단계
다음은 측정값을 바탕으로 상태를 업데이트하는 부분이다.
# 측정 함수 정의 (위치만 측정하는 경우)
def h(x):
return np.array([x[0], x[1]]) # 측정값은 위치(x_position, y_position)
# 측정 함수의 야코비 행렬
H = np.array([[1, 0, 0, 0],
[0, 1, 0, 0]])
# 측정값 z (실제 측정된 값)
z = np.array([2, 3]) # 예: 측정된 위치가 [2, 3]
# 칼만 이득 계산 및 상태 업데이트
def update(x_pred, P_pred, z, H, R):
# 측정값 예측
z_pred = h(x_pred)
# 측정 오차
y = z - z_pred
# 측정 오차 공분산 계산
S = H @ P_pred @ H.T + R
# 칼만 이득 계산
K = P_pred @ H.T @ np.linalg.inv(S)
# 상태 업데이트
x_update = x_pred + K @ y
# 공분산 업데이트
P_update = (np.eye(len(x_pred)) - K @ H) @ P_pred
return x_update, P_update
# 상태 및 공분산 업데이트 수행
x_update, P_update = update(x_pred, P_pred, z, H, R)
위의 코드는 간단한 선형 모델을 바탕으로 확장 칼만 필터를 구현한 예시이다. 비선형 시스템에 대한 실제 확장 칼만 필터는 상태 전이 함수 \mathbf{f}(\mathbf{x})와 측정 함수 \mathbf{h}(\mathbf{x})가 비선형이므로, 야코비 행렬을 구하는 과정이 필수적이다.