top of page

철도 압축 공기 처리 장치(APU), 시계열 DB로 "설명 가능한" 상태 진단 화면 만들기

12시간 전
4분 분량

들어가며

Predictive Maintenance라고 하면 보통 머신러닝 모델이 고장을 맞히는 장면부터 떠올립니다. 하지만 현장에서 정비 담당자가 정말 묻는 것은 "그래서 왜 그렇게 판단했는데?"입니다. 점수 하나만 던져 주는 시스템은 신뢰를 얻기 어렵고, 센서 데이터와 시간축을 함께 보면서 결과를 설명할 수 있어야 비로소 쓸모가 생깁니다.

이번 글에서는 UCI Machine Learning Repository의 MetroPT-3 데이터셋을 Machbase Neo에 적재하고, 철도 차량의 압축 공기 처리 장치(APU) 상태를 인터랙티브 대시보드로 탐색하는 데모를 소개합니다. 이 데모의 Health Score와 이벤트는 학습된 모델이 아니라 프로젝트에서 직접 정의한 규칙 기반 지표입니다. 산식이 공개되어 있으니 왜 그 점수가 나왔는지 누구나 따라가 볼 수 있습니다.

왜 MetroPT-3인가

MetroPT-3는 2020년 2월부터 8월까지 철도 차량 APU에서 수집된 텔레메트리로, 시점이 1,516,948개이고 압력, 온도, 전류, 밸브, 스위치, 임펄스 등 원본 센서가 15종, 센서 값은 약 2,275만 개에 이릅니다. 무엇보다 데이터셋 저자가 공개한 공기 누출 고장 구간이 4개 있어서, 센서 변화가 실제 고장과 어떻게 이어지는지 눈으로 확인할 수 있습니다. 압축기, 삼상 모터, 사이클론 분리 필터, 드라이어 타워, 저장 탱크, 밸브, 공압 패널로 이어지는 공기 흐름이 직관적이어서 시각화하기에도 좋고, CC BY 4.0 라이선스라 재사용도 자유롭습니다.

한 가지 짚어 둘 점이 있습니다. 공개 자료에는 장비가 철도 차량 압축기 APU라는 사실만 명시되어 있고 제조사, 모델, 차량 번호는 알 수 없습니다. 또 CSV에서 실제 관찰되는 데이터 간격은 약 9~10초(약 0.1Hz)로, 데이터셋 설명의 1Hz 표기와 다릅니다. 그래서 이 데모는 임의의 샘플링 주파수를 가정하지 않고 실제 시점 1,516,948개를 기준으로 표시합니다. 원본 시간대도 공개되지 않았기 때문에 시각은 원본 그대로 보존하고, 화면에 "데이터셋 현지 시각 · 시간대 미지정"이라고 안내합니다. 모르는 것을 아는 척하지 않는 것이 설명 가능한 분석의 출발점이라고 생각했습니다.

데모가 보여 주는 것

대시보드에서는 약 151만 시점 전체를 시간축 위에서 탐색할 수 있고, 3D로 표현된 APU의 공기 흐름과 장비 상태를 함께 볼 수 있습니다. 15종 센서의 변화, 공식 공기 누출 구간, 규칙 기반 Health Score와 이벤트가 같은 시간축에 겹쳐 표시되며, 재생 기능으로 센서 데이터를 시간순으로 돌려 볼 수도 있습니다. 영문과 한글 UI, 90초 가이드 투어를 지원합니다.

여기서 중요한 설계 원칙은 구분입니다. 데이터셋이 제공하는 공식 고장 구간과 프로젝트가 계산한 파생 이벤트는 화면에서 명확히 다르게 표시됩니다. 머신러닝 정확도를 주장하지 않고, 어디까지가 원본 사실이고 어디부터가 우리가 계산한 해석인지를 분리해서 보여 줍니다.

Machbase Neo에는 어떻게 저장했나

핵심 테이블은 IIOT_METRO_TIMELINE입니다. value JSON SUMMARIZED WITH ROLLUP을 사용하는 태그 테이블이고, 데이터셋 metropt-3-uci-791과 자산 apu-01 아래에 telemetry, baseline, event 세 종류의 JSON 행을 저장합니다. 원시 텔레메트리뿐 아니라 기준선과 파생 이벤트도 같은 시간축 모델 안에 넣은 셈입니다.

