SciPy를 활용한 필터 설계 및 적용 (butter, filtfilt)
1. 개요
디지털 신호 처리에서는 노이즈 제거, 특정 주파수 대역의 강조 또는 차단과 같은 목적으로 필터를 설계하고 적용하는 과정이 중요합니다. SciPy의 scipy.signal
모듈은 이러한 작업을 간편하게 수행할 수 있도록 다양한 필터 설계 및 적용 도구를 제공합니다.
이번 포스팅에서는 Butterworth 필터를 중심으로 저역 통과(low-pass), 고역 통과(high-pass), 대역 통과(band-pass), 대역 차단(band-stop) 필터를 설계하고 filtfilt
함수를 활용하여 신호에 적용하는 방법을 살펴보겠습니다.
2. Butterworth 필터란?
Butterworth 필터는 통과 대역에서 평탄한 주파수 응답을 갖는 필터입니다. 다른 필터들과 비교했을 때 급격한 전이 특성은 없지만, 신호의 왜곡을 최소화하면서 안정적인 성능을 제공합니다.
Butterworth 필터는 다음과 같은 특징을 갖습니다.
- 통과 대역에서 주파수 응답이 매우 평탄하다.
- 위상 왜곡이 비교적 적다.
- 차단 대역에서 선형적으로 감쇠된다.
이러한 특징 덕분에 오디오, 바이오메디컬 신호 처리 등 다양한 분야에서 널리 사용됩니다.
3. SciPy에서 필터 설계하기
SciPy의 scipy.signal.butter
함수를 이용하면 Butterworth 필터를 간단하게 설계할 수 있습니다. butter
함수는 다음과 같이 사용됩니다.
from scipy.signal import butter
b, a = butter(N, Wn, btype='low', analog=False, output='ba')
N
: 필터의 차수(Order)를 의미합니다. 값이 클수록 필터의 성능이 향상되지만 위상 왜곡이 증가할 수 있습니다.Wn
: 차단 주파수(Normalized frequency)입니다. 일반적으로 0과 1 사이의 값으로 설정합니다.btype
: 필터의 종류를 지정합니다. ('low'
,'high'
,'bandpass'
,'bandstop'
)analog
: 아날로그 필터 여부를 결정합니다. 디지털 필터를 사용하는 경우False
로 설정합니다.output
: 출력 형식을 결정합니다. 기본적으로 분자와 분모 계수(ba
)로 반환됩니다.
4. 필터 적용하기 (filtfilt)
필터를 설계한 후에는 scipy.signal.filtfilt
함수를 활용하여 실제 신호에 적용할 수 있습니다. filtfilt
는 신호를 전방향과 역방향으로 두 번 필터링하는 방식으로, 위상 왜곡을 최소화하는 장점이 있습니다.
from scipy.signal import filtfilt
filtered_signal = filtfilt(b, a, signal)
b
,a
: 필터 계수입니다.signal
: 필터링할 원본 신호입니다.filtered_signal
: 필터가 적용된 결과 신호입니다.
filtfilt
는 신호의 위상을 유지하면서도 필터링 효과를 적용할 수 있어 많은 신호 처리 작업에서 선호됩니다.
5. 예제: 노이즈가 포함된 신호 필터링
아래는 노이즈가 포함된 사인파 신호에 저역 통과 필터를 적용하는 예제입니다.
(1) 예제 코드
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import butter, filtfilt
# 샘플링 주파수와 시간 설정
fs = 1000 # Hz
t = np.linspace(0, 1.0, int(fs), endpoint=False)
# 원본 신호 (10Hz 사인파)
signal = np.sin(2 * np.pi * 10 * t)
# 노이즈 추가
noise = 0.5 * np.random.normal(size=t.shape)
noisy_signal = signal + noise
# 저역 통과 필터 설계
cutoff = 20 # 차단 주파수 (Hz)
nyquist = 0.5 * fs
normal_cutoff = cutoff / nyquist
b, a = butter(4, normal_cutoff, btype='low', analog=False)
# 필터 적용
filtered_signal = filtfilt(b, a, noisy_signal)
# 결과 시각화
plt.figure(figsize=(12, 8))
plt.plot(t, noisy_signal, label='노이즈가 포함된 신호', alpha=0.6)
plt.plot(t, signal, label='원본 신호', linestyle='dashed')
plt.plot(t, filtered_signal, label='필터 적용 후 신호', linewidth=2)
plt.xlabel('시간 [초]')
plt.ylabel('진폭')
plt.legend(loc='upper right')
plt.grid(True)
plt.title('Butterworth 저역 통과 필터 적용 예제')
plt.show()
(2) 코드 설명
- 신호 생성: 10Hz 사인파에 랜덤 노이즈를 추가하여 신호를 생성합니다.
- 필터 설계: 차단 주파수가 20Hz인 4차 저역 통과 필터를 설계합니다.
- 필터 적용:
filtfilt
함수를 사용해 필터를 적용하고, 위상 왜곡 없는 결과를 얻습니다. - 시각화: 필터 적용 전후의 신호를 비교합니다.
(3) 결과 분석
결과 그래프를 살펴보면, 노이즈가 포함된 신호에 비해 필터링된 신호는 원본 사인파와 훨씬 더 유사해진 것을 확인할 수 있습니다. 이는 Butterworth 필터가 신호의 주요 구성 요소를 보존하면서 노이즈를 효과적으로 제거했음을 보여줍니다.
6. 다양한 필터 적용 방법
(1) 고역 통과 필터
고역 통과 필터는 특정 주파수 이상의 성분만 통과시키는 필터입니다.
# 고역 통과 필터 설계 (30Hz 이상 통과)
high_cutoff = 30
normal_high_cutoff = high_cutoff / nyquist
b, a = butter(4, normal_high_cutoff, btype='high', analog=False)
high_passed_signal = filtfilt(b, a, noisy_signal)
(2) 대역 통과 필터
특정 주파수 범위만 통과시키는 필터입니다.
# 대역 통과 필터 설계 (10Hz ~ 30Hz)
band_low = 10
band_high = 30
normal_band = [band_low / nyquist, band_high / nyquist]
b, a = butter(4, normal_band, btype='band', analog=False)
band_passed_signal = filtfilt(b, a, noisy_signal)
(3) 대역 차단 필터
특정 주파수 범위를 차단하는 필터입니다.
# 대역 차단 필터 설계 (20Hz ~ 40Hz 차단)
stop_low = 20
stop_high = 40
normal_stop = [stop_low / nyquist, stop_high / nyquist]
b, a = butter(4, normal_stop, btype='bandstop', analog=False)
band_stopped_signal = filtfilt(b, a, noisy_signal)
7. 실전 응용 사례
- 생체 신호 처리: 심전도(ECG) 신호에서 노이즈를 제거하거나 특정 주파수 성분만 분석할 때 활용됩니다.
- 오디오 신호 처리: 오디오 파일에서 불필요한 잡음을 제거하거나 특정 주파수를 강조하는 데 사용됩니다.
- 환경 데이터 분석: 환경 센서에서 수집된 데이터에서 신호의 급격한 변화나 이상치를 감지할 때 필터링 기법이 유용합니다.
8. 결론
SciPy의 signal.butter
와 filtfilt
함수는 디지털 신호 처리에서 필터 설계와 적용을 간편하게 수행할 수 있도록 도와줍니다. Butterworth 필터는 평탄한 응답과 위상 왜곡 최소화라는 장점을 제공하여, 다양한 신호 처리 분야에서 널리 사용되고 있습니다.
실제 프로젝트에서 노이즈를 제거하거나 특정 주파수 대역을 분석해야 할 때, 본 포스팅에서 소개한 방법을 활용해보시기 바랍니다.
9. 참고 자료
- SciPy 공식 문서: scipy.signal
- Oppenheim, A. V., & Schafer, R. W. (2009). "Discrete-Time Signal Processing."
'Python SciPy' 카테고리의 다른 글
주파수 분석과 스펙트로그램 (0) | 2025.03.13 |
---|---|
SciPy 푸리에 변환 (FFT) (0) | 2025.03.12 |
SciPy.optimize - 제약 조건과 경계 설정 방법 (0) | 2025.03.10 |
SciPy를 활용한 곡선 맞추기 (curve_fit) (0) | 2025.03.09 |
비선형 방정식 찾기 (SciPy.optimize.root) (0) | 2025.03.08 |