제6장
WIA-BIO-011 센서가 첫 교정에서 출발하여 일상 측정, 정도관리, 재교정을 거치는 과정과, 그 과정에서 참조 SDK가 강제하는 것과 강제하지 않는 것을 정리한다.
앞 장들에서는 바이오센서가 무엇을 측정하는지(제1장·제2장), 그 성능을 어떤 수치로 표현하는지(제3장), 그 수치를 어떤 레코드에 담는지(제4장), 그리고 어떤 SDK·CLI 호출이 그 레코드를 만드는지(제5장)를 다루었다. 이 장은 그 조각들을 시간 순서로 엮는다. 실험실 책임자나 기기 펌웨어 엔지니어가 평범한 근무일에 던지는 질문에 답하는 것이 목표이다. 센서는 지금 어떤 상태인가, 언제 다시 교정해야 하는가, 어떤 결과를 내보내도 되는가, 그리고 관리 시료가 허용 범위를 벗어나면 무엇을 해야 하는가.
먼저 출처를 밝혀 둔다. WIA-BIO-011 저장소에는 PHASE-3-PROTOCOL.md라는 파일이 있지만, 이 파일은 범용 템플릿 문서이다. 다른 표준의 식별자가 적혀 있고, 제목이 파일 이름과 맞지 않으며, 바이오센서 절차는 전혀 기술하지 않는다. 따라서 이 장은 그 파일을 사용하지 않는다. 여기서 제시하는 프로토콜은 표준 가운데 실제로 운영을 기술하는 부분에서 구성하였다. 곧 규격 §7(교정 절차, 교정 검증, 재교정 주기, 정도관리), §5.4와 §6.5–§6.9(온도 보상, 선택성, 응답 시간, 정확도, 정밀도, 안정성), README의 품질 보증(Quality Assurance) 목록, 그리고 참조 구현 BiosensorSDK의 상태·오류 동작이다. v1.0에 없는 상태 전이를 제안하거나 QC 규칙을 Westgard 방식 규칙에 대응시키는 것처럼 이 책이 출처를 넘어서는 곳에서는 본문에 "이 책의 권고"라고 표시한다.
제4장에서 정의한 Biosensor 레코드에는 status 필드가 있고, 허용되는 값은 active, calibrating, measuring, idle, error, expired의 여섯 가지이다. 상태 필드는 센서를 다루는 모든 프로그램이 그 값이 언제 바뀌는지에 합의할 때에만 쓸모가 있다. 타입 정의는 값을 나열할 뿐 상태 사이의 이동을 규정하지 않으므로, 실제 동작은 SDK 코드에서 읽어 내야 한다.
참조 SDK에서 실제로 대입되는 값은 여섯 가지 가운데 세 가지뿐이다. createSensor는 새 센서를 idle로 시작한다. calibrateSensor는 호출이 시작될 때 calibrating으로 바꾸고, 적합이 승인되면 idle로 되돌린다. measureAnalyte는 measuring으로 바꾸었다가 결과를 저장한 뒤 idle로 되돌린다. active, error, expired는 타입에만 존재하며, 이 값을 대입하는 코드 경로는 없다.
그 결과는 실패 경로에서 드러난다. 두 메서드의 모든 검사는 상태를 바꾼 뒤에 실행된다. 교정 점이 다섯 개보다 적거나(BIO010) R²가 0.99 미만이어서(BIO011) 교정이 거부되면, 예외가 발생한 뒤에도 센서는 calibrating에 머문다. 센서 만료(BIO007), 미교정(BIO003), 교정 유효기간 경과(BIO004)로 측정이 거부되면 센서는 measuring에 머문다. 그러면 status를 읽는 대시보드는 이미 예외로 끝난 작업을 센서가 아직 수행 중인 것처럼 보여 준다. 수명주기 한도 두 가지도 기록만 되고 실행되지 않는다. lifetime.maxMeasurements는 저장되지만 measurementCount와 비교되지 않으며, QC 불합격 결과는 센서 상태를 전혀 바꾸지 않는다.
수명(lifetime)이 만들어지는 방식에도 미묘한 점이 있다. createSensor는 biorecognitionElement 문자열에 oxidase나 ase가 포함될 때에만 기본 수명(180일, 측정 1,000회, "2-8°C, dry")을 붙인다. glucose-oxidase나 urease처럼 효소 이름으로 구성한 센서는 기본값을 받는다. 그러나 범용 열거값 enzyme으로 구성한 센서는 수명을 전혀 받지 못하며, 따라서 SDK 안에서는 영원히 만료되지 않는다. 구현자는 이 문자열 일치에 기대지 말고 제조사 자료에 근거하여 lifetime을 항상 명시적으로 설정해야 한다.
다음 상태 기계는 구현자를 위한 제안이다. types.ts에 이미 정의된 여섯 가지 상태값만 사용하므로, 이 방식으로 기록한 레코드도 유효한 v1.0 레코드이다. 핵심은 idle을 "결과를 내보낼 준비가 된 상태"로 정의하고, 센서를 쓸 수 없는 이유를 두 상태로 나누는 데 있다. error는 재교정으로 회복할 수 있는 상태이고, expired는 되돌릴 수 없는 종료 상태이다.
createSensor()
|
v
+---------> [idle] <------------------------------+
| | \ |
| 교정 승인 | \ 측정 (사전 점검 통과) | 결과 저장
| v \-----------> [measuring] -----+
| [calibrating] |
| | | BIO003 / BIO004
| 교정 거부 | v
| (BIO010/011)+-----------------> [error] <-- QC 불합격, 드리프트 경보
| |
+-------- 재교정 승인 -------------------+
모든 상태 --(lifetime.expirationDate 경과
또는 measurementCount >= maxMeasurements
또는 BIO007)--> [expired] (종료 상태: 센서 교체)
| 사건 | 이전 상태 | 다음 상태 (이 책의 권고) | v1.0 SDK 동작 |
|---|---|---|---|
| 센서 생성 | — | idle, 단 첫 교정 전까지 결과 출력 차단 | idle |
| 교정 승인 | calibrating | idle | idle |
| 교정 거부 (BIO002, BIO010, BIO011) | calibrating | error | calibrating에 머묾 |
| 교정 후 24시간 경과 | idle | error (타이머로 선제 전환) | 다음 측정 때에야 감지 (BIO004) |
| QC 불합격 | idle | 시정 조치 완료 전까지 error | 변화 없음 |
| 수명 날짜 경과 또는 측정 횟수 도달 | 모든 상태 | expired | 날짜는 측정 시에만 점검 (BIO007), 횟수는 점검하지 않음 |
| 측정 사전 점검 실패 | measuring | error 또는 expired | measuring에 머묾 |
실무에서는 SDK를 얇게 감싸는 래퍼로 이를 구현할 수 있다. 래퍼는 BiosensorError를 잡아 오류 코드마다 목표 상태를 정하고 그 상태를 다시 기록한다. 아래는 그 발상을 보여 주는 스케치이며, 표준의 일부는 아니다.
import { BiosensorSDK } from './index'; // api/typescript/src
import { BiosensorError, BiosensorErrorCode } from './types';
const TERMINAL = new Set(['BIO007']); // 센서 만료
const RECOVERABLE = new Set(['BIO002', 'BIO003', 'BIO004', 'BIO010', 'BIO011']);
function guarded<T>(sdk: BiosensorSDK, sensorId: string, op: () => T): T {
const sensor = sdk.getSensor(sensorId);
const lt = sensor.lifetime;
if (lt && sensor.measurementCount >= lt.maxMeasurements) {
sensor.status = 'expired'; // v1.0은 이 조건을 점검하지 않는다
throw new BiosensorError(BiosensorErrorCode.SENSOR_EXPIRED,
'Measurement budget exhausted');
}
try {
return op();
} catch (e) {
if (e instanceof BiosensorError) {
if (TERMINAL.has(e.code)) sensor.status = 'expired';
else if (RECOVERABLE.has(e.code)) sensor.status = 'error';
}
throw e;
}
}
규격 §7.1은 다점 교정의 최소 요건 네 가지를 정한다. 교정 점은 최소 다섯 개여야 하고, 분석 범위 전체를 포괄해야 하며, 블랭크(농도 0)를 포함해야 하고, 각 점을 이중으로 측정해야 한다. 이어서 표준 용액을 C1 = LOQ, C2 = 0.25 × Cmax, C3 = 0.5 × Cmax, C4 = 0.75 × Cmax, C5 = Cmax로 제시한다.
이 조항들을 함께 읽으면 필요한 농도는 다섯 개가 아니라 여섯 개이다. 곧 블랭크 하나와 0이 아닌 다섯 수준이다. SDK는 이를 다르게 세기 때문에 이 구분이 중요하다. calibrateSensor는 standardConcentrations 배열의 원소가 STANDARD_CALIBRATION_POINTS(5) 이상인지만 확인하며, 블랭크도 그 하나로 센다. 예컨대 0, 7.5, 15, 22.5, 30 mM로 이루어진 설계는 SDK 점검을 통과하지만 §7.1은 충족하지 못한다. 0이 아닌 수준이 넷뿐이고 LOQ에 해당하는 표준이 없기 때문이다. 이 책은 "블랭크 + 다섯 수준"을 규범적 설계로 보고, SDK 점검은 큰 실수만 걸러 내는 하한으로 취급한다.
LOQ 표준은 보고 가능 구간의 하단도 결정한다. SDK는 0이 아닌 가장 낮은 표준 농도를 linearRange.min으로 삼고, 그보다 낮은 결과에는 플래그를 붙인다. 따라서 가장 낮은 표준이 LOQ보다 한참 높으면 쓸 수 있는 범위 일부를 스스로 버리게 된다. 반대로 첫 표준을 실제 LOQ보다 낮게 두면 그 점 자체의 부정밀도가 하단 잔차를 지배할 수 있다.
| 수준 | §7.1 정의 | 예시: 포도당, Cmax = 30 mM | 목적 |
|---|---|---|---|
| 블랭크 | 농도 0 | 0 mM (완충액 또는 분석물이 없는 매질) | 절편, LOD 산출용 블랭크 표준편차 |
| C1 | LOQ | 0.061 mM (부록 A.1의 σ = 0.007 µA, S = 1.15 µA/mM에서 10σ/S) | 보고 가능한 최저값 |
| C2 | 0.25 × Cmax | 7.5 mM | 중하단 |
| C3 | 0.5 × Cmax | 15 mM | 중심, 직선이 가장 잘 결정되는 영역 |
| C4 | 0.75 × Cmax | 22.5 mM | 중상단, 곡률이 처음 나타나는 곳 |
| C5 | Cmax | 30 mM | 보고 가능 구간의 상한 |
§7.1이 요구하는 이중 측정은 실무적인 문제를 낳는다. SDK는 농도 하나당 신호 하나만 받기 때문이다. CalibrationPoint에는 replicates와 stdDev 필드가 있지만 calibrateSensor는 이를 채우지 않는다. 합리적인 방법은 두 가지이다. 첫째는 반복 측정값을 각각 별도의 점으로 넘기고 농도값을 반복하는 방법이다. 그러면 회귀는 여섯 점이 아니라 열두 점을 보게 되고, 잔차 표준편차의 자유도가 늘며, 반복 측정의 산포가 qualityControl.residuals에 드러난다. 둘째는 수준별 평균을 넘기고, 호출이 끝난 뒤 개별 반복값을 points[i].replicates에 저장하는 방법이다. 이 책은 주간 전체 교정에는 첫째 방법을, 속도가 중요한 일상 교정에는 둘째 방법을 권한다. 어느 쪽을 택하든 두 방법의 R²는 서로 비교할 수 없으므로, 어떤 방법을 썼는지 레코드에 남겨야 한다.
// 전체 교정: 블랭크 + 5수준, 이중 측정값을 별도의 점으로 전달
const standards = [0, 0, 0.061, 0.061, 7.5, 7.5, 15, 15, 22.5, 22.5, 30, 30];
const signals = readDuplicates(standards); // 판독기에서 읽은 값, µA
const cal = sdk.calibrateSensor({
sensorId: sensor.id,
standardConcentrations: standards,
measuredSignals: signals,
concentrationUnit: 'mM',
signalUnit: 'µA',
calibrationType: 'linear', // 이 값과 무관하게 SDK는 항상 직선을 적합한다
});
제1장의 효소 반응 속도론에서 나오는 설계상 주의점이 하나 있다. 포도당 산화효소 전극은 포화형 응답을 보이며, 그 겉보기 미카엘리스 상수는 막에 따라 달라진다. SDK 기본값 GOX_KM 33 mM를 가정하면 0–30 mM 구간은 선형이 아니며, 이 구간 전체를 덮는 설계는 다음 절의 승인 시험에서 불합격한다. 개발자는 Cmax를 정하기 전에 예비 자료로 선택한 범위가 응답 곡선의 선형 부분에 들어가는지 확인해야 한다.
규격 §7.2는 네 가지 승인 시험을 제시한다. 적합의 R²는 0.99를 넘어야 한다(목표 0.995). 잔차는 0을 중심으로 무작위로 분포하고 체계적 패턴이 없어야 한다. 반복 측정의 상대표준편차는 n ≥ 3에서 각 수준마다 5 % 미만이어야 한다. 첨가 시료의 회수율은 90–110 %여야 한다. SDK가 자동화하는 것은 첫째 시험뿐이며, 그나마 낮은 기준인 0.99만 적용한다. SDK는 잔차를 계산하여 maxResidual과 함께 저장하지만, R²가 통과하면 qualityControl.passed를 언제나 true로 설정한다. 나머지 세 시험은 운영자의 몫이다.
| 시험 (규격 조항) | 기준 | SDK 강제 여부 | 수행 방법 |
|---|---|---|---|
| 선형성 (§7.2.1) | R² > 0.99, 목표 > 0.995 | 예, 0.99만 (BIO011) | 자동. 0.995 미만이면 경고를 추가 |
| 잔차 패턴 (§7.2.1) | 0 주위의 무작위 분포, 추세 없음 | 아니요. 잔차만 저장 | qualityControl.residuals의 부호와 크기를 검토 |
| 정밀도 (§7.2.2) | 수준별 RSD < 5 %, n ≥ 3 | 아니요 | 각 수준 삼중 측정, 수준별 CV 계산 |
| 정확도 (§7.2.3) | 회수율 90–110 % | 아니요 | 새 교정으로 첨가 시료를 측정 |
§7.1은 이중 측정을, §7.2.2는 n ≥ 3을 요구한다는 점에 유의해야 한다. 이중 측정을 일상의 최소 요건으로 두고, 정밀도를 입증해야 할 때, 예컨대 주간 전체 교정과 밸리데이션(제8장)에서는 삼중 측정을 쓰면 두 조항은 서로 모순되지 않는다.
R²는 직선이 분산을 얼마나 설명하는지를 나타낼 뿐, 직선이 올바른 모델인지는 말해 주지 않는다. 교정은 R²를 여유 있게 통과하고도 범위 중간에서 수 퍼센트의 편향을 가질 수 있다. 다음 예는 설명을 위해 구성한 것이다. 확산 제한 막으로 겉보기 Km을 100 mM까지 높인 포도당 전극을 가정하고, 저농도 기울기를 1.15 µA/mM로 둔다. 0–30 mM의 일곱 표준이 잡음 없이 정확히 미카엘리스–멘텐 곡선을 따른다고 하자.
| 표준 (mM) | 신호 (µA) | 직선에 대한 잔차 (µA) | 역산 농도 (mM) | 오차 |
|---|---|---|---|---|
| 0 | 0.00 | −1.02 | −1.15 | — |
| 5 | 5.48 | +0.06 | 5.07 | +1.3 % |
| 10 | 10.45 | +0.62 | 10.71 | +7.1 % |
| 15 | 15.00 | +0.77 | 15.87 | +5.8 % |
| 20 | 19.17 | +0.53 | 20.60 | +3.0 % |
| 25 | 23.00 | −0.05 | 24.95 | −0.2 % |
| 30 | 26.54 | −0.91 | 28.96 | −3.5 % |
최소제곱 직선은 신호 = 1.015 + 0.8813 × C이고 R² ≈ 0.9943이다. 0.9943은 SDK의 한계 0.99보다 크므로 SDK는 이 교정을 승인한다. 그러나 이 교정을 거부해야 할 근거가 세 가지 있다. 첫째, R²가 규격의 목표값 0.995에 못 미친다. 둘째, 잔차가 양끝에서 음수, 가운데에서 양수인 아치 모양을 이룬다. 이것은 곡률의 전형적 흔적이며, 바로 §7.2.1이 금지하는 체계적 패턴이다. 셋째, 이 직선은 블랭크를 1 mM 넘게 잘못 놓고 10 mM를 약 7 % 과대 판독한다. 이는 §6.7의 정확도 목표 ±5 %를 벗어난다. 이 예는 절편을 눈여겨봐야 하는 이유도 보여 준다. 블랭크 전류가 작아야 할 전류법 센서에서 절편이 크게 양수로 나오면, 직선이 휘고 있다는 첫 신호인 경우가 많다.
이런 패턴이 나타나면 선호도 순으로 세 가지 처방이 있다. 잔차가 무작위가 될 때까지 Cmax를 줄인다. 센서 화학을 바꾸어(예컨대 확산 막을 두껍게 하여) 선형 영역을 넓힌다. 또는 비선형 모델로 옮긴다. 마지막 방법은 v1.0에서 처음부터 끝까지 지원되지 않는다. calibrateSensor는 항상 직선을 적합하고, measureAnalyte는 type이 linear가 아니면 BIO002를 던진다. 따라서 4PL이나 미카엘리스–멘텐 교정은 SDK 밖에서 적합하고 역산해야 하며, 레코드에는 해당 type 값을 넣어 저장한다.
규격 자체의 부록 A.2 자료(표준 0, 1, 5, 10, 50, 100 mM)에서는 다른 잔차 패턴이 나타난다. 다시 계산하면 기울기는 약 1.1585 µA/mM, 절편은 약 0.047 µA, R² ≈ 0.99999이고, 잔차는 약 +0.003, −0.006, +0.010, −0.133, +0.226, −0.100 µA이다. 아치 모양은 없지만 잔차의 크기가 농도와 함께 커진다. 이것은 곡률이 아니라 이분산성이며, 잡음이 전류에 비례하여 커지는 전류법 센서에서 흔하다. 이분산성이 교정을 무효로 만들지는 않는다. 다만 가중치 없는 적합에서는 높은 표준이 하단에 과도한 영향을 미친다. 통상의 해법은 가중 회귀(예컨대 1/x 또는 1/x² 가중)이다. SDK는 이를 제공하지 않으므로, 하단이 중요할 때에는 이것 역시 SDK 밖에서 수행해야 하는 단계가 된다.
측정 실행은 하나의 원신호를 보고 가능한 농도로 바꾸는 과정이다. 각 단계는 앞 단계가 끝났다는 전제 위에 서 있으므로 순서가 중요하다. 이 책은 측정 실행을 사전 점검, 신호 처리, 역산, 플래그 부여, 그리고 필요할 경우 희석의 다섯 단계로 나눈다.
신호를 받아들이기 전에 세 조건이 성립해야 한다. 센서가 수명 안에 있어야 하고, 교정이 유효해야 하며, 시료 온도가 관리되고 있어야 한다. SDK는 measureAnalyte 첫머리에서 앞의 두 조건을 점검한다. lifetime.expirationDate가 지났으면 BIO007을, 교정이 없으면 BIO003을, 교정이 validUntil(교정 후 24시간)을 넘겼으면 BIO004를 던진다. 6.1에서 보았듯이 측정 횟수 한도는 점검하지 않는다.
온도는 더 세심하게 다뤄야 한다. README의 품질 보증 목록은 효소 바이오센서의 온도를 ±1 °C 이내로 유지하라고 한다. 그런데 SDK는 시료 온도가 25 °C에서 10 °C 넘게 벗어날 때에만 temperature-out-of-range 플래그를 붙인다. 이것은 관리 한계가 아니라 명백한 이상값을 거르는 한계이다. ±1 °C의 실무적 의미는 SDK 기본 온도 계수 3 %/°C에서 나온다. 실제로는 26 °C인 시료를 25 °C로 기록하면 보정이 적용되지 않아 결과가 약 3 % 높게 나온다. 다른 오차를 세기도 전에 §6.7의 정확도 예산 ±5 % 가운데 절반 이상을 써 버리는 셈이다. 구현은 셀 온도를 ±1 °C로 관리하거나, 측정마다 실제 온도를 기록하여 보상이 적용되도록 해야 한다. 아울러 좁은 허용 구간을 벗어나면 자체 경고를 내야 한다.
SignalProcessingParams 타입은 네 가지 처리 단계를 예정한다. 기저선 보정, 온도 보정, 잡음 필터링(이동 평균, Savitzky–Golay, 저역 통과, 중앙값), 드리프트 보상(시간당 신호 변화율에 교정 후 경과 시간을 곱한 값)이다. 논리적인 순서도 이 나열과 같다. 기저선은 가산적이고 분석물과 무관하므로 가장 먼저 제거한다. 온도 보정은 곱셈적이며 분석물에 관련된 부분에만 작용해야 한다. 그다음 필터링으로 남은 신호를 매끄럽게 하고, 드리프트 보상으로 마지막 교정 이후의 느린 변화를 제거한다.
v1.0 SDK는 비공개 메서드 processSignal에서 처음 두 단계만 구현하며, measureAnalyte는 그 메서드에 온도만 넘긴다. 측정 과정 안에서 기저선은 한 번도 차감되지 않는다. 필터링과 드리프트 보상 필드는 타입에 선언만 되어 있고 무시된다. 따라서 판독기는 measureAnalyte를 호출하기 전에 스스로 기저선을 빼고 필터링을 적용해야 하며, 드리프트는 보정이 아니라 일정에 따른 재교정으로 다뤄야 한다.
온도 보상에는 규약을 명시할 필요도 있다. 제3장에서 보았듯이 규격 §5.4는 보상된 신호를 신호 × [1 + α(T − Tref)]로 쓰지만, SDK와 CLI는 같은 인자로 나눈다. 이 책은 SDK 규약을 따른다. 곧 α를 1 °C당 센서 응답의 상대 증가율로 정의하고, 측정 신호를 [1 + α(T − Tref)]로 나누어 25 °C 기준값으로 환산한다. 어떤 규약을 쓰든 보정을 재현할 수 있도록 제품은 α와 Tref를 교정과 함께 기록해야 한다.
보정된 신호 y가 있으면 SDK는 저장된 절편 a와 기울기 b로 농도 C = (y − a)/b를 계산한다. 다시 계산한 부록 A.2 직선을 쓰면 25 °C에서 23.5 µA의 신호는 C = (23.5 − 0.047)/1.1585 ≈ 20.2 mM가 된다. 규격에 20.3 mM로 적힌 것은 회귀 계수를 다르게 반올림했기 때문이다. 같은 23.5 µA를 26 °C에서 기록하면 먼저 1.03으로 나누어져 약 19.7 mM가 된다. 0.6 mM의 차이는 온도를 반드시 기록해야 하는 이유를 보여 준다.
이어서 SDK는 품질 플래그를 붙인다. 프로토콜에 영향을 주는 동작이 두 가지 있다. 첫째, 배열은 언제나 ok로 시작하고 경고는 이를 대체하지 않고 뒤에 덧붙는다. 그러므로 소비 측은 ok가 있는지가 아니라 ok 이외의 플래그가 있는지를 검사해야 한다. 둘째, 0이 아닌 가장 낮은 표준보다 낮은 결과는 실제 LOD보다 높더라도 below-lod로 표시된다. 결과 출력 판단을 위해 이 책은 다음 해석을 권한다.
| 역산 후 조건 | SDK 플래그 | 권장 보고 조치 |
|---|---|---|
| C < LOD | below-lod | LOD 값과 함께 "불검출(< LOD)"로 보고 |
| LOD ≤ C < LOQ | below-loq (가장 낮은 표준보다 낮으면 below-lod도) | "검출되었으나 LOQ 미만"으로 보고, 임상용 수치는 내지 않음 |
| LOQ ≤ C < 가장 낮은 표준 | below-lod (오해 소지) | 주석을 달아 보고하거나 교정 범위를 아래로 확장 |
| 교정 범위 안 | ok만 | 출력 |
| C > 가장 높은 표준 | above-range | 희석 후 재측정 (6.4.4) |
| |T − 25 °C| > 10 °C | temperature-out-of-range | 거부. 이 책은 효소 센서에 대해 관리 설정점 ±1 °C로 좁힐 것을 권함 |
드리프트, 잡음, 간섭에 대한 플래그는 QualityFlag 어휘에 있지만 SDK는 이를 붙이지 않는다. 구현이 이런 상황을 감지하면, 예컨대 QC 추세, 원신호 파형에서 임계값을 넘는 잡음, 외부 교정과 어긋나는 표준 첨가 결과를 발견하면, 레코드에 그 이유가 남도록 해당 플래그를 스스로 추가해야 한다.
above-range 플래그가 붙은 결과는 수치로 보고해서는 안 된다. 교정은 Cmax 위의 응답에 대해 아무것도 말해 주지 않고, 포화 때문에 외삽값은 낮게 읽히기 때문이다. 표준 절차는 시료를 교정용 희석액으로 알려진 배율 D만큼 희석하여 다시 측정하고 결과에 D를 곱하는 것이다. 희석한 결과 자체도 범위 안에, 가급적 가운데 3분의 1에 들어와야 한다. MeasurementRequest에는 희석 필드가 없으므로, 희석 배율은 원래의 범위 초과 측정에 대한 참조와 함께 sample.metadata에 기록한다. 희석은 매질도 바꾼다. 6.7의 회수율 점검이 필요한 이유 가운데 하나이다.
유효한 교정은 센서가 교정 시점에 정확했음을 보여 줄 뿐이다. 그 뒤로도 정확성이 유지되고 있음을 보여 주는 것이 정도관리이다. 규격 §7.4는 3수준 체계를 정의한다. 저농도 관리 시료는 LOQ 부근에, 중농도 관리 시료는 범위 중간에, 고농도 관리 시료는 범위 상단에 둔다. 모든 관리 시료에 두 가지 승인 기준이 적용된다. 결과는 목표값의 ±10 % 이내여야 하고, 해당 관리 물질의 과거 평균 ±2 SD 이내여야 한다. QualityControlSample 타입은 blank 수준도 허용하며, 이는 오염과 기저선 이동을 감지하는 데 유용하다. (README 목록은 이보다 짧아 블랭크·저·고 관리 시료만 언급한다. 이 책은 규격의 3수준 체계를 따르고 블랭크를 더한다.)
SDK 메서드 runQualityControl(sensorId, qcSample, measuredConcentration)는 스스로 측정하지 않는다. 호출자가 관리 시료를 일반 시료처럼 measureAnalyte로 측정하고, 그 농도를 넘긴다. 메서드는 세 가지 일을 한다. 값이 qcSample.acceptableRange 안에 있는지로 passed를 정한다. targetConcentration에 대한 백분율 편차 deviation을 계산한다. 과거 평균과 SD가 주어지면 zScore를 계산한다. 결과가 불합격이면 편차 크기에 따라 세 가지 시정 조치 가운데 하나를 붙인다. 20 % 초과이면 "Recalibrate sensor immediately", 10 % 초과이면 "Run additional QC sample to confirm", 그 밖에는 "Monitor next QC result"이다.
여기서 두 가지가 뒤따른다. z-점수는 계산되지만 passed 판정에는 관여하지 않으므로, §7.4의 ±2 SD 기준은 호출자가 이를 acceptableRange에 반영할 때에만 적용된다. 가장 간단한 방법은 아래 코드처럼 두 허용 구간의 교집합을 쓰는 것이다. 또 QC 측정은 measureAnalyte를 거치므로 measurementCount를 늘리고, getMeasurements에서 환자 결과나 현장 결과와 나란히 나타난다. sampleType을 qc-medium과 같은 값으로 지정하면 두 종류의 결과를 구분할 수 있다.
function qcRange(target: number, histMean: number, histSD: number) {
// 규격 §7.4: 목표값 ±10 % 이내 그리고 과거 평균 ±2 SD 이내
return {
min: Math.max(target * 0.90, histMean - 2 * histSD),
max: Math.min(target * 1.10, histMean + 2 * histSD),
};
}
const medium = {
level: 'medium' as const,
targetConcentration: 10.0, // mM, 예시용 관리 물질
historicalMean: 10.1,
historicalStdDev: 0.3,
acceptableRange: qcRange(10.0, 10.1, 0.3), // { min: 9.5, max: 10.7 }
lotNumber: 'QC-M-0425',
};
const m = sdk.measureAnalyte({ sensorId: sensor.id, signal: s, temperature: 25,
sampleType: 'qc-medium' });
const qc = sdk.runQualityControl(sensor.id, medium, m.concentration);
위의 예시 중농도 관리 시료(목표 10.0 mM, 과거 평균 10.1 mM, SD 0.3 mM, 결합 허용 구간 9.5–10.7 mM)로 다섯 결과를 판정하면 다음과 같다.
| 측정값 (mM) | 편차 | z-점수 | ±10 %만 적용 | §7.4 (두 기준 모두) | SDK 조치 문구 |
|---|---|---|---|---|---|
| 10.3 | +3 % | +0.67 | 합격 | 합격 | — |
| 9.5 | −5 % | −2.00 | 합격 | 합격 (경계값) | — |
| 10.8 | +8 % | +2.33 | 합격 | 불합격 | Monitor next QC result |
| 11.6 | +16 % | +5.00 | 불합격 | 불합격 | Run additional QC sample to confirm |
| 12.5 | +25 % | +8.00 | 불합격 | 불합격 | Recalibrate sensor immediately |
교훈을 주는 것은 10.8 mM 행이다. 이 결과는 해당 관리 물질의 과거 SD가 작기 때문에만 규격에 불합격한다. ±10 % 구간만 썼다면 SDK는 합격으로 판정했을 것이다. 결합 구간을 쓰면 SDK는 불합격을 보고하지만, 편차가 10 % 미만이므로 가장 약한 조치를 제안한다. 프로토콜은 이것을 재교정 사유가 아니라 두 번째 관리 시료를 요구하는 경고로 다뤄야 한다.
관리 시료 측정 (measureAnalyte, sampleType = 'qc-<수준>')
|
v
acceptableRange 안인가? (목표 ±10 % 그리고 과거 ±2 SD)
|-- 예 ----> 합격 기록, 추세 점검 (최근 4-10개가 한쪽에 몰렸나?)
| |-- 추세 없음 --> 환자/현장 측정 계속
| `-- 추세 있음 --> 'drift-detected' 표시, 재교정 예약
`-- 아니요 --> |편차| > 20 % ? -- 예 --> 상태 'error', 즉시 재교정,
| 모든 QC 수준 재실행
아니요
v
|편차| > 10 % ? -- 예 --> 결과 보류, 관리 시료 재측정
| (새 분주), 다시 불합격이면 재교정
아니요
v
±2 SD만 벗어남 --> 경고, 배치 출력 전
다른 수준 관리 시료 추가 측정
임상 검사실은 보통 Westgard와 결부된 다중 규칙 체계로 QC 승인을 표현한다. 잘 알려진 규칙은 12s(결과 하나가 2 SD를 벗어남, 경고), 13s(하나가 3 SD를 벗어남, 거부), 22s(연속 두 결과가 같은 쪽 2 SD를 벗어남, 거부), R4s(한 런 안의 범위가 4 SD 초과, 거부), 그리고 체계적 이동을 잡는 추세 규칙 41s와 10x̄이다. §7.4의 ±2 SD 기준은 12s 한계를 경고가 아니라 거부 규칙으로 적용한 것에 해당한다.
이 선택에는 쉽게 계산되는 비용이 따른다. 정규분포를 따르는 완벽하게 안정된 공정에서도 관리 시료 하나가 ±2 SD를 벗어날 확률은 약 4.6 %이다. 런마다 독립적인 관리 시료 세 수준을 측정하면, 그 가운데 적어도 하나가 벗어날 확률은 약 13 %가 된다. 아무 문제가 없는데도 대략 여덟 런에 한 번꼴로 거부된다는 뜻이다. 20–50개 시료마다 QC를 돌리는 기기라면 불필요한 재교정이 그만큼 많아진다. 흔히 쓰는 절충안이자 이 책이 권하는 방식은 ±2 SD를 경고 기준으로 두고 13s, 22s, R4s를 거부 규칙으로 쓰는 것이다. 목표값 ±10 % 구간은 절대 한계로 유지한다. SDK는 모든 QC 결과에 z-점수를 기록하므로, 데이터 모델을 바꾸지 않고도 저장된 QualityControlResult 레코드에서 이 규칙들을 평가할 수 있다.
규격 §7.3은 네 가지 시점을 나열한다. 최초 사용 전 초기 교정, 연속 사용 시 매일 일상 교정, 20–50개 시료마다 정도관리, 그리고 매주 또는 QC 불합격 시 전체 재교정이다. 규격은 "일상" 교정과 "전체" 교정이 어떻게 다른지 정의하지 않는다. 이 책은 이를 다음과 같이 해석한다. 일상 교정은 SDK 최소 요건과 §7.2.1 선형성 시험을 충족하고 이중 측정을 쓴다. 전체 교정은 §7.1 설계 전체를 삼중 측정으로 적용하고, 첨가 회수율을 포함한 §7.2의 승인 시험 네 가지를 모두 반복한다.
SDK는 이 일정의 한 부분을 코드에 고정해 두었다. 모든 교정은 생성 후 24시간이 지나면 만료되고, 그 뒤의 첫 측정은 BIO004로 거부된다. 무인 현장 센서처럼 매일 재교정할 수 없는 배치에서는 validUntil을 더 길게 잡은 자체 calibration 객체를 measureAnalyte에 넘겨야 한다. SDK 기본값에서 벗어난 이 결정은 기록해 두고 안정성 자료로 정당화해야 한다.
| 주기 | 활동 | 출처 | 생성 레코드 |
|---|---|---|---|
| 최초 사용 전 | 전체 교정(블랭크 + 5수준, 삼중 측정), 승인 시험 네 가지, 3수준 QC | §7.3, §7.1–§7.2 | CalibrationData, QualityControlResult ×3 |
| 매일 또는 근무조 시작 시 (연속 사용) | 일상 교정, 온도 점검, 블랭크 관리 시료 | §7.3, SDK 24시간 만료 | CalibrationData |
| 20–50개 시료마다 (배치) | 배치 앞뒤를 감싸는 저·중·고 관리 시료 | §7.3, §7.4 | BatchMeasurement.qualityControl |
| QC 불합격 시 | 배치 보류, 6.5.3 판정 흐름에 따름, 필요 시 재교정, 영향받은 시료 재측정 | §7.3 | 새 CalibrationData, 시정 조치 기록 |
| 매주 | 첨가 회수율을 포함한 전체 교정 | §7.3 | CalibrationData + 회수율 결과 |
| 안정성 연구의 각 시점 | 보관 센서의 감도와 QC | §6.9 (6.8 참조) | PerformanceMetrics.stability |
"배치 앞뒤를 감싼다"는 표현은 풀어서 설명할 가치가 있다. 배치 앞의 관리 시료는 배치를 시작할 때 센서가 관리 상태였음을 보여 준다. 배치 뒤의 관리 시료는 배치가 끝날 때에도 여전히 관리 상태였음을 보여 준다. 마지막 관리 시료가 불합격하면 마지막으로 합격한 관리 시료 이후의 모든 결과가 의심받는다. 그래서 20–50개라는 QC 간격은 불합격 뒤에 다시 측정해야 할 수 있는 결과의 최대 개수이기도 하다. 시료가 비싸거나 다시 얻을 수 없는 검사실은 하한 쪽을 택해야 한다.
연속혈당측정기(CGM)는 몸에서 꺼내 여섯 개의 표준 용액에 노출시킬 수 없다. 그래서 CGM 시스템은 공장에서 제조 로트별로 감도를 부여하는 방식으로 교정하거나, 사용 중에 모세혈관 채혈 측정값을 기준으로 1점 또는 소수점 재교정을 한다. 1점 재교정은 다른 매개변수를 안다고 가정하고 감도(또는 오프셋) 하나만 조정한다. 간질액 포도당은 혈중 포도당보다 늦게 따라가므로, 포도당이 빠르게 변하는 동안 얻은 기준값은 틀린 감도를 준다. 따라서 이 방식은 기준 측정의 시점에 크게 좌우된다.
이 모델은 v1.0 SDK와 맞지 않는다. calibrateSensor는 다섯 점 미만을 거부하고, 24시간 validUntil은 여러 날에 걸친 데이터 스트림을 멈춰 세운다. CGM 구현은 교정 논리를 기기나 동반 앱 안에 두고, 그 결과를 실제로 쓴 기준값을 points에 담은 CalibrationData 레코드로 저장하며, validUntil은 제조사의 교정 정책에 맞춰야 한다. CGM 데이터 흐름은 제7장에서 다시 다룬다.
제3장에서 보였듯이 부록 A.3의 선택성 자료를 농도로 정규화하면 감도비는 과당에 대해 약 39:1, 아스코르브산염에 대해 약 1.5:1, 요산염에 대해 약 4.9:1에 불과하다. 이는 §6.5의 목표인 100:1 초과에 크게 못 미친다. 운영 관점에서 이는 전류법 포도당 센서의 간섭이 이론상의 문제가 아니라는 뜻이다. 간섭은 화학, 프로토콜, 플래그로 관리해야 한다.
| 간섭 물질 또는 매질 요인 | 영향받는 센서 | 기전 | 운영상 대책 |
|---|---|---|---|
| 아스코르브산염, 요산염, 아세트아미노펜 | 높은 작업 전위(예: Ag/AgCl 대비 +0.6 V)의 전류법 산화효소 센서 | 전극에서 직접 산화되어 분석물과 무관한 전류를 더함 | 선택 투과성 막, 낮은 전위를 가능케 하는 매개체, 차감용 효소 없는 감시 전극 |
| 적혈구 용적률(헤마토크릿) | 전혈 스트립 센서 | 시료층의 혈장 부피 분율과 확산을 바꿈 | 측정기 내 적혈구 용적률 보정, 주장하는 적혈구 용적률 범위 제한, 밸리데이션 때 범위 전체에서 시험 |
| 산소 분압 | 1세대 산화효소 센서 | O₂가 공동 기질이므로 O₂가 부족하면 응답이 제한됨 | 매개체 또는 O₂ 비의존 설계, 시료 취급 관리 |
| pH | 효소 센서, 앱타머 센서 | 효소 활성과 앱타머 접힘이 pH에 의존 | 완충 희석액, MeasurementRequest에 pH 기록 |
| 이온 강도, 2가 양이온 | 앱타머·DNA 센서 | 접힘과 혼성화가 염 농도, 특히 Mg²⁺에 의존 | 매질을 맞춘 교정 물질, 고정된 완충액 조성 |
| 단백질, 지질 (오염 부착) | 혈청·혈액·폐수 속 대부분의 전극 | 흡착층이 시간에 따라 감도를 떨어뜨림 | 오염 방지 코팅, QC 추세 감시, 재교정 간격 단축 |
규격 §7.2.3은 회수율을 C측정/C첨가 × 100 %로 정의한다. 이 식은 분석물이 없는 매질에 첨가할 때 그대로 적용된다. 이미 분석물이 들어 있는 실제 시료에 첨가할 때에는 첨가 전 결과를 빼는 형태를 흔히 쓴다. 곧 회수율 = (C첨가 시료 − C원시료)/C첨가량 × 100 %이다. 90–110 %를 벗어나면 그 매질에서의 감도가 교정 물질에서의 감도와 다르다는 뜻이다.
매질 효과가 의심되면 표준 첨가법으로 시료 자체 안에서 감도를 측정한다. 시료 분취액에 알려진 양의 분석물을 더하고, 기저선을 보정한 신호를 첨가 농도에 대해 그린다. 원래 농도는 농도 축 절편의 크기(절편/기울기)이다. 다음 수치는 예시이며, 단순화를 위해 첨가에 따른 부피 변화는 무시한다.
첨가 포도당 (mM): 0 2 4
기저선 보정 신호 (µA): 6.20 8.36 10.52
표준 첨가 적합: 기울기 = 1.080 µA/mM, 절편 = 6.20 µA
시료 농도: 6.20 / 1.080 = 5.74 mM
외부 교정 (부록 A.2 재계산 값):
(6.20 - 0.047) / 1.1585 = 5.31 mM
매질 내 감도 / 교정 물질 내 감도 = 1.080 / 1.1585 = 0.93
=> 감도가 약 7 % 억제됨. 외부 교정 결과는 약 7 % 낮게 읽힘
이 예에서 외부 교정은 약 7 % 과소 판독한다. 이는 ±5 % 정확도 목표를 벗어나며, 회수율로는 약 93 %로 나타날 것이다. 프로토콜상 대응은 영향받은 결과에 interference-detected를 추가하고, 해당 시료 유형에 대해 매질을 맞춘 교정 물질로 바꾸거나, 매질 효과를 허용 한계 안으로 줄이는 희석 조건을 검증하는 것이다. 표준 첨가법은 손이 많이 가서 현장진단 기기의 일상 방법으로는 쓰지 않는다. 방법 개발 단계와 QC·회수율 불합격을 조사할 때 가장 유용하다.
README의 품질 보증 목록은 제조사 지침에 따라, 대개 2–8 °C에서 보관하고, 성능 저하를 감시하면서 유효기간을 관리하라고 한다(대개 3–12개월). 규격 §6.9도 같은 유효기간 범위를 제시하고, 운영 안정성 100–1,000회 측정과 장기 드리프트 월 5 % 미만이라는 두 목표를 덧붙인다. 이 수치들은 전형적인 설계 목표이다. 실제 제품의 유효기간은 그 제품의 안정성 자료가 뒷받침하는 만큼이다.
데이터 모델에는 결과를 담을 자리가 있다. PerformanceMetrics.stability는 shelfLife(일), operationalStability(측정 횟수), drift(월당 %)를 담는다. 안정성 연구는 이 세 값을 다음과 같이 산출한다. 최소 한 개 생산 로트의 센서를 표시된 조건에서 보관한다. 계획된 시점마다 일부를 교정하고 QC 물질을 측정한다. 감도 손실을 §6.9의 1차 감쇠 S(t) = S₀e−kt 같은 모델에 적합한다. 그런 다음 미리 정한 승인 한계에 도달하는 시간을 유효기간으로 정의한다. 체외진단 시약의 안정성 연구 설계에 관한 지침은 WIA 표준 밖에 있다. 예컨대 ISO 23640과 CLSI EP25가 있다. 이는 이 책의 추가 사항이며 WIA-BIO-011의 일부가 아니다.
| 경과 일수 | 감도 (µA/mM) | 0일 대비 손실 |
|---|---|---|
| 0 | 1.158 | — |
| 90 | 1.100 | 5.0 % |
이 두 예시 점에서 k = ln(1.158/1.100)/90 ≈ 5.7 × 10⁻⁴ /일이다. 그러면 반감기 ln2/k는 약 1,200일이고, 평균 드리프트는 월 약 1.7 %이다. 그렇다고 센서를 3년 동안 쓸 수 있다는 뜻은 아니다. 반감기는 신호의 50 %를 잃는 데 걸리는 시간이며, 재교정 없이 감도의 절반을 잃고도 ±5 % 정확도를 유지하는 정량 센서는 없다. 의미 있는 유효기간 기준은 "재교정 없이 감도가 초기값의 10 % 이내이고 모든 QC 수준이 합격"과 같은 한계이다. 적합한 k를 쓰면 10 % 손실에 이르는 시간은 ln(1/0.9)/k ≈ 185일이다. 이 예에서 유효기간은 3년이 아니라 약 6개월이다. 물론 두 점 적합은 설명용일 뿐이다. 실제 연구는 여러 시점과 둘 이상의 로트를 쓰고, 적합한 감쇠율의 신뢰구간을 보고한다.
운영 안정성은 별개의 측정이다. 센서가 QC에 불합격하기 전까지 몇 번 측정할 수 있는지, 또는 시료 속에서 얼마나 오래 작동할 수 있는지를 센다. 달력이 아니라 이 수치가 lifetime.maxMeasurements를 정해야 하며, 구현은 그 한도를 스스로 강제해야 한다(6.1). 고온 가속 연구로 초기 추정값을 얻을 수는 있다. 그러나 그 외삽은 아레니우스 거동을 따르는 단일 열화 기전을 가정하며, 단백질 기반 층에서는 이 가정이 자주 깨진다. 따라서 주장하는 유효기간은 보관 조건에서의 실시간 자료로 확인해야 한다.
WIA-BIO-011의 운영 프로토콜은 규격에서는 짧지만 실무에서 파급 효과가 크다. 아래 표는 이 장의 규칙을 구현자용 점검표로 모은 것이다. 셋째 열은 참조 SDK가 각 규칙을 강제하는지를 적었다. 답이 "아니요"인 곳마다 그 부담은 SDK를 감싸는 응용 프로그램이 진다.
| 규칙 | 출처 | v1.0 SDK 강제 여부 |
|---|---|---|
| 블랭크 + 0이 아닌 5수준, 첫 수준은 LOQ | §7.1 | 부분적 (블랭크 포함 배열 원소 5개 이상) |
| 각 수준 이중 측정, 정밀도 입증 시 n ≥ 3 | §7.1, §7.2.2 | 아니요 |
| R² > 0.99, 목표 0.995 | §7.2.1 | 0.99만 |
| 무작위 잔차 | §7.2.1 | 아니요 (잔차만 저장) |
| 회수율 90–110 % | §7.2.3 | 아니요 |
| 연속 사용 시 교정 유효기간 1일 | §7.3 | 예 (24시간 validUntil) |
| 온도 ±1 °C 관리 (효소 센서) | README 품질 보증 | 아니요 (±10 °C에서만 플래그) |
| 20–50개 시료마다 3수준 QC | §7.3, §7.4 | 일정 관리 없음, 결과별 판정만 |
| QC가 목표 ±10 %와 과거 ±2 SD 이내 | §7.4 | 호출자의 acceptableRange를 통해서만 |
| 매주 또는 QC 불합격 시 전체 재교정 | §7.3 | 아니요 |
| 수명과 측정 횟수 한도 준수 | §6.9, Biosensor.lifetime | 날짜는 측정 시에만, 횟수는 점검 안 함 |
| 센서 상태가 실패를 반영 | Biosensor.status | 아니요 (calibrating/measuring에 머묾) |
제7장은 이 절차들을 실제 제품으로 옮긴다. 혈당 측정기와 CGM, 면역분석 현장진단 검사, 측방유동 판독기, 현장 모니터에서는 교정과 QC 단계가 기기와 사용자의 제약에 맞춰져야 한다. 이어서 제8장은 이 프로토콜이 만든 증거가 어떻게 밸리데이션 파일과 적합성 주장이 되는지를 보인다.