이 구조의 장점은 롤업에서 나옵니다. Machbase Neo가 전체 JSON 값을 대상으로 SEC, MIN, HOUR 롤업 계층을 자동으로 관리하기 때문에, API는 한 번의 AVG(value) 쿼리로 모든 숫자 필드를 집계한 다음 사용자가 선택한 센서만 뽑아 쓰면 됩니다. 센서가 15종이든 30종이든 센서별 집계 쿼리를 따로 짤 필요가 없습니다. 화면을 확대하고 축소할 때 해상도에 맞는 롤업 계층이 선택되므로 151만 시점도 빠르게 조회됩니다. 행 종류, 이벤트 종류, 이벤트 출처, 건전성 등급처럼 자주 거르는 조건에는 JSON 경로 인덱스를 걸었습니다.

적재는 CSV를 메모리에 한 번에 올리지 않고 스트리밍으로 처리합니다. 약 218MB 원본을 JSH 메모리에 통째로 올리지 않으려고 다운로드 스크립트도 명령만 출력하도록 만들었습니다.

설명 가능한 Health Score

건전성 지수는 2020년 2월 한 달을 기준 기간으로 삼아 시작합니다. 이 기간의 시간 단위 특성에서 p05, p50, p95 분위수를 구하고, 최근 1시간 이동 구간의 값이 이 기준 분포에서 얼마나 벗어났는지를 위험도로 환산합니다. 이동 구간은 실제 타임스탬프 간격을 사용하며 최소 45분의 데이터가 있어야 유효하고, 데이터 간격이 120초를 넘으면 구간을 초기화합니다. 센서 공백을 억지로 메우지 않는다는 뜻입니다.

위험도는 값이 높을수록 위험한 지표와 낮을수록 위험한 지표로 나누어 0에서 1 사이로 정규화합니다.

높을수록 위험 = clamp((x - p95) / max(3 × (p95 - p50), ε), 0, 1)
낮을수록 위험 = clamp((p05 - x) / max(3 × (p50 - p05), ε), 0, 1)

이렇게 만든 네 가지 위험도를 가중 결합한 것이 건전성 지수입니다.

건전성 지수 = 100 × (1
  - 0.40 × 압력 저하 위험도
  - 0.25 × 압력 회복 위험도
  - 0.20 × 시간당 기동 횟수 위험도
  - 0.15 × 압축기 부하 운전율 위험도)

공기 누출이 주된 고장이므로 압력 저하와 회복 지연에 가장 큰 가중치를 두었고, 누출이 있으면 압축기가 더 자주 기동하고 더 오래 부하 운전을 하게 된다는 점을 나머지 두 항이 반영합니다. 오일 온도는 운전 상태를 설명하려고 화면에는 표시하지만, 계절 변화 때문에 건전성 산식에서는 일부러 뺐습니다. 2월을 기준으로 8월까지 보는 데이터에서 온도를 넣으면 고장이 아니라 계절을 탐지하게 되기 때문입니다.

이벤트도 순간값이 아니라 지속 조건으로 정의했습니다. 건전성 지수가 60 미만이면서 비정상 기여 요인이 2개 이상인 상태가 3시간 연속되면 조기 경고, 지수가 30 미만이고 기여 요인이 3개 이상인 상태가 1시간 지속되면 위험, 지수가 70 이상으로 3시간 유지되면 회복으로 판단합니다. 일시적인 튀는 값에 경보가 울리지 않도록 한 것입니다. 이 기준은 어디까지나 검증 가능한 데모 정책이며 학습된 고장 분류 모델이 아닙니다.

결과까지 보여 주는 Evidence API

백엔드는 읽기 전용 API 몇 개로 구성했습니다. /api/health와 /api/manifest는 상태와 메타데이터를, /api/frame은 특정 시각의 한 시점을 돌려줍니다. 이때 seek=next|prev 옵션으로 텔레메트리 공백을 건너뛰어 다음 또는 이전 데이터로 이동할 수 있습니다. /api/window는 구간 조회, /api/signals는 선택한 센서의 시계열(예: signals=reservoirs,health_score), /api/events는 이벤트 목록을 제공합니다.

