거짓말을 한 선
예전에 한 공장장이 야간 교대조 온도 트렌드를 보여주면서, 배치는 실패했는데 왜 공정은 이렇게 안정돼 보이냐고 물었다. 트렌드는 완만하게 기울어진 깨끗한 직선이었다. 그리고 그건 완전히 가짜였다. 02시 14분에 OPC UA 서버가 PLC 연결을 잃었고, 히스토리언은 마지막 good 샘플과 수집기 재접속 직후 샘플 사이의 네 시간 공백을 직선으로 채웠다. 공정이 안정된 게 아니라 히스토리언이 눈이 먼 것이었고, 기본 설정이 그 거짓말을 그대로 통과시켰다.
히스토리언 공백 처리의 핵심 문제가 여기 있다. 빠진 샘플은 그 자체로 정보다. 네트워크가 끊겼거나, 계측기가 fault났거나, 타임스탬프가 거부됐다는 뜻이다. 트렌드가 그 위를 이어 버리거나 리포트가 그 구간을 평균 내는 순간, 그 정보는 사라지고 믿음직해 보이지만 사실이 아닌 숫자가 자리를 대신한다.
태그가 리포트에 등장하기 전에 나는 딱 하나를 확인하고 싶다. 이 태그의 공백은 무슨 의미이고, 그걸 채우면 누가 손해를 보는가. 답은 태그마다 크게 다르다.
- 공정은 정상이고 네트워크만 끊김 — 채워도 대체로 괜찮다.
- PLC가 계측기 스캔을 멈춤 — 값을 알 수 없으니 지어내면 안 된다.
- 계측기 fault — 히스토리언은 유지된 숫자가 아니라 Bad 품질을 남겨야 한다.
- 타임스탬프가 너무 과거이거나 미래라 거부됨 — 샘플이 없는 데다 시계도 틀렸다. 시계부터 고쳐라.
이 결정을 태그별로, 미리 내려 두자. 리포트 코드 안에 묻어 두면 감사 때 다시 발견하게 되는데, 그때가 최악의 타이밍이다.
품질을 저장하지 않으면 소문을 저장하는 것이다
샘플은 숫자가 아니다. 숫자에, 그걸 믿어도 되는지 알려 주는 맥락이 붙은 것이다. 최소한 이 다섯 필드는 있어야 한다.
| 항목 | 필요한 이유 |
|---|---|
| 값 | 측정값 또는 계산값 |
| 소스 타임스탬프 | 컨트롤러가 그 값이 맞다고 본 시간 |
| 서버 타임스탬프 | 수집기가 실제로 값을 받은 시간 |
| 품질 | Good / Uncertain / Bad 와 구체적 하위 상태 |
| 수집 출처 | 어느 OPC UA 서버, MQTT 노드, PLC 드라이버, 수기 입력인지 |
품질 필드는 boolean이 아니다. 그걸 참/거짓으로 다루는 순간부터 대부분의 시스템이 어긋난다. OPC UA(스펙 Part 8)는 완전한 StatusCode를 준다. 상위 2비트가 Good / Uncertain / Bad를 가르지만, 진단은 하위 코드에 들어 있다. Bad_NoCommunication(0x80310000)은 통신 링크가 죽었다는 뜻으로 네트워크 문제다. Uncertain_LastUsableValue(0x40900000)는 서버가 오래된 걸 알면서 stale 샘플을 넘겨주고 있다는 뜻이다. Uncertain_SubstituteValue는 누군가 강제 입력했다는 뜻이다. 이 모두를 "bad" 하나로 뭉개면, 어디를 봐야 할지 알려 주던 바로 그 바이트를 버리는 셈이다. DNP3(IEEE 1815)도 플래그 옥텟으로 같은 일을 한다 — COMM_LOST, RESTART, REMOTE_FORCED, LOCAL_FORCED — 드라이버 단에서 버리지 말고 히스토리언 품질 모델로 매핑해 두는 편이 좋다.
문제 분석에서는 소스 타임스탬프와 품질이 값보다 훨씬 많은 걸 말해 준다. Good 품질의 평평한 온도선은 안정된 공정이다. Uncertain_LastUsableValue의 평평한 선은 죽은 PLC 링크다. 그림은 같고, 의미는 정반대다.
모든 태그에 같은 보간 규칙을 쓰는 건 사고다
가장 자주 보는 실수가 이거다. 누군가 히스토리언 기본 보간을 전역으로 "linear"에 놓고 그냥 넘어간다. 그러면 이산 펌프 운전 비트가 공백에서 반쪽 상태를 갖고, 적산값이 유령 직선 상승을 만들고, 알람 상태가 평균이 난다. 어느 것도 물리적으로 실재하지 않는다.
보간은 태그 성격을 따라가야 한다.
| 태그 종류 | 공백에서 해야 할 처리 |
|---|---|
| 연속 아날로그(느린 공정) | 짧은 공백에 한해 선형(sloped) 채움 허용 |
| 이산 상태 | 계단형 — 마지막 상태 유지, 반쪽 값 금지 |
| 카운터/적산값 | 롤오버를 고려한 delta 계산, 맹목적 선형 채움 금지 |
| 실험실/수기 샘플 | 기간 대표값이라는 업무 기준이 있을 때만 유지 |
| 알람/이벤트 | 이벤트 시간 보존, smoothing이나 평균 금지 |
| 계산 KPI | 입력 품질로 재계산, 입력 공백이 있으면 결과 품질 강등 |
OPC UA Historical Access(Part 11)는 실제로 이걸 모델링한다. 히스토리화된 변수마다 HA 설정에 Stepped 플래그가 있어서, history read가 기울기로 보간할지 마지막 값을 유지할지를 정한다. 이산 태그에 이걸 잘못 두면, 서버 자체가 interpolated read에서 지어낸 중간값을 넘겨준다. boolean 하나면 되는데 다들 그런 게 있다는 걸 잊는다.
그리고 화면 표시 규칙과 리포트 규칙을 따로 두자. 운전원 트렌드를 읽기 편하게 하는 30초 선형 채움은 괜찮다. 같은 채움이 환경 규제 리포트에 들어가면 규정 위반이 될 수도 있다. 두 규칙이니까 두 규칙으로 적어라.
채움을 제한하지 않으면 두 시간 장애가 직선이 된다
보간을 허용한다면 최대 공백 시간을 반드시 정해야 한다. 없으면 서두의 네 시간 장애가 깔끔한 직선 하나로 그려진다. 선형 채움에는 유효한 양끝점 두 개면 충분하기 때문이다.
내가 실제로 설정하는 값은 이렇다.
- 아날로그 온도: 운전 트렌드 가독성을 위해 30초까지만, 그 이상은 안 됨.
- 환경 보고용 pH: 아무것도 채우지 않음 — 구간을 invalid로 표시하고 리포트에 공백을 그대로 보여줌.
- 이산 운전 상태: 공백 동안 PLC 스캔과 이벤트 수집이 정상일 때만 다음 이벤트까지 유지.
- 유틸리티 미터: 주변 적산값으로 짧은 공백을 추정하되, 일일 리포트에 추정 표시를 찍어 계량값으로 오해하지 않게 함.
이 최댓값은 히스토리언 출하 기본값이 아니라 공정 동특성과 리포트 리스크에서 나와야 한다. 느린 열 루프는 초 단위로 흔들리는 유량보다 긴 채움을 견딘다.
bad quality를 놓칠 수 없게 만든다
운전원과 엔지니어는 원본 아카이브를 열지 않고도 품질 문제를 트렌드에서 봐야 한다. 트렌드가 bad quality 구간을 조용히 이어 버리면, 이후 모든 조사가 엔지니어링이 아니라 발굴 작업이 된다.
내게 타협 불가인 항목들.
- 품질이 Bad이고 채움 규칙이 없으면 선을 끊는다. 눈에 보이는 공백이 그럴듯한 거짓말보다 낫다.
- 추정/보간 구간은 점선으로 — 측정 데이터와 한눈에 구분되게.
- 커서 아래에 값뿐 아니라 품질 하위 코드와 소스 타임스탬프를 보여준다.
- 수집기 장애 구간을 배경 밴드로 그려서 장애 길이가 바로 보이게 한다.
- 내보내기에 값 과 품질을 같이 담는다. 품질을 떨어뜨린 내보내기는 좋은 데이터가 익명이 되는 곳이다.
리포트에는 평균이 아니라 품질 기준이 필요하다
있는 샘플을 그냥 평균 내는 리포트는 장애 구간까지 태연하게 평균 내서 뻔뻔한 숫자를 내놓는다. 모든 구간에 커버리지 규칙이 필요하다.
교대조 리포트라면 이렇게 쓴다.
- 생산 수량: 교대 시작과 종료 시점 카운터 품질이 둘 다 Good일 때만 인정.
- 평균 온도: Good 품질 커버리지 ≥95%, 아니면 partial 표시.
- 최대 압력: Good 품질 샘플만, 단일 장애가 60초를 넘으면 표시.
- 가동률: 상태 품질이 확인되는 구간의 state/event 데이터로만 계산.
- 에너지 사용량: 짧은 공백 추정은 허용하되 추정 방식을 리포트에 기록.
결과에는 숫자 바로 옆에 valid, partial, estimated, invalid 상태가 붙는다. 품질 결과 없는 숫자 하나는 "수율 0.3% 손실"이 운영 회의에서 두 시간짜리 논쟁으로 바뀌는 지점이다.
실제로 깨지는 네 가지 방식
마지막 값이 영원히 살아 있음. 수집기가 끊겼는데 대시보드는 마지막 Good 값을 계속 보여주고, 히스토리언이 아무것도 못 보는 동안 모든 게 평온해 보인다. 해결: 태그별 예상 업데이트 주기에 묶인 stale 판정. stale 제한을 넘으면 값을 Bad 또는 Uncertain으로 뒤집어라. 살아 있는 척 놔두지 말고.
셧다운 구간을 직선으로 채움. 계획 정지 중 온도가 내려갔는데 히스토리언이 마지막 운전값에서 재기동값까지 직선을 그리고, 리포트에는 있지도 않은 열 변화가 남는다. 해결: 설비 상태나 배치 단계로 보간을 게이트해서 셧다운 경계를 못 넘게 한다.
bad quality가 평균에 스며듦. 전형적인 경우다. 품질이 별도 컬럼에 있는데 리포트 쿼리가 그걸로 필터하는 걸 잊는다. 해결: 가동 전에 일부러 Bad 샘플을 넣어 리포트가 제외하거나 표시하는지 확인한다. bad 데이터로 시험하지 않았다면 bad 데이터에서 뭘 하는지 모르는 것이다.
증거를 지우는 수기 보정. 리포트를 완전해 보이게 하려고 누군가 수정하거나 backfill하면서 원래 Bad 품질 구간이 사라진다. 해결: 모든 수기 보정은 사유, 사용자, 시간, 원래 값, 대체 값, 결과 품질을 남긴다. 감사할 수 없는 보정은 그냥 UI만 예쁜 조작이다.
시운전 때 증명하라
일부러 깨뜨려 보기 전까지는 아무것도 믿지 마라. 리포트를 신뢰하기 전에.
- 수집기를 뽑거나 PLC 경로를 잠시 막는다 — 트렌드가 깔끔한 선이 아니라 규칙대로 공백 또는 추정 구간을 보여주는지 확인.
- 드라이버가 되면 계측기 fault 품질을 강제한다 — 리포트가 그 구간을 제외/표시하는지 확인.
- 과거 소스 타임스탬프의 late 데이터를 backfill한다 — 도착 시간이 아니라 올바른 시간에 저장하는지 확인.
- 모의 장애 중 이산 상태를 토글한다 — 시스템이 이벤트 시간을 지어내지 않는지 확인.
- 트렌드를 내보내 품질과 타임스탬프가 같이 나오는지 확인.
- 커버리지를 기준 미만으로 만든 뒤 교대조 리포트가
partial또는invalid로 돌아오는지 확인.
규칙은 리포트 코드가 아니라 태그 옆에 둔다
마지막으로 고집하는 것. 보간과 품질 규칙을 리포트 계층 안에만 묻어 두지 마라. 태그를 관리하는 엔지니어에게는 보이지 않는다. 스캔 주기, 단위, 데드밴드, 보존 기간이 이미 사는 곳 — 태그나 설비 정의 — 에 같이 둬라.
- 예상 업데이트 주기
- stale 제한 시간
- 공백 채움 방식
- 최대 채움 시간
- 리포트 커버리지 요구값
- 추정 데이터 허용 여부
- 수기 보정 승인 필요 여부
나중에 다른 엔지니어가 태그만 보고도 트렌드가 왜 끊겼는지, 리포트가 왜 partial인지, 그 채워진 값을 믿어도 되는지 말할 수 있다면 제대로 한 것이다. 새벽 2시에 리포트 쿼리를 역공학해서 알아내야 한다면, 그러지 못한 것이다.