ORBIT · 승강기 PHM

진단 방법론

무엇을 어떻게 판단하는지, 그리고 그 판단을 무엇으로 뒷받침했는지.

이 문서의 원칙

여기 적힌 값은 모두 실제로 측정한 것입니다. 관례나 통념으로 정한 것은 그렇다고 밝혔습니다. 우리가 틀렸던 것도 함께 적었습니다 — 같은 함정을 다시 밟지 않기 위해서입니다.

1전체 구조

계산은 현장에서 하고, 판단 기준은 중앙에서 정합니다.

센서 ─▶ 게이트웨이(진단) ─▶ ThingsBoard ─▶ 사람 │ │ │ 판정만 82 B │ 기준선·임계·베어링 제원 └────────◀───────────┘

원파형은 서버로 가지 않습니다. 1초 분량이 100 KB인데 판정 결과는 82 B입니다. 약 1,250배 차이라, 2,756대 규모에서 하루 95 GB가 0.9 GB가 됩니다. 규모가 커지면 이 방법 말고는 감당할 수가 없습니다.

계층을 반드시 함께 올립니다

판정에는 diag_tier가 함께 붙습니다. 어디까지 계산해서 나온 결론인지를 알려 줍니다.

계층볼 수 있는 것필요한 것
MCU시간 영역만 봅니다 — 이미 진행된 불평형·과부하없음(정수 연산)
게이트웨이포락 분석과 이상탐지 — 베어링 결함까지numpy·scipy·sklearn 196 MB
서버설비끼리 비교, 추세 보기
왜 계층이 필요한가

시간영역만 보는 장치가 "정상"을 올리면 화면에 초록불이 켜집니다. 그런데 그 장치는 애초에 베어링 결함을 볼 수 없습니다. 못 본 것과 없는 것은 다릅니다. 일반 사용자 화면에서는 이걸 "간이 감시 / 정밀 감시"로 옮겨 보여 줍니다.

2진단 — 원인을 지목하는 방법

베어링이 상하면 일정한 간격으로 충격이 생깁니다. 그 간격이 뚜렷할 때만 어디가 상했는지 말합니다.

파형 ─▶ 대역통과 ─▶ 포락(Hilbert) ─▶ 스펙트럼 ─▶ 결함주파수 성분 비교 ─▶ 판정

베어링 치수(볼 개수·볼 지름·피치 지름)로 회전마다 나타날 충격 간격을 계산하고, 포락 스펙트럼에서 그 간격의 성분이 얼마나 큰지 봅니다. 가장 큰 성분이 차순위보다 4배 이상 뚜렷할 때만 부위를 지목합니다.

근거가 모자라면 말하지 않습니다

임계를 못 넘으면 diag_part를 비웁니다. 빈칸이 틀린 답보다 낫습니다. 대신 diag_route에 "BPFO 최대이나 차순위 대비 1.6배 — 부위를 지목하지 않음"처럼 이유를 남겨 사람이 검증할 수 있게 합니다.

베어링 치수를 모르면 이 단계 전체가 소용없습니다. 치수가 틀리면 찾아야 할 주파수가 틀리고, 결국 엉뚱한 곳을 보게 됩니다. 그래서 현장 세팅에서 제원 입력을 사람 손에 맡기지 않고 템플릿이 자동으로 내려보냅니다.

3이상탐지 — 기준선 대비 얼마나 벗어났는가

원인을 몰라도 "평소와 다르다"는 말할 수 있습니다. 기준선과 얼마나 떨어졌는지로 봅니다.

여러 알고리즘의 합의로 봅니다

서로 다른 원리의 탐지기 8종(마할라노비스·kNN·LOF·PCA 재구성·오토인코더· IsolationForest·OneClassSVM·최대 z)이 각자 판정하고, 몇 종이 동의했는지를 봅니다. 한 알고리즘이 가진 버릇에 끌려가지 않기 위해서입니다.

실측 · Paderborn 베어링

오탐률을 맞추고 비교한 탐지율입니다.

방식오탐탐지
8종 합의5%100%
마할라노비스 단독10%100%
kNN 단독10%100%
PCA 재구성10%97%
오토인코더10%40%

ECOD·Extended IsolationForest는 측정 후 기각했습니다. 표준 IsolationForest보다 분리가 나빴습니다.

센서를 많이 붙인다고 좋아지지 않습니다 — 다만 조건이 있습니다

실측 ① 반응하는 채널이 하나뿐일 때
구성σ 중앙값3σ 넘긴 탐지기
반응하는 채널 1개9.57/8
반응하는 채널 4개8.18/8
+ 무관한 채널 3개2.73/8
+ 무관한 채널 19개1.72/8
여기서 우리가 한 번 지나쳤습니다

