Edge AI 기반 실시간 진동 분석: Raspberry Pi와 MEMS 센서로 구현하는 저비용 예지보전 시스템

Updated Feb 6, 2026

들어가며

제조 현장에서 설비 고장은 막대한 생산 손실로 이어집니다. 전통적인 예지보전(Predictive Maintenance) 시스템은 고가의 장비와 클라우드 인프라를 필요로 했지만, Edge AI 기술의 발전으로 이제 Raspberry Pi와 저가형 MEMS 센서만으로도 실시간 진동 분석 시스템을 구축할 수 있습니다.

Edge AI란 클라우드가 아닌 현장(Edge) 디바이스에서 직접 AI 모델을 실행하여 낮은 지연시간과 데이터 프라이버시를 보장하는 기술입니다.

이번 글에서는 Raspberry Pi 4ADXL345 MEMS 가속도 센서를 활용해 회전 기계의 진동을 실시간으로 모니터링하고, TinyML 모델로 이상을 탐지하는 시스템을 구현하는 방법을 소개합니다.


시스템 구성 요소

하드웨어

구성 요소 모델명 가격 용도
컴퓨팅 보드 Raspberry Pi 4 (4GB) ~$55 Edge AI 추론 실행
진동 센서 ADXL345 (3축 MEMS) ~$5 가속도 데이터 수집
통신 I2C 인터페이스 내장 센서-보드 연결
전원 5V 3A 어댑터 ~$10 안정적인 전원 공급

총 비용: 약 $70 (상용 CBM 시스템 대비 1/50 수준)

소프트웨어 스택

# 필수 라이브러리
import adafruit_adxl34x
import board
import numpy as np
from scipy import signal
import tflite_runtime.interpreter as tflite
  • 센서 제어: Adafruit CircuitPython 라이브러리
  • 신호처리: NumPy, SciPy (FFT, 필터링)
  • AI 추론: TensorFlow Lite Runtime
  • 알림: MQTT 프로토콜 (경량 IoT 통신)

진동 데이터 수집 및 전처리

센서 초기화

import busio
import adafruit_adxl34x

# I2C 버스 초기화
i2c = busio.I2C(board.SCL, board.SDA)
accel = adafruit_adxl34x.ADXL345(i2c)

# 샘플링 레이트 설정 (1600Hz)
accel.data_rate = adafruit_adxl34x.DataRate.RATE_1600_HZ
accel.range = adafruit_adxl34x.Range.RANGE_16_G

실시간 데이터 수집

import time

SAMPLE_RATE = 1600  # Hz
WINDOW_SIZE = 1024  # 샘플 수 (약 0.64초)

def collect_vibration_data():
    """1024개 샘플 수집 (약 0.64초 윈도우)"""
    buffer = []
    for _ in range(WINDOW_SIZE):
        x, y, z = accel.acceleration
        # 3축 벡터 크기 계산
        magnitude = np.sqrt(x**2 + y**2 + z**2)
        buffer.append(magnitude)
        time.sleep(1 / SAMPLE_RATE)
    return np.array(buffer)

샘플링 이론: ISO 10816 기준에 따르면 회전 기계 진동 분석에는 최소 2~10kHz 샘플링이 권장됩니다. 1600Hz는 저속 회전체(~800 RPM) 모니터링에 적합합니다.

주파수 도메인 변환

시간 도메인 신호를 FFT(고속 푸리에 변환)로 주파수 스펙트럼으로 변환합니다.

def extract_frequency_features(signal_data, sample_rate=1600):
    """FFT를 통한 주파수 특징 추출"""
    # Hanning 윈도우 적용 (스펙트럼 누수 방지)
    windowed = signal_data * np.hanning(len(signal_data))

    # FFT 계산
    fft_vals = np.fft.rfft(windowed)
    fft_freq = np.fft.rfftfreq(len(windowed), 1/sample_rate)
    fft_mag = np.abs(fft_vals)

    # 주요 특징 추출
    features = {
        'peak_freq': fft_freq[np.argmax(fft_mag)],  # 최대 진폭 주파수
        'rms': np.sqrt(np.mean(signal_data**2)),     # RMS (진동 강도)
        'kurtosis': np.mean((signal_data - np.mean(signal_data))**4) / np.std(signal_data)**4,
        'spectral_centroid': np.sum(fft_freq * fft_mag) / np.sum(fft_mag)
    }
    return features, fft_mag[:128]  # 128개 주파수 빈 사용

