본문 바로가기

Theory/ControlTheory

Python class로 만드는 1차 저역통과필터 Low Pass Filter

디지털 필터에 대해서는 예전에 많이 다루었는데요. 당시에 다룰때는 간단히 Python의 함수(def)를 사용해서 많이 다루었습니다. 이번에는 class를 이용해서 조금 사용성을 높인 코드를 보여드리는 것이 어떨까하고 글을 작성합니다. 일단 1차 저역통과필터는 예전에 소개한 글에서 수식을 가져오겠습니다.

저 식을 코드로 단순 변환 시켜보면 

out = (tau * pre_out + ts * data) / (tau + ts)

입니다. 수식에서 분모가 같으니 tau + ts는 빼서 보면 저렇게 되죠. 문제는 pre_out입니다. 현재 출력값 out, 수식에서는 yn의 이전 값이거든요. 그래서 저 코드가 실행된 직후 현재 출력을 별도로 저장해야 합니다. 만약 class를 사용하지 않는다면, 1차 저역통과필터가 필요할때마다 만들어야할 변수 때문에 고생을 하겠죠. 저 핵심 코드를 코함해서 간단히 클래스로 만들어 보겠습니다.

import numpy as np

class LowPassFilter:
    def __init__(self, cutoff_freq, ts):
        self.ts = ts
        self.cutoff_freq = cutoff_freq
        self.pre_out = 0.
        self.tau = self.calc_filter_coef() 
        
    def calc_filter_coef(self):
        w_cut = 2*np.pi*self.cutoff_freq
        return 1/w_cut
        
    def filter(self, data):
        out = (self.tau * self.pre_out + self.ts * data) / (self.tau + self.ts)
        self.pre_out = out
        return out

어떤가요. 입력 부분만 조금 편하게 Hz 단위의 차단 주파수를 넣었습니다. 선언하는 방법은

lpf = LowPassFilter(cutoff_freq = 0.5, ts = 0.01)

이렇게 차단 주파수를 0.5Hz로 샘플링타임을 0.01로 잡아주면 되겠죠. 필터를 한 번 테스트해보겠습니다.

import matplotlib.pyplot as plt
%matplotlib inline

t = np.arange(0, 10, 0.01)
y = np.sin(t)
plt.plot(t, y);

간단하게 0부터 10초까지 0.01초 간격으로 sin 함수를 만들어 둡니다.

이렇게 생겼습니다. 이제 잡음을 살짝 입히도록 하죠 

y = 10*np.sin(t) + 5*np.random.rand(len(y))
plt.plot(t, y);

이렇게 두겠습니다. 이 결과는 

이렇게 생겼습니다. 이제 아까 선언해둔 lpf를 적용시켜보죠.

filtered_data = [lpf.filter(data) for data in y]
plt.plot(t, y)
plt.plot(t, filtered_data, 'r', lw=3);

코드는 이렇게 사용하면 됩니다. 이제 결과를 보겠습니다.

타임 딜레이가 있지만, 연습용이니까요.^^. 0.5Hz 차단 주파수는 역시 좀 심했군요^.^ 아무튼 노이즈 들어간 신호를 잘 잡았네요. 이제 저역통과필터가 필요하신 분들은 위 class를 가져다 사용하시면 되겠습니다.^^

반응형