위 결과를 보고 "쓸모없는 채널 3개면 무너진다"고 적었는데, 그건 반응하는 채널이 하나뿐인 취약한 조건에서 잰 값이었습니다. 실제 진동 특징량으로 다시 재니 달랐습니다.

구성채널오탐탐지
실제 특징량만910%55%
+ 무관한 잡음 3개1210%55%
+ 무관한 잡음 9개1810%38%

무관한 채널이 해로운 것은 맞지만 비율의 문제입니다. 쓸 만한 특징량이 충분하면 몇 개 섞여도 견딥니다.

실측 ② 같은 신호에서 나온 특징량은 빼면 손해입니다
채널 묶음채널오탐탐지
전부 넣기910%75%
베어링 관련만 골라 넣기410%55%

첨도처럼 그 자체로는 거의 안 움직이는 값도 빼면 손해입니다. 같은 신호에서 나온 값들은 서로 연관돼 있고, 마할라노비스는 그 연관 구조에서 정보를 얻기 때문입니다. "평소엔 같이 움직이던 둘이 따로 논다"가 신호가 됩니다.

정리하면 설비에서 나온 값은 다 넣고, 설비와 무관한 값만 뺍니다. 그리고 아예 변하지 않는 채널은 반드시 뺍니다 — 정보가 없을 뿐 아니라 표준편차가 0이라 나눗셈이 깨집니다.

기준선은 증명할 수 없습니다

우리가 네 번 확인한 것

"그 구간이 정상이었다"는 데이터로 증명할 수 없습니다. 처음부터 나빴을 수도 있기 때문입니다. 그래서 화면에 기준선 구간을 함께 적고, 정비 이력이 있으면 그쪽을 우선합니다. 기준선이 바뀌면 baseline_status도 함께 올려 이전 판정과 섞이지 않게 합니다.

4잔여수명 — 왜 조심하는가

보이지 않는 것은 예측할 수 없습니다. 이게 전부입니다.

실측 · FEMTO / XJTU

같은 데이터에 순수 ML·통계 추세·물리 제약을 같은 조건으로 걸었습니다.

조건ML물리 제약
관측 가능 (시간–건강지표 상관 ρ>0.3)199%99%
관측 불가~200%~200%
XJTU (RMS가 수명 93~97%까지 평평)오차 104~107%

물리 제약은 관측 가능할 때만 2배 개선입니다. 급작스러운 고장에는 어떤 방법도 소용없습니다. 막히는 곳은 모델 성능이 아니라 애초에 신호에 드러나느냐입니다.

그래서 잔여수명은 켜고 끄는 기능이 아닙니다. 신호에 드러나는지 먼저 확인하고, 통과한 설비에만 붙입니다.

5엣지 배치

현장은 계산하고, 중앙은 기준을 정합니다.

방향무엇이어떻게
서버 → 엣지기준선·임계·베어링 제원·보고 주기·모델TB 공유 속성
엣지 → 서버판정 결과 14키TB 텔레메트리

ThingsBoard Edge를 쓰지 않는 이유

실측
방식현장에 올라가는 것하루 전송
우리 게이트웨이196 MB1.4 MB
ThingsBoard Edge약 4.5 GB동일

TB Edge의 핵심 가치는 통신 두절 시 버퍼링인데, 우리가 버퍼링할 양은 24시간에 1.4 MB입니다 — 파일 하나면 됩니다. 그리고 TB Edge는 자바 룰엔진이라 포락 분석과 이상탐지를 대신해 주지 못합니다.

통신이 끊긴 동안 현장에서 제어·차단이 필요하거나 역무실에 자체 화면이 필요해지면, 그때는 TB Edge가 맞습니다. 계약이 그대로라 서버 쪽은 바꿀 것이 없습니다.

원파형은 이상이 잡힌 자리에서만 남깁니다

진단(베어링 결함 주파수·포락·사이드밴드)은 원파형이 있어야 합니다. 판정 14키로는 “이상하다”까지만 말할 수 있고 “왜”는 말하지 못합니다. 그렇다고 원파형을 계속 쌓을 수는 없습니다.

실측 · 1초 @ 12.8 kHz
방식한 조각하루 100건1년
계속 저장50 KB/초4.3 GB/일1.6 TB
float32 조각50.0 KB4.9 MB1.74 GB
int16 조각25.0 KB2.4 MB0.87 GB

gzip 은 쓰지 않습니다 — 진동 잡음은 압축이 되지 않아 25 KB 그대로였습니다. 재 보고 뺐습니다.

그래서 이상으로 판정된 순간의 1초짜리 조각만 남깁니다. 엣지가 이미 그 시점을 알고 있으므로, 판정을 올릴 때 조각을 함께 올리면 됩니다. 저장은 텔레메트리(ts_kv)가 아니라 우리 스키마에 둡니다 — TB 텔레메트리는 스칼라를 위한 자리라, 25 KB 문자열을 밀어 넣으면 하이퍼테이블이 부풀고 TB 화면이 그 값을 그리려다 멎습니다.

