CH06첫 분석: 카페인 표준물
카페인 표준물을 주입해 첫 크로마토그램을 얻고, 적분과 피크 정보를 읽은 뒤 이동상 조성이 분리에 주는 영향을 실험합니다.
학습 목표#
- 카페인 원액(stock)을 조제하고 C₁V₁ = C₂V₂ 로 사용 표준용액의 희석량을 계산해, 시뮬레이터의 <b>편집 › 표준용액 조제</b> 에서 블랭크 · 표준물 바이알을 준비할 수 있습니다.
- 퍼지 → 평형 → 블랭크 주입 → 표준물 주입 순서의 시스템 준비 체크리스트를 따라 첫 크로마토그램을 얻고, <b>모드 › 데이터 분석</b> 에서 확대 · 커서로 머무름 시간과 높이를 읽을 수 있습니다.
- 자동 적분 결과 표의 tR · 면적 · 높이 · 면적% 를 읽고, 적분 파라미터(기울기 감도 · 피크 폭 · 면적 거부)와 베이스라인을 고쳤을 때 결과가 어떻게 바뀌는지 설명할 수 있습니다.
- 머무름 인자(k) · 선택성(α) · 분리도(Rs) · 이론단수(N) · 대칭도(T)를 정의하고, 메탄올 비율 20 · 30 · 40 % 에서 얻은 혼합 표준물 결과로 가장 알맞은 조성을 근거를 들어 고를 수 있습니다.
- Python 으로 크로마토그램 CSV 를 불러와 사다리꼴 적분으로 면적을 계산하고, 반복 주입의 상대표준편차(RSD) 와 k · α · Rs · N 을 구하는 함수를 만들 수 있습니다.
이론#
1교시 — 카페인 표준물 분석과 적분#
이 단원에서 할 일#
ch03 ~ ch05 에서 이동상 · 펌프 · 샘플러 · 컬럼 · 검출기를 맞추고, 메서드 PRAC_ISO_W70M30_v01(C18 · 물:메탄올 70:30 · 1 mL/min · 30 °C · 273 nm · 정지 시간 10 min)을 저장했습니다. 이번 차시에서 드디어 진짜 시료를 주입합니다. 이번 단원에서는 카페인 표준용액을 직접 만들고, 시스템 준비 체크리스트를 따라 블랭크와 표준물을 주입한 뒤, 데이터 분석 화면에서 피크를 읽고 적분 결과를 확인합니다. 마지막으로 Python 으로 같은 크로마토그램 CSV 를 불러와 면적을 직접 계산하고, 3회 반복 주입의 RSD 를 구합니다.
3D 장비 모델(assets/robot/robot.json)은 강좌 진행에 맞춰 추가됩니다. 차시 머리에 3D 뷰어 버튼이 보이지 않으면 아직 준비 중입니다. 이 차시는 대부분 데이터 분석 화면과 Playground 에서 진행합니다. 모델이 준비되면 주입 순간 샘플러 니들과 주입 밸브가 움직이는 모습을 3D 로 다시 확인해 봅니다.
표준용액 만들기 — 원액과 희석#
표준물(standard) 은 농도를 정확히 아는 분석물 용액입니다. 보통 두 단계로 만듭니다.
- 원액(stock solution): 순수한 분석물을 저울로 달아 부피 플라스크에 녹여 진한 용액을 만듭니다. 농도가 높아 무게 오차의 비율이 작습니다.
- 사용 표준(working standard): 원액을 피펫으로 덜어 부피 플라스크에서 묽혀, 검출기가 잘 재는 농도로 맞춥니다.
희석에는 녹아 있는 물질의 양은 그대로라는 관계를 씁니다.
C₁ · V₁ = C₂ · V₂ → V₁ = C₂ · V₂ / C₁
| 기호 | 뜻 | 이번 실습 값 |
|---|---|---|
| C₁ | 원액 농도 | 카페인 25.0 mg ÷ 25 mL = 1000 mg/L |
| V₁ | 덜어 낼 원액 부피 | 구할 값 |
| C₂ | 만들 용액 농도 | 50 mg/L |
| V₂ | 만들 용액 부피 (부피 플라스크) | 10 mL |
V₁ = 50 × 10 / 1000 = 0.500 mL 입니다. 원액 0.500 mL 를 10 mL 부피 플라스크에 넣고 이동상(물:메탄올 70:30) 으로 눈금까지 채웁니다.
- 단위를 맞춥니다. mg/L 와 µg/mL 는 같은 값입니다(1000 mg/L = 1000 µg/mL = 1 mg/mL). C₁ · C₂ 단위가 같고 V₁ · V₂ 단위가 같으면 공식이 그대로 맞습니다.
- 저울에 25.0 mg 이 아니라 25.3 mg 이 찍혔다면 억지로 맞추지 말고 실제 무게로 농도를 다시 계산합니다(25.3 mg ÷ 25 mL = 1012 mg/L). 사용 표준 농도도 이 값으로 다시 계산해 기록합니다.
- 사용 표준은 가능하면 이동상과 같은 용매로 묽힙니다. 시료 용매가 이동상보다 유기용매가 훨씬 많으면(예: 100 % 메탄올) 피크가 앞쪽으로 끌리거나 갈라집니다(오류 5번).
- 0.5 mL 보다 작은 부피를 덜어야 하면 오차가 커집니다. 그럴 때는 중간 희석 용액을 한 번 더 만듭니다.
실물 실험실에서 용액을 만들 때는 다음을 지킵니다(시뮬레이터에서도 같은 순서로 확인 창이 뜹니다).
- 메탄올은 인화성이며 마시거나 들이마시거나 피부로 흡수되면 독성이 있습니다. 후드 안에서 다루고, 불꽃 · 열원 가까이 두지 않습니다.
- 실험복 · 보안경 · 니트릴 장갑을 착용합니다. 카페인 · 테오필린 분말은 삼키면 해롭습니다 — 무게를 달 때 가루가 날리지 않게 합니다.
- 피펫은 입으로 빨지 않고 피펫 필러(보조기)를 씁니다.
- 남은 용액과 폐액은 실험실 규정에 따라 유기 폐액 통에 버립니다. 시약별 취급 주의는 각 시약의 물질안전보건자료(MSDS/SDS) 를 확인합니다.
시스템 준비 체크리스트#
주입 버튼을 누르기 전에 아래 순서를 위에서부터 하나씩 확인합니다. 하나를 건너뛰면 그 뒤 결과가 모두 의심스러워집니다.
| 순서 | 할 일 | 확인할 것 | 앞 차시 |
|---|---|---|---|
| ① 퍼지 | 오늘 처음 켰거나 용매를 바꿨으면 A · B 채널 퍼지 | 퍼지 밸브 닫힘, 로그 Purge valve closed | ch03 |
| ② 평형 | 메서드 조건(70:30, 1 mL/min, 30 °C)으로 10 컬럼 부피(약 16 min) 이상 흘림 | 압력 리플 작음 · 컬럼 30.0 °C · 베이스라인 안정 → Balance(<kbd>Z</kbd>) | ch04 |
| ③ 블랭크 주입 | 이동상만 든 바이알(위치 1)을 메서드 그대로 주입 | 카페인이 나올 자리(약 5.2 min)에 피크가 없음 · 큰 드리프트 없음 | ch05 |
| ④ 표준물 주입 | STD-CAF-50(위치 2)을 주입 | 피크 하나가 뚜렷이 · 압력 정상 · 로그에 경고 없음 | 이번 차시 |
- 블랭크를 먼저 주입하는 이유는 ch05 의 시퀀스 설계와 같습니다. 블랭크에서 보이는 피크는 시료와 상관없는 바탕이므로, 나중에 표준물 · 시료에서 그 자리를 빼고 봐야 합니다.
- 블랭크에도 t₀ 부근(약 1.6 min) 에 작은 위아래 출렁임이 보입니다. 주입한 용액과 이동상이 아주 조금 달라 생기는 용매 피크(주입 교란) 로, 정상입니다. 이 시간이 바로 머무르지 않는 성분이 컬럼을 지나는 시간 t₀ 입니다(2교시에서 씀).
따라하기 — 표준용액 준비와 첫 주입#
- <b>편집 › 표준용액 조제</b>를 고릅니다. 시약 목록에서
Caffeine, 부피 플라스크25 mL, 용매Water를 고르고 무게 달기를 누릅니다. 저울 값(예:25.3 mg)을 기록합니다. - 만들기를 누르면 원액
STOCK-CAF가 생기고, 창 아래에 실제 농도(예:1012 mg/L)가 표시됩니다. - 같은 창의 희석 탭에서 원액
STOCK-CAF, 만들 농도50mg/L, 플라스크10 mL, 용매이동상 A70/B30을 넣습니다. 계산을 누르면 덜어 낼 부피(V₁)가 나옵니다. 손으로 계산한 값과 같은지 확인한 뒤 만들기를 누릅니다 →STD-CAF-50. - <b>편집 › 바이알 준비</b>(ch04)에서 위치 1 에
BLANK(이동상), 위치 2 에STD-CAF-50을 놓습니다. 액량은 1.5 mL 로 둡니다. - 체크리스트 ① ~ ② 를 확인합니다. <b>모드 › 실행 모니터</b>(<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>R</kbd>) B 영역이 모두
● 준비됨이면 검출기 Balance(<kbd>Z</kbd>)를 누릅니다. - <b>Method › Open Method</b>(<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>O</kbd>)로
PRAC_ISO_W70M30_v01을 엽니다. - <b>Run › Single Run</b>(<kbd>F5</kbd>) → 위치
1, 시료 이름BLANK-1→ 시작. 10분 동안 C 영역 실시간 크로마토그램을 지켜봅니다(<kbd>Ctrl</kbd>+<kbd>]</kbd> 로 배속 가능). - 블랭크가 끝나면 다시 <kbd>F5</kbd> → 위치
2, 시료 이름STD-CAF-50→ 시작. 약 5분에 큰 피크 하나가 올라오는지 봅니다. - 같은 바이알을 두 번 더 주입합니다(<kbd>F5</kbd> 두 번, 시료 이름은 그대로). 시뮬레이터가 파일 이름 끝에
-01,-02,-03을 붙입니다. 반복 주입 결과는 실습 C 에서 씁니다.
3 ~ 9단계를 ch05 의 시퀀스로 짜도 됩니다. 1번 줄 BLANK-1(위치 1, 1회), 2번 줄 STD-CAF-50(위치 2, 주입 3회) 두 줄이면 됩니다. 시퀀스 이름은 SEQ_CAF 로 저장합니다.
데이터 분석 화면#
| 영역 | 하는 일 |
|---|---|
| A 데이터 목록 | 시퀀스 · 단일 주입 데이터 폴더와 파일. 더블클릭으로 열고, <kbd>Ctrl</kbd>+클릭으로 여러 개를 골라 겹쳐 봅니다. |
| B 크로마토그램 창 | 신호와 적분 결과(피크 시작 · 끝 표시, 베이스라인)를 그립니다. 마우스로 사각형을 끌면 그 부분이 확대됩니다. |
| C 커서 정보 | 커서가 가리키는 점의 시간 · 신호와, 기준점(<kbd>Shift</kbd>+클릭)에서 잰 차이(Δt · Δ신호) |
| D 적분 결과 표 | 피크마다 RT · Type · Width · Area · Height · Area% |
| E 적분 이벤트 | 적분 파라미터와 시간 이벤트(예: 0 ~ 2 min 적분 끄기) |
확대 · 커서로 머무름 시간과 높이 읽기#
- <b>모드 › 데이터 분석</b>(<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd>)을 고릅니다.
- A 영역에서
002-STD-CAF-50-01을 더블클릭합니다. 파일이 안 보이면 <b>파일 › 데이터 열기</b>(<kbd>Ctrl</kbd>+<kbd>O</kbd>)로 데이터 폴더를 고릅니다. - B 창에서 4.5 ~ 6 min, 0 ~ 180 mAU 를 감싸도록 마우스로 사각형을 끌어 확대합니다. 너무 확대했으면 <kbd>Backspace</kbd> 로 이전 확대로, <kbd>A</kbd> 로 전체 보기로 돌아갑니다.
- <kbd>C</kbd> 를 눌러 커서를 켜고 피크 근처를 클릭합니다. <kbd>P</kbd> 를 누르면 커서가 가장 가까운 피크 꼭대기로 갑니다.
- C 영역에서 시간 5.161 min, 신호 160.2 mAU 근처 값을 읽어 기록합니다. <kbd>←</kbd> <kbd>→</kbd> 로 한 점씩 옮기며 꼭대기가 맞는지 확인합니다.
- 피크 바로 앞 베이스라인(약 4.6 min)을 <kbd>Shift</kbd>+클릭해 기준점으로 잡고, 다시 꼭대기로 갑니다(<kbd>P</kbd>). C 영역의 Δ신호 가 베이스라인에서 잰 피크 높이입니다.
- 1.5 ~ 1.8 min 을 확대해 용매 피크(t₀)를 보고, 커서로 그 시간(약 1.62 min)을 기록합니다.
- 데이터 점은 2.5 Hz(0.4 s 간격, ch04 의 피크 폭
>0.1 min설정)로 찍혀 있습니다. 커서로 읽은 꼭대기 시간은 점 간격(약 0.007 min)만큼 결과 표의 RT 와 다를 수 있습니다. 결과 표는 꼭대기 근처 점들로 곡선을 맞춰 더 정밀한 값을 냅니다. - 높이를 커서 신호 값 그대로 읽으면 베이스라인이 0 이 아닐 때 그만큼 틀립니다. 그래서 기준점과의 차이(Δ신호) 로 읽습니다.
자동 적분 결과 표 읽기#
Integration › Auto Integrate(F8)를 누르면 B 창에 피크 시작 · 끝 표시와 베이스라인이 그려지고 D 표가 채워집니다. 이번 STD-CAF-50 첫 주입의 결과 예시입니다(적분 끄기 0 ~ 2 min 이벤트 적용 후).| # | RT [min] | Type | Width [min] | Area [mAU*s] | Height [mAU] | Area % |
|---|---|---|---|---|---|---|
| 1 | 3.102 | BB | 0.118 | 4.5 | 0.60 | 0.27 |
| 2 | 5.161 | BB | 0.161 | 1641.8 | 160.2 | 99.73 |
| 칸 | 뜻 | 읽는 법 |
|---|---|---|
| RT (머무름 시간, retention time) | 주입부터 피크 꼭대기까지 시간 | 무엇인지(정성) 를 알려 줌. 같은 조건이면 같은 물질은 같은 RT |
| Type | 피크 시작 · 끝이 어디에 붙었나. B = 베이스라인, V = 골짜기(valley, 옆 피크와의 골) | BB 는 앞뒤 모두 베이스라인 — 홀로 떨어진 깨끗한 피크 |
| Width | 피크 폭. 이 시뮬레이터는 반높이 폭(w½) 을 표시 | 2교시의 N · Rs 계산에 씀 |
| Area (면적) | 베이스라인 위 신호를 시간으로 적분한 값. 단위 mAU × s | 얼마나 들어 있는지(정량) 의 기본 값 (ch07 검량선) |
| Height (높이) | 베이스라인에서 꼭대기까지 | 피크가 좁고 대칭이면 면적 대신 쓰기도 함 |
| Area % | 그 피크 면적 ÷ 전체 피크 면적 합 × 100 | 순도 · 불순물 비율을 대략 볼 때만 |
면적% 99.73 은 "카페인이 99.73 % 들어 있다" 는 뜻이 아닙니다. 물질마다 273 nm 에서 빛을 흡수하는 정도(흡광계수)가 달라서, 같은 양이라도 면적이 다릅니다. 또 적분 파라미터를 바꿔 작은 피크가 빠지거나 들어오면 면적% 도 함께 바뀝니다. 농도를 구하려면 표준물로 만든 검량선이 필요합니다(ch07).
적분 파라미터와 베이스라인 수정#
자동 적분기는 신호의 기울기를 보고 피크 시작 · 꼭대기 · 끝을 찾습니다. E 영역(<b>Integration › Integration Events</b>, <kbd>Ctrl</kbd>+<kbd>E</kbd>)에서 그 기준을 바꿉니다.
| 파라미터 | 이 시뮬레이터에서의 뜻 | 값을 올리면 | 기본값 |
|---|---|---|---|
| 기울기 감도 (Slope Sensitivity) | 피크 시작 · 끝으로 볼 신호 기울기의 문턱값(mAU/min) | 둔감해져 작은 피크 · 노이즈를 덜 잡고, 피크 시작 · 끝이 안쪽으로 들어와 면적이 조금 줄어듦 | 1.0 |
| 피크 폭 (Peak Width) | 예상하는 가장 좁은 피크의 반높이 폭(min). 기울기를 계산하기 전 평활 정도를 정함 | 평활이 세져 노이즈에 강해지지만, 아주 좁은 피크를 놓치거나 둘을 하나로 봄 | 0.10 |
| 면적 거부 (Area Reject) | 이 값보다 면적이 작은 피크는 표에서 뺌(mAU*s) | 작은 피크가 표에서 사라짐 | 1.0 |
| 높이 거부 (Height Reject) | 이 값보다 낮은 피크는 표에서 뺌(mAU) | 낮은 피크가 표에서 사라짐 | 0.2 |
| 시간 이벤트 | 특정 시간 구간의 적분 끄기 · 켜기 등 | — | 0.00 Integration Off · 2.00 On |
- 파라미터를 바꾼 뒤에는 <kbd>F8</kbd> 로 다시 적분해야 표가 바뀝니다. 바꾼 값은 데이터가 아니라 처리 조건에 저장되어, 같은 시퀀스의 다른 파일에도 똑같이 적용할 수 있습니다(<b>Integration › Apply to All</b>).
- 피크 폭 파라미터는 ch04 의 검출기 피크 폭 설정과 이름은 같지만 다른 값입니다. 검출기 설정은 데이터를 기록할 때 쓰이고, 적분 파라미터는 기록된 데이터를 처리할 때 쓰입니다. 보통 같은 크기(0.1 min)로 맞춥니다.
- 실물 CDS(OpenLab CDS · ChemStation 등)도 비슷한 이름의 파라미터를 쓰지만, 단위 · 기본값 · 세부 동작은 소프트웨어와 버전마다 다릅니다. 실물에서는 그 소프트웨어 설명서를 확인합니다.
자동 적분이 이상하게 그은 베이스라인은 수동 적분으로 고칠 수 있습니다.
| 동작 | 메뉴 | 단축키 |
|---|---|---|
| 베이스라인 직접 긋기 | <b>Integration › Manual › Draw Baseline</b> → 피크 시작점에서 끝점까지 끌기 | <kbd>B</kbd> |
| 피크 지우기 | <b>Integration › Manual › Delete Peak</b> → 지울 피크 클릭 | <kbd>Del</kbd> |
| 수동 적분 모두 되돌리기 | <b>Integration › Manual › Undo All Manual</b> | — |
수동 적분한 피크는 결과 표 Type 칸에 MM(manual) 으로 표시되고, 누가 언제 고쳤는지가 기록(감사 추적, audit trail)에 남습니다. 먼저 적분 파라미터 · 이벤트를 고쳐 모든 파일에 같은 규칙이 적용되게 하고, 그래도 안 되는 파일만 수동으로 고친 뒤 그 이유를 실험 노트에 적습니다. 원하는 숫자가 나올 때까지 베이스라인을 옮기는 것은 데이터 조작입니다.
따라하기 — 파라미터를 바꿔 가며 다시 적분하기#
002-STD-CAF-50-01을 연 상태에서 <kbd>F8</kbd> 로 자동 적분합니다. 처음에는 E 영역 시간 이벤트가 비어 있어 1.66 min 의 용매 피크도 표에 들어옵니다. 피크 수(3개)와 면적% 를 기록합니다.- <kbd>Ctrl</kbd>+<kbd>E</kbd> 로 E 영역을 열고 시간 이벤트 표에
0.00 Integration Off,2.00 Integration On두 줄을 넣은 뒤 <kbd>F8</kbd> 을 누릅니다. 용매 피크가 빠지고 카페인 면적% 가 99.73 이 되는지 확인합니다. - 면적 거부를
10으로 올리고 <kbd>F8</kbd> → 3.10 min 의 작은 피크(면적 4.5)가 표에서 사라집니다. 카페인 면적은 그대로이고 면적% 만 100.00 으로 바뀌는 것을 확인합니다. - 면적 거부를
1.0으로 되돌리고 기울기 감도를20으로 올린 뒤 <kbd>F8</kbd> → 작은 피크가 사라지고 카페인 면적도 0.5 ~ 1 % 정도 줄어드는지 봅니다(피크 시작 · 끝이 안쪽으로 들어옴). - 기울기 감도를
1.0으로 되돌리고 다시 적분합니다. - 연습으로 카페인 피크를 <kbd>Del</kbd> 로 지웠다가 <kbd>B</kbd> 로 4.90 min 에서 5.46 min 까지 베이스라인을 직접 그어 봅니다. Type 이
MM으로 바뀌는지 확인한 뒤 <b>Integration › Manual › Undo All Manual</b> 로 되돌립니다. - <b>Integration › Apply to All</b> 로 같은 처리 조건을
-02,-03파일에도 적용하고 D 표의 RT · Area 를 기록합니다(실습 C). - <b>파일 › 그래프 내보내기 › CSV</b>(ch04)로
-01신호를002-STD-CAF-50-01.csv로 저장합니다(실습 B).
- 블랭크를 건너뛰고 표준물부터 주입합니다 → 피크가 표준물에서 왔는지, 이전 실험 잔류물인지 구별할 수 없습니다.
- 평형이 끝나기 전에 Balance 하고 주입합니다 → 베이스라인이 계속 올라가 피크 시작 · 끝이 틀어지고, 반복 주입마다 RT 가 조금씩 밀립니다(오류 4번).
- 원액(1000 mg/L) 바이알을 위치 2 에 잘못 놓습니다 → 피크 꼭대기가 평평하게 잘립니다(오류 3번).
- 파라미터를 파일마다 다르게 바꾸고 결과를 비교합니다 → 같은 처리 조건(Apply to All)으로 처리해야 비교가 공정합니다.
- 결과 표의 Width 를 바닥 폭으로 착각해 2교시 Rs · N 식에 넣습니다 → 값이 크게 틀립니다(오류 7번).
단축키 · 메뉴 정리#
| 동작 | 메뉴 | 단축키 |
|---|---|---|
| 표준용액 조제 창 | <b>편집 › 표준용액 조제</b> | — |
| 데이터 분석 화면 | <b>모드 › 데이터 분석</b> | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd> |
| 데이터 열기 | <b>파일 › 데이터 열기</b> | <kbd>Ctrl</kbd>+<kbd>O</kbd> |
| 확대 / 이전 확대 / 전체 보기 | 마우스 끌기 / — / — | 끌기 / <kbd>Backspace</kbd> / <kbd>A</kbd> |
| 커서 켜기 · 끄기 / 꼭대기로 | — | <kbd>C</kbd> / <kbd>P</kbd> |
| 커서 한 점 / 10점 이동 | — | <kbd>←</kbd> <kbd>→</kbd> / <kbd>Shift</kbd>+<kbd>←</kbd> <kbd>→</kbd> |
| 기준점 잡기 | — | <kbd>Shift</kbd>+클릭 |
| 여러 데이터 겹쳐 보기 | A 영역 <kbd>Ctrl</kbd>+클릭 | <kbd>O</kbd> |
| 자동 적분 | <b>Integration › Auto Integrate</b> | <kbd>F8</kbd> |
| 적분 이벤트 | <b>Integration › Integration Events</b> | <kbd>Ctrl</kbd>+<kbd>E</kbd> |
| 처리 조건을 모든 파일에 | <b>Integration › Apply to All</b> | — |
| 결과 표 저장 | <b>파일 › 결과 내보내기 › CSV</b> | — |
| 신호 저장 | <b>파일 › 그래프 내보내기 › CSV</b> | — |
단축키는 시뮬레이터 버전에 따라 바뀔 수 있습니다. <b>도움말 › 단축키 목록</b>(<kbd>?</kbd>)에서 항상 최신 목록을 확인합니다.
결과 확인#
- 블랭크(
001-BLANK-1-01)에는 1.6 min 부근 용매 피크 외에 5.2 min 부근 피크가 없습니다. - STD-CAF-50 의 카페인 피크는 **RT 약 5.16 min · 높이 약 160 mAU · 면적 약 1640 mAU*s · 반높이 폭 약 0.16 min** 이고 Type 은
BB입니다. - 3회 주입의 RT 는 서로 0.01 min 안쪽, 면적은 1 % 안쪽으로 비슷합니다(실습 C 에서 RSD 로 확인).
적분기는 어떻게 피크를 찾을까 — Python 으로 흉내 내기#
자동 적분기의 핵심은 "기울기가 문턱을 넘으면 피크 시작, 다시 문턱 아래로 내려와 한동안 조용하면 피크 끝" 입니다. 아래 코드는 이것을 아주 단순하게 흉내 냅니다. 기울기 감도 · 면적 거부를 바꾸면 결과 표가 어떻게 달라지는지 보세요.
import numpy as np
# 시뮬레이터 신호와 같은 모양: 2.5 Hz, 0 ~ 8 min
rng = np.random.default_rng(6)
t = np.arange(0, 8, 0.4 / 60) # min
y = 0.6 * np.exp(-0.5 * ((t - 3.10) / 0.05) ** 2) # 작은 불순물
y += 160 * np.exp(-0.5 * ((t - 5.16) / 0.068) ** 2) # 카페인
y += rng.normal(0, 0.01, t.size) # 노이즈
def integrate(t, y, slope_sens, area_reject, smooth=5):
ys = np.convolve(y, np.ones(smooth) / smooth, mode="same") # 평활 (피크 폭 파라미터 역할)
slope = np.gradient(ys, t) # 기울기 mAU/min
active = np.abs(slope) > slope_sens # 문턱을 넘는 점
peaks, i = [], 0
while i < t.size:
if active[i]:
j = i
while j < t.size and active[j:j + 10].any(): # 10점 동안 조용하면 끝
j += 1
seg = slice(i, min(j, t.size - 1) + 1)
tt, yy = t[seg], y[seg]
base = np.interp(tt, [tt[0], tt[-1]], [yy[0], yy[-1]]) # 시작 - 끝 직선 베이스라인
h = yy - base
area = float(np.sum((h[1:] + h[:-1]) / 2 * np.diff(tt))) * 60 # mAU*s
if area >= area_reject:
k = int(np.argmax(h))
peaks.append((round(float(tt[k]), 3), round(area, 1)))
i = j + 1
else:
i += 1
return peaks
for ss, ar in [(1.0, 1.0), (5.0, 1.0), (20.0, 1.0), (5.0, 10.0)]:
print(f"기울기 감도 {ss:5.1f}, 면적 거부 {ar:5.1f} -> {integrate(t, y, ss, ar)}")- 기울기 감도 1.0 에서는 작은 피크(3.09 min, 면적 약 4.5)와 카페인이 모두 잡힙니다.
- 5.0 으로 올리면 작은 피크의 시작 · 끝이 안쪽으로 들어와 면적이 2.6 으로 줄고, 20 에서는 아예 사라집니다. 카페인 면적도 1636 → 1625 로 약 0.7 % 줄어듭니다.
- 면적 거부 10 은 피크 찾기는 그대로 두고 표에서만 작은 피크를 뺍니다.
- 진짜 적분기는 이보다 훨씬 정교하지만(골짜기 · 어깨 피크 처리 등), "파라미터가 피크 시작 · 끝과 면적을 바꾼다" 는 원리는 같습니다.
2교시 — 이동상 조성이 분리에 주는 영향#
이 단원에서 할 일#
1교시에서는 카페인 하나만 들어 있는 표준물을 분석했습니다. 실제 시료(차 · 초콜릿 · 의약품)에는 카페인과 구조가 비슷한 테오브로민(theobromine) · 테오필린(theophylline) 이 함께 들어 있는 경우가 많습니다. 이번 단원에서는 세 물질을 섞은 혼합 표준물을 메탄올 비율 20 · 30 · 40 % 에서 분석하고, 분리를 숫자로 나타내는 k · α · Rs · N · T 를 계산해 어느 조성이 가장 알맞은지 근거를 들어 고릅니다.
크로마토그래피의 기본 숫자#
| 숫자 | 식 | 뜻 | 좋은 범위 (입문 기준) |
|---|---|---|---|
| 머무름 인자 k (retention factor) | k = (tR − t₀) / t₀ | 분석물이 이동상에 있는 시간보다 고정상에 붙어 있는 시간이 몇 배인가 | 대략 1 ~ 10. 너무 작으면 t₀ 근처 방해 성분과 겹치고, 너무 크면 분석이 길어지고 피크가 넓어짐 |
| 선택성 α (selectivity) | α = k₂ / k₁ (k₂ > k₁, 이웃한 두 피크) | 두 물질을 얼마나 다르게 붙잡는가 | 1 보다 커야 분리 가능. 1.0 이면 아무리 좋은 컬럼도 분리 못 함 |
| 분리도 Rs (resolution) | Rs = 2(tR₂ − tR₁) / (w₁ + w₂) = 1.18(tR₂ − tR₁) / (w½₁ + w½₂) | 두 피크 꼭대기 사이 거리를 피크 폭으로 나눈 값 | 1.5 이상 (기준선 분리) |
| 이론단수 N (plate number) | N = 16(tR / w)² = 5.54(tR / w½)² | 컬럼이 피크를 얼마나 좁게 유지하는가 | 같은 컬럼 · 조건에서 비교. 150 × 4.6 mm, 5 µm 이면 수천 ~ 1만 정도 |
| 대칭도 T (tailing factor) | T = W0.05 / (2f) | 5 % 높이에서 잰 폭 ÷ 앞쪽 반폭의 2배 | 1.0 대칭. 1 보다 크면 꼬리(tailing), 작으면 앞끌림(fronting) |
- t₀ (불감 시간, dead time) 는 머무르지 않는 성분이 나오는 시간입니다. 1교시에서 본 용매 피크 시간(약 1.62 min)을 씁니다. ch04 에서 계산한 컬럼 부피 V₀ ≈ 1.62 mL 를 유속 1 mL/min 으로 나눈 값과 같습니다.
- tR · t₀ · w 는 같은 단위(min)로 넣습니다. Rs · N · k · α · T 는 모두 단위가 없는 수입니다.
- Rs 식은 두 가지가 있습니다. 바닥 폭 w 는 피크 양쪽 변곡점에 그은 접선이 베이스라인과 만나는 폭이라 그리기가 번거롭기 때문에, 보통 결과 표의 반높이 폭 w½ 로 계산합니다(가우스 피크에서 w ≈ 1.70 w½ 이므로 2 ÷ 1.70 ≈ 1.18).
- 대칭도의 합격 기준(예: T ≤ 2.0)과 RSD 기준은 시스템 적합성으로 ch07 에서 정리합니다.
세 숫자는 분리도 식 하나로 묶입니다(퍼넬, Purnell 식).
Rs = (√N / 4) · ((α − 1) / α) · (k₂ / (1 + k₂))
- N(효율) 을 높이려면 더 긴 컬럼 · 더 작은 입자를 씁니다. 하지만 Rs 는 √N 에 비례하므로 N 을 4배로 해야 Rs 가 2배입니다.
- α(선택성) 가 Rs 에 가장 크게 듣습니다. α 가 1.05 → 1.10 이면 (α−1)/α 가 거의 2배가 됩니다. α 는 이동상 · 고정상의 종류와 조성으로 바뀝니다.
- k(머무름) 는 1 근처까지는 Rs 를 빨리 키우지만, 5 를 넘으면 k₂/(1+k₂) 가 0.83 → 0.9 정도로 거의 늘지 않고 시간만 길어집니다.
메탄올 비율과 머무름 — log k 의 직선 관계#
역상(reversed-phase) 크로마토그래피에서 이동상의 유기용매(메탄올)가 많아지면 이동상이 분석물을 더 잘 녹여, 분석물이 C18 고정상에서 더 빨리 떨어져 나옵니다. 그래서 메탄올 비율 φ(0 ~ 1)가 커질수록 k 가 작아지고, 꽤 넓은 범위에서 다음 관계가 대략 성립합니다.
log k ≈ log kw − S · φ
- kw 는 메탄올 0 %(물만) 일 때로 외삽한 k, S 는 직선의 기울기로 물질마다 다릅니다. 작은 분자는 대략 S 가 3 ~ 5 정도입니다.
- 경험 규칙: 유기용매 10 %p 를 늘리면 k 가 약 2 ~ 3배 줄어듭니다. 이 차시의 카페인은 S ≈ 3.5 라 10 %p 마다 k 가 약 2.2배 바뀝니다.
- 물질마다 S 가 다르기 때문에 조성을 바꾸면 k 만이 아니라 α 도 바뀝니다. 이번 혼합물은 메탄올이 많아질수록 테오필린 · 카페인의 α 가 1 에 가까워져 두 피크가 겹칩니다.
- 이 관계는 대략적인 직선이며 범위가 넓어지면 휘어집니다. 세 점으로 직선을 맞춰 그 사이를 짐작하는 데만 쓰고, 예측한 조건은 반드시 실제로 주입해 확인합니다. 조건을 체계적으로 찾는 방법은 ch08 에서 다룹니다.
세 물질은 모두 크산틴(xanthine) 골격에 메틸기가 붙은 분자입니다. 메틸기가 2개인 테오브로민 · 테오필린보다 3개인 카페인이 덜 극성이라 C18 에 더 오래 붙어 있어, 이 조건에서는 테오브로민 → 테오필린 → 카페인 순서로 나옵니다. 다만 순서를 구조만 보고 짐작하지 않고, 단일 표준물을 따로 주입해 RT 로 확인하는 것이 원칙입니다. 이번 차시에서는 1교시의 STD-CAF-50(RT 5.16 min)으로 카페인 피크를 확인합니다.
분리도 1.5 가 필요한 이유#
두 피크가 가우스 모양이고 크기가 비슷하다고 하면, 분리도에 따라 겹치는 정도는 대략 다음과 같습니다.
| Rs | 꼭대기 사이 거리 | 겹치는 정도 (같은 크기 두 피크) | 판단 |
|---|---|---|---|
| 0.8 | 약 3.2σ | 골짜기가 얕아 두 피크가 한 덩어리처럼 보임 | 분리 안 됨 |
| 1.0 | 4σ | 서로의 면적 약 2 % 가 겹침, 골짜기가 베이스라인에 닿지 않음 | 면적이 틀어짐 |
| 1.5 | 6σ | 약 0.1 % 만 겹침, 골짜기가 거의 베이스라인 | 기준선 분리 |
| 2.0 이상 | 8σ 이상 | 사실상 겹치지 않음 | 피크 크기 차이가 커도 안전 |
- Rs 가 1.5 보다 작으면 적분기가 두 피크 사이를 골짜기(V) 에서 나누어 Type 이
BV·VB가 되고, 한쪽 면적이 다른 쪽으로 넘어갑니다. 같은 시료라도 적분 파라미터에 따라 면적이 흔들려 정량 결과를 믿기 어렵습니다. - 두 피크 크기가 크게 다르면(큰 피크 옆의 작은 불순물) 1.5 로도 부족해 2.0 이상을 목표로 하기도 합니다.
- 반대로 Rs 가 필요 이상으로 크면(예: 6) 분리는 좋지만 분석 시간 · 용매가 낭비됩니다. "1.5 이상이면서 가장 짧은 조건" 이 이번 차시의 선택 기준입니다.
따라하기 — 세 가지 조성으로 혼합 표준물 분석하기#
- <b>편집 › 표준용액 조제</b>에서 원액 세 개를 만듭니다:
STOCK-CAF(1교시),STOCK-TPH(테오필린 25.0 mg / 25 mL 물, 1000 mg/L),STOCK-TBR(테오브로민 25.0 mg / 100 mL 물, 250 mg/L). - 혼합 희석 탭에서 세 원액을 골라 각 20 mg/L, 10 mL, 용매
이동상 A70/B30으로MIX-XAN을 만듭니다. 덜어 낼 부피는 카페인 · 테오필린 각 0.200 mL, 테오브로민 0.800 mL 입니다(실습 A 에서 계산). - <b>편집 › 바이알 준비</b>에서 위치 3 에
MIX-XAN을 놓습니다. - 메서드를 조성별로 준비합니다.
PRAC_ISO_W70M30_v01을 열고 <b>Method › Save As</b> 로 펌프 조성만 바꿔 두 개를 더 만듭니다.
| 메서드 이름 | %A (물) | %B (메탄올) | 정지 시간 | 이유 |
|---|---|---|---|---|
PRAC_ISO_W80M20_v01 | 80 | 20 | 13 min | 카페인이 약 9.6 min 에 나오므로 여유를 둠 |
PRAC_ISO_W70M30_v01 | 70 | 30 | 10 min | 1교시 메서드 그대로 |
PRAC_ISO_W60M40_v01 | 60 | 40 | 6 min | 모두 3.5 min 안에 나옴 |
- 30 % 부터 시작합니다.
PRAC_ISO_W70M30_v01이 이미 평형되어 있으므로 <kbd>F5</kbd> → 위치3, 이름MIX-XAN-M30으로 주입합니다. PRAC_ISO_W80M20_v01을 열고 <b>Method › Send to Instrument</b> 로 보낸 뒤 10 컬럼 부피(약 16 min) 이상 평형합니다. 조성이 바뀌면 베이스라인 · 압력이 함께 바뀌므로 둘 다 안정되고 B 영역이● 준비됨이 되면 Balance(<kbd>Z</kbd>) → <kbd>F5</kbd> → 이름MIX-XAN-M20.- 같은 방법으로
PRAC_ISO_W60M40_v01을 보내고 평형한 뒤MIX-XAN-M40을 주입합니다. 기다리기 길면 배속(<kbd>Ctrl</kbd>+<kbd>]</kbd>)을 씁니다. - <b>모드 › 데이터 분석</b>에서 세 파일을 <kbd>Ctrl</kbd>+클릭으로 고르고 <kbd>O</kbd> 로 겹쳐 봅니다. 1교시 처리 조건을 Apply to All 로 적용하고 <kbd>F8</kbd> 로 적분합니다.
- 파일마다 D 표의 RT · Width(w½) · Type 을 기록합니다. 40 % 에서 테오필린 · 카페인이
BV·VB로 표시되는지 봅니다. - 끝나면
PRAC_ISO_W70M30_v01을 다시 보내 평형시켜 둡니다(다음 사용자 · ch07 을 위해).
- 조성을 바꾸고 평형 없이 바로 주입합니다 → 첫 주입의 RT 가 그 조성의 값과 다르게 나와 k · Rs 가 틀어집니다. 조성을 바꾼 뒤 첫 주입은 버리고 두 번째부터 쓰는 실험실도 있습니다.
- 20 % 메서드의 정지 시간을 10 min 그대로 둡니다 → 9.6 min 의 카페인 피크 꼬리가 잘리거나, 늦게 나온 피크가 다음 주입에 끼어듭니다(ch05).
- 피크 순서를 확인하지 않고 "가장 큰 피크 = 카페인" 으로 짐작합니다 → 농도 · 흡광계수에 따라 크기 순서는 바뀝니다. RT 와 단일 표준물로 확인합니다.
- 40 % 처럼 겹친 피크의 Width 를 그대로 Rs 식에 넣습니다 → 골짜기에서 잘린 피크의 폭은 실제보다 작게 나올 수 있으므로, 겹친 피크의 Rs 는 "대략 1 근처" 정도로만 해석합니다.
결과 확인#
| 조성 (메탄올) | 테오브로민 tR | 테오필린 tR | 카페인 tR | Rs (TBR-TPH) | Rs (TPH-CAF) |
|---|---|---|---|---|---|
| 20 % | 5.08 | 6.97 | 9.53 | 약 6.0 | 약 6.0 |
| 30 % | 3.52 | 4.37 | 5.16 | 약 4.1 | 약 3.2 |
| 40 % | 2.67 | 3.03 | 3.20 | 약 2.4 | 약 1.0 |
- 메탄올이 10 %p 늘 때마다 모든 피크가 앞당겨지고, 카페인처럼 늦게 나오는 물질일수록 더 크게 당겨집니다(S 가 큼).
- 30 % 의 카페인 RT 5.16 min 은 1교시 단일 표준물과 같습니다 → 세 번째 피크가 카페인임을 확인할 수 있습니다.
- 세 조성의 Rs · k · N 을 Python 으로 계산하는 것이 실습 D · E 입니다.
단축키 · 메뉴 정리 (2교시)#
| 동작 | 메뉴 | 단축키 |
|---|---|---|
| 메서드 열기 / 다른 이름 저장 | <b>Method › Open Method</b> / <b>Method › Save As</b> | <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>O</kbd> / <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>S</kbd> |
| 메서드를 장비로 보내기 | <b>Method › Send to Instrument</b> | — |
| 단일 주입 | <b>Run › Single Run</b> | <kbd>F5</kbd> |
| 겹쳐 보기 | A 영역 <kbd>Ctrl</kbd>+클릭 후 | <kbd>O</kbd> |
| 시간 배속 | <b>보기 › 시간 배속</b> | <kbd>Ctrl</kbd>+<kbd>]</kbd> |
| 검출기 Balance | 검출기 설정 화면 | <kbd>Z</kbd> |
실습 (시뮬레이터)#
C₁V₁ = C₂V₂ 로 덜어 낼 원액 부피를 계산하는 함수를 만들고, 1교시 STD-CAF-50 과 2교시 MIX-XAN 의 희석량을 구합니다.
stock_conc()로 실제 무게(mg) · 플라스크 부피(mL)에서 원액 농도(mg/L)를 구합니다.aliquot_mL()로 덜어 낼 부피 V₁ 을 구합니다.- MIX-XAN 은 세 원액을 한 플라스크에 넣으므로, 덜어 낸 부피의 합이 플라스크 부피보다 작은지(용매를 채울 자리가 있는지) 확인합니다.
- 0.1 mL 보다 작은 부피가 나오면 "중간 희석 필요" 라고 출력합니다.
def stock_conc(mass_mg, flask_mL):
"""원액 농도 (mg/L)"""
return 0.0 # TODO 1: mg / mL 를 mg/L 로 (x 1000)
def aliquot_mL(c1, c2, v2_mL):
"""C1 V1 = C2 V2 -> V1 (mL)"""
return 0.0 # TODO 2
stocks = {
"CAF": stock_conc(25.3, 25), # 카페인: 저울 25.3 mg, 25 mL
"TPH": stock_conc(25.0, 25), # 테오필린
"TBR": stock_conc(25.0, 100), # 테오브로민: 물에 잘 안 녹아 100 mL
}
print("원액 농도 (mg/L):", stocks)
v1 = aliquot_mL(stocks["CAF"], 50, 10)
print(f"STD-CAF-50: 원액 {v1:.3f} mL -> 10 mL")
# TODO 3: MIX-XAN (각 20 mg/L, 10 mL) 의 원액별 부피와 합계, 용매 부피 출력
# TODO 4: 0.1 mL 미만이면 "중간 희석 필요" 출력def stock_conc(mass_mg, flask_mL):
"""원액 농도 (mg/L)"""
return mass_mg / flask_mL * 1000
def aliquot_mL(c1, c2, v2_mL):
"""C1 V1 = C2 V2 -> V1 (mL)"""
if c2 >= c1:
raise ValueError(f"만들 농도 {c2} 가 원액 {c1:.0f} mg/L 보다 크거나 같음")
return c2 * v2_mL / c1
stocks = {
"CAF": stock_conc(25.3, 25),
"TPH": stock_conc(25.0, 25),
"TBR": stock_conc(25.0, 100),
}
print("원액 농도 (mg/L):", {k: round(v, 1) for k, v in stocks.items()})
v1 = aliquot_mL(stocks["CAF"], 50, 10)
print(f"STD-CAF-50: 원액 {v1:.3f} mL -> 10 mL")
# 피펫이 0.500 mL 고정이라면 실제 농도는?
print(f" 0.500 mL 를 넣으면 실제 {stocks['CAF'] * 0.500 / 10:.1f} mg/L")
target, v2 = 20, 10
total = 0.0
print(f"MIX-XAN (각 {target} mg/L, {v2} mL):")
for name, c1 in stocks.items():
v = aliquot_mL(c1, target, v2)
total += v
note = " <- 중간 희석 필요" if v < 0.1 else ""
print(f" {name}: {v:.3f} mL{note}")
print(f" 원액 합계 {total:.3f} mL, 채울 용매 약 {v2 - total:.2f} mL")
if total >= v2:
print(" 원액 합계가 플라스크 부피 이상 -> 더 큰 플라스크나 더 진한 원액 필요")카페인 원액은 25.3 mg / 25 mL = 1012 mg/L 이고, 50 mg/L 를 만들려면 0.494 mL 가 필요합니다. 0.500 mL 피펫을 그대로 쓴다면 억지로 맞추지 말고 실제 농도 50.6 mg/L 로 기록하는 편이 정확합니다. MIX-XAN 은 카페인 0.198 mL · 테오필린 0.200 mL · 테오브로민 0.800 mL, 합계 약 1.2 mL 로 용매 자리가 충분합니다. 테오브로민은 물에 잘 녹지 않아(대략 0.3 g/L 수준, PubChem 참고) 원액을 묽게(250 mg/L) 만들었기 때문에 덜어 낼 부피가 4배 큽니다.
시뮬레이터에서 내보낸 002-STD-CAF-50-01.csv 는 # 으로 시작하는 머리 정보 몇 줄, 열 이름 줄(time_min,signal_mAU), 그 아래 숫자 줄로 되어 있습니다. 아래 코드 위쪽은 같은 형식의 CSV 글자를 만듭니다(직접 내보낸 파일이 있으면 그 내용을 CSV_TEXT 에 붙여 넣어도 됩니다).
- 머리 정보는 딕셔너리로, 숫자 줄은 numpy 배열로 읽습니다.
- 꼭대기 위치에서 RT 를 구하고, 꼭대기에서 양쪽으로 가며 신호가 바탕 + 0.05 mAU 아래로 내려가는 점을 피크 시작 · 끝으로 잡습니다.
- 시작 · 끝을 잇는 직선 베이스라인을 빼고, 사다리꼴 공식 Σ(yᵢ + yᵢ₊₁)/2 · Δt 로 면적을 구합니다. 시간이 min 이므로 × 60 해서 mAU*s 로 바꿉니다.
- 높이 · 반높이 폭도 구해, 시뮬레이터 결과 표(1641.8 mAU*s, 160.2 mAU, 0.161 min)와 비교합니다.
import io
import numpy as np
# ---- 시뮬레이터가 저장한 002-STD-CAF-50-01.csv 와 같은 형식의 데이터를 만듭니다 ----
rng = np.random.default_rng(21)
t = np.round(np.arange(0, 10.0001, 0.4 / 60), 4) # 2.5 Hz
sig = np.where(t < 5.161, 160.2 * np.exp(-0.5 * ((t - 5.161) / 0.0633) ** 2),
160.2 * np.exp(-0.5 * ((t - 5.161) / 0.0733) ** 2))
sig += 0.6 * np.exp(-0.5 * ((t - 3.102) / 0.05) ** 2)
sig += -1.2 * np.exp(-0.5 * ((t - 1.60) / 0.02) ** 2) + 1.0 * np.exp(-0.5 * ((t - 1.66) / 0.02) ** 2)
sig += rng.normal(0, 0.01, t.size) + 0.02
lines = ["# Sample: STD-CAF-50", "# Method: PRAC_ISO_W70M30_v01",
"# Injected: 2026-10-11 10:21:40", "# Signal: VWD1 A, 273 nm",
"time_min,signal_mAU"]
lines += [f"{a:.4f},{b:.4f}" for a, b in zip(t, sig)]
CSV_TEXT = "\n".join(lines)
# ---------------------------------------------------------------------------
meta, rows = {}, []
for line in io.StringIO(CSV_TEXT):
line = line.strip()
# TODO 1: "#" 줄은 meta 에 "키: 값" 으로, 숫자 줄은 rows 에 [시간, 신호] 로 (열 이름 줄은 건너뜀)
data = np.array(rows) if rows else np.zeros((1, 2))
t, y = data[:, 0], data[:, 1]
print(meta)
print(f"점 {t.size}개")
i_top = int(np.argmax(y))
tR = t[i_top]
base_level = float(np.median(y[(t > 4.0) & (t < 4.6)])) if rows else 0.0
thr = base_level + 0.05
i0 = i1 = i_top
# TODO 2: i0 은 왼쪽으로, i1 은 오른쪽으로 y 가 thr 이하가 될 때까지 이동
tt, yy = t[i0:i1 + 1], y[i0:i1 + 1]
area = 0.0 # TODO 3: 직선 베이스라인을 빼고 사다리꼴 적분 (x 60 -> mAU*s)
height = 0.0 # TODO 4: 베이스라인을 뺀 신호의 최대값
w_half = 0.0 # TODO 4: 높이의 절반 이상인 점들의 시간 폭
print(f"tR = {tR:.3f} min, 높이 = {height:.1f} mAU, 면적 = {area:.1f} mAU*s, w1/2 = {w_half:.3f} min")import io
import numpy as np
# ---- 시뮬레이터가 저장한 002-STD-CAF-50-01.csv 와 같은 형식의 데이터를 만듭니다 ----
rng = np.random.default_rng(21)
t = np.round(np.arange(0, 10.0001, 0.4 / 60), 4) # 2.5 Hz
sig = np.where(t < 5.161, 160.2 * np.exp(-0.5 * ((t - 5.161) / 0.0633) ** 2),
160.2 * np.exp(-0.5 * ((t - 5.161) / 0.0733) ** 2))
sig += 0.6 * np.exp(-0.5 * ((t - 3.102) / 0.05) ** 2)
sig += -1.2 * np.exp(-0.5 * ((t - 1.60) / 0.02) ** 2) + 1.0 * np.exp(-0.5 * ((t - 1.66) / 0.02) ** 2)
sig += rng.normal(0, 0.01, t.size) + 0.02
lines = ["# Sample: STD-CAF-50", "# Method: PRAC_ISO_W70M30_v01",
"# Injected: 2026-10-11 10:21:40", "# Signal: VWD1 A, 273 nm",
"time_min,signal_mAU"]
lines += [f"{a:.4f},{b:.4f}" for a, b in zip(t, sig)]
CSV_TEXT = "\n".join(lines)
# ---------------------------------------------------------------------------
meta, rows = {}, []
for line in io.StringIO(CSV_TEXT):
line = line.strip()
if line.startswith("#"): # 머리 정보: "# 키: 값"
key, _, val = line[1:].partition(":")
meta[key.strip()] = val.strip()
elif line and not line.startswith("time"): # 열 이름 줄은 건너뜀
rows.append([float(v) for v in line.split(",")])
data = np.array(rows)
t, y = data[:, 0], data[:, 1]
print(meta)
print(f"점 {t.size}개, {t[0]:.2f} ~ {t[-1]:.2f} min, 간격 {np.diff(t).mean() * 60:.2f} s")
i_top = int(np.argmax(y))
tR = t[i_top]
base_level = float(np.median(y[(t > 4.0) & (t < 4.6)]))
thr = base_level + 0.05 # 바탕 + 0.05 mAU
i0 = i_top
while i0 > 0 and y[i0] > thr:
i0 -= 1
i1 = i_top
while i1 < t.size - 1 and y[i1] > thr:
i1 += 1
tt, yy = t[i0:i1 + 1], y[i0:i1 + 1]
base = np.interp(tt, [tt[0], tt[-1]], [yy[0], yy[-1]]) # 시작 - 끝 직선
h = yy - base
area = float(np.sum((h[1:] + h[:-1]) / 2 * np.diff(tt))) * 60 # mAU*min -> mAU*s
height = float(h.max())
above = tt[h >= height / 2]
w_half = above[-1] - above[0]
print(f"머무름 시간 tR = {tR:.3f} min")
print(f"적분 구간 {tt[0]:.3f} ~ {tt[-1]:.3f} min ({tt.size}점)")
print(f"높이 = {height:.1f} mAU, 면적 = {area:.1f} mAU*s, 반높이 폭 = {w_half:.3f} min")
print(f"시뮬레이터 결과 표 1641.8 과의 차이: {(area - 1641.8) / 1641.8 * 100:+.2f} %")1501개 점(0 ~ 10 min, 0.40 s 간격)을 읽어 **tR 5.160 min · 높이 160.2 mAU · 면적 약 1644.6 mAU*s · 반높이 폭 0.160 min 이 나옵니다. 결과 표와 면적이 약 0.2 % 다른 것은 피크 시작 · 끝을 잡는 규칙(문턱 0.05 mAU)과 점 간격 때문입니다. tR 이 5.161 이 아니라 5.160 인 것은 가장 높은 데이터 점**의 시간을 썼기 때문입니다(점 간격 약 0.007 min). 문턱을 0.5 mAU 로 올려 보면 적분 구간이 좁아져 면적이 줄어드는 것도 확인해 보세요 — 1교시의 기울기 감도와 같은 효과입니다.
1교시 따라하기 9단계에서 STD-CAF-50 을 3회 주입한 결과(D 표)를 옮겨 적었습니다. 직접 얻은 값이 있으면 그 값으로 바꿔 넣습니다.
- RT · 면적 · 높이 각각의 평균, 표본 표준편차(n − 1 로 나눔), RSD(%) = 표준편차 ÷ 평균 × 100 을 구합니다.
- RT 와 면적 중 어느 쪽 RSD 가 더 큰지 비교하고, 그 이유를 한 줄로 씁니다.
- 확장: 3회째 면적을 1580.0 으로 바꿔(바이알 공기 흡입 같은 문제를 가정) RSD 가 얼마나 커지는지 봅니다.
import statistics as st
runs = {
"002-STD-CAF-50-01": {"rt": 5.161, "area": 1641.8, "height": 160.2},
"002-STD-CAF-50-02": {"rt": 5.158, "area": 1652.3, "height": 161.0},
"002-STD-CAF-50-03": {"rt": 5.166, "area": 1636.9, "height": 159.7},
}
def rsd(values):
return 0.0 # TODO 1: statistics.stdev (n-1) / mean * 100
for key in ("rt", "area", "height"):
vals = [r[key] for r in runs.values()]
# TODO 2: 평균, 표준편차, RSD 출력
print(key, vals, f"RSD = {rsd(vals):.2f} %")import statistics as st
runs = {
"002-STD-CAF-50-01": {"rt": 5.161, "area": 1641.8, "height": 160.2},
"002-STD-CAF-50-02": {"rt": 5.158, "area": 1652.3, "height": 161.0},
"002-STD-CAF-50-03": {"rt": 5.166, "area": 1636.9, "height": 159.7},
}
def rsd(values):
return st.stdev(values) / st.mean(values) * 100
for key, unit in (("rt", "min"), ("area", "mAU*s"), ("height", "mAU")):
vals = [r[key] for r in runs.values()]
print(f"{key:6s} 평균 {st.mean(vals):9.3f} {unit:6s} SD {st.stdev(vals):7.3f} RSD {rsd(vals):.2f} %")
# 확장: 3회째에 문제가 있었다면
bad = [1641.8, 1652.3, 1580.0]
print(f"\n3회째 면적 1580.0 이면 면적 RSD {rsd(bad):.2f} %")
# 참고: n 으로 나눈 모표준편차를 쓰면 RSD 가 작게 나옴
vals = [r["area"] for r in runs.values()]
print(f"pstdev 로 계산하면 {st.pstdev(vals) / st.mean(vals) * 100:.2f} % (반복 주입에는 stdev 사용)")RT RSD 는 약 0.08 %, 면적 RSD 는 약 0.48 %, 높이 RSD 는 약 0.41 % 입니다. RT 는 펌프 유속 · 조성 · 온도만 일정하면 매우 잘 재현되지만, 면적은 주입량의 작은 차이와 적분 시작 · 끝의 흔들림이 더해져 RSD 가 더 큽니다. 3회째가 1580.0 이면 면적 RSD 가 약 2.4 % 로 뛰어 한 번의 이상 주입이 전체 반복성을 크게 나쁘게 만든다는 것을 알 수 있습니다. 이럴 때는 ch05 처럼 실행 로그부터 확인합니다. 몇 % 까지를 합격으로 볼지는 ch07 시스템 적합성에서 정합니다.
카페인 원액 1000 mg/L 에서 25 mg/L 사용 표준 20 mL 를 만들려고 합니다. 덜어 낼 원액 부피와 채울 용매로 가장 알맞은 것은?
- 0.25 mL, 메탄올 100 %
- 0.50 mL, 이동상(물:메탄올 70:30)
- 0.50 mL, 메탄올 100 %
- 5.0 mL, 이동상(물:메탄올 70:30)
정답 보기
② — V₁ = C₂V₂ / C₁ = 25 × 20 / 1000 = 0.50 mL 입니다. 묽히는 용매는 이동상과 같게 하는 것이 좋습니다. 메탄올 100 % 처럼 이동상보다 강한 용매에 녹인 시료를 주입하면 피크가 앞끌림 · 갈라짐을 보일 수 있습니다(오류 5번). ① 은 10 mL 로 착각한 값, ④ 는 단위를 잘못 맞춘 값입니다.자동 적분 결과 표에서 카페인 피크 면적% 가 99.73 % 로 나왔습니다. 면적 거부를 10 으로 올려 다시 적분하자 작은 피크(면적 4.5)가 사라지고 카페인 면적% 가 100.00 % 가 되었습니다. 옳은 설명은?
- 카페인 면적도 함께 늘어났기 때문에 100 % 가 되었다
- 카페인 면적은 그대로이고, 전체 면적 합에서 작은 피크가 빠져 비율만 바뀌었다
- 면적% 가 100 % 이므로 이 표준물의 순도는 100 % 이다
- 면적 거부는 피크 높이를 기준으로 피크를 뺀다
정답 보기
② — 면적 거부는 "면적이 이 값보다 작은 피크를 표에서 뺀다" 는 뜻입니다. 카페인 면적(1641.8)은 그대로이고 분모(전체 면적 합)만 줄어 면적% 가 바뀝니다. ③ 면적% 는 물질마다 흡광계수가 달라 순도 · 농도% 가 아니며, 적분 파라미터에 따라서도 바뀝니다. ④ 높이 기준은 높이 거부(Height Reject)입니다.2교시 식을 함수로 만들고, 1교시 카페인 피크와 30 % 혼합 표준물 결과로 시험합니다.
k_factor(tR, t0),selectivity(k1, k2),resolution(t1, t2, w1, w2, half=True),plates(tR, w, half=True),tailing(w005, f)를 만듭니다.half=True면 반높이 폭 식,False면 바닥 폭 식을 씁니다.- 1교시 카페인(tR 5.161, w½ 0.161, t₀ 1.62, W0.05 0.304, f 0.142)의 k · N · T 를 구합니다.
- 30 % 테오필린(4.37, w½ 0.135) · 카페인(5.16, w½ 0.158)의 α · Rs 를 구하고, 퍼넬 식으로 계산한 Rs 와 비교합니다.
import math
def k_factor(tR, t0):
return 0.0 # TODO 1
def selectivity(k1, k2):
return 0.0 # TODO 2: 큰 쪽 / 작은 쪽
def resolution(t1, t2, w1, w2, half=True):
return 0.0 # TODO 3: half 면 1.18 * dt / (w1 + w2), 아니면 2 * dt / (w1 + w2)
def plates(tR, w, half=True):
return 0.0 # TODO 4: half 면 5.54 (tR/w)^2, 아니면 16 (tR/w)^2
def tailing(w005, f):
return 0.0 # TODO 5
t0 = 1.62
k = k_factor(5.161, t0)
print(f"카페인 k = {k:.2f}, N = {plates(5.161, 0.161):.0f}, T = {tailing(0.304, 0.142):.2f}")import math
def k_factor(tR, t0):
if tR <= t0:
raise ValueError(f"tR {tR} 가 t0 {t0} 보다 작거나 같음 - t0 를 확인")
return (tR - t0) / t0
def selectivity(k1, k2):
return max(k1, k2) / min(k1, k2)
def resolution(t1, t2, w1, w2, half=True):
coef = 1.18 if half else 2.0
return coef * abs(t2 - t1) / (w1 + w2)
def plates(tR, w, half=True):
return (5.54 if half else 16.0) * (tR / w) ** 2
def tailing(w005, f):
return w005 / (2 * f)
def purnell(N, alpha, k2):
return math.sqrt(N) / 4 * (alpha - 1) / alpha * k2 / (1 + k2)
t0 = 1.62
k = k_factor(5.161, t0)
print(f"카페인 k = {k:.2f}, N = {plates(5.161, 0.161):.0f}, T = {tailing(0.304, 0.142):.2f}")
t_tph, w_tph = 4.37, 0.135
t_caf, w_caf = 5.16, 0.158
k1, k2 = k_factor(t_tph, t0), k_factor(t_caf, t0)
a = selectivity(k1, k2)
rs = resolution(t_tph, t_caf, w_tph, w_caf)
N = plates(t_caf, w_caf)
print(f"30 %: 테오필린 k {k1:.2f}, 카페인 k {k2:.2f}, alpha {a:.3f}")
print(f" Rs (반높이 폭) = {rs:.2f}")
print(f" Rs (퍼넬 식, N={N:.0f}) = {purnell(N, a, k2):.2f}")
# 흔한 실수: 반높이 폭을 바닥 폭 식에 넣기
print(f" [실수] 반높이 폭을 바닥 폭 식에 넣으면 Rs = {resolution(t_tph, t_caf, w_tph, w_caf, half=False):.2f}")카페인은 k ≈ 2.19 · N ≈ 5700 · T ≈ 1.07(살짝 꼬리)입니다. k 가 1 ~ 10 범위라 t₀ 근처 방해와 떨어져 있고 분석 시간도 짧습니다. 30 % 테오필린 · 카페인은 α ≈ 1.29, Rs ≈ 3.2 로 기준선 분리입니다. 퍼넬 식(약 2.9)도 비슷한 값을 줘서, 세 숫자(N · α · k)가 Rs 를 어떻게 만드는지 확인할 수 있습니다. 반높이 폭을 바닥 폭 식(2 × Δt)에 넣으면 Rs 가 약 5.4 로 1.7배 부풀려집니다 — 결과 표 Width 가 어떤 폭인지 먼저 확인해야 하는 이유입니다(오류 7번).
2교시 따라하기에서 얻은 세 조성의 RT · 반높이 폭(D 표)을 아래 results 에 넣었습니다. 직접 얻은 값이 있으면 바꿔 넣습니다.
- 조성마다 이웃한 두 피크의 Rs 와 그중 가장 작은 Rs(임계 쌍) 를 구합니다.
- 조성마다 마지막 피크 RT 를 분석 시간으로 봅니다.
- "모든 Rs ≥ 1.5 이면서 분석 시간이 가장 짧은 조성" 을 고르는 코드를 씁니다.
- 물질마다 log k 와 메탄올 비율 φ 로
np.polyfit직선을 맞춰 S 를 구하고, 35 % 에서 Rs 를 예측해 봅니다(예측은 반드시 실제 주입으로 확인할 값). - 고른 조성과 근거(임계 쌍 Rs · 분석 시간 · k 범위)를 세 줄로 씁니다.
import numpy as np
t0 = 1.62
names = ["테오브로민", "테오필린", "카페인"]
# 메탄올 비율: [(tR, w1/2), ...] 이름 순서대로
results = {
20: [(5.08, 0.156), (6.97, 0.214), (9.53, 0.292)],
30: [(3.52, 0.108), (4.37, 0.135), (5.16, 0.158)],
40: [(2.67, 0.083), (3.03, 0.094), (3.20, 0.099)],
}
def resolution(t1, t2, w1, w2):
return 1.18 * (t2 - t1) / (w1 + w2)
summary = {}
for pct, peaks in results.items():
rs_list = [] # TODO 1: 이웃한 두 피크의 Rs
last_tR = 0.0 # TODO 2: 마지막 피크 tR
summary[pct] = (rs_list, last_tR)
print(f"MeOH {pct} %: Rs {rs_list}, 분석 {last_tR} min")
best = None # TODO 3: 모든 Rs >= 1.5 인 조성 중 last_tR 가 가장 작은 것
print("고른 조성:", best)
# TODO 4: log k vs phi 직선 (np.polyfit) 으로 물질별 S 구하고 35 % tR 예측import numpy as np
t0 = 1.62
N_assumed = 6000 # 예측용: 세 조건에서 얻은 N 의 대략적인 평균
names = ["테오브로민", "테오필린", "카페인"]
results = {
20: [(5.08, 0.156), (6.97, 0.214), (9.53, 0.292)],
30: [(3.52, 0.108), (4.37, 0.135), (5.16, 0.158)],
40: [(2.67, 0.083), (3.03, 0.094), (3.20, 0.099)],
}
def resolution(t1, t2, w1, w2):
return 1.18 * (t2 - t1) / (w1 + w2)
summary = {}
for pct, peaks in results.items():
rs_list = [round(resolution(a[0], b[0], a[1], b[1]), 2) for a, b in zip(peaks, peaks[1:])]
last_tR = peaks[-1][0]
ks = [(tr - t0) / t0 for tr, _ in peaks]
Ns = [5.54 * (tr / w) ** 2 for tr, w in peaks]
summary[pct] = (rs_list, last_tR)
print(f"MeOH {pct} %: k {[round(k, 2) for k in ks]}, N 평균 {np.mean(Ns):.0f}, "
f"Rs {rs_list}, 임계 Rs {min(rs_list)}, 분석 {last_tR} min")
ok = {p: v for p, v in summary.items() if min(v[0]) >= 1.5}
best = min(ok, key=lambda p: ok[p][1]) if ok else None
print("\n기준(모든 Rs >= 1.5)을 만족:", sorted(ok))
print("고른 조성:", f"MeOH {best} %" if best else "없음")
# log k = log kw - S * phi
phis = np.array(sorted(results)) / 100
pred = {}
print("\n물질별 직선 log k = log kw - S * phi")
for i, name in enumerate(names):
logk = np.array([np.log10((results[p][i][0] - t0) / t0) for p in sorted(results)])
slope, intercept = np.polyfit(phis, logk, 1)
k35 = 10 ** (intercept + slope * 0.35)
pred[name] = t0 * (1 + k35)
print(f" {name}: S = {-slope:.2f}, log kw = {intercept:.2f}, 35 % 예측 tR = {pred[name]:.2f} min")
tr = [pred[n] for n in names]
w = [2.355 * x / np.sqrt(N_assumed) for x in tr]
rs35 = [resolution(tr[j], tr[j + 1], w[j], w[j + 1]) for j in range(2)]
print(f" 35 % 예측 Rs = {[round(float(r), 2) for r in rs35]} (반드시 실제 주입으로 확인)")| 조성 | 임계 쌍 | 임계 Rs | 분석 시간 | 판단 |
|---|---|---|---|---|
| 20 % | 테오필린 - 카페인 | 약 6.0 | 9.5 min (정지 13 min) | 분리는 넘치지만 너무 김 |
| 30 % | 테오필린 - 카페인 | 약 3.2 | 5.2 min (정지 10 min) | 선택 |
| 40 % | 테오필린 - 카페인 | 약 1.0 | 3.2 min | 기준선 분리 실패 |
예시 근거: "① 30 % 는 모든 피크 쌍의 Rs 가 3 이상으로 기준선 분리(1.5)를 넉넉히 넘는다. ② 같은 조건을 만족하는 20 % 보다 분석이 약 4 min 짧고 정지 시간도 3 min 짧다. ③ k 가 1.2 ~ 2.2 로 t₀ 근처를 피하면서 너무 길지 않은 범위다." 직선 맞춤으로 구한 S 는 테오브로민 약 2.6 · 테오필린 약 2.9 · 카페인 약 3.5 로 카페인이 가장 크며, 그래서 메탄올을 늘리면 카페인이 테오필린 쪽으로 가장 빨리 다가갑니다. 35 % 예측 임계 Rs 는 약 2 로 기준을 넘지만, 예측은 어디까지나 짐작이므로 쓰려면 반드시 실제로 주입해 확인합니다 — 이런 조건 탐색은 ch08 에서 이어서 합니다.
어떤 조건에서 t₀ = 1.62 min, 피크 1 의 tR = 3.03 min(w½ 0.094), 피크 2 의 tR = 3.20 min(w½ 0.099)입니다. 옳은 판단은?
- Rs 는 약 1.04 로 기준선 분리가 안 되었으므로, 메탄올 비율을 낮추는 방향으로 조건을 바꿔 본다
- Rs 는 약 1.76 이므로 기준선 분리이다
- α 가 1 보다 크므로 Rs 와 상관없이 정량에 문제가 없다
- 피크 폭이 좁으므로 Rs 를 계산할 필요가 없다
정답 보기
① — Rs = 1.18 × (3.20 − 3.03) / (0.094 + 0.099) = 1.18 × 0.17 / 0.193 ≈ 1.04 로 1.5 에 못 미칩니다. 이 혼합물에서는 메탄올을 줄이면 k 와 α 가 함께 커져 분리가 좋아집니다(40 % → 30 %). ② 는 반높이 폭에 바닥 폭 식(2 × Δt)을 쓴 값입니다. ③ α 가 1 보다 조금 커도 N · k 가 부족하면 피크가 겹칩니다.역상 C18 컬럼에서 메탄올 비율을 30 % → 40 % 로 올렸을 때 일반적으로 나타나는 변화로 가장 알맞은 것은?
- 모든 피크의 k 가 커지고 분석 시간이 길어진다
- 모든 피크의 k 가 작아져 일찍 나오며, 물질마다 줄어드는 정도(S)가 달라 α 도 바뀔 수 있다
- k 는 그대로이고 피크 높이만 바뀐다
- t₀ 가 크게 늘어나 k 가 작아진다
정답 보기
② — 역상에서는 유기용매가 많을수록 분석물이 고정상에서 잘 떨어져 k 가 작아지고, log k 가 φ 에 대해 대략 직선으로 줄어듭니다. 기울기 S 가 물질마다 달라 이번 혼합물처럼 α 가 1 에 가까워져 겹치기도 합니다. ④ t₀ 는 컬럼 부피 ÷ 유속이라 조성에 따라 거의 바뀌지 않습니다.자주 나는 오류와 해결#
1) 블랭크에 카페인 자리 피크가 나옴#
[Data] 001-BLANK-1-01: peak at 5.16 min, area 12.4 mAU*s (Blank)
[Integration] Warning: blank contains peak at analyte retention time- 원인: 앞 주입(진한 표준물 · 원액)이 니들 · 주입 밸브에 남아 다음 주입에 섞인 잔류(carry-over) 이거나, 블랭크 바이알 · 이동상이 오염되었습니다.
- 해결: 니들 세척 방식 · 세척 바이알(ch04)을 확인하고 블랭크를 한 번 더 주입합니다. 두 번째 블랭크에서 사라지면 잔류, 그대로면 이동상 · 바이알을 새로 준비합니다. 진한 용액 다음에는 블랭크를 한 줄 넣습니다(ch05).
2) 자동 적분에서 피크를 하나도 찾지 못함#
[Integration] 0 peaks found (Slope Sensitivity 50.0, Area Reject 5000.0)- 원인: 앞 실습에서 바꾼 기울기 감도 · 면적 거부가 너무 크게 남아 있거나, 시간 이벤트의
Integration Off가 피크 시간을 덮고 있습니다. 다른 신호(파장)를 열었을 수도 있습니다. - 해결: <kbd>Ctrl</kbd>+<kbd>E</kbd> 로 E 영역을 열어 파라미터를 기본값(1.0 · 0.10 · 1.0 · 0.2)으로 되돌리고, 시간 이벤트 구간을 확인한 뒤 <kbd>F8</kbd> 로 다시 적분합니다. 머리 정보의 신호 이름이
273 nm인지 봅니다.
3) 피크 꼭대기가 평평하게 잘림#
[VWD] Warning: signal exceeds linear range (> 2000 mAU) at 5.14 - 5.19 min- 원인: 사용 표준(50 mg/L) 대신 원액(1000 mg/L) 을 주입했거나, 주입량을 10 µL 가 아닌 100 µL 로 넣었습니다. 검출기가 잴 수 있는 범위를 넘으면 면적 · 높이가 농도에 비례하지 않습니다.
- 해결: <b>편집 › 바이알 준비</b>에서 위치 2 의 용액 이름 · 농도와 메서드 주입량을 확인하고, 올바른 용액으로 다시 주입합니다. 잘린 피크의 데이터는 쓰지 않습니다.
4) 반복 주입마다 머무름 시간이 한쪽으로 밀림#
[Data] STD-CAF-50 RT: 5.02 -> 5.10 -> 5.16 min (RSD 1.38 %)- 원인: 조성을 바꾸거나 장비를 켠 뒤 평형이 덜 된 상태에서 주입했습니다. 컬럼 온도가 아직 오르는 중이어도 같은 모양이 나옵니다.
- 해결: 10 컬럼 부피 이상 흘리고 압력 · 온도 · 베이스라인이 안정된 뒤(B 영역
● 준비됨) 다시 주입합니다. 연속 두 번의 RT 가 0.02 min 안으로 맞을 때부터 결과로 씁니다.
5) 카페인 피크가 앞으로 끌리거나 둘로 갈라짐#
[Integration] Peak 2 (5.08 min): tailing factor 0.72 (fronting), shoulder detected- 원인: 사용 표준을 이동상이 아니라 메탄올 100 % 로 묽혔습니다. 주입 순간 시료 용매가 이동상보다 강해, 분석물 일부가 컬럼 입구에서 붙지 못하고 먼저 흘러갑니다. 주입량이 너무 많아도 비슷합니다.
- 해결: 시료 용매를 이동상(70:30)이나 그보다 약한 용매로 바꿔 다시 조제합니다(<b>편집 › 표준용액 조제</b> 의 용매 칸). 바꿀 수 없으면 주입량을 줄입니다.
6) Python 에서 CSV 를 숫자로 바꾸지 못함#
ValueError: could not convert string to float: '# Sample: STD-CAF-50'- 원인: 시뮬레이터 CSV 맨 위의
#머리 정보 줄과 열 이름 줄(time_min,signal_mAU)까지float()로 바꾸려 했습니다. - 해결: 실습 B 처럼
#줄과 열 이름 줄을 건너뛰고 숫자 줄만 읽습니다.np.loadtxt를 쓸 때는comments="#"를 주고, 열 이름 줄 처리 방식(skiprows)이 numpy 버전마다 다를 수 있으니 결과 배열의 첫 줄을 꼭 출력해 확인합니다.
7) 직접 계산한 Rs · N 이 시뮬레이터와 크게 다름#
Rs (내 계산) = 5.39 / 시뮬레이터 = 3.18
N (내 계산) = 16441 / 시뮬레이터 = 5693- 원인: 결과 표 Width 는 반높이 폭(w½) 인데 바닥 폭 식(Rs = 2Δt / Σw, N = 16(tR/w)²)에 넣었습니다. 또는 tR 은 min, 폭은 s 로 단위를 섞었습니다.
- 해결: 반높이 폭이면 Rs = 1.18Δt / (w½₁ + w½₂), N = 5.54(tR / w½)² 를 씁니다(실습 D 의
half=True). tR · t₀ · w 를 모두 min 으로 맞춥니다.
과제 / 팀 미션#
아래 다섯 문제를 풀고, 각 답의 근거를 한 줄씩 적어 제출합니다. 실습 C 의 RSD 출력과 실습 E 의 조성 선택 근거(세 줄)도 함께 냅니다.
- 1000 mg/L 원액으로 40 mg/L 사용 표준 25 mL 를 만들 때 덜어 낼 원액은? ① 0.4 mL ② 1.0 mL ③ 2.5 mL ④ 4.0 mL
- 시스템 준비 순서로 알맞은 것은? ① 표준물 주입 → 블랭크 주입 → 평형 → 퍼지 ② 퍼지 → 평형 → 블랭크 주입 → 표준물 주입 ③ 평형 → 퍼지 → 표준물 주입 → 블랭크 주입 ④ 블랭크 주입 → 퍼지 → 표준물 주입 → 평형
- 적분 결과 표에서 정량(얼마나 들어 있나) 의 기본이 되는 값은? ① RT ② Type ③ Area ④ Area %
- t₀ = 1.62 min, tR = 5.16 min 인 카페인의 k 는? ① 0.31 ② 2.19 ③ 3.19 ④ 3.54
- 메탄올 20 · 30 · 40 % 의 임계 Rs 가 각각 6.0 · 3.2 · 1.0, 분석 시간이 9.5 · 5.2 · 3.2 min 일 때 "Rs ≥ 1.5 이면서 가장 짧은" 조성은? ① 20 % ② 30 % ③ 40 % ④ 고를 수 없음
정답 보기
1-② V₁ = 40 × 25 / 1000 = 1.0 mL. 2-② 기포를 빼고(퍼지), 조건을 안정시키고(평형), 바탕을 확인한(블랭크) 뒤 표준물을 주입합니다. 3-③ 면적이 농도에 비례하며 검량선(ch07)의 기본 값입니다. 면적% 는 흡광계수 차이 때문에 농도% 가 아닙니다. 4-② k = (5.16 − 1.62) / 1.62 ≈ 2.19 (③ 은 tR/t₀). 5-② 40 % 는 1.5 미만이고, 30 % 가 기준을 만족하는 조성 중 가장 짧습니다.1교시 "적분기 흉내 내기" 코드와 실습 B 의 CSV 읽기를 합쳐, 시뮬레이터에서 내보낸 MIX-XAN-M30 · M40 신호 CSV 를 적분하는 작은 프로그램을 만듭니다.
- 피크마다 RT · 면적 · 높이 · w½ · Type(
B/V) 을 표로 출력하고, 시뮬레이터 D 표와 면적 차이(%)를 비교합니다. - 40 % 에서 겹친 테오필린 · 카페인을 골짜기 수직 분할(drop line) 로 나누면 면적이 어떻게 나뉘는지, 시뮬레이터 결과와 같은지 봅니다.
- 기울기 감도를 1 · 5 · 20 으로 바꿔 면적이 몇 % 바뀌는지 정리하고, "파라미터를 정해 두고 모든 파일에 같게 적용해야 하는 이유" 를 세 줄로 씁니다.
참고자료#
- Agilent OpenLab CDS 제품 페이지 (데이터 분석 · 적분 · 보고서 개요): https://www.agilent.com/en/product/software-informatics/analytical-software-suite/chromatography-data-systems/openlab-cds
- Agilent OpenLab CDS · ChemStation Edition 데이터 분석(적분 이벤트 · 수동 적분) 설명서와 1260 Infinity II VWD (G7114A) User Manual — Agilent 문헌 라이브러리에서 제품명 · 모델 번호로 검색: https://www.agilent.com/en/support
- Agilent, The LC Handbook — Guide to LC Columns and Method Development (k · α · N · Rs, 이동상 조성과 머무름): https://www.agilent.com/cs/library/primers/public/LC-Handbook-Complete-2.pdf
- L. R. Snyder, J. J. Kirkland, J. W. Dolan, Introduction to Modern Liquid Chromatography, 3rd ed., Wiley (2010) — 분리도 식 · log k 와 유기용매 비율의 관계
- USP 일반 시험법 〈621〉 Chromatography — 분리도 · 이론단수 · 대칭도(tailing factor) 정의 (최신판은 USP-NF 에서 확인)
- PubChem: 카페인 https://pubchem.ncbi.nlm.nih.gov/compound/Caffeine · 테오필린 https://pubchem.ncbi.nlm.nih.gov/compound/Theophylline · 테오브로민 https://pubchem.ncbi.nlm.nih.gov/compound/Theobromine (물성 · 용해도 · 안전 정보)
- Python 공식 문서
statistics모듈: https://docs.python.org/3/library/statistics.html · NumPypolyfit: https://numpy.org/doc/stable/reference/generated/numpy.polyfit.html - 이 사이트의 도구: Python Playground · 3D 뷰어 · 3D 시뮬레이터
- 이전 차시: ch05 메서드와 시퀀스 작성 · 다음 차시: ch07 정량 분석: 검량선과 시스템 적합성