주파수 분석과 스펙트로그램
1. 서론
신호 처리에서 주파수 분석은 시간 도메인에서 관측된 신호를 주파수 도메인으로 변환하여 신호의 구성 성분을 분석하는 과정입니다. 이는 소리, 이미지, 진동 등 다양한 형태의 데이터를 분석하는 데 필수적인 과정으로, 신호의 특성을 파악하고 문제를 진단하는 데 중요한 역할을 합니다.
특히, 주파수 분석을 시각화하는 대표적인 방법으로 스펙트로그램(Spectrogram)이 있습니다. 스펙트로그램은 시간과 주파수의 변화를 동시에 시각화하여 신호의 특성을 쉽게 이해할 수 있도록 도와줍니다. 이 글에서는 SciPy
의 signal
모듈을 활용해 주파수 분석과 스펙트로그램을 생성하는 방법을 살펴보겠습니다.
2. 푸리에 변환을 통한 주파수 분석
2.1 푸리에 변환의 개념
푸리에 변환(Fourier Transform)은 신호를 주파수 성분으로 분해하는 수학적 기법입니다. 주어진 신호를 사인과 코사인 함수의 조합으로 표현하는 방식으로, 시간 영역(time domain)의 신호를 주파수 영역(frequency domain)으로 변환합니다.
푸리에 변환의 수식은 다음과 같이 정의됩니다.
$$
X(f) = \int_{-\infty}^{\infty} x(t) e^{-j 2 \pi f t} dt
$$
하지만 실생활에서는 대부분 이산 신호를 다루므로, 이산 푸리에 변환(DFT)를 많이 사용합니다. SciPy에서는 빠른 푸리에 변환(FFT)을 이용해 효율적으로 주파수 분석을 수행할 수 있습니다.
2.2 SciPy를 이용한 FFT 구현
아래는 SciPy
의 fft
모듈을 사용하여 임의의 신호를 주파수 분석하는 예제입니다.
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft, fftfreq
# 샘플링 속성과 신호 생성
fs = 1000 # 샘플링 주파수 (Hz)
T = 1.0 / fs # 샘플 간격
N = 1000 # 샘플 수
t = np.linspace(0.0, N * T, N, endpoint=False)
signal = np.sin(50.0 * 2.0 * np.pi * t) + 0.5 * np.sin(120.0 * 2.0 * np.pi * t)
# FFT 수행
yf = fft(signal)
xf = fftfreq(N, T)[:N // 2]
# 결과 시각화
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, signal)
plt.title("시간 도메인에서의 신호")
plt.xlabel("시간 (s)")
plt.ylabel("진폭")
plt.subplot(2, 1, 2)
plt.plot(xf, 2.0 / N * np.abs(yf[0:N // 2]))
plt.title("주파수 도메인에서의 신호")
plt.xlabel("주파수 (Hz)")
plt.ylabel("진폭")
plt.tight_layout()
plt.show()
이 예제에서는 50Hz와 120Hz의 주파수를 가지는 신호를 생성하고, 이를 빠른 푸리에 변환을 통해 주파수 성분을 분석했습니다. 주파수 그래프에서 해당 성분이 뚜렷하게 나타나는 것을 확인할 수 있습니다.
3. 스펙트로그램 생성
3.1 스펙트로그램의 개념
스펙트로그램은 시간에 따른 주파수 성분의 변화를 시각적으로 표현하는 방법입니다. 이는 단일 창 푸리에 변환(STFT, Short-Time Fourier Transform)을 통해 구현됩니다. STFT는 신호를 일정한 길이의 창(window)으로 나누고, 각 창에 대해 푸리에 변환을 수행하는 방식입니다.
스펙트로그램의 축은 다음과 같이 구성됩니다.
- X축: 시간 (Time)
- Y축: 주파수 (Frequency)
- 색상: 진폭 (Amplitude)
3.2 SciPy를 이용한 스펙트로그램 생성
다음은 SciPy의 signal.spectrogram
함수를 이용해 스펙트로그램을 생성하는 예제입니다.
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import spectrogram
# 신호 생성
fs = 1000 # 샘플링 주파수
t = np.linspace(0, 10, 10000, endpoint=False)
signal = np.sin(2 * np.pi * 50 * t) + np.sin(2 * np.pi * 150 * t)
signal += 0.5 * np.random.normal(size=t.shape)
# 스펙트로그램 생성
frequencies, times, Sxx = spectrogram(signal, fs)
# 시각화
plt.figure(figsize=(12, 6))
plt.pcolormesh(times, frequencies, 10 * np.log10(Sxx), shading='gouraud')
plt.colorbar(label='dB')
plt.ylabel("주파수 (Hz)")
plt.xlabel("시간 (s)")
plt.title("스펙트로그램")
plt.tight_layout()
plt.show()
이 코드에서는 50Hz와 150Hz 성분을 가지는 신호에 노이즈를 추가한 후, 이를 스펙트로그램으로 시각화했습니다. 색상의 강도가 주파수 성분의 크기를 나타내며, 시간에 따라 주파수 성분이 어떻게 변화하는지 확인할 수 있습니다.
4. 고급 분석: 웨이브릿 변환과 비교
스펙트로그램은 시간과 주파수 해상도 간의 트레이드오프가 존재합니다. 이는 창의 크기에 따라 해상도가 결정되기 때문입니다. 주파수 분석의 또 다른 방법으로 웨이브릿 변환(Wavelet Transform)이 있으며, 이는 다양한 크기의 창을 사용해 시간과 주파수 해상도를 동시에 최적화하는 기법입니다.
4.1 웨이브릿 변환과 스펙트로그램 비교
특징 | 스펙트로그램 | 웨이브릿 변환 |
---|---|---|
시간 해상도 | 고정된 창 크기에 따라 결정 | 주파수에 따라 가변적 |
주파수 해상도 | 고정된 창 크기에 따라 결정 | 주파수에 따라 가변적 |
비선형 신호 분석 | 제한적 | 우수 |
계산 복잡도 | 상대적으로 낮음 | 상대적으로 높음 |
웨이브릿 변환은 특히 비정상(non-stationary) 신호 분석에 적합하며, 스펙트로그램과 보완적으로 사용하면 보다 깊이 있는 분석이 가능합니다.
5. 결론
이번 포스팅에서는 SciPy
의 signal
모듈을 이용해 주파수 분석과 스펙트로그램을 생성하는 방법을 살펴보았습니다. 푸리에 변환을 통해 신호의 주파수 성분을 분석하고, 스펙트로그램을 통해 시간에 따른 주파수 변화를 시각화하는 과정은 신호 처리에서 필수적인 작업입니다.
스펙트로그램은 오디오 분석, 진동 모니터링, 생체 신호 분석 등 다양한 분야에서 활용될 수 있습니다.
'Python SciPy' 카테고리의 다른 글
Python SciPy로 배우는 기술 통계 (평균, 중앙값, 표준편차 등) (0) | 2025.03.15 |
---|---|
SciPy 신호 간 상관 분석 (0) | 2025.03.14 |
SciPy 푸리에 변환 (FFT) (0) | 2025.03.12 |
SciPy를 활용한 필터 설계 및 적용 (butter, filtfilt) (0) | 2025.03.11 |
SciPy.optimize - 제약 조건과 경계 설정 방법 (0) | 2025.03.10 |