보존 상한을 반드시 겁니다

하루 100건이면 1년에 0.87 GB 지만, 500건이면 4.34 GB 입니다. 설비가 늘거나 임계가 헐거워지면 건수는 쉽게 늘어납니다. 건수·일수 상한을 걸고, 사람이 ‘맞음’ 이라 표시한 것은 상한에서 뺍니다 — 그게 나중에 다시 볼 유일한 자료이기 때문입니다.

보고는 상황에 따라 조절합니다

판정은 이미 82 B라 더 줄일 것이 없습니다. 남은 방법은 얼마나 자주 보내느냐뿐입니다. 정상이면 뜸하게, 이상하면 촘촘하게 보냅니다.

실측 · 24시간을 1분 간격으로
상황매번조절 시감소
하루 종일 정상1,44014410.0배
18시간 뒤 고장 시작1,4402396.0배
처음부터 고장 진행1,4409861.5배

문제가 있으면 절감이 줄어드는 것이 맞습니다 — 그때는 자료가 필요합니다.

두 가지를 반드시 지킵니다

6엣지 추론 모델

학습은 서버가 하고, 현장은 계산만 합니다.

기준선에서 마할라노비스 모델을 만들어 내려보냅니다. 학습할 때는 이상치에 흔들리지 않는 계산이 필요하지만, 판정할 때는 그 결과 값만 있으면 됩니다. 그래서 현장 장치에 학습용 라이브러리를 넣지 않아도 됩니다.

대상형식크기엣지에 필요한 것
게이트웨이JSON 파라미터3.0 KBnumpy 몇 줄
MCUemlearn C 헤더3.2 KBC99 · 동적할당 없음

MCU용 C는 GaussianMixture(성분 1개·완전공분산)으로 표현합니다 — 수학적으로 마할라노비스와 같습니다. 실측으로 확인했습니다: 점수 상관 0.9844 · 판정 일치 100%.

LiteRT를 쓰지 않는 이유

LiteRT는 신경망 전용입니다. 우리 8종 중 변환되는 것은 오토인코더 하나인데, 실측에서 탐지율 40%로 가장 나쁩니다. 기준선이 설비당 20~30점인데 신경망은 그 정도로 학습이 안 됩니다.

원파형에서 직접 학습하는 CNN이 필요해지거나, 여러 설비 자료를 모아 사전학습한 모델을 쓸 단계가 되면 그때가 맞습니다. 배포 통로는 그대로 두고 모델만 갈아 끼우면 됩니다.

7추가 학습

할 수 있습니다. 다만 저절로 돌아가게 두지는 않습니다.

마할라노비스는 충분통계만 있으면 옛 자료 없이도 정확히 갱신됩니다. 신경망처럼 전체 재학습이 필요 없습니다. 그런데 재봤더니, 계속 배우게 두면 고장을 늦게 찾습니다.

실측 · 천천히 나빠지는 경우
방식오탐발견까지
고정 (추가 학습 없음)1.8%62회
무조건 추가 학습0.8%124회
"정상일 때만" 학습0.8%130회
정상일 때만 + 경보 후 멈춤1.1%83회

"정상일 때만 배운다"는 안전해 보이지만 아닙니다. 고장 초기에는 아직 σ가 낮아 그 조건을 통과하고, 그때 배운 것이 이미 오염입니다. 모델이 고장을 따라가 버리면, 그 뒤로는 영영 이상해 보이지 않습니다. 그리고 베어링이 바로 천천히 나빠지는 쪽입니다.

그래서 이렇게 나눕니다.

8우리가 틀렸던 것

같은 실수를 되풀이하지 않으려고 적어 둡니다.

증상원인
진단 API가 조용히 모든 점수를 0으로 냄 특징량 키 목록을 vib_*로 고정해 둬서, 다른 키를 주면 전부 0벡터가 됐다
게이트웨이가 3키만 전송 추출 함수가 내는 키 이름을 추측해서 매핑했다. 실제 이름과 달라 전부 비었다
MCU용 C에 std = 0.000000f 회전수가 상수라 표준편차가 0이었다. C에서 0으로 나누면 그 결과가 화면에는 "이상"으로 보인다
같은 계획을 두 번 적용하니 화면이 두 벌 중복 방지를 에셋·디바이스에만 걸고 대시보드에는 안 걸었다
번역을 고쳤는데 화면은 그대로 번역 파일에 만료 캐시를 걸어 브라우저가 하루 동안 옛 파일을 썼다
고장을 주입해도 매번 보고가 나감 변화 판단을 비율로만 해서, 0.019와 0.022 같은 잡음이 15% 변화로 읽혔다