개요
일상생활을 하다보면 이론과 현실이 다른 경우가 꽤 많이 존재합니다. 회로에 10V의 전압을 가해줘도 전압계에서는 정확히 10V로 표시되지 않으며, 로봇에게 20도만큼 회전하도록 명령해도 수치적으로 정확히 그만큼 회전하지는 않습니다.
로봇에 사용되는 센서의 경우 이론 상으로는 측정값들이 정직하게 들어와야하는 반면 실제 환경에서는 여러 요인에 의해 측정값에 잡음이 포함된 값이 측정되고 사용됩니다.
때문에 시뮬레이션 상에서는 로봇이 원하는 대로 동작했던 알고리즘이 실제 환경에서는 제대로 동작하지 않고 오류가 날 수 있습니다. 따라서 실제 환경에서는 필수적으로 이 잡음을 제거해줄 방법이 필요합니다.
칼만 필터는 측정값의 잡음을 잘 제거해줄 뿐만 아니라 실제로 측정할 수 없는 물리량도 추정할 수 있게 해주는 능력 때문에 여러 분야에서 사용되고 있습니다.
당장 ROS의 SLAM에서도 로봇의 위치 추정 방법에 일반적으로 칼만 필터가 사용되고 있으며, 앞으로 제가 공부해야 할 센서 퓨전에서도 칼만 필터가 사용되고 있다고 하니 공부하지 않을 이유가 없었습니다.
그 시작으로 저는 김성필 작가님의 "칼만 필터는 어렵지 않아"라는 책을 읽으면서 칼만 필터에 대한 전반적인 내용을 공부했고요, 앞으로 이 책 내용을 정리하여 포스팅하려고 합니다.
되도록 자세히 설명하려 하겠지만 이해되지 않는 부분이나 설명이 부족한 부분은 본책을 참고하시면 되겠습니다. 그리고 책에서는 예제가 MATLAB으로 구현되어있는데 저는 이를 저에게 익숙한 파이썬으로 재구현하여 사용하려고 합니다.
평균 필터(Averaging Filter)
이름만 들어도 알 수 있듯이 평균 필터는 말 그대로 측정값의 평균을 이용해 잡음을 제거하는 필터입니다.
평균은 아시다시피 데이터의 총합을 데이터 개수로 나눈 값으로 k개의 데이터가 있을 때 평균은 다음과 같이 계산할 수 있죠.
$\large{\overline{x}_k = \frac{x_1 + x_2 + ... + x_k}{k}}$
위의 식과 같이 데이터를 모두 모아서 한꺼번에 계산하는 식을 배치식이라고 하는데, 이 식을 이용하여 다음 데이터(k+1번째 데이터) 값이 들어왔을 때의 평균값을 구한다고 하면 다시 k+1까지의 데이터를 모두 더한 후 k+1로 나눠줘야 합니다.
직감적으로 상당히 비효율적이라는 것을 느끼실 수 있을 것입니다. 이렇게 배치식은 앞서 계산한 값들을 사용하지 못하고 처음부터 다시 계산하기 때문에 계산량이 많아져 주로 데이터를 실시간으로 처리해야 하는 필터에 사용하기에는 무리가 있습니다.
이 때문에 저희는 이전 결과를 다시 사용하는 재귀식 형태의 필터를 사용해야 하며 앞으로 나올 필터들 또한 모두 재귀식 형태입니다.
그렇다면 이제 위의 평균의 배치식을 재귀식으로 바꿔보겠습니다.
방금 설명했다시피 재귀식은 이전 결과를 다시 사용하는 식입니다. 즉 $\overline{x}_k$ 와 $\overline{x}_{k-1}$의 관계식을 찾으면 그 식이 재귀식이 되겠죠.
$\overline{x}_{k-1}$은 평균의 정의에 따라 다음과 같습니다.
$\large{\overline{x}_{k-1} =\frac{x_1 + x_2 + ... + x_{k-1}}{k-1}}$
두 식을 살펴보면 $\overline{x}_{k-1}$에 $\frac{k-1}{k}$를 곱하고 $\frac{x_k}{k}$를 더하면 $\overline{x}_{k}$이 된다는 것을 알 수 있죠.
따라서 재귀식은 다음과 같습니다.
$\large{\overline{x}_k = \frac{k-1}{k}\overline{x}_{k-1} + \frac{1}{k}x_k}$
식을 더 간단하게 표현하기 위해서 $α ≡ \frac{k-1}{k}$ 라고 하면 식을 다음과 같이 쓸 수 있습니다.
$\large{\overline{x}_k = α\overline{x}_{k-1} + (1 - α)x_k}$
바로 위 식의 형태를 평균 필터(Averaging Filter)라고 부르며, 이는 잡음 제거와 센서 초기화에 사용됩니다.
칼만 필터에 대해서 공부하는데 웬 대뜸 평균 필터가 나오냐고 생각하실 수도 있겠지만 이 평균의 재귀식 형태는 뒤에서 설명할 저주파 통과 필터와 칼만필터에도 등장하게 됩니다.
그렇다면 파이썬으로 평균필터를 구현하여 예제에 적용시키고 잡음이 잘 제거되는지 확인해보도록 하겠습니다.
적용
평균 필터를 구현하여 아래 예제에 적용해보도록 하겠습니다.
예제)
고평균 연구원은 전기차의 배터리를 연구한다. 어느 날 고평균 연구원이 새로 들어온 배터리의 전압을 측정하는데, 잡음이 심해서 잴 때마다 그 값이 달랐다. 그래서 일정 시간 동안 측정 데이터를 모아서 평균을 내보기로 했다. 전압은 0.2초 간격으로 측정한다.
1) 평균 필터 함수
def AvgFilter(pre_avg, k, z):
alpha = (k - 1) / k
avg = alpha * pre_avg + (1 - alpha) * z
return avg
$\large{\overline{x}_k = α\overline{x}_{k-1} + (1 - α)x_k}$
위의 평균 필터 식을 이용해 현재 측정값 z, α를 계산하기 위한 데이터 개수 k, 직전 평균값인 pre_avg를 입력으로 받아 현재 측정값까지의 평균을 반환하도록 평균 필터 함수를 구현해줍니다.
2) 전압 측정값 생성 함수
# 전압 측정값 생성 함수
def GetVolt():
# 평균이 0, 표준편차가 4인 정규분포를 따르는 잡음 생성
w = 0 + 4 * np.random.randn(1)
# 측정 전압의 평균은 14.4V로 위의 잡음이 섞인 값을 측정값으로 설정
z = 14.4 + w
return z
기본 14.4V에 평균이 0, 표준편차가 4인 정규분포를 따르는 잡음을 더해주어 측정값으로 설정하고 이를 반환해줍니다.
3) 결과값 저장
# 측정 간격 0.2
dt = 0.2
# arange 함수를 이용해 0 ~ 10까지 0.2 간격으로 수 생성
# 여기서는 10초까지의 측정값 개수를 구하기 위해 사용
t = np.arange(0, 10, dt)
# 측정값 개수
Nsamples = len(t)
# 측정값과 평균필터를 통과한 값을 저장할 array 생성
Zsaved = np.zeros(Nsamples)
Avgsaved = np.zeros(Nsamples)
np.random.seed(1)
pre_avg = 0
# 새로운 측정값이 들어올 때마다 평균필터를 통과시켜 평균 계산
for k in range(Nsamples):
k += 1
z = GetVolt()
avg = AvgFilter(pre_avg, k, z)
Zsaved[k-1] = z
Avgsaved[k-1] = avg
pre_avg = avg
0~10초까지 0.2초 간격으로 측정값을 받고 평균 필터를 통과시켜 평균값을 계산해줍니다. 측정값과 평균 필터를 통과시킨 출력값은 array에 저장했습니다.
출력값이 저장된 Avgsaved array를 출력해본 결과 시간이 지날수록 잡음이 제거되어 14.4V에 근접하는 것을 확인할 수 있습니다.
array([20.89738145, 16.4251779 , 15.0458896 , 13.81144858, 14.62148496,
13.05021167, 14.24007387, 13.87946119, 14.07909399, 14.01143644,
14.57843601, 13.87685277, 13.81788957, 13.74973907, 14.09542832,
13.83949123, 13.83189099, 13.66837296, 13.71576675, 13.86654145,
13.68230249, 13.92305669, 14.10059174, 14.19681614, 14.34908045,
14.24584999, 14.23335329, 14.10562361, 14.07882444, 14.16024436,
14.07873186, 14.0391773 , 13.96681766, 13.88012236, 13.81826216,
13.83301437, 13.727548 , 13.76991944, 13.95631147, 14.0416081 ,
14.0316337 , 13.95586824, 13.89669379, 14.06199207, 14.07401961,
14.02571521, 14.04992684, 14.23224129, 14.24547384, 14.29794061])
4) 결과값 확인
아래 그림은 측정값(빨간 별)과 평균 필터의 출력값(파란 동그라미)을 그래프로 나타낸 결과입니다.
측정 전압은 위아래로 변동이 심한 반면에 평균 필터의 출력값은 시간이 지날수록 즉 데이터가 쌓여갈수록 측정 잡음이 제거되고14.4V에 근접해가는 것을 확인할 수 있습니다.
이렇게 평균필터는 측정값에 평균을 취해줌으로써 잡음 제거의 역할을 수행합니다.
전체 코드는 아래 깃허브에 올려놓았으니 참고하시면 되겠습니다.
https://github.com/goodhsm2000/Kalman_Filter_Study
https://www.aladin.co.kr/shop/wproduct.aspx?ISBN=K712635309&start=pnaver_02
※ 이 글은 위의 책 내용을 바탕으로 작성한 글입니다.