← 전체 글
히스토리언/약 12분 읽기/ 조회

운전 이벤트를 가짜 analog tag로 저장하지 마라

히스토리언에서 calibration, manual 전환, bypass를 sampled stream과 분리된 event record로 남기고 asset ID와 시간 구간으로 다시 붙이는 방법. 21 CFR 11, Annex 11, OPC UA Part 11 기준.

히스토리언트렌드HMI문제 해결프로젝트 노트

14:07에 P-204 discharge pressure trend가 평평해진다. 20분 뒤에 다시 움직인다. 반년 뒤 그 구간을 여는 엔지니어는 설비가 섰던 건지 계기를 뽑았던 건지 알 방법이 없다. 실제로는 FT-1203 calibration이었고 output을 last good value로 hold했을 뿐이다.

이 공백을 메우는 게 annotation이다. 다만 붙이는 자리가 중요하다. Controller와 계기가 만드는 sampled stream은 고치지 않는다. HMI나 MES에서 사람이 만드는 event record는 따로 저장하고, 틀리면 덮어쓰지 말고 revision으로 고친다. 둘은 asset ID와 시간 구간을 키로 trend와 report에서 다시 만난다.

히스토리언에 들어가는 두 흐름. 위쪽은 Controller와 계기가 만드는 sampled stream이고 고치지 않는다. 아래쪽은 HMI와 MES가 만드는 event record이고 revision으로 수정한다. 두 흐름은 asset ID와 시간 구간을 키로 trend와 report에서 다시 만난다. 히스토리언에 들어가는 두 흐름 Controller / 계기 sampled stream HMI / MES event record trend / report asset ID + 시간 구간 고치지 않는다 revision으로 수정

Event를 sampled tag에 끼워 넣지 마라

"pump checked"는 압력 sample이 아니다. 그런데 현장에서 제일 흔한 구현이 string tag 하나 파서 운전자 메모를 그 tag의 값으로 밀어 넣는 것이다. 세 가지가 동시에 깨진다.

  • Compression이 메모를 먹는다. 히스토리언의 swinging door나 deadband 압축은 같은 값이 반복되면 버린다. 같은 문구를 두 번 쓴 운전자의 두 번째 입력은 저장되지 않는다.
  • 구간을 표현할 수 없다. Calibration은 09:00–09:35라는 시작과 끝이 있는 구간이다. Sample은 시점 하나뿐이다.
  • 검색이 안 된다. Tag value로 들어간 텍스트는 event query가 아니라 trend query로 뒤져야 한다.

정비 구간을 Boolean tag로 만드는 것도 같은 문제다. Controller가 실제로 그 bit를 만들지 않는다면, 그건 process 상태가 아니라 사람이 주장한 사실이다. 나중에 조사에서 이 둘은 완전히 다르게 취급된다.

Alarm도 여기 섞지 마라. Alarm record는 ISA-18.2(IEC 62682)가 정의하는 alarm system의 소유물이고, annotation으로 다시 복제하면 두 벌이 서로 어긋난다. Annotation은 alarm이 남기지 않는 것 — 왜 그렇게 했는가 — 만 담당한다.

Event record에 최소한 필요한 것

항목
Event time2026-06-26T14:07:32+09:00 — ISO 8601 offset 형식
Created time입력된 시각. Event time과 별도 컬럼
Asset referenceISA-95(IEC 62264-1) 계층의 안정된 ID. Site/Area2/P-204
Event typeManual mode, calibration, bypass, maintenance, quality hold
Start / end time구간이 있는 event만
SourceHMI user, maintenance system, PLC event, MES
Reason codePlanned maintenance, troubleshooting, product change
Free text짧고 구체적인 현장 메모
Related recordWork order, alarm id, batch id, lot id

Asset reference를 화면 이름으로 잡으면 3년 뒤 화면 개편 때 전부 끊긴다. HMI 표시명은 alias로 두고, 저장은 ISA-95 계층에서 나온 ID로 한다. 이건 나중에 고치기 가장 비싼 항목이다.

Timezone은 offset을 박아 두는 것으로 끝나지 않는다. 한국 site는 DST가 없으니 +09:00으로 고정이고 아무도 신경 쓰지 않는데, 같은 히스토리언이 유럽 라인 데이터를 받는 순간 터진다. Offset을 저장하되 IANA tz 이름(Asia/Seoul, Europe/Berlin)도 같이 남기면 나중에 교대 경계를 다시 계산할 수 있다.

Reason code와 자유 메모는 같이 간다

Free text만 있으면 검색이 안 되고, reason code만 있으면 "Planned maintenance" 스무 건이 똑같이 보인다. 둘 다 쓴다.

  • Type: Calibration
  • Reason: Scheduled PM
  • Asset: Site/Area2/FT-1203
  • Window: 09:00-09:35
  • Note: Transmitter 교체 후 loop check. Output은 last good value로 hold.
  • Work order: WO-78412

