728x90
- Filter : 어떤 신호에서 원하지 않는 신호를 차단하거나, 원하는 신호만을 통과시키는 기능을 하는 회로 등의 장치나 과정
- 신호 처리의 일부로, 특정 Frequency를 차단 혹은 통과시킨다
- 원하지 않는 신호인 Noise를 제거하기 위해 사용
- 모든 Filter들은 이전의 값이 현재 값에 영향을 주는 Recursive(재귀)적인 구조를 갖는다
1) Average Filter
- N개의 Sample을 모두 더하고 N으로 나눠 평균을 구하는 단순한 방식의 Filter
- 평균 계산에 직전 평균값과 데이터 갯수, 새로 추가된 데이터 만을 필요로 함
- 간단하지만 Noise 제거에 효과적
- (1 - N) x 이전까지의 평균 + N x 현재값 = Average Filter
- (수식 찍어서 사진 추가)
- 이전의 값 (x_k-1) 이 현재값(x_k)에 영향을 주는 Recursive(재귀) 적인 구조
- 데이터가 순차적으로 입력되는 경우 데이터를 저장할 필요가 없고 계산 효율이 높아 실시간 처리에 유리
- 평균을 취함으로써 Noise 제거 가능
- Average Filter 식 유도 과정
- (아래 과정 수식으로 정리)
- Avg Filter는 Sensor 초기화에도 유용하게 쓰일 수 있다
- 어떤 이유로 Sensor의 영점이 틀어질 경우 (Ex) 체중계) 처음 일정시간 동안의 Sensor값의 평균을 초기값으로 잡아 영점을 잡을 수 있음
- Average Filter C 코드
int k; // Number of sample
double x_prev; // Previous Average
double AvgFilter(double x){
double average, alpha;
k += 1; // Add 1 to the number of sample
alpha = (k - 1) / (k + 0.0); // Alpha value of the Average Filter
average = alpha * x_prev + (1 - alpha) * x; // Recursive expression of average filter
x_prev = average; // Update the previous state value of average filter
return average;
}
- Matlab 코드
clear all
dt = 1; % Set time interval to 1second
t = 0:dt:100; % Make 100 Time samples (0~100)
Nsamples = length(t); % Fix the number of samples to 100
avgsaved = zeros(Nsamples, 1); % Make an array which has zero only
xmsaved = zeros(Nsamples, 1);
for k=1:Nsamples
xm = getvolt(); % Get the value which Noise is added to 14V value
avg = avgfilter(xm); % Put the filtered values
avgsaved(k) = avg; % Save the measurements and estimated values to array
xmsaved(k) = xm;
end
figure
plot(t, xmsaved, 'r:*')
hold on
plot(t, avgsaved, 'o-')
legend('measured', 'average')
- Exavgfilter.m
function z = getvolt()
w = 0+randn(1,1);
z = 14 + w; % Add noise to 14V
% (Assume that the system`s voltage is 14V)
- getvolt.m
function avg = avgfilter(x)
persistent preavg k
persistent firstrun
if isempty(firstrun) % If the firstrun array is empty,
k = 1;
preavg = 0;
firstrun = 1;
end
alpha = (k-1) / k;
avg = alpha * preavg + (1 - alpha) * x; % Main Part of Average Filter
preavg = avg;
k = k+1;
- avgfilter.m
2. Moving Average Filter
- 측정하려는 값이 위처럼 일정하지 않고, 지속적으로 변하면 Average Filter로는 대상의 동적인 움직임을 따라가지 못함
- Average Filter는 전체 데이터에 대한 평균만을 측정하므로 최근 데이터의 변화량을 감지할 수 없다
- 이로 인해 시간이 지날수록 오차가 쌓이게 됨
- Ex) 1 ~ 5까지의 입력이 들어오는 경우
측정 값 | 1 | 2 | 3 | 4 | 5 |
Average Filter | 1 | 1.5 | 2 | 2.5 | 3 |
Moving Avg Filter | 1 | 1.5 | 2.5 | 3.5 | 4.5 |
- 즉 동적인 대상체의 값을 추정하려는 경우 시간의 변화에 따른 변화를 반영하기 위해 Moving Average Filter 사용
- 현재 시점에서 과거의 일부분만 보며 계속 평균을 구하는 방식
- 혹은 구간을 이동시키며 그 구간에 있는 값들의 평균값을 구하여 현재 값을 추정하는 Filter
- $ \tilde{x}_{k} = \frac{x_{k-n+1} + x_{k-n+2} ... + x_{k}}{n} = \tilde{x}_{k-1} + \frac{x_{k}-x_{k-n}}{n} $
(수식으로 대체)
- 이후 추정값이 설정치보다 크고 작음에 따른 동작 설정 필요
- Ex) 모터 속도
- 추정값이 설정 속도보다 크다면 감속, 작다면 가속
- 구간 크기가 클 경우 추정치의 정확도는 향상되나 구간 크기만큼의 값이 들어오기 전까지는 정확한 추정치를 얻지 못하는 지연 구간이 발생
- 또한 해당 길이만큼의 데이터를 가지고 있어야 하므로 메모리를 많이 차지하고, 연산량이 증가하게 됨
- MovAvgFilter C코드
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define FALSE (0)
#define TRUE (!FALSE)
typedef struct {
int32_t* buffer;
int32_t sum;
uint32_t length;
uint32_t currentIdx;
}ST_MovingAverage;
int32_t MovingAverageInit(ST_MovingAverage* movingAverage, uint32_t length)
{
int32_t result;
movingAverage->currentIdx = 0;
movingAverage->sum = 0;
movingAverage->length = length;
movingAverage->buffer = (int32_t*)malloc(length * sizeof(int32_t));
if (movingAverage->buffer == NULL) {
result = FALSE;
}
else {
memset(movingAverage->buffer, 0, length * sizeof(int32_t));
result = TRUE;
}
return result;
}
void MovingAverageDelete(ST_MovingAverage* movingAverage)
{
free(movingAverage->buffer);
}
int32_t MovingAverage(ST_MovingAverage* movingAverage, int32_t value)
{
int32_t result;
movingAverage->sum -= movingAverage->buffer[movingAverage->currentIdx];
movingAverage->sum += value;
movingAverage->buffer[movingAverage->currentIdx] = value;
movingAverage->currentIdx++;
movingAverage->currentIdx %= movingAverage->length;
result = movingAverage->sum / movingAverage->length;
return result;
}
int main()
{
int32_t InitResult = 0;
int32_t sensorOutput = 0;
ST_MovingAverage movingAverage[2];
InitResult = MovingAverageInit(&movingAverage[0], 10);
if (InitResult == FALSE) {
printf("Fail MovingAverage[0] Init\n");
return 0;
}
InitResult = MovingAverageInit(&movingAverage[1], 50);
if (InitResult == FALSE) {
printf("Fail MovingAverage[1] Init\n");
return 0;
}
for (int i = 0; i < 100; i++) {
sensorOutput = 50 + (rand() % 21 - 10);
printf("%d, %d, %d, %d\n", i, sensorOutput, MovingAverage(&movingAverage[0], sensorOutput), MovingAverage(&movingAverage[1], sensorOutput));
}
MovingAverageDelete(&movingAverage[0]);
MovingAverageDelete(&movingAverage[1]);
return 0;
}
- Matlab 코드
clear all
Nsamples = length(t);
Xsaved = zeros(Nsamples, 1);
Xmsaved = zeros(Nsamples, 1);
for k=1:Nsamples
xm = getvolt_moving(); % y = x + 1 form
x = MovAvgfilter(xm);
Xsaved(k) = x;
Xmsaved(k) = xm;
end
dt = 1;
t = 0:dt:Nsamples*dt - dt;
figure
hold on
plot(t, Xmsaved, 'r.')
plot(t, Xsaved, 'b')
legend('measured', 'moving average')
- ExMovAvgfilter.m
- 1초 간격으로 총 100개의 샘플에 Moving Average Filter를 적용하는 코드
function avg = MovAvgfilter(x)
persistent preAvg n xbuf
persistent firstrun
if isempty(firstrun)
n = 5; % Take Mov Avg Filter to 5 previous values
xbuf = x*ones(n+1, 1); % Initialize xbuf to [1 1 1 1 1]*input(x)
k = 1;
preavg = x;
firstrun = 1;
end
for m = 1:n % Renew input values to 1 ~ n
xbuf(m) = xbuf(m+1); % Ex) [1,2,3,4,5] -> [2,3,4,5,6] -> [3,4,5,6,7]
% As [1,2,3,4,5,6,7] is input sequentially
end
xbuf(n+1) = x; % [1,2,3,4,5] -> [2,3,4,5,6]
% Remove the first value and add the input value
avg = preAvg + (x - xbuf(1)) / n;
preAvg = avg;
- MovAvgFilter.m
- 평균 값 산출에 5개의 Sample 사용
3. Low Pass Filter (1st Order)
- Low Frequency 신호는 통과시키고 High Frequency 신호는 차단하는 Filter
- 보통 측정하려는 신호는 Low Frequency이고 Noise는 High Frequency인 경우가 많아 Noise 제거용으로 사용
- (LPF 회로 사진 추가)
- 회로 중 C(Capacitor)는 Frequency에 따라 바뀌는 하나의 가변저항이라 생각할 수 있다
- 위와 같은 주파수 응답 특성 곡선에서 -3dB가 되는 지점을 Cutoff Frequency라 한다
- -3dB는 아래와 같이 전력 (입력 대비 출력)이 1/2가 되는 주파수 지점이다
- 특정 수식의 Filter가 아닌 Low Frequency 신호만을 통과시키는 특성을 갖는 모든 Filter를 총칭
- 위의 Moving Average Filter에서 과거의 값들보다 현재에 가까운 값에 가중치를 더 크게 부여하는 방식
- Moving Average Filter의 경우 아래와 같이 모든 데이터에 동일한 가중치를 적용
- (수식 추가)
- 이는 가장 최근의 데이터와 가장 오래된 데이터에 동일한 가중치를 적용하는 방식으로, 자동차나 비행기 처럼 빠르게 움직이는 물체에서는 노이즈를 제거하며 변화 추이를 반영하기 어려움
- Average Filter와 동일한 식
- 스텝이 지날 수록 이전 데이터에는 낮은 가중치가 곱해지게 됨
- α가 크면 Noise 제거율이 올라가나 변화에 둔감해짐
- α가 크면 추정값 x^_k-1 의 비중이 더 커지게 되어 직전 추정값과 현재 추정값이 크게 달라지지 않게 됨
- α가 작으면 Noise는 많아지나 변화에 민감해짐
- α가 작으면 1 - α 가 상대적으로 카져 추정값 계산에 측정값 x_k가 더 많이 반영되게 되어 측정값의 변화에 더 민감해짐
function avg = MovingFilter(x)
persistent preAvg n xbuf
persistent firstRun
if isempty(firstRun)
n = 5;
xbuf = x*ones(n+1, 1);
k = 1;
preAvg = x;
firstRun = 1;
end
for m = 1:n
xbuf(m) = xbuf(m+1);
end
xbuf(n+1) = x;
avg = preAvg + 1.5*(x - xbuf(1)) / n; % Give 1.5 weighting value to present input value
preAvg = avg;
- MovAvgFilter.m
- 기존의 MovAvgFilter 코드에서 Weighting 부분만 추가
참고 자료 :
https://limitsinx.tistory.com/69
https://gaussian37.github.io/autodrive-ose-table/
'Study_Engineering' 카테고리의 다른 글
표준편차, 분산, 공분산 (0) | 2024.01.16 |
---|---|
EKF를 통한 자율주행 로봇의 Localization (2) | 2024.01.15 |
State Space Equation이란 (0) | 2024.01.12 |
About Electric Circuit (1) | 2024.01.08 |
전기/전자 관련 기초 지식 (0) | 2023.12.15 |