주요 특징 설명:

  • fpeakf_{peak}: 가장 큰 에너지를 가진 주파수 (베어링 결함 주파수 탐지)
  • RMS=1Ni=1Nxi2RMS = \sqrt{\frac{1}{N}\sum_{i=1}^{N} x_i^2}: 진동 강도의 총량 (전체 상태 지표)
  • 첨도(Kurtosis): 충격성 신호 탐지 (정상: 3, 베어링 결함: >5)
  • 스펙트럼 중심: 주파수 분포의 무게중심 (고주파 성분 증가 = 마모 진행)

TinyML 모델 학습 및 배포

모델 아키텍처

1D CNN(Convolutional Neural Network)을 사용해 주파수 스펙트럼에서 이상 패턴을 학습합니다.

import tensorflow as tf

def build_model():
    model = tf.keras.Sequential([
        tf.keras.layers.Input(shape=(128, 1)),  # 128개 주파수 빈
        tf.keras.layers.Conv1D(16, 5, activation='relu'),
        tf.keras.layers.MaxPooling1D(2),
        tf.keras.layers.Conv1D(32, 5, activation='relu'),
        tf.keras.layers.GlobalAveragePooling1D(),
        tf.keras.layers.Dense(16, activation='relu'),
        tf.keras.layers.Dense(1, activation='sigmoid')  # 이상/정상 (0/1)
    ])
    return model

model = build_model()
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

TensorFlow Lite 변환

# 양자화(Quantization)로 모델 크기 1/4 축소
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()

with open('vibration_model.tflite', 'wb') as f:
    f.write(tflite_model)

양자화: Float32 → Int8 변환으로 모델 크기를 4MB → 1MB로 축소하고 추론 속도를 3배 향상시킵니다.

Raspberry Pi에서 실시간 추론

import tflite_runtime.interpreter as tflite

# 모델 로드
interpreter = tflite.Interpreter(model_path='vibration_model.tflite')
interpreter.allocate_tensors()

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

def predict_anomaly(fft_spectrum):
    """실시간 이상 탐지"""
    # 입력 데이터 정규화
    input_data = fft_spectrum.reshape(1, 128, 1).astype(np.float32)
    input_data = (input_data - np.mean(input_data)) / np.std(input_data)

    # 추론 실행
    interpreter.set_tensor(input_details[0]['index'], input_data)
    interpreter.invoke()
    output = interpreter.get_tensor(output_details[0]['index'])

    return output[0][0]  # 이상 확률 (0~1)

실무 활용 시나리오

베어링 결함 탐지

회전 기계의 베어링 결함은 특정 주파수 패턴을 생성합니다.

결함 유형 결함 주파수 공식 특징
외륜 결함 BPFO=Nb2fs(1dDcosα)BPFO = \frac{N_b}{2}f_s(1-\frac{d}{D}\cos\alpha) 반복적인 충격파
내륜 결함 BPFI=Nb2fs(1+dDcosα)BPFI = \frac{N_b}{2}f_s(1+\frac{d}{D}\cos\alpha) 회전 동기 패턴
볼 결함 BSF=D2dfs[1(dDcosα)2]BSF = \frac{D}{2d}f_s[1-(\frac{d}{D}\cos\alpha)^2] 고주파 노이즈

공식 용어:
NbN_b: 볼 개수
fsf_s: 샤프트 회전 주파수 (Hz)
dd: 볼 직경
DD: 피치 직경
α\alpha: 접촉각

def calculate_bpfo(rpm, n_balls, ball_dia, pitch_dia, contact_angle=0):
    """외륜 결함 주파수 계산"""
    fs = rpm / 60  # Hz 변환
    return (n_balls / 2) * fs * (1 - (ball_dia / pitch_dia) * np.cos(contact_angle))

# 예시: 1800 RPM 모터, 9개 볼 베어링
bpfo = calculate_bpfo(1800, 9, 7.9, 39.0)
print(f"외륜 결함 주파수: {bpfo:.2f} Hz")  # 약 120 Hz

