음향 방출(Acoustic Emission)이란?
음향 방출(AE, Acoustic Emission)은 재료 내부에 균열이 발생하거나 마찰, 충격 등의 응력이 가해질 때 방출되는 고주파 탄성파입니다. 사람의 귀로는 들을 수 없는 초음파 대역(일반적으로 100kHz~1MHz)에서 발생하며, 압전(piezoelectric) 센서로 포착할 수 있습니다.
핵심 포인트: AE 신호는 고장이 발생하는 바로 그 순간에 방출되므로, 진동이나 온도 센서보다 조기 진단에 유리합니다.
AE vs 진동 센서 비교
| 항목 | 음향 방출(AE) | 진동 센서 |
|---|---|---|
| 주파수 대역 | 100kHz~1MHz (초음파) | 1Hz~10kHz (가청 주파수 근처) |
| 탐지 시점 | 결함 발생 직후 (조기) | 결함이 어느 정도 진행된 후 |
| 센서 감도 | 매우 높음 (미세 균열 탐지) | 상대적으로 낮음 |
| 노이즈 영향 | 환경 소음에 덜 민감 | 환경 진동에 취약 |
| 적용 분야 | 베어링, 기어, 균열 탐지 | 회전체 불균형, 공진 분석 |
기어박스 고장 메커니즘과 AE 신호
기어박스는 회전 동력을 전달하는 핵심 부품으로, 다음과 같은 고장 모드가 주로 발생합니다:
- 치면 피팅(Pitting): 반복 하중으로 치면에 미세 구멍 발생
- 스폴링(Spalling): 피팅이 확대되어 큰 조각이 떨어져 나감
- 치면 마모(Wear): 윤활 부족으로 치면이 점진적으로 닳음
- 균열(Crack): 과부하나 피로로 치면/치저에 균열 발생
각 고장 모드는 고유한 AE 신호 패턴을 생성합니다. 예를 들어:
– 피팅/균열: 짧고 강한 버스트(burst) 신호
– 마모: 연속적인 백색소음(continuous) 신호
시간-주파수 특징 추출 전략
AE 신호는 시간에 따라 주파수 특성이 변하는 비정상(non-stationary) 신호입니다. 따라서 단순 FFT보다는 시간-주파수 분석이 필수입니다.
1. 단시간 푸리에 변환(STFT)
신호를 짧은 구간으로 나누어 각 구간의 주파수 스펙트럼을 계산합니다.
- : 원본 AE 신호
- : 윈도우 함수 (Hann, Hamming 등)
- : 시간 , 주파수 에서의 복소 스펙트럼
장점: 구현이 간단하고 해석이 직관적
단점: 시간-주파수 분해능 트레이드오프 (윈도우 크기 고정)
2. 웨이블릿 변환(Wavelet Transform)
STFT의 단점을 보완하여 적응적 시간-주파수 분해능을 제공합니다.
- : 스케일(주파수에 반비례)
- : 시간 이동
- : 모 웨이블릿 함수 (Morlet, Daubechies 등)
장점: 고주파는 좁은 시간 창, 저주파는 넓은 시간 창 자동 조정
단점: 계산량 증가
3. 힐베르트-황 변환(HHT)
EMD(Empirical Mode Decomposition)로 신호를 IMF로 분해 후 힐베르트 변환 적용.
장점: 비선형/비정상 신호에 최적
단점: 모드 혼합(mode mixing) 문제, 수학적 이론 미흡
실무 추천 조합
import numpy as np
from scipy import signal
import pywt
def extract_ae_features(ae_signal, fs=1e6):
"""
AE 신호에서 시간-주파수 특징 추출
Parameters:
- ae_signal: 1D numpy array (AE 센서 raw data)
- fs: 샘플링 주파수 (Hz)
Returns:
- features: dict (RMS, 피크 주파수, 웨이블릿 에너지 등)
"""
features = {}
# 1. 시간 도메인 특징
features['rms'] = np.sqrt(np.mean(ae_signal**2))
features['peak'] = np.max(np.abs(ae_signal))
features['kurtosis'] = np.mean((ae_signal - np.mean(ae_signal))**4) / (np.std(ae_signal)**4)
# 2. 주파수 도메인 (FFT)
fft_vals = np.fft.rfft(ae_signal)
fft_freq = np.fft.rfftfreq(len(ae_signal), 1/fs)
features['peak_freq'] = fft_freq[np.argmax(np.abs(fft_vals))]
features['spectral_centroid'] = np.sum(fft_freq * np.abs(fft_vals)) / np.sum(np.abs(fft_vals))
# 3. 웨이블릿 분해 (5레벨 db4)
coeffs = pywt.wavedec(ae_signal, 'db4', level=5)
for i, coeff in enumerate(coeffs):
features[f'wavelet_energy_level{i}'] = np.sum(coeff**2)
# 4. STFT 기반 시간-주파수 특징
f, t, Zxx = signal.stft(ae_signal, fs, nperseg=256)
features['stft_max_power'] = np.max(np.abs(Zxx))
features['stft_bandwidth'] = np.std(f) # 주파수 분산
return features
1D-CNN 분류 모델 구현
왜 1D-CNN인가?
전통적인 머신러닝(SVM, Random Forest)은 수작업 특징 추출이 필요하지만, 1D-CNN은:
– 자동 특징 학습: Convolutional 레이어가 최적 필터 자동 발견
– 시계열 패턴 포착: 국소적 시간 패턴과 전역 추세 동시 학습
– 연산 효율: 2D-CNN보다 파라미터 적고 학습 빠름
모델 아키텍처
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
def build_1d_cnn(input_length, num_classes):
"""
AE 신호 분류용 1D-CNN 모델
Parameters:
- input_length: 입력 신호 샘플 길이 (예: 2048)
- num_classes: 고장 클래스 수 (정상 + 고장 유형)
"""
model = keras.Sequential([
# 입력: (batch, timesteps, 1)
layers.Input(shape=(input_length, 1)),
# Conv Block 1: 저수준 필터 (고주파 노이즈 제거)
layers.Conv1D(32, kernel_size=7, activation='relu', padding='same'),
layers.BatchNormalization(),
layers.MaxPooling1D(pool_size=2),
layers.Dropout(0.2),
# Conv Block 2: 중간 수준 패턴
layers.Conv1D(64, kernel_size=5, activation='relu', padding='same'),
layers.BatchNormalization(),
layers.MaxPooling1D(pool_size=2),
layers.Dropout(0.3),
# Conv Block 3: 고수준 추상 특징
layers.Conv1D(128, kernel_size=3, activation='relu', padding='same'),
layers.BatchNormalization(),
layers.MaxPooling1D(pool_size=2),
layers.Dropout(0.4),
# Global Average Pooling (파라미터 감소)
layers.GlobalAveragePooling1D(),
# Dense Layer
layers.Dense(128, activation='relu'),
layers.Dropout(0.5),
layers.Dense(num_classes, activation='softmax')
])
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=0.001),
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
return model
# 예시: 4클래스 분류 (정상, 피팅, 스폴링, 균열)
model = build_1d_cnn(input_length=2048, num_classes=4)
model.summary()
학습 전략
from sklearn.model_selection import train_test_split
# 데이터 준비 (X: AE 신호, y: 라벨)
X_train, X_val, y_train, y_val = train_test_split(
ae_signals, labels, test_size=0.2, stratify=labels, random_state=42
)
# 정규화
X_train = (X_train - np.mean(X_train)) / np.std(X_train)
X_val = (X_val - np.mean(X_train)) / np.std(X_train) # 주의: train 통계로 정규화
# 데이터 증강 (시간 이동, 노이즈 추가)
def augment_ae(signal, noise_level=0.01, shift_range=100):
# 랜덤 노이즈
augmented = signal + np.random.normal(0, noise_level, signal.shape)
# 랜덤 시간 이동
shift = np.random.randint(-shift_range, shift_range)
augmented = np.roll(augmented, shift)
return augmented
# 콜백 설정
callbacks = [
keras.callbacks.EarlyStopping(patience=20, restore_best_weights=True),
keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=10),
keras.callbacks.ModelCheckpoint('best_ae_model.h5', save_best_only=True)
]
# 학습
history = model.fit(
X_train, y_train,
validation_data=(X_val, y_val),
epochs=200,
batch_size=32,
callbacks=callbacks,
verbose=1
)
실무 활용 시나리오
1. 실시간 모니터링 파이프라인
import time
class AEMonitor:
def __init__(self, model, threshold=0.8):
self.model = model
self.threshold = threshold
self.alert_log = []
def process_stream(self, ae_stream, fs=1e6, window_size=2048):
"""
실시간 AE 스트림 처리
"""
buffer = []
for sample in ae_stream:
buffer.append(sample)
if len(buffer) >= window_size:
# 윈도우 추출 및 전처리
window = np.array(buffer[-window_size:])
window_norm = (window - np.mean(window)) / (np.std(window) + 1e-8)
# 예측
pred = self.model.predict(window_norm.reshape(1, -1, 1), verbose=0)
fault_prob = 1 - pred[0][0] # 0번 클래스가 정상이라고 가정
# 임계값 초과 시 알림
if fault_prob > self.threshold:
fault_type = np.argmax(pred[0][1:])
self.alert_log.append({
'timestamp': time.time(),
'fault_type': ['피팅', '스폴링', '균열'][fault_type],
'confidence': fault_prob
})
print(f"⚠️ 고장 감지: {self.alert_log[-1]['fault_type']} (확률: {fault_prob:.2%})")
# 슬라이딩 윈도우 (50% 오버랩)
buffer = buffer[window_size//2:]
2. 성능 평가 지표
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
# 테스트 데이터 예측
y_pred = np.argmax(model.predict(X_test), axis=1)
# 혼동 행렬 시각화
cm = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['정상', '피팅', '스폴링', '균열'],
yticklabels=['정상', '피팅', '스폴링', '균열'])
plt.ylabel('실제')
plt.xlabel('예측')
plt.title('AE 기반 기어박스 고장 분류 혼동 행렬')
plt.show()
# 분류 보고서
print(classification_report(y_test, y_pred,
target_names=['정상', '피팅', '스폴링', '균열']))
3. 산업 현장 적용 체크리스트
- [ ] 센서 부착 위치: 베어링 하우징 근처, 진동 전달 경로 최소화
- [ ] 샘플링 주파수: 최소 500kHz 이상 (Nyquist 정리, AE 신호 최대 주파수의 2배)
- [ ] 데이터 저장: 연속 저장 시 저장 공간 폭발 → 트리거 방식 권장 (임계값 초과 시만 저장)
- [ ] 환경 노이즈 제거: 고주파 대역 통과 필터 (100kHz~), 전자기 차폐
- [ ] 라벨링 데이터 확보: 인위적 결함 주입(seeded fault) + 런투페일(run-to-failure) 테스트
- [ ] 모델 재학습 주기: 운전 조건 변화 시 (온도, 하중, RPM) 분기별 업데이트
마무리
음향 방출 센서는 기어박스 고장을 조기에 탐지할 수 있는 강력한 도구입니다. 핵심은:
- 시간-주파수 특징 추출: STFT, 웨이블릿으로 비정상 신호의 숨겨진 패턴 포착
- 1D-CNN 자동 학습: 수작업 특징 엔지니어링 없이 end-to-end 분류
- 실시간 파이프라인: 슬라이딩 윈도우 + 임계값 기반 알림 시스템
실무 팁: 초기 도입 시 진동 센서와 병행 운영하여 상호 검증하고, AE 센서는 조기 경보, 진동 센서는 추세 분석용으로 역할을 분담하면 효과적입니다.
현장 데이터가 부족하다면 Case Western Reserve University 베어링 데이터셋이나 FEMTO 베어링 데이터셋으로 먼저 파일럿 모델을 구축한 후, 전이 학습(Transfer Learning)으로 실제 기어박스에 적용하는 전략을 추천합니다.
Did you find this helpful?
☕ Buy me a coffee
Leave a Reply