이 데모에서 제가 가장 마음에 들어 하는 부분은 모든 데이터 응답에 증거 정보가 함께 들어 있다는 점입니다. 실행된 SQL, 바인딩 값, 대상 테이블, 결과 예시, 실제 쿼리 시간, 사용된 롤업 간격까지 응답에 실려 오기 때문에, 화면의 숫자가 어떤 쿼리에서 어떻게 나왔는지 추적할 수 있습니다. 센서 이름은 허용 목록으로 제한해서 API 입력값이 임의의 SQL 표현식으로 쓰이지 않도록 막았습니다. "빠르다"는 말을 믿어 달라고 하는 대신, 쿼리 시간을 응답에 박아 두는 방식입니다.

직접 실행해 보기

필요한 것은 Machbase Neo 8.5.x와 git, curl, sha256sum, unzip, WebGL을 지원하는 브라우저입니다. machbase-neo 실행 파일이 있는 디렉터리에서 저장소를 받습니다.

cd <MACHBASE_NEO_INSTALL_DIR>
git clone https://github.com/machbase/neo-train-apu-demo.git
cd neo-train-apu-demo

원본 데이터는 저장소에 재배포하지 않으므로 직접 내려받아 해시를 검증합니다. 안내 스크립트를 실행하면 다운로드 명령이 출력되고, 그것을 셸에서 실행하면 됩니다.

../machbase-neo jsh scripts/download-data.js

curl -L --fail --output 'data/raw/metropt-3/metropt-3-dataset.zip' \
  'https://archive.ics.uci.edu/static/public/791/metropt%2B3%2Bdataset.zip'

printf '%s  %s\n' \
  'aab991a970e58210de853bb8078ce0e63abb4d9412fdc5c79792dae3d8e1721a' \
  'data/raw/metropt-3/metropt-3-dataset.zip' | sha256sum --check

unzip -j -o 'data/raw/metropt-3/metropt-3-dataset.zip' \
  'MetroPT3(AirCompressor).csv' -d 'data/raw/metropt-3'

그다음 스키마를 만들고 전체 CSV를 적재한 뒤 서버를 띄웁니다. 기존 텔레메트리가 있으면 importer가 덮어쓰기를 거부하며, 다시 적재하려면 --reset을 붙입니다.

../machbase-neo jsh scripts/ingest.js
../machbase-neo jsh app/server.js --host 127.0.0.1 --port 56802

브라우저에서 http://127.0.0.1:56802를 열면 됩니다. 다른 PC에서 접속하려면 --host 0.0.0.0으로 실행하고 방화벽에서 포트를 열어야 합니다. 적재 후에는 scripts/selftest.js로 텔레메트리 행 1,516,948개, 원본 시각 범위 2020-02-01 00:00:00~2020-09-01 03:59:50, 공식 공기 누출 구간 4개가 맞는지 확인할 수 있습니다. 데이터가 없을 때는 합성 데이터를 대신 보여 주지 않고 설치 안내를 표시한다는 점도 의도한 동작입니다.

마치며

Industrial AI에서 모델의 정확도만큼 중요한 것은 결과를 사람이 검증하고 설명할 수 있느냐입니다. 이 데모는 철도 APU의 시계열 데이터가 롤업 기반 조회, 규칙 기반 건전성 지표, 근거를 포함한 API를 거쳐 하나의 상태 진단 화면으로 이어지는 흐름을 보여 줍니다. 전체 소스는 GitHub(machbase/neo-train-apu-demo)에서, 시연 영상은 쇼케이스 페이지에서 확인할 수 있습니다. 데모나 파생 자료를 배포할 때는 MetroPT-3의 UCI 출처 표기를 유지해 주세요.


최근 게시물

전체 보기
공짜의 대가는 항상 뒤늦게 청구됩니다

정부는 공공정보화 사업에서 오픈소스 소프트웨어 도입을 장려합니다. 특정 벤더에 종속되지 말자, 라이선스 비용을 아끼자, 기술을 개방하자. 명분은 훌륭합니다. 하지만 명분이 훌륭하다고 해서 결과까지 훌륭한 것은 아닙니다. 라이선스가 무료라는 것은 비용이 없다는 뜻이 아닙니다. 비용은 사라지지 않습니다. 설치 비용, 통합 비용, 성능 검증 비용, 보안 패치 비

 
 
call
english
bottom of page