경보 시스템 구현

import paho.mqtt.client as mqtt

def send_alert(anomaly_score, features):
    """MQTT로 경보 전송"""
    client = mqtt.Client()
    client.connect("mqtt.local", 1883)

    payload = {
        "timestamp": time.time(),
        "anomaly_score": float(anomaly_score),
        "peak_freq": features['peak_freq'],
        "rms": features['rms'],
        "kurtosis": features['kurtosis']
    }

    client.publish("factory/vibration/alert", json.dumps(payload))
    client.disconnect()

# 메인 루프
while True:
    signal_data = collect_vibration_data()
    features, fft_spectrum = extract_frequency_features(signal_data)
    anomaly_score = predict_anomaly(fft_spectrum)

    if anomaly_score > 0.75:  # 임계값 75%
        send_alert(anomaly_score, features)
        print(f"⚠️  이상 탐지! (확률: {anomaly_score:.2%})")

    time.sleep(10)  # 10초마다 분석

성능 최적화

배터리 절전 모드

# 적응형 샘플링: 정상 시 10초, 이상 시 1초 간격
if anomaly_score < 0.3:
    sleep_time = 10
elif anomaly_score < 0.7:
    sleep_time = 5
else:
    sleep_time = 1  # 고위험 시 실시간 모니터링

추론 속도 벤치마크

플랫폼 추론 시간 FPS
Raspberry Pi 4 (4 Core) 8ms 125
Raspberry Pi Zero 2 35ms 28
Arduino Nano 33 BLE 120ms 8

상용 시스템 대비 장단점

장점

  • 초저비용: 기기당 70vs상용70 vs 상용3,500
  • 실시간 처리: 클라우드 왕복 지연(100~500ms) 제거
  • 데이터 프라이버시: 민감한 생산 데이터 외부 유출 차단
  • 오프라인 동작: 네트워크 없이 독립 운영

한계

  • ⚠️ 샘플링 속도: 1.6kHz (상용 시스템은 50kHz+)
  • ⚠️ 센서 정밀도: MEMS는 고정밀 IEPE 센서 대비 노이즈 多
  • ⚠️ 분석 깊이: 복잡한 다변량 분석 불가 (RUL 예측 제한적)

권장 적용 분야: 중소형 회전기계(펌프, 팬, 컨베이어), 교육용 시스템, PoC(Proof of Concept) 검증


확장 가능성

멀티센서 융합

# 온도 센서 추가 (DS18B20)
import w1thermsensor

temp_sensor = w1thermsensor.W1ThermSensor()
temperature = temp_sensor.get_temperature()

# 진동 + 온도 융합 분석
if anomaly_score > 0.7 and temperature > 70:
    alert_level = "CRITICAL"  # 베어링 과열 + 진동 이상

디지털 트윈 연동

수집된 데이터를 시뮬레이션 모델과 연동해 RUL(잔여 수명) 예측:

RUL = \frac{L_{10} – L_{current}}{\text{degradation_rate}}

여기서 L10L_{10}은 베어링 설계 수명, LcurrentL_{current}는 현재 누적 운전 시간입니다.


마무리

Edge AI 기반 진동 분석 시스템은 $70의 하드웨어로 실시간 예지보전을 구현할 수 있는 현실적인 솔루션입니다. Raspberry Pi의 범용성과 TinyML의 효율성을 결합하면, 중소 제조 현장에서도 스마트 팩토리의 첫걸음을 내딛을 수 있습니다.

핵심 요약:

  1. ADXL345 MEMS 센서로 1600Hz 진동 데이터 수집
  2. FFT + 통계 특징(RMS, Kurtosis)으로 신호 분석
  3. 1D CNN TFLite 모델로 8ms 이내 실시간 추론
  4. MQTT 경보로 즉각적인 이상 알림
  5. 70vs70 vs3,500: 상용 대비 50배 저렴

다음 단계로는 무선 센서 네트워크(WSN) 구축과 클라우드 대시보드 연동을 고려해보세요. Edge에서 전처리하고 클라우드에서 장기 트렌드를 분석하는 하이브리드 아키텍처가 최적의 균형점입니다.

Did you find this helpful?

☕ Buy me a coffee

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

TODAY 369 | TOTAL 2,592