Reason list는 짧게 유지한다. 항목이 열 개를 넘어가면 운전자는 내용을 읽지 않고 첫 번째나 마지막 항목을 고른다. 그러면 데이터는 채워지는데 쓸모는 없다. 상세 분류가 정말 필요하면 그건 maintenance system이나 MES가 할 일이지 HMI 팝업이 할 일이 아니다.

Trend에 그리는 규칙

Annotation은 trend를 설명해야지 덮으면 안 된다.

Calibration, manual override, bypass, 통신 장애로 인한 bad data 구간은 interval marker로 그린다. Mode 전환, recipe 변경, lab result 수신은 point marker로 그린다. Event type과 asset으로 필터가 되어야 하고, trend 위에는 짧은 문구만 두고 전체 record는 클릭해서 들어가게 한다.

실패하는 화면은 대개 이렇다. Area 전체 log가 모든 trend에 뜬다. 긴 comment가 curve를 가린다. Pump에 붙인 note가 상위 unit report에 그대로 올라온다. 사람이 입력한 메모가 controller가 만든 event와 같은 모양으로 보인다. 마지막 것이 제일 나쁘다 — 조사 자리에서 근거의 등급이 달라진다.

Troubleshooting용 trend에서는 context를 한 번에 끄고 켤 수 있어야 한다. 항상 켜져 있으면 결국 아무도 안 본다.

Audit trail — 여기서 규제가 들어온다

GMP 라인이면 annotation은 그냥 메모가 아니라 전자기록이다. 21 CFR Part 11 §11.10(e)는 생성·수정·삭제를 기록하는 secure, computer-generated, time-stamped audit trail을 요구하고, 변경이 이전 기록을 가려서는 안 된다고 명시한다. EU GMP Annex 11 clause 9(Audit Trails)도 GMP 관련 변경과 삭제의 기록을 요구한다. Silent overwrite는 이 두 줄에 정면으로 걸린다.

그래서 최소 동작은 이렇게 된다.

  • 만든 사람 또는 import한 source system identity를 저장한다.
  • Created time과 event time을 따로 둔다. ALCOA+의 contemporaneous가 여기서 판정된다.
  • 수정은 revision으로 쌓고 원본을 남긴다.
  • 삭제·취소에도 사유를 남긴다.
  • Interval 생성·수정·종료 권한을 role로 나눈다.

OPC UA를 쓴다면 이 모델이 이미 규격에 있다. Part 11 Historical Access(OPC 10000-11)의 HistoryRead에서 ReadRawModifiedDetailsisReadModified를 켜면 HistoryModifiedData가 오고, 각 값에 ModificationInfo가 붙는다 — ModificationTime, UpdateType(Insert/Replace/Update/Remove), UserName. 직접 revision table을 설계하기 전에 쓰는 히스토리언이 이걸 노출하는지부터 확인해라.

사후 입력 자체는 문제가 아니다. 교대 끝나고 몰아서 쓰는 게 현실이다. 문제는 시스템이 그 사실을 숨기는 것이다. Created time이 event time과 같은 값으로 저장되는 순간 히스토리언은 실제보다 깨끗해 보이고, 그건 감사에서 데이터 무결성 지적으로 돌아온다.

자주 생기는 문제

증상원인고치는 방향
Calibration 중 trend가 평평한데 설명이 없음Output hold는 했지만 event marker가 없음Calibration interval을 work order와 함께 저장
Report가 downtime을 제외했는데 근거가 free text뿐구조화된 reason이나 related record 없음Event type + reason code + downtime record link
운전자가 note를 안 씀Form이 느리거나 사소한 조작에도 강제자동 event는 자동 수집, note는 필요한 곳만
Annotation 시각이 어긋남Local time / UTC / DST 처리 불일치Offset과 IANA tz 이름을 같이 저장, 교대 경계에서 시험
나중에 note를 못 찾음HMI·히스토리언·정비 시스템의 asset 이름이 서로 다름ISA-95 계층 ID로 저장하고 표시명은 alias

Annotation 프로젝트가 실패하는 이유는 text box가 없어서가 아니다. 시간, asset 식별자, 소유권, audit 동작을 정하지 않았기 때문이다.

시운전에서 실제로 해볼 것

  1. Loop를 10분 manual로 두고 auto로 복귀 — marker 두 개가 정확한 시각에 찍히는지.
  2. 수집이 도는 상태에서 transmitter calibration — hold 구간과 interval marker가 겹치는지.
  3. Bypass 투입·해제를 사유 입력과 함께.
  4. Event time보다 나중에 note를 추가하고, audit trail에 late entry로 보이는지.
  5. 같은 구간을 report에서 조회해 event가 보이거나 link되는지.
  6. Event 하나를 수정해 보고 이전 값이 남아 있는지 — 여기서 대부분의 제품이 걸린다.

6번이 통과 못 하면 앞의 다섯 개는 의미가 없다. 규격 문서에 "audit trail 지원"이라고 적혀 있어도 실제로 revision을 쌓는지, 그냥 마지막 값만 두고 로그 한 줄 남기는지는 직접 눌러 봐야 안다.