docs: 안전 피드램프 advisory 설계 브레인스토밍 + 작업지시서
- docs/안전피드램프-한계치-브레인스토밍.md (§0~§10): C-6111 피드램프/듀티/드로우 advisory 설계 — 램프율·ceiling 공식, 자기조절 캐스케이드, 편차 trim 소스, 압력 서브시스템(pi-6111b/ΔP/PCT), tray 레이아웃(패킹 3구간), 온도 역전 판정 spec - plans/안전피드램프-advisory-작업지시서.md: WP0 Sim Override + WP1 시나리오매트릭스 + WP2 현행엔진 프로빙 + WP3 FeedRampAdvisor 구현 지시 (다른 LLM 실행용) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
497
docs/안전피드램프-한계치-브레인스토밍.md
Normal file
497
docs/안전피드램프-한계치-브레인스토밍.md
Normal file
@@ -0,0 +1,497 @@
|
|||||||
|
# 안전 피드 램프 · 운전 한계치 — 브레인스토밍
|
||||||
|
|
||||||
|
> 2026-06-01, C-6111 PGMEA 측류 추출식 증류탑 기준
|
||||||
|
> 상태: **보류(brainstorming)** — 구현 착수 전 헛점 검토 단계
|
||||||
|
|
||||||
|
## 0. 배경 / 발단
|
||||||
|
|
||||||
|
선행 논의에서 출발:
|
||||||
|
1. FF의 LevelDriven 스트림(D=ficq-6114, B=ficq-6116)이 `recommendedSp = K×피드`를 **"권장 SP" 컬럼에 상승값으로 그대로 표시** → 운전원이 추종 시 *피드↑ → 레벨↑ → 드로우 SP↑ → 중비물(B) 일시 과추출* 을 시스템이 부추기는 구조라는 지적.
|
||||||
|
2. "advisory라 안전"은 근거 없는 합리화 (advisory 라벨은 그 숫자의 타당성을 보증하지 않음).
|
||||||
|
3. → **관점 전환**: "권장값을 어떻게 표시하나"가 아니라, **"피드를 평형 깨지 않고 얼마나·얼마나 빨리 올릴 수 있나"를 계산**하는 쪽으로.
|
||||||
|
|
||||||
|
## 1. 문제 정의 — 두 개를 분리
|
||||||
|
|
||||||
|
| | 정체 | 성격 | 예시 질문 |
|
||||||
|
|---|------|------|-----------|
|
||||||
|
| **한계치 (ceiling)** | 평형 깨지 않는 **최대 피드** | 정적 상한 (level) | "1100이 애초에 가능한가?" |
|
||||||
|
| **RATE 한계치 (ramp)** | 900→1100을 얼마나 **빨리** | 동적 상한 (rate) | "몇 분에 걸쳐 올려야 안전한가?" |
|
||||||
|
|
||||||
|
사용자 원안: 900 → 1100 (Δ=200), RATE LIMIT + 시간 고려한 **점진 SP 상승 안전 램프**.
|
||||||
|
|
||||||
|
## 2. C-6111 실제 config (ff_stream_config, column_id=1)
|
||||||
|
|
||||||
|
| 스트림 | flow_tag | 역할 | K | θ_up/dn | τ | sp_max | rate_up/dn (kg/hr·min) | level_tag |
|
||||||
|
|--------|----------|------|-----|---------|------|--------|------------------------|-----------|
|
||||||
|
| P | ficq-6118 | Commanded | 0.95 | 60/60 | **900** | 2000 | 30/60 | – |
|
||||||
|
| R | ficq-6113 | Commanded | 0.80 | 0/0 | 0 | 2000 | 30/30 | – |
|
||||||
|
| D | ficq-6114 | LevelDriven | 0.02 | – | – | 1000 | 0/0 | lica-6113 |
|
||||||
|
| B | ficq-6116 | LevelDriven | 0.03 | – | – | 500 | 0/0 | li-6111 |
|
||||||
|
|
||||||
|
피드 = ficq-6101. (K 합 P+D+B = 0.95+0.02+0.03 = 1.00 → 물질수지 폐합. R은 내부 환류.)
|
||||||
|
|
||||||
|
## 3. 계산 프레임워크
|
||||||
|
|
||||||
|
### 3.1 RATE 한계치 (램프율)
|
||||||
|
|
||||||
|
램프율 `R_feed`(kg/hr per min)에 걸리는 두 제약 중 **작은 쪽**이 binding:
|
||||||
|
|
||||||
|
**(a) 밸브 슬루 제약** — 각 commanded 드로우가 제 rate 한계 안에서 피드를 추종:
|
||||||
|
```
|
||||||
|
R_feed ≤ min_i( rate_up_i / K_i ) = min(30/0.95, 30/0.80) = 31.6 kg/hr·min (P binding)
|
||||||
|
→ 200 kg/hr 를 약 6.3분
|
||||||
|
```
|
||||||
|
|
||||||
|
**(b) 동적 불균형 제약** — P의 지연(τ=900s + θ=60s)이 만드는 물질수지 결손:
|
||||||
|
```
|
||||||
|
ΔI(결손, kg/hr) ≈ K_P · (τ_P + θ_P) · R_feed
|
||||||
|
= 0.95 · 960s · (R_feed/60) ≈ 15.2 · R_feed[kg/hr·min]
|
||||||
|
```
|
||||||
|
이 결손이 컬럼에 누적 → 레벨 상승 → D·B 과추출. 허용 밴드 ΔI_allow로 역산:
|
||||||
|
```
|
||||||
|
R_feed ≤ ΔI_allow / 15.2
|
||||||
|
ΔI_allow = 50 kg/hr → R_feed ≤ 3.3 → 200kg/hr 에 약 60분
|
||||||
|
ΔI_allow = 100 → R_feed ≤ 6.6 → 약 30분
|
||||||
|
```
|
||||||
|
|
||||||
|
**핵심 결론**: 밸브 속도론 "6분"이지만, P의 15분 지연 때문에 내부 균형 유지 시 **~1시간 램프**가 맞다. binding은 (b) 동특성이지 (a) 밸브가 아니다. `ΔI_allow`는 운전원이 정하는 손잡이(= 허용 레벨 스윙/과추출량).
|
||||||
|
|
||||||
|
### 3.2 한계치 (ceiling)
|
||||||
|
|
||||||
|
**밸브 포화 상한** (config만으로):
|
||||||
|
```
|
||||||
|
feed_max = min_i( sp_max_i / K_i )
|
||||||
|
P: 2000/0.95 = 2105 ← binding
|
||||||
|
R: 2000/0.80 = 2500
|
||||||
|
D: 1000/0.02 = 50000
|
||||||
|
B: 500/0.03 = 16667
|
||||||
|
→ 1100은 여유 충분 (P_sp=1045, R=880, D=22, B=33 모두 sp_max 이내)
|
||||||
|
```
|
||||||
|
단, **진짜 상한은 더 낮음** (라이브 데이터 필요):
|
||||||
|
- **플러딩**: 내부 traffic ↑ → ΔP ↑. `DeltaPFloodLimit` 대비 투영
|
||||||
|
- **리보일러/스팀**: `SteamOpTag` OP%가 포화(>~95%)하면 분리 붕괴
|
||||||
|
|
||||||
|
### 3.3 엔진 통합 — 자기조절(self-throttling) 램프
|
||||||
|
|
||||||
|
기존 FF 엔진은 "주어진 피드에서 각 스트림 기대치"를 이미 계산. 그 위에 **Feed Ramp Advisor**:
|
||||||
|
1. 목표 피드 타당성 검사(ceiling) → 초과 시 클램프 + 제한 제약 보고
|
||||||
|
2. (a)(b)로 R_feed 산출 → 궤적 `feed(t)=900+R_feed·t`
|
||||||
|
3. 램프 중 레벨·ΔP·프론트 감시 → 밴드 접근 시 R_feed 자동 감속/정지
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. ⚠ 헛점 / 리스크 분석 (이 문서의 핵심)
|
||||||
|
|
||||||
|
### A. 모델 신뢰성 헛점
|
||||||
|
|
||||||
|
| # | 헛점 | 영향 | 비고 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| A1 | **θ·τ가 실측인가 placeholder인가** | R_feed 전부가 이 값에 비례 → 틀리면 램프 전체 오류 | 특히 R의 θ=0/τ=0은 비현실(환류 즉답 가정). config가 추정치일 가능성 큼 → `CrossCorrLagEstimator` 실측으로 교체 필요 |
|
||||||
|
| A2 | **1차 선형 lag 가정** | deficit 공식은 선형. 증류탑은 비선형(분리효율·게인이 부하 의존) | 22% step은 근사 OK일 수 있으나 큰 변화엔 부정확 |
|
||||||
|
| A3 | **운전점 의존 K** | 램프 계산에 config K vs 실측 K_obs 어느 것? 운전점마다 다름 | K_obs MA 기능 이미 존재 → 그쪽 사용 검토 |
|
||||||
|
|
||||||
|
### B. 모델이 빠뜨린 물리 (가장 위험)
|
||||||
|
|
||||||
|
| # | 헛점 | 영향 | 비고 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| B1 | **D·B 제약 미반영** | 정작 우려한 **과추출의 주체가 D·B level loop**인데, binding을 P commanded로만 계산. D·B의 rate_up=0(미설정) → 밸브 포화·레벨 루프 속도 한계가 모델에 없음 | **모순**: P 지연이 만든 결손을 D·B가 흡수(과추출)하는데 D·B 자체 한계는 무시 |
|
||||||
|
| B2 | **에너지 동특성 누락** | 안전 램프 전제 = "피드 올릴 때 reboil/reflux도 비례 상승". R은 commanded지만 **리보일러/스팀은 monitor만**(commanded 아님). 스팀이 못 따라가면 분리 붕괴·프론트 드리프트 | 램프 중 듀티 자동조정 없으면 공식 무의미 |
|
||||||
|
| B3 | **R의 P 종속 연쇄지연** | R=R_f×P_sp(외부환류, P 지연 상속) → 램프 중 reflux도 지연 → 분리 약화 → 프론트 | 연쇄 lag, 단일 τ로 표현 안 됨 |
|
||||||
|
| B4 | **결손→레벨 환산 미정** | deficit(kg/hr)를 레벨 스윙(%)으로 환산하려면 홀드업·단면적·밀도 필요. 없으면 ΔI_allow를 kg/hr로 줘야 해 비직관적 | 운전원은 레벨(%)로 주고 싶을 것 |
|
||||||
|
|
||||||
|
### C. 동적/과도 안전 헛점
|
||||||
|
|
||||||
|
| # | 헛점 | 영향 | 비고 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| C1 | **transient 플러딩** | 정적 ceiling 체크는 램프 중 순간 ΔP 스파이크(reflux 일시 과잉) 못 잡음 | self-throttle이 부분 보완하나 ΔP 측정 자체 지연 존재 |
|
||||||
|
| C2 | **감시 stall 시 폭주** | self-throttle은 라이브 레벨/ΔP에 의존. realtime stall(과거 실제 발생) 시 감시가 멀어버림 | **램프는 신선도 게이트 + stall 시 즉시 freeze 필수**. corroboration 재사용 |
|
||||||
|
| C3 | **방향 비대칭 미처리** | up(부하↑)과 down 동특성 다름(P rate 30↑/60↓). 공식은 up만 | down ramp 별도 유도 필요 |
|
||||||
|
| C4 | **램프완료 ≠ 신평형** | 1100 도달 후에도 τ=900s 때문에 ~15분 더 정착. "완료"와 "평형 도달" 구분 필요 | 정착 판정 기준 미정 |
|
||||||
|
| C5 | **동시 외란** | 램프 중 압력변동·조성변화·상류 트립 겹치면 "다른 건 정상" 전제 붕괴 | transient detection 있으나 램프 vs 외란 구분 필요 |
|
||||||
|
|
||||||
|
### D. 운전/권한 헛점
|
||||||
|
|
||||||
|
| # | 헛점 | 영향 | 비고 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| D1 | **피드 쓰기는 AdvisoryOnly 정면 위반** | 현재 시스템은 advisory-only 정책. 자동 램프 쓰기는 WriteGuard·운전원 ARM·rate clamp 전부 통과해야 | **보고(advisory)와 실행(write) 명확 분리** 필수 |
|
||||||
|
| D2 | **피드를 이 탑이 제어하나?** | ficq-6101이 상류 공정/탱크에서 오면 이 탑이 임의 ramp 불가. 피드 SP 쓰기 권한·상류 제약 확인 안 됨 | 미확인 — 현장 확인 필요 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 미해결 / 필요 데이터
|
||||||
|
|
||||||
|
- D·B 밸브 최대 드로우율 (현재 config 0) 또는 레벨 루프 게인
|
||||||
|
- 라이브 ΔP(`DeltaPTag`)·스팀 OP(`SteamOpTag`) → flooding/듀티 ceiling
|
||||||
|
- 홀드업·단면적·밀도 → 결손 kg/hr ↔ 레벨 % 환산
|
||||||
|
- θ·τ 실측치 (estimator vs config 검증)
|
||||||
|
- 피드(ficq-6101) 쓰기 권한·상류 제약 (현장)
|
||||||
|
|
||||||
|
## 6. 다음 단계 (모두 보류 상태)
|
||||||
|
|
||||||
|
- **(1)** 공식을 **계산기 advisory**로 구현 (목표 피드 입력 → 한계치/램프율/예상시간/binding 제약 표시, 쓰기 없음)
|
||||||
|
- **(2)** 데이터 식별 θ/τ(`CrossCorrLagEstimator`) 연동
|
||||||
|
- **(3)** 라이브 ΔP·스팀으로 flooding/듀티 ceiling 포함
|
||||||
|
- **(우선)** 종이 위 손계산 — 현재 라이브 피드/ΔP/스팀으로 실제 한계치·램프 1회 산출해 숫자 감각 확보
|
||||||
|
|
||||||
|
> 헛점 B1(D·B 제약 미반영)·B2(에너지 동특성)·C2(stall freeze)·D1(쓰기 분리)이 가장 시급한 검토 대상.
|
||||||
|
|
||||||
|
## 7. 추가 브레인스토밍 — 자기조절 캐스케이드 + (목표제거량 + 편차) SP 구조 (2026-06-01 b)
|
||||||
|
|
||||||
|
### 7.1 실제 물리 캐스케이드 (운전원 정정)
|
||||||
|
|
||||||
|
```
|
||||||
|
FICQ-6101(피드)↑
|
||||||
|
→ LI-6111(리보일러 레벨)↑
|
||||||
|
→ TICA-6111A 온도↓ (액 증가/희석)
|
||||||
|
→ 스팀밸브 출력↑ → 스팀투입↑
|
||||||
|
→ 온도↑ → 증발량↑
|
||||||
|
→ LI-6111 레벨 유지
|
||||||
|
```
|
||||||
|
|
||||||
|
**핵심 정정**: LI-6111(리보일러 레벨)은 **B 드로우가 아니라 리보일러 듀티(스팀, TICA-6111A 온도 캐스케이드)로 유지**된다. → 레벨은 *에너지(증발)*, B(중비물)는 *조성 목표* 로 잡는 **decoupled 구조**. 피드 증가가 B 과추출을 강제하지 않는다.
|
||||||
|
|
||||||
|
### 7.2 선행 헛점에 주는 영향
|
||||||
|
|
||||||
|
| 선행 헛점 | 캐스케이드 반영 후 |
|
||||||
|
|---|---|
|
||||||
|
| **B1** (D·B 과추출 강제) | **부분 해소** — 레벨은 듀티가 잡음. 단 FF config가 B를 `LevelDriven by li-6111`로 둔 것은 **모델 오류 의심**(B는 실제 조성구동) → §7.4 |
|
||||||
|
| **B2** (에너지 동특성 "수동") | **재정의** — 스팀은 수동 아님. TICA-6111A 온도 캐스케이드로 **자동 추종**(closed loop). 단 이 루프도 *자체 lag* 보유 → 새 binding 제약 §7.3 |
|
||||||
|
|
||||||
|
### 7.3 새 binding 제약 — 리보일러 에너지 루프 대역폭
|
||||||
|
|
||||||
|
자기조절 캐스케이드는 피드 증가를 **자동 흡수**하지만, 온도/스팀/증발 루프는 자체 시상수(스팀 동특성 + 리보일러 열관성 + 온도측정 지연)를 가진다. 피드를 이보다 빨리 올리면:
|
||||||
|
- TICA-6111A 온도 언더슈트 → 분리 약화(중비물이 P로 상승 / P 오염)
|
||||||
|
- LI-6111 레벨 스윙
|
||||||
|
|
||||||
|
→ 램프율 제약에 **(c) 에너지 루프 제약** 추가. binding = (a)밸브슬루 · (b)생성물 지연결손 · **(c)에너지 루프** 중 **최솟값**.
|
||||||
|
|
||||||
|
**유추 검증**: *최대 피드 RATE 기준으로 SP를 움직이면 자기조절 캐스케이드가 평형 유지하며 증가 피드에 대응* → **맞다.** 단 그 "최대 RATE"는 (a)(b)(c) 중 가장 느린 루프가 결정.
|
||||||
|
|
||||||
|
### 7.4 SP 구조 정정 — (목표제거량) + (advisory 편차)
|
||||||
|
|
||||||
|
**SP = 제거 목표량 + advisory 편차** → **표준 피드포워드(조성×피드) + 피드백 트림(편차) 구조. 맞다.**
|
||||||
|
|
||||||
|
```
|
||||||
|
B_SP(중비물) = [중비물분율(원료분석) × 피드] + 편차_trim
|
||||||
|
D_SP(경비물) = [경비물분율(원료분석) × 피드] + 편차_trim
|
||||||
|
```
|
||||||
|
|
||||||
|
| 항 | 정체 | 비고 |
|
||||||
|
|---|------|------|
|
||||||
|
| **제거 목표량 (base)** | 원료분석 조성분율 × 피드율 | 현재 고정 K(B 0.03 / D 0.02) 대신 **실제 원료분석값**. 분석 갱신 시 갱신 |
|
||||||
|
| **편차 trim (advisory)** | 물질수지 오차 / 조성 드리프트 / 프론트 보정 | **반드시 clamp + rate limit (bounded)** |
|
||||||
|
|
||||||
|
**원래 불만 정면 해결**:
|
||||||
|
- 기존 `B_SP = K×피드` (무제한 상승, 레벨 추종) → 폐기
|
||||||
|
- 신규 `B_SP = 분석목표 + bounded 편차` → base는 물질수지 정합(피드포워드), 편차는 유계 트림(피드백). **runaway 없음.**
|
||||||
|
|
||||||
|
### 7.5 7.4가 남기는 미해결
|
||||||
|
|
||||||
|
- **편차 소스 정의**: 무엇으로? (a) vloss 중 B 귀속분 (b) 조성분석기 드리프트 (c) 프론트 위치 — 측정 가능성 확인
|
||||||
|
- **원료분석 입력 경로**: 분율은 어디서? (랩 수동입력 / 온라인 분석기 / KB) · 갱신 주기
|
||||||
|
- **config 모델 정정**: B·D를 `LevelDriven` → `Commanded(조성구동)` 재분류? li-6111 level_tag은 모니터로 강등? → **현장 확인 필수** (li-6111 실제 제어 주체가 듀티인지)
|
||||||
|
- **편차 한계**: clamp 폭·rate를 제거 목표량의 ±몇 %로?
|
||||||
|
- **(c) 에너지 루프 시상수 식별**: TICA-6111A 온도↔스팀 응답 — 데이터 식별 가능?
|
||||||
|
|
||||||
|
### 7.6 리보일러 듀티 피드포워드 — TI-6103 + TICA-6111A.OP (2026-06-01 c)
|
||||||
|
|
||||||
|
운전원 제안: 원료 프리히터 공급온도 **TI-6103**을 알 수 있고, 현재 평형에서 **TICA-6111A.OP**를 안다. TI-6103↔TICA-6111A ΔT를 감안해 OP가 얼마나 올라야 하는지 제안 가능. (**TICA-6111A.OP → FIQ-6115 스팀투입량** 결정)
|
||||||
|
|
||||||
|
#### 에너지수지
|
||||||
|
```
|
||||||
|
Q_reboiler = 현열(피드 승온) + 잠열(증발)
|
||||||
|
= F·Cp·(T_b − T_feed[TI-6103]) + V·λ
|
||||||
|
필요 스팀 ≈ Q / λ_steam → FIQ-6115 target → OP
|
||||||
|
```
|
||||||
|
- F(피드)·T_feed(TI-6103) = 피드포워드 입력, **둘 다 외란**
|
||||||
|
- **증분형이 강건**: ΔOP ≈ (dOP/dSteam)·ΔSteam, 현재 평형 OP 기준
|
||||||
|
|
||||||
|
#### 핵심 — §7.3 제약 (c)를 완화
|
||||||
|
(c) 에너지 루프 lag가 binding이었던 이유 = TICA PID가 **피드백**(온도 droop 후 반응). 스팀 피드포워드(F·TI-6103로 OP/FIQ-6115 선제 구동)를 더하면 리보일러가 **선제 대응** → 온도 upset 없이 피드 램프 가능. **이 제안은 검증도구일 뿐 아니라 피드램프 가속 디커플러.**
|
||||||
|
|
||||||
|
#### AUTO / MANUAL 활용 (운전원 통찰 — 맞다)
|
||||||
|
| PID 상태 | advisory 역할 |
|
||||||
|
|---|---|
|
||||||
|
| **AUTO** | advisory OP vs 실제 PID OP 비교 → **모델 검증**(정상상태에서만 valid). 일치=모델OK, 괴리=모델오차/미관측외란. **OP 쓰기 금지**(PID 소유), 표시만 |
|
||||||
|
| **MANUAL** | advisory OP = **운전원 의사결정 지원** ("이 피드엔 OP X로") |
|
||||||
|
|
||||||
|
#### 보너스 — TI-6103 자체가 외란 피드포워드
|
||||||
|
피드 일정해도 TI-6103↓(프리히터 파울링/상류 외란) → 현열부하↑ → 스팀 더 필요. advisory가 TICA 온도 droop **전에** 포착. 피드램프와 독립적 외란제거 가치.
|
||||||
|
|
||||||
|
#### 일관성 — 또 같은 구조
|
||||||
|
```
|
||||||
|
OP_advisory = [에너지수지 base(FF)] + [PID/운전원 trim]
|
||||||
|
```
|
||||||
|
B·D 드로우(§7.4)와 **동형**. 온 시스템이 "FF base + bounded 피드백 trim"으로 통일.
|
||||||
|
|
||||||
|
#### 헛점 / 확인필요
|
||||||
|
- **OP↔flow 비선형**: 절대 OP 계산은 밸브특성·스팀압 의존 → **flow 도메인(FIQ-6115 SP) advisory + 증분형**이 강건. **캐스케이드(TICA→FIQ flow loop)인지 OP직결인지 확인 필요**
|
||||||
|
- **AUTO 비교는 정상상태만**: 과도 중 PID OP는 동적/미분동작 포함 → 정상상태 비교만 valid
|
||||||
|
- **물성치**(Cp·λ·λ_steam)·**T_b**(압력·조성 의존, TICA PV 근사) 필요
|
||||||
|
- **효율/열손실**: FF 게인의 미지 효율계수 → **AUTO 정상상태 OP vs 피드 회귀로 역산 보정** 가능
|
||||||
|
- **안전**: 스팀 OP 직접쓰기 고위험 → AUTO=표시만, MANUAL=제안만, AdvisoryOnly 유지(D1)
|
||||||
|
- **상호작용**: 듀티가 선제적이 되면 드로우 trim과의 싸움(§6말미 헛점2) 오히려 **감소**
|
||||||
|
|
||||||
|
### 7.7 결론적 산출물 — FIQ-6115 권장 스팀투입량 (운전원 deliverable)
|
||||||
|
|
||||||
|
**최종적으로 운전원에게 줘야 하는 것 = "FIQ-6115를 얼마로 하라"** (스팀 flow 단위). OP가 아니라 flow로 주면 밸브 비선형(§7.6 헛점) 우회 + 운전원 즉시 실행 가능.
|
||||||
|
|
||||||
|
#### 현재 평형 앵커링 — 물성치 없이도 강건
|
||||||
|
현재 평형(F_cur, FIQ-6115_cur)을 신뢰(플랜트가 찾은 값) → 미지 상수(Cp·λ·효율) **소거**.
|
||||||
|
```
|
||||||
|
FIQ-6115_target ≈ FIQ-6115_cur × [ 잠열분율·(F_new/F_cur)
|
||||||
|
+ 현열분율·(F_new·(T_b−TI6103_new)) / (F_cur·(T_b−TI6103_cur)) ]
|
||||||
|
|
||||||
|
1차 근사: FIQ-6115_target ≈ FIQ-6115_cur × (F_new/F_cur) + TI-6103 현열보정
|
||||||
|
```
|
||||||
|
- 잠열/현열 분율 모르면 → 피드비례(1차) + TI-6103 ΔT 보정으로 시작, **AUTO 정상상태 데이터로 분율 역산** 정밀화
|
||||||
|
- 결과: **"피드 900→1100이면 FIQ-6115를 X→Y kg/hr로"** 운전원에게 직접 제시
|
||||||
|
- "물성치 필요" 헛점(§7.6) 해소 — 절대계산 아닌 **현재 운전점 대비 증분**
|
||||||
|
|
||||||
|
#### advisory 통합 산출물 (한 화면, 한 세트)
|
||||||
|
| 산출물 | 권장값 | 근거 |
|
||||||
|
|---|---|---|
|
||||||
|
| **FIQ-6115 (스팀)** | 목표 flow ("X→Y") | 에너지수지 앵커링 §7.6·7.7 |
|
||||||
|
| **B·D 드로우** | 목표제거량 + 편차 | 조성 §7.4 |
|
||||||
|
| **피드 램프율** | max RATE + 예상시간 | (a)밸브·(b)지연·(c)에너지 §3.1·7.3 |
|
||||||
|
|
||||||
|
→ 피드를 올리되(램프율), 스팀을 **선제** 상향(FIQ-6115), 드로우를 조성목표로 맞춘다. 세 권장이 연동.
|
||||||
|
|
||||||
|
### 7.8 캐스케이드 확인 결과 — OP 직결 (FIQ-6115 측정전용) 확정 (2026-06-01 d)
|
||||||
|
|
||||||
|
**운전원 확인: TICA-6111A.OP는 스팀밸브 직결, FIQ-6115는 측정 전용**(스팀 flow 컨트롤러 없음).
|
||||||
|
|
||||||
|
함의:
|
||||||
|
- 운전원이 직접 넣는 값은 **OP(%)**, FIQ-6115엔 SP가 없다 → "FIQ-6115 SP를 줘라"는 불가
|
||||||
|
- §7.6 **OP↔flow 비선형 헛점 재활성** → 단, FIQ-6115 측정이 있어 해결 가능
|
||||||
|
|
||||||
|
#### 산출물 정정 (해결책)
|
||||||
|
- **1차 deliverable = FIQ-6115 목표 스팀 flow** (에너지수지 앵커링, 견고 — 밸브곡선 불요)
|
||||||
|
- **운전원 handle = OP(%)**. 두 가지 브리지:
|
||||||
|
1. **운전원이 곧 flow 컨트롤러 (MANUAL)**: advisory가 flow 목표("X kg/hr까지")를 주고, 운전원이 OP를 올리며 **FIQ-6115 읽으면서** 도달. **밸브 모델 0 필요.** 가장 정직·견고.
|
||||||
|
2. **시작 OP 제안 (보조)**: 라이브 OP↔FIQ-6115 회귀로 **local gain dFlow/dOP 온라인 추정** → `ΔOP ≈ ΔFlow / local_gain` → "OP X%→Y%부터" 제시해 도달 가속. 운전점 이동 시 재추정.
|
||||||
|
- **AUTO**: OP 자동. FIQ-6115 측정으로 **예측 flow vs 실측 검증** + local gain 역산.
|
||||||
|
|
||||||
|
#### 부가 통찰
|
||||||
|
스팀 공급압 변동 시 OP 고정이어도 flow 드리프트 → **FIQ-6115 측정이 그래서 필수 피드백**. "측정 전용"이 약점이 아니라 강점.
|
||||||
|
|
||||||
|
#### 정정된 스팀 deliverable (§7.7 갱신)
|
||||||
|
| 산출물 | 운전원에게 | handle |
|
||||||
|
|---|---|---|
|
||||||
|
| 스팀 | **FIQ-6115 목표 flow "X→Y kg/hr"** | OP(%) 수동조작 + FIQ-6115 보며 도달 (+ 시작 OP 제안) |
|
||||||
|
|
||||||
|
## 8. 편차(trim) 소스 정의 — 상세 브레인스토밍 (2026-06-01 e)
|
||||||
|
|
||||||
|
### 8.1 편차의 역할 (재확인)
|
||||||
|
`B_SP = [조성분율×피드](base, 개루프 FF) + 편차_trim(피드백)`. base는 개루프라 오차 누적 → **편차가 측정 기반으로 보정**. 관건 = **무엇을 측정해 무엇을 목표로 driving 하나.**
|
||||||
|
|
||||||
|
### 8.2 후보 소스 평가
|
||||||
|
| 소스 | 타임스케일 | 장점 | 치명적 약점 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| (a) 물질수지 vloss | 분~시간 | 질량보존 직접 | **스칼라 — 귀속 불가**(D/P/B·성분·계기바이어스 구분 못함) |
|
||||||
|
| (b) 조성분석(GC/랩) | 분(온라인)~시간(랩) | 직접·정확 | 온라인 없으면 느림, 랩은 trim용 불가 |
|
||||||
|
| (c) 온도·프론트(PCT) | 초~분 | 빠름·상시·**이미 구축**(WO-2/WO-5) | 간접 proxy, 압력·조성 민감, 섹션별 tray 필요 |
|
||||||
|
|
||||||
|
### 8.3 핵심 문제 — vloss를 fast trim에 직접 넣으면 안 됨
|
||||||
|
`vloss=F−(D+P+B)`는 스칼라. 중비물 축적인지 경비물 부족인지 구분 못함(상쇄 가능). **계기 바이어스일 수도** → 보정하면 공정을 계측오차에 맞춰 틀어버림(위험). → **vloss 단독 fast trim 금지.**
|
||||||
|
|
||||||
|
### 8.4 제안 구조 — 2-타임스케일 + 프론트 귀속
|
||||||
|
```
|
||||||
|
B_SP = [중비물분율 × 피드] ← base (FF)
|
||||||
|
+ fast_trim_B ← 하부 프론트/PCT error, bounded
|
||||||
|
base 분율 ← slow re-baseline ← vLossMa + 랩분석 (운전원 리뷰)
|
||||||
|
```
|
||||||
|
1. **fast trim (초~분)**: 섹션별 sensitive-tray PCT/프론트 편차. **B=하부 프론트, D=상부 프론트**. 유계(clamp+rate)
|
||||||
|
2. **귀속 트릭**: vloss를 "**프론트 드리프트하는 스트림**"에 귀속 → 스칼라 모호성을 프론트가 해소(상부 고정·하부 상승=B 오차 국소화)
|
||||||
|
3. **slow re-baseline (시간)**: vLossMa+랩분석으로 base 분율 천천히 재보정. 자동 runaway 아닌 **운전원 리뷰**
|
||||||
|
|
||||||
|
### 8.5 방향(sign) 로직 (calibrate 필요)
|
||||||
|
- **B**: 하부 PCT > ref (heavies 축적/프론트 상승, 제품 위협) → **B↑** / < ref (과추출, 수율손실) → **B↓**
|
||||||
|
- **D**: 상부 대칭
|
||||||
|
|
||||||
|
### 8.6 기존 자산 재사용
|
||||||
|
PCT(WO-2)·sensitive tray·front indicator(WO-5)·vloss/vLossMa(WO-4)·transient gating 전부 이미 코드 존재. **편차 소스 = 이것들을 타임스케일 분리 + 유계로 배선.**
|
||||||
|
|
||||||
|
### 8.7 이 구조의 헛점
|
||||||
|
- **sensitive tray config 1개뿐** → 사이드드로우 2-프론트엔 **상/하 2개 필요**(B 하부·D 상부)
|
||||||
|
- **ref 온도 기준**: 평형 시드(PRef식)면 피드조성 변할 때 ref도 drift → 갱신 방법?
|
||||||
|
- **결합**: B·D trim + 듀티가 모두 온도 이동 → 상호작용. **trim rate ≤ 듀티 대역폭** 제약
|
||||||
|
- **transient 중 온도는 조성 아닌 열동특성** → fast trim에 **transient 게이트 필수**(기존 재사용)
|
||||||
|
- **PCT 부정확**(DTdP 오보정) → proxy 붕괴
|
||||||
|
- **편차 clamp 폭**: 좁으면 실드리프트 못잡고, 넓으면 듀티와 싸움 → 정하는 기준 미정
|
||||||
|
|
||||||
|
### 8.8 sensitive tray 1→2개 + tray 레이아웃 확정 (2026-06-01 h)
|
||||||
|
|
||||||
|
#### 왜 2개인가 — 사이드드로우 = 3제품 = 2 front
|
||||||
|
제품 3개(D 경비물·**P 측류 주생성물 95%**·B 중비물) → 분리 front 2개. **sensitive tray 1개는 한 front만 보고 나머지 구간은 장님** → §8.4 "front 귀속" 트릭 작동 불가(B/D 독립 trim 불가). 제어공학 표준: 2-제품탑=온도1점, **3-제품(사이드드로우)탑=온도 2점**(dual/two-point temperature control).
|
||||||
|
|
||||||
|
현재 `ColumnConfig.SensitiveTrayTag`는 **단일** + C-6111은 null이라 비활성.
|
||||||
|
|
||||||
|
#### 확정된 전체 레이아웃 (P&ID 확인, 2026-06-01 j) — 패킹 3구간
|
||||||
|
> **태그 번호 (확정)**: P&ID는 **10111**(TICA-10111A, TI-10111B/C/D), DCS/DB는 **6111**(tica-6111a, ti-6111b/c/d). **동일 계기 — 10111→6111 치환**(운전원 확인 2026-06-01).
|
||||||
|
```
|
||||||
|
탑정 (pica-6111, 진공/경비물 D)
|
||||||
|
REFLUX DISTRIBUTOR (R ficq-6113 진입)
|
||||||
|
TI-6111D
|
||||||
|
PACKING (상부) — 정류, 제품 vs 경비물 D
|
||||||
|
제품추출노즐 P (ficq-6118) ← 전체높이 70~75%
|
||||||
|
TI-6111C (긴 패킹 상단 = 추출 직하)
|
||||||
|
PACKING (긴 구간) — 주 분리, 제품 vs 중비물 B ★ 핵심
|
||||||
|
TI-6111B
|
||||||
|
원료 PREHEATER DISTRIBUTOR (피드 ficq-6101, TI-6103 온도)
|
||||||
|
PACKING (하부, 짧음) — stripping, 제품 회수 vs B
|
||||||
|
TICA-6111A(TE) — 컬럼 최하부/리보일러부, B 추출 (pi-6111b≈여기)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 패킹 | 위치 | 역할 | bracket 온도 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 상부 | 제품~리플럭스 | 정류(경비물 D 제거) | TI-6111D ↔ TI-6111C |
|
||||||
|
| **중간(가장 김)** | **피드~제품** | **주 분리(중비물 B front)** | **TI-6111B ↔ TI-6111C** |
|
||||||
|
| 하부(짧음) | 리보일러~피드 | stripping(제품 탑저손실 방지) | TICA-6111A ↔ TI-6111B |
|
||||||
|
|
||||||
|
- **이전 오류 수정**: 피드는 "리보일러 바로 위"가 아니라 **하부 짧은 패킹 위 PREHEATER DISTRIBUTOR**로 진입. **피드~제품 긴 패킹이 주 분리 구간** → B front가 최장 패킹에 걸쳐 **해상도 높음**. D 제거는 위쪽 짧은 정류.
|
||||||
|
- **TI-6111D = 리플럭스 직하** → R 즉답. R이 상부 front 조작변수라 위치 이상적
|
||||||
|
- 두 front 모두 단일 단 아닌 **패킹 구배** → 민감도 충분
|
||||||
|
- 제품·TI-6111C가 **70~75% 높이** → 위 25~30%만 정류(D), 아래 70%가 주분리+stripping
|
||||||
|
|
||||||
|
#### ti-6111c 공유 기준 차온 + B 이중신호
|
||||||
|
- **상부 front (D)** = `ΔT(TI-6111C − TI-6111D)` (상부 정류 패킹): 경비물(저비점) 제품쪽 하강 시 구배 변화 → 침투 → **D↑**. **⚠ §10.2-B: TI-6111D는 환류 서브쿨링 오염 → 이 정의 재검토 필요(D 보정/대체)**
|
||||||
|
- **하부 front (B)** = `ΔT(TI-6111C − TI-6111B)` (긴 중간 주분리 패킹): 중비물(고비점) 제품쪽 상승 시 침투 → **B↑**
|
||||||
|
- **(보너스) stripping** = `ΔT(TI-6111B − TICA-6111A)` (하부 짧은 패킹): 제품(저비점)이 탑저로 손실되면 구배 변화 → **제품 탑저손실/B 과추출 조기경보** → B는 신호 2개(중간=중비물 침투 / 하부=제품 손실)
|
||||||
|
- ti-6111c 공유 pivot → 차온 자연 분리 → §8.4 귀속 작동
|
||||||
|
|
||||||
|
#### 보너스 — 제어 위계 명확화
|
||||||
|
- **ti-6111c(PCT) = 제품 품질 proxy = 주 제어변수**(제품 spec). reflux(R)/duty로 1차
|
||||||
|
- 상/하 front(D·B trim) = spec 유지 받치는 2차 보조
|
||||||
|
|
||||||
|
#### 보너스 — 압력 프로파일 보간 (§9 연결)
|
||||||
|
압력 2점(pica-6111 탑정, pi-6111b≈리보일러) → 단높이 선형보간으로 각 온도에 국소압 부여:
|
||||||
|
ti-6111d≈pica-6111 / tica-6111a≈pi-6111b / **ti-6111c·ti-6111b=보간**. → §9 PCT를 단일압이 아닌 **프로파일 기반**으로. ti-6111c 제품온도 보정 정확도가 핵심.
|
||||||
|
|
||||||
|
#### 코드/모델 변경
|
||||||
|
| 현재 | 필요 |
|
||||||
|
|---|---|
|
||||||
|
| `SensitiveTrayTag` (단일) | `UpperSensitiveTrayTag`+`LowerSensitiveTrayTag` (또는 섹션별 차온쌍) |
|
||||||
|
| `st.FrontInd` 1개 | 상/하 2개 인스턴스 |
|
||||||
|
| `ApplyFront`→단일 (state,trim) | 섹션별 반환 |
|
||||||
|
| §8 귀속 | 상부→D trim, 하부→B trim |
|
||||||
|
|
||||||
|
#### sub-헛점 / 확인필요
|
||||||
|
- **two-point 루프 간섭**: D·B 완전독립 아님(reflux/duty·내부 traffic 공유). 디커플링 또는 한쪽 detune 필요할 수 있음(RGA 영역)
|
||||||
|
- **tray 선정**: 각 구간 최민감 지점은 운전 프로파일로 확인(고정가정 위험)
|
||||||
|
- ~~태그 10111 vs 6111~~ → **확정**: 동일계기, P&ID 10111 → DCS 6111 치환
|
||||||
|
- ~~ti-6111b 위치·피드 진입단·ti-6111c~d 중간단~~ → **해소**(2026-06-01 j): 전체 레이아웃 확정. 피드=하부 짧은패킹 위 PREHEATER DIST, ti-6111b=피드 직상, ti-6111c~d 사이=상부 정류 패킹
|
||||||
|
|
||||||
|
## 9. 진공압 프로파일 — pi-6111b 미사용 + ΔP/PCT 함의 (2026-06-01 f)
|
||||||
|
|
||||||
|
### 9.1 현재 실태 (DB 확인, ff_column_config id=1)
|
||||||
|
| 항목 | 값 | 의미 |
|
||||||
|
|---|---|---|
|
||||||
|
| `pressure_tag` | **pica-6111만** | **pi-6111b 미사용** |
|
||||||
|
| `dtdp` | **0.0** | **PCT(압력보정온도) 꺼짐** — pct=raw |
|
||||||
|
| `delta_p_tag` | **null** | ΔP 플러딩 트리거 비활성 |
|
||||||
|
| `sensitive_tray_tag` | **null** | 프론트/θ 기능 비활성 |
|
||||||
|
| `p_ref` | null | 첫 압력 시드 |
|
||||||
|
| `temp_tags` | tica-6111a, ti-6111b, ti-6111c, ti-6111d | 수집됨 |
|
||||||
|
|
||||||
|
- pi-6111b는 **OPC 태그로 수집은 됨**(realtime/history DB 존재) — FF 엔진이 안 읽을 뿐
|
||||||
|
- pica-6111조차 현재 `pUnstable`(과도감지)용뿐 + `PressureBand` 기본 무한대 → 사실상 거의 비작동
|
||||||
|
- **즉 압력/PCT/ΔP/sensitive-tray 서브시스템이 통째로 dormant**
|
||||||
|
|
||||||
|
### 9.2 압력 프로파일 의미
|
||||||
|
진공탑 → 아래로 갈수록 절대압↑. **pica-6111(최상단) < pi-6111b(≈ 리보일러 위, 피드 디스트리뷰터 하단)**.
|
||||||
|
|
||||||
|
**운전원 정정 (2026-06-01 g): pi-6111b ≈ 리보일러 압력**으로 간주. → 탑저 압력이 실측되는 셈.
|
||||||
|
```
|
||||||
|
컬럼 ΔP(전탑, top→bottom) = pi-6111b − pica-6111 (> 0)
|
||||||
|
```
|
||||||
|
함의: **피드가 탑 하부 진입**(디스트리뷰터 하단=리보일러 위) → §7.6 에너지 노드가 한 점에 모임(피드 TI-6103 진입 → pi-6111b 비점까지 승온 → 직하 리보일러 듀티).
|
||||||
|
|
||||||
|
### 9.3 pi-6111b가 우리 설계의 빠진 조각인 이유
|
||||||
|
| 설계 항목 | pi-6111b 기여 |
|
||||||
|
|---|---|
|
||||||
|
| **§3.2 플러딩 ceiling** | 별도 ΔP 트랜스미터 없이 **pi-6111b − pica-6111 = ΔP** → flooding 지표. `delta_p_tag`을 이 식/파생태그로 채움 |
|
||||||
|
| **§7.6/7.7 에너지수지 T_b** | 비점=국소 압력 함수. pi-6111b≈리보일러압이므로 **탑저 비점 = pi-6111b 비점, tica-6111a가 그 실측치** → 추가 ΔP 보정 불요 + **tica-6111a ≈ 탑저조성 비점@pi-6111b** 교차검증 |
|
||||||
|
| **§8 편차 trim PCT proxy** | §8.7 "PCT 부정확→proxy 붕괴" 헛점의 근원. dtdp=0이라 PCT 꺼짐 + 단일 탑정압으론 하부(B 귀속) 보정 부정확. **pi-6111b가 하부 섹션 PCT의 기준압** → §8 B fast-trim 작동 전제 |
|
||||||
|
|
||||||
|
### 9.4 제안 배선
|
||||||
|
- `pi-6111b` 수집값 → **ΔP 파생** = pi-6111b − pica-6111 → `delta_p_tag`(또는 계산 컬럼)로 플러딩 ceiling 공급
|
||||||
|
- **단별 기준압 = 패킹가중 보간**(높이선형 아님, 긴 중간 패킹이 ΔP 대부분): pica-6111(탑정)~pi-6111b(탑저) 사이를 패킹구간/traffic로 분배. ti-6111d≈pica-6111+상부패킹ΔP / **제품·ti-6111c(70~75%높이)≈pica-6111+상부패킹ΔP** / ti-6111b≈+상부+중간패킹ΔP / tica-6111a≈pi-6111b. **제품온도(ti-6111c) PCT 기준압 = 제품 품질추정 직결**
|
||||||
|
- `dtdp` 실측 보정계수로 설정(현재 0=꺼짐) → PCT 활성화
|
||||||
|
- → §8 편차 trim(특히 B 하부)이 비로소 유효해짐 (의존성)
|
||||||
|
|
||||||
|
### 9.5 헛점/확인필요
|
||||||
|
- ~~pi-6111b는 중하부라 탑저는 더 아래 미계측~~ → **해소** (2026-06-01 g): pi-6111b ≈ 리보일러압. 탑저 압력 실측되는 셈, 추가 ΔP 보정 불요
|
||||||
|
- ΔP = pi-6111b − pica-6111 의 부호·스팬 실측 확인 (둘 다 진공, mmHg). 이제 **전탑 ΔP**
|
||||||
|
- 진공계 신선도/stall 게이트 (압력도 corroboration 대상)
|
||||||
|
- tica-6111a(리보일러 온도) = 탑저 비점@pi-6111b 교차검증 활용 — 괴리 시 조성변화/계기이상 신호
|
||||||
|
|
||||||
|
## 10. 온도 프로파일 단조성 · 역전 판정 · 프론트 부호 (2026-06-01 k)
|
||||||
|
|
||||||
|
### 10.1 확정 baseline (운전원)
|
||||||
|
정상 생산 시 **A>B>C>D 단조 감소** (탑저 tica-6111a 최고온 → 탑정 ti-6111d 최저온). A−D ≈ 10°C — 단 그 상당분은 **D의 환류 서브쿨링**(리플럭스 디스트리뷰터 냉액)에서 옴(조성 아님).
|
||||||
|
|
||||||
|
### 10.2 발견된 버그/문제 (코드 확인)
|
||||||
|
| # | 문제 | 영향 | 등급 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| A | **부호 역전 버그** — `DiffTemp.Delta(tHi,tLo)=tHi−tLo` 주석="상단−하단", 그러나 `ApplyFront`(engine.cs:255) 호출=`Delta(temps[0]=A=하단, temps[^1]=D=상단)`=A−D=**하단−상단** → 규약 반대부호 | FrontPositionIndicator `dev>0→프론트상승→환류↑` 매핑이 "상단−하단" 가정 → **트림 권고 반전 + ApplyRecovery sigFront 오판** | 🔴 |
|
||||||
|
| B | **D 환류 서브쿨링 오염** — ti-6111d=리플럭스 직하라 조성 아닌 환류온도 추종 | A−D·ΔT(C−D)가 분리 아닌 환류에 끌림 → §8.8 상부 front(D 사용) 약화 | 🔴 |
|
||||||
|
| C | **역전 가드 부재** — 단조성 검증 없음, 순서 가정 silent | 실제 이상역전(플러딩 등) 미검출 | 🟡 |
|
||||||
|
|
||||||
|
### 10.3 역전(inversion) 판정 — 구체 spec (설계, 미구현)
|
||||||
|
|
||||||
|
#### 입력
|
||||||
|
- **신뢰 구간 = A,B,C** (조성 트레이). C-6111: A=`tica-6111a`, B=`ti-6111b`, C=`ti-6111c`. **D(`ti-6111d`)는 환류 서브쿨링 오염이라 단조 체인에서 제외**(§10.2-B).
|
||||||
|
- 온도는 **PCT 적용값** 사용(§9 압력 프로파일 보간 의존). PCT 미활성(dtdp=0)이면 raw + warning="PCT off, 역전판정 정확도 저하".
|
||||||
|
- **게이팅**: `transient`(피드 이동·압력 불안정·정착대기) 중에는 판정 보류(열동특성 노이즈). 모든 입력 `Good`(신선) 필수, stale 시 보류.
|
||||||
|
|
||||||
|
#### 판정량
|
||||||
|
인접쌍 하강폭(정상 양수):
|
||||||
|
```
|
||||||
|
ΔAB = T(A) − T(B) , ΔBC = T(B) − T(C) // 정상 둘 다 > 0
|
||||||
|
span = T(A) − T(C) // 정상 양수 (분리 강도 지표)
|
||||||
|
```
|
||||||
|
기준값 `spanRef`: cfg 지정 또는 **최초 정상상태에서 시드**(PRef 방식).
|
||||||
|
|
||||||
|
#### 상태 분류 (우선순위 순)
|
||||||
|
| 상태 | 조건 | 의미 | 등급 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **온도역전** | 임의 인접쌍 `ΔAB < −tolInv` 또는 `ΔBC < −tolInv` (상단이 하단보다 더 뜨거움) | 조성 upset / 플러딩 / 센서이상 | 🔴 |
|
||||||
|
| **프로파일 붕괴** | `span < spanCollapseFrac × spanRef` | 분리 손실(평탄화) | 🟠 |
|
||||||
|
| **약화** | `span < spanWarnFrac × spanRef` (붕괴 전 단계) | 분리 여유 감소 | 🟡 |
|
||||||
|
| **정상** | 위 해당 없음 | — | — |
|
||||||
|
|
||||||
|
#### 파라미터 (기본값, 운전 데이터로 튜닝)
|
||||||
|
- `tolInv` = 0.5 °C (센서 노이즈 + 여유; 이 이상 음수라야 역전 인정)
|
||||||
|
- `spanWarnFrac` = 0.5, `spanCollapseFrac` = 0.3 (spanRef 대비)
|
||||||
|
- `spanRef` 시드: 최초 비-transient·전부 Good 인 tick의 span
|
||||||
|
|
||||||
|
#### 조치
|
||||||
|
- **front advice**: 역전/붕괴 시 front trim **HOLD** + confidence 강등(역전 중 front 방향 신뢰 불가).
|
||||||
|
- **ApplyRecovery 연동**: 새 severity 신호 `sigInv`(역전) / `sigCollapse`(붕괴)를 기존 `sigVloss·sigFront·sigDp`와 **병렬 OR**로 추가. (advisory·ARM 게이트 유지 — 자동쓰기 아님.)
|
||||||
|
- **센서 vs 공정 구분(corroboration)**: 역전이 ΔP(`pi-6111b−pica-6111`)·vloss와 **동반·지속**이면 공정(플러딩/조성); 단발·점프성이면 **센서이상 의심** → 역전 신호 억제 + 계기점검 권고. (단독 온도로 공정 단정 금지.)
|
||||||
|
- **D 특수처리**: C−D 쌍은 서브쿨 baseline이라 절대 단조검증서 제외. 필요시 **서브쿨 보정 후 deviation**으로만 별도 모니터(역전 트리거엔 미포함).
|
||||||
|
|
||||||
|
#### 출력 (advisory 필드 추가 제안)
|
||||||
|
`tempProfileState`(정상/약화/붕괴/역전) + `inversionPair`(예 "B-C") + `span`/`spanRef`.
|
||||||
|
|
||||||
|
#### 구현 메모
|
||||||
|
- 신규 순수함수 `TempProfileJudge.Evaluate(temps[A,B,C], spanRef, params)` → 단위테스트(정상/역전/붕괴 각 케이스). `FeedforwardEngine`은 호출만(엔진 로직 최소 변경).
|
||||||
|
- §10.2-A(부호) 버그픽스와 독립. WP2 P6에서 정상 프로파일·역전 재현으로 검증.
|
||||||
|
|
||||||
|
### 10.4 제안 — 프론트 부호 정정
|
||||||
|
- metric을 명시 "상단−하단"으로: `Delta(temps[^1], temps[0])`(D−A) 또는 부호 반전 → FrontPositionIndicator 매핑과 정합.
|
||||||
|
- 단 D 오염 때문에 상부 front는 D 대신: (b1) D를 환류온도 기준 보정, (b2) C 단독 PCT 변화, (b3) D=에너지/서브쿨용 재지정 + 경비물 front는 탑정 조성/분석.
|
||||||
|
- 하부 front(B)는 A,B,C만 쓰므로 부호 정정 후 신뢰 가능.
|
||||||
|
|
||||||
|
### 10.5 작업 항목
|
||||||
|
- (버그픽스, 엔진수정이라 별도) DiffTemp 호출 부호 정정 + 단위테스트.
|
||||||
|
- (WP2 프로브) 정상시 A>B>C>D 확인, A−D≈10 중 환류 서브쿨 기여 측정, 부호 역전 재현.
|
||||||
|
- (§8.8 갱신) 상부 front 센서 D 의존 재검토(b1/b2/b3).
|
||||||
|
|
||||||
|
## 11. 참고
|
||||||
|
|
||||||
|
- `docs/측류추출식-통합유량설정공식.md` (§9~§12 advisory 엔진)
|
||||||
|
- `src/Infrastructure/Control/FeedforwardEngine.cs` (ComputeStream, deadtime/lag/rate)
|
||||||
|
- `src/Core/Application/Feedforward/FeedforwardModels.cs` (StreamConfig)
|
||||||
|
- `docs/운전원교육-FF과도상태-메커니즘.md`
|
||||||
364
plans/안전피드램프-advisory-작업지시서.md
Normal file
364
plans/안전피드램프-advisory-작업지시서.md
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
# 작업지시서 — 안전 피드램프 Advisory (WP1·WP2·WP3)
|
||||||
|
|
||||||
|
> 대상: 다른 LLM/개발자가 단독 실행 가능하도록 작성. 사전 맥락 없이 이 문서 + 참조 문서만으로 수행.
|
||||||
|
> 작성: 2026-06-01. 컬럼: C-6111 PGMEA 측류추출 증류탑.
|
||||||
|
> 설계 근거: `docs/안전피드램프-한계치-브레인스토밍.md` (§0~§9) — **반드시 먼저 통독**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 배경 (요약)
|
||||||
|
|
||||||
|
LevelDriven 드로우가 `recommendedSp=K×피드`를 무제한 상승 표시하는 문제에서 출발 → "피드를 평형 깨지 않고 얼마나·얼마나 빨리 올리나"를 계산하는 **advisory(쓰기 없음)** 로 전환. 본 작업은 그 첫 구현 + 검증 체계.
|
||||||
|
|
||||||
|
작업 패키지:
|
||||||
|
- **WP0** Sim Override Layer (실행자가 입력값을 직접 조정해 자율 시뮬레이션; 제어 쓰기 아님)
|
||||||
|
- **WP1** 검증 시나리오 매트릭스 (문서, 구현 spec 겸 합격기준)
|
||||||
|
- **WP2** 현행 FF 엔진 프로빙 (시뮬레이션으로 baseline 거동 캡처)
|
||||||
|
- **WP3** Feed Ramp Advisor 구현 (read-only 계산기 + 엔드포인트 + 단위테스트)
|
||||||
|
|
||||||
|
실행 순서: **WP1(spec) + WP0(테스트 하네스) → WP2(자율 프로빙) → WP3(구현) → WP3를 WP1로 검증**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0.1 공통 제약 (전 WP 적용, 위반 금지)
|
||||||
|
|
||||||
|
1. **쓰기 절대 금지**: OPC UA 쓰기·DB 쓰기 없음. 현 시스템은 AdvisoryOnly 정책. WP3는 순수 계산 + 조회만.
|
||||||
|
2. **DEMO 시스템**: 모든 실시간 값은 운전원이 주입한 합성값(테스트 벤치). 로직/기능 검증엔 유효하나, 데모 값으로 실제 플랜트 τ/θ·플러딩 임계를 단정하지 말 것. (메모리 `project_demo_system_synthetic_data` 참조.)
|
||||||
|
3. **시뮬레이션 절차 (2가지 경로)**:
|
||||||
|
- **(자율, 권장) Sim Override** — WP0에서 만드는 in-app 입력 오버라이드. 실행자(LLM)가 `POST /api/ff/sim/override`로 입력 태그값을 직접 세팅 → `GET /api/ff/ramp-advisor`/`advisory` 관찰. **운전원 없이 루프 자율 구동.** OPC/제어 SP 쓰기 아님(입력값 치환만).
|
||||||
|
- **(실계측 경로) 운전원 주입** — 운전원이 합성 DCS 값을 맞춰줌. 실행자는 "태그=값" 요청 후 `GET /api/ff/advisory` 또는 `run_sql`(realtime_table)로 관찰.
|
||||||
|
- 두 경로 결과는 일치해야 함(오버라이드는 동일 입력을 in-app으로 대체).
|
||||||
|
4. **JSON 직렬화**: 신규 DTO 반환 시 PascalCase 패스스루 주의 → `[JsonPropertyName("camelCase")]` 명시 (메모리 `reference_json_serializer_pascalcase`). 기존 컨트롤러는 익명객체로 수동 camelCase 처리하는 패턴도 있음 — `GetDashboard` 응답 빌더 참고.
|
||||||
|
5. **빌드/테스트 명령**:
|
||||||
|
- 빌드: `dotnet build src/Web/ExperionCrawler.csproj` → 경고 0 / 에러 0 필수
|
||||||
|
- 테스트: `dotnet test tests/ExperionCrawler.Tests/ExperionCrawler.Tests.csproj`
|
||||||
|
6. **건드리지 말 것**: 기존 `FeedforwardEngine.Tick` 로직, `FeedforwardSupervisor.AutoWriteAsync`, config 스키마(ff_column_config/ff_stream_config). WP3는 **신규 파일 추가** 위주.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0.2 핵심 시스템 사실 (C-6111, column_id=1)
|
||||||
|
|
||||||
|
### 스트림 config (ff_stream_config)
|
||||||
|
| key | flow_tag | role | K(target_coeff) | θ_up/dn(s) | τ(s) | sp_min/max | rate_up/dn(kg/hr·min) | level_tag |
|
||||||
|
|---|---|---|---|---|---|---|---|---|
|
||||||
|
| P | ficq-6118 | Commanded | 0.95 | 60/60 | 900 | 0/2000 | 30/60 | – |
|
||||||
|
| R | ficq-6113 | Commanded | 0.80 | 0/0 | 0 | 0/2000 | 30/30 | – |
|
||||||
|
| D | ficq-6114 | LevelDriven | 0.02 | – | – | 0/1000 | 0/0 | lica-6113 |
|
||||||
|
| B | ficq-6116 | LevelDriven | 0.03 | – | – | 0/500 | 0/0 | li-6111 |
|
||||||
|
|
||||||
|
ProductKey = P. 피드 = ficq-6101. (K합 P+D+B=1.00 물질수지 폐합, R=내부환류.)
|
||||||
|
|
||||||
|
### 컬럼 config (ff_column_config id=1) — 현재 dormant 항목 주의
|
||||||
|
- pressure_tag=**pica-6111만**, sensitive_tray_tag=**null**, delta_p_tag=**null**, steam_op_tag=**null**, p_ref=**null**, dtdp=**0.0**, temp_tags=`tica-6111a,ti-6111b,ti-6111c,ti-6111d`
|
||||||
|
- → 압력/PCT/ΔP/front 서브시스템 전부 비활성
|
||||||
|
|
||||||
|
### 추가 태그 (수집됨, FF 미사용)
|
||||||
|
- `pi-6111b.pv` ≈ 리보일러 진공압 (탑저). `pica-6111.pv` = 탑정 진공압. **전탑 ΔP = pi-6111b − pica-6111**.
|
||||||
|
- `ti-6103.pv` = 원료 프리히터 공급온도. `ficq-6115.pv` = 스팀 투입 flow(측정전용). `tica-6111a.op` = 스팀밸브 OP(밸브직결).
|
||||||
|
- 태그 번호: P&ID는 10111, DCS는 6111 (동일계기, 10111→6111 치환).
|
||||||
|
|
||||||
|
### 물리 레이아웃 (위→아래, 패킹 3구간)
|
||||||
|
```
|
||||||
|
pica-6111 탑정 / REFLUX DIST(R) / TI-6111D / 상부PACKING(정류,D) /
|
||||||
|
제품추출 P(ficq-6118, 70~75%높이) / TI-6111C(제품 pivot) /
|
||||||
|
긴 중간PACKING(주분리,B front) / TI-6111B / PREHEATER DIST(피드,TI-6103) /
|
||||||
|
하부 짧은PACKING(stripping) / TICA-6111A 리보일러(pi-6111b≈여기) → B
|
||||||
|
```
|
||||||
|
|
||||||
|
### 코드 색인
|
||||||
|
| 역할 | 경로 |
|
||||||
|
|---|---|
|
||||||
|
| 엔진(수정금지) | `src/Infrastructure/Control/FeedforwardEngine.cs` |
|
||||||
|
| supervisor (스냅샷 빌드 참고) | `src/Infrastructure/Control/FeedforwardSupervisor.cs` (`BuildSnapshotAsync`) |
|
||||||
|
| config store | `src/Infrastructure/Control/FeedforwardConfigStore.cs` (`LoadAllAsync`) |
|
||||||
|
| 모델 | `src/Core/Application/Feedforward/FeedforwardModels.cs` (ColumnConfig/StreamConfig/PvSnapshot/TagSample) |
|
||||||
|
| stores 인터페이스 | `src/Core/Application/Feedforward/IFeedforwardStores.cs` |
|
||||||
|
| 컨트롤러 | `src/Web/Controllers/FeedforwardController.cs` (route `api/ff`, `GET dashboard`=`_store.GetAll()`) |
|
||||||
|
| 실시간 조회 | `IExperionDbService.GetRealtimeRecordsByTagNamesAsync(tags)` (반환 row: TagName/LiveValue/Timestamp) |
|
||||||
|
| DI 등록 | `src/Web/Program.cs` |
|
||||||
|
| 프론트 | `src/Web/wwwroot/js/ff.js` |
|
||||||
|
| 테스트 | `tests/ExperionCrawler.Tests/` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WP0 — Sim Override Layer (Claude 자율 테스트용 입력 변수)
|
||||||
|
|
||||||
|
### 목적
|
||||||
|
실행자(LLM)가 **운전원 없이 직접 입력값을 조정**해 시뮬레이션 루프를 자율 구동. 임의의 입력 태그(피드/압력/온도/스팀/스트림 PV)를 HTTP로 세팅 → advisor가 그 값을 읽음. **제어 쓰기 아님 — 입력 데이터 치환 계층.**
|
||||||
|
|
||||||
|
### 안전 원칙 (필수)
|
||||||
|
1. **OPC UA·제어 SP 쓰기 절대 없음**. 오버라이드는 *advisor가 읽는 입력값*만 in-memory로 대체.
|
||||||
|
2. **DB 쓰기 없음** (realtime_table 불변). 순수 in-memory 오버라이드 스토어.
|
||||||
|
3. **게이팅**: `appsettings`의 `Feedforward:SimOverrideEnabled=true`(기본 false, DEMO 전용)일 때만 동작. production 플래그면 엔드포인트 403.
|
||||||
|
4. 오버라이드 활성 시 advisory 응답/로그에 `simOverrideActive=true` 명시(은폐 금지).
|
||||||
|
|
||||||
|
### 설계
|
||||||
|
- **`SimOverrideStore`** (싱글톤, in-memory): `volatile bool Enabled`, `ConcurrentDictionary<string,(double value,DateTime ts)> Values`. 메서드: `SetMany(dict)`, `Clear()`, `TryGet(tag,out v)`, `Snapshot()`.
|
||||||
|
- **⚠ thread-safety 필수**: Singleton이므로 동시 HTTP 요청 간 Dictionary 경합 가능. `Dictionary`는 thread-safe하지 않음 → 반드시 `ConcurrentDictionary` 사용. `Enabled`도 ARM64 메모리 모델 고려해 `volatile` 또는 `Interlocked`로 보호.
|
||||||
|
- 경로: `src/Infrastructure/Control/SimOverrideStore.cs` (+ 인터페이스 `ISimOverrideStore` in Core).
|
||||||
|
- **읽기측 통합**: `FeedRampAdvisorService`(WP3-C)가 라이브 태그를 읽을 때, `SimOverrideStore.Enabled && TryGet(tag)` 이면 **오버라이드값 우선**(ts=now로 신선 처리), 없으면 live. 한 곳(태그 read 헬퍼)에서만 분기.
|
||||||
|
- **엔드포인트** (`FeedforwardController`, DEMO 게이트):
|
||||||
|
- `POST /api/ff/sim/override` body `{ "enabled":true, "values":{"ficq-6101.pv":1100,"pica-6111.pv":40,"pi-6111b.pv":80,"ti-6103.pv":150,"ficq-6115.pv":300} }`
|
||||||
|
- `GET /api/ff/sim/override` → 현재 스냅샷
|
||||||
|
- `DELETE /api/ff/sim/override` → Clear + Enabled=false
|
||||||
|
- **DI**: `SimOverrideStore` 싱글톤 등록(Program.cs).
|
||||||
|
|
||||||
|
### 산출물
|
||||||
|
- `ISimOverrideStore`/`SimOverrideStore`, 3개 엔드포인트, DI 등록, appsettings 플래그.
|
||||||
|
|
||||||
|
### 합격기준
|
||||||
|
- `SimOverrideEnabled=true`에서 `POST`로 ficq-6101.pv 세팅 → `GET /api/ff/ramp-advisor`가 그 값을 currentFeed로 사용.
|
||||||
|
- `SimOverrideEnabled=false`(기본)에서 sim 엔드포인트 403, advisor는 live만 사용.
|
||||||
|
- 코드 grep: sim 경로에서 `WriteTagAsync`/SQL write **0건**.
|
||||||
|
|
||||||
|
### 실행자 사용 예 (자율 루프)
|
||||||
|
```
|
||||||
|
curl -s -XPOST :5000/api/ff/sim/override -H 'Content-Type: application/json' \
|
||||||
|
-d '{"enabled":true,"values":{"ficq-6101.pv":900}}'
|
||||||
|
curl -s ':5000/api/ff/ramp-advisor?columnId=1&targetFeed=1100&deltaIAllow=50'
|
||||||
|
# → 기대치(WP1 S1)와 대조
|
||||||
|
curl -s -XDELETE :5000/api/ff/sim/override
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WP1 — 검증 시나리오 매트릭스 (문서)
|
||||||
|
|
||||||
|
### 목적
|
||||||
|
WP3 구현 **전에** "입력값 → 기대 advisory 출력"을 명세. 이 문서가 곧 WP3의 구현 spec이자 합격기준(WP3 단위테스트 = 이 시나리오들).
|
||||||
|
|
||||||
|
### 선행조건
|
||||||
|
- §0.2 숙지, 브레인스토밍 §3·§7 공식 숙지.
|
||||||
|
|
||||||
|
### 산출물
|
||||||
|
- `docs/안전피드램프-검증시나리오매트릭스.md`
|
||||||
|
|
||||||
|
### 상세 단계
|
||||||
|
1. 시나리오 표 형식 정의(열): `ID | 목적 | 주입값(태그=값) | 기대 출력(ceiling/binding, rampRate/binding, rampTimeMin, steamTarget, warnings) | 합격기준`.
|
||||||
|
2. 아래 시나리오를 채울 것 (값·기대치 계산 포함). **숫자는 §0.2 config로 직접 계산해 명시**:
|
||||||
|
|
||||||
|
| ID | 목적 | 주입 | 기대(요지) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| S0 | baseline 평형 | 현 설정값(피드 ~900 등) | 변화요청 없음 → 현상태 표시, warning에 dormant 항목 |
|
||||||
|
| S1 | 피드 증량(동특성 binding) | targetFeed=1100, 압력·조성 고정 | rampRate≈3.29(ΔI=50), binding=**dynamic**, rampTime≈61min, steam ×1.222 |
|
||||||
|
| S2 | 밸브 슬루 binding | (가정) P rate_up=2 로 낮춤 + targetFeed=1100 | rampRate=2/0.95=2.1, binding=**valveSlew** |
|
||||||
|
| S3 | ceiling 초과 목표 | targetFeed=2200 | clampedTarget=2105(=2000/0.95), binding=**P sp_max** |
|
||||||
|
| S4 | flooding ceiling | ΔP(pi-6111b−pica-6111) 크게 주입 + floodLimit 설정 | ceiling이 flooding으로 더 낮아짐, binding=**flooding** |
|
||||||
|
| S5 | TI-6103 하강(현열FF) | 피드 고정(900), ti-6103 150→140, sensibleGain·feedTempRef 지정 | steamTarget↑ = sensibleGain×900×(150−140) 만큼. 피드 무관 외란 FF |
|
||||||
|
| S6 | stale/stall | 태그 timestamp frozen(>stale_sec) | advisory HOLD/무효 + warning=stale |
|
||||||
|
| S7 | 과추출 감지(현행엔진) | B의 ficq-6116.pv 를 0.03×feed 대비 크게 주입, D+P+B≠feed | (현행) mbState "물질수지 불일치" 플래그 |
|
||||||
|
|
||||||
|
3. 각 시나리오에 **검증 방법**(주입 태그 목록 + 관찰 엔드포인트/SQL) 명기.
|
||||||
|
4. S1 worked example 계산을 부록으로 첨부(아래 §부록 공식 사용).
|
||||||
|
|
||||||
|
### 합격기준
|
||||||
|
- 7개 시나리오 모두 주입값·기대출력·합격기준·검증방법이 구체 수치로 채워짐.
|
||||||
|
- 기대 수치가 §부록 공식과 일치(재현 가능).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WP2 — 현행 FF 엔진 프로빙 (baseline 캡처)
|
||||||
|
|
||||||
|
### 목적
|
||||||
|
시뮬레이션으로 현행 엔진의 실제 거동을 캡처 → (a) 코드리딩 주장 검증, (b) WP3 전 baseline 확보, (c) dormant 서브시스템 동작상 확인.
|
||||||
|
|
||||||
|
### 선행조건
|
||||||
|
- 웹앱 가동(`:5000`), `GET /api/ff/advisory` 응답 확인. 운전원에게 값 주입 요청 가능 상태.
|
||||||
|
|
||||||
|
### 산출물
|
||||||
|
- `docs/안전피드램프-현행엔진-프로빙결과.md` (각 프로브: 주입값 → 관찰된 advisory 표)
|
||||||
|
|
||||||
|
### 상세 단계 (각 프로브 = 운전원 주입 요청 → dashboard/SQL 관찰 → 기록)
|
||||||
|
| 프로브 | 주입 요청 | 관찰 포인트 | 예상(코드기준) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| P0 | (없음) 현 상태 | dashboard 전체 | 각 스트림 recommendedSp/valid/grade, vloss/mbState 스냅샷 |
|
||||||
|
| P1 | ficq-6101.pv 900→1100 | B(ficq-6116) recommendedSp | 0.03×ff로 **상승**, clamp/rate 미적용 확인 |
|
||||||
|
| P2 | pica-6111.pv 변동 | transient/pUnstable | PressureBand=max라 **pUnstable 미발화**, PCT=raw(dtdp=0) |
|
||||||
|
| P3 | pi-6111b.pv 변동 | advisory 전체 | **무반응**(미사용) 확인 |
|
||||||
|
| P4 | ficq-6101.pv 급변 | c.transient, valid | transient=true, 스트림 valid=false |
|
||||||
|
| P5 | D+P+B ≠ feed 주입 | mbState, vloss | "물질수지 불일치" |
|
||||||
|
| P6 | 정상 온도프로파일 + front 부호 | frontPositionState/trimAdvice, temps | 정상 A>B>C>D 확인. **DiffTemp 부호버그(브레인스토밍 §10.2-A) 재현**: 프론트 상승/하강 라벨·환류↑/boilup↑ 권고가 반전됐는지. D의 환류 서브쿨 기여 측정 |
|
||||||
|
|
||||||
|
### 합격기준
|
||||||
|
- 6개 프로브 결과가 표로 기록됨.
|
||||||
|
- P1·P2·P3가 코드리딩 주장(B 무제한 상승 / 압력 dormant / pi-6111b 미사용)을 **동작상 확인 또는 반증**. 반증 시 차이를 문서화.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WP3 — Feed Ramp Advisor 구현 (read-only)
|
||||||
|
|
||||||
|
### 목적
|
||||||
|
목표 피드 입력 → **한계치(ceiling) · 램프율(rate) · 예상시간 · binding 제약 · 스팀(FIQ-6115) 목표**를 계산해 반환하는 advisory. **쓰기 없음**. WP1 시나리오를 통과해야 함.
|
||||||
|
|
||||||
|
### 설계
|
||||||
|
|
||||||
|
#### (A) 순수 계산기 (단위테스트 대상) — `FeedRampCalculator`
|
||||||
|
신규: `src/Infrastructure/Control/FeedRampCalculator.cs`. **순수 함수**(부수효과 0)로 작성해 테스트 용이하게.
|
||||||
|
|
||||||
|
```
|
||||||
|
public static FeedRampAdvisory Compute(
|
||||||
|
ColumnConfig cfg,
|
||||||
|
PvSnapshot pv, // 현재 PV (feed/streams/pressure 등)
|
||||||
|
double targetFeed,
|
||||||
|
double deltaIAllow, // 허용 순간 불균형 kg/hr (기본 50)
|
||||||
|
double sensibleGain, // (a) 현열 게인 ≈ Cp_feed/λ_steam [kg스팀/(kg피드·°C)]. NaN/0=현열보정 off+warning
|
||||||
|
double feedTempRef, // (a) 앵커 기준 feed 온도(평형). NaN=현열보정 off+warning
|
||||||
|
RampExtraInputs extra); // pica/pi6111b/ti6103/fiq6115/op 등 부가 태그 값 (옵션)
|
||||||
|
```
|
||||||
|
|
||||||
|
계산 순서:
|
||||||
|
1. `currentFeed = pv.Feed.Value` (Good 아니면 HOLD 반환 + warning=feed-bad).
|
||||||
|
2. **Ceiling**:
|
||||||
|
- `valveCeiling = min over (Commanded ∪ K>0 streams) of (sp_max_i / K_i)`; binding=해당 key.
|
||||||
|
- `floodingCeiling`: extra에 pica·pi6111b 둘 다 있고 `floodLimit`(파라미터/옵션) 있으면: `ΔPnow=pi6111b−pica`; `feedFlood=currentFeed×(floodLimit/ΔPnow)^(1/n)` (n 기본 1.8). 없으면 skip + warning="flooding ceiling 미산정(ΔP/limit 부재)".
|
||||||
|
- `steamCeiling`: 산정 근거(최대 OP/스팀) 없으면 skip + warning.
|
||||||
|
- `ceiling = min(존재하는 것들)`; binding 라벨.
|
||||||
|
3. **Ramp rate** (kg/hr per min):
|
||||||
|
- `(a) valveSlew = min over Commanded (rate_up_i / K_i)`
|
||||||
|
- `(b) dynamic = deltaIAllow × 60 / (K_P × (τ_P + θ_P))` (P=ProductKey, θ_P=ThetaUpSec, τ_P=TauSec)
|
||||||
|
- `(c) energyLoop`: 에너지루프 시상수 입력 있으면 산정, 없으면 skip + warning.
|
||||||
|
- `R_feed = min(존재)`; binding 라벨.
|
||||||
|
4. `clampedTarget = min(targetFeed, ceiling)`.
|
||||||
|
5. `rampTimeMin = max(0, (clampedTarget − currentFeed)) / R_feed` (target<current면 down-ramp: rate_dn 사용 분기 + 별도 표기).
|
||||||
|
6. **Steam target** (extra.fiq6115 있을 때) — (a)안 현열 보정 포함:
|
||||||
|
```
|
||||||
|
fiq6115To = fiq6115Cur × (clampedTarget / currentFeed) // 처리량 비례(앵커 온도 기준)
|
||||||
|
+ sensibleGain × clampedTarget × (feedTempRef − ti6103Now) // 현열 보정(앵커 대비 편차)
|
||||||
|
```
|
||||||
|
- **T_b 소거 유도**: 전량식 `FIQ=[F·Cp·(T_b−T_feed)+c·F]/λs`에서 비례항을 빼면 잔차 = `(Cp/λs)·F·(T0−T1)` → 비점 불필요, `sensibleGain`만으로 충분.
|
||||||
|
- `sensibleGain` 또는 `feedTempRef`가 NaN/0이면 현열항=0 + warning="현열보정 off". `ti6103Now`=extra의 ti-6103 값.
|
||||||
|
- S1(온도 고정: ti6103Now≈feedTempRef)→편차≈0→순수 비례. S5(피드 고정·온도↓)→편차>0→steam↑.
|
||||||
|
- startOP 제안은 local gain 부재 시 omit + warning.
|
||||||
|
7. `warnings[]`: dormant/부재 항목 전부 적재(dtdp=0 PCT off, pi-6111b 미사용, flood/energy/steam 근거 부재 등).
|
||||||
|
|
||||||
|
#### (B) DTO — `src/Core/Application/Feedforward/FeedRampModels.cs`
|
||||||
|
record + `[JsonPropertyName]` camelCase:
|
||||||
|
```
|
||||||
|
FeedRampAdvisory(columnId, currentFeed, targetFeed, clampedTarget,
|
||||||
|
Bound ceiling, Bound rampRate, double rampTimeMin,
|
||||||
|
SteamTarget steam, bool simOverrideActive, string[] warnings)
|
||||||
|
Bound(double value, string binding) // binding 예: "valveSlew@P","dynamic","P sp_max","flooding"
|
||||||
|
SteamTarget(double? fiq6115From, double? fiq6115To, double? startOpPct)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### (C) 서비스 — `FeedRampAdvisorService`
|
||||||
|
신규 `src/Infrastructure/Control/FeedRampAdvisorService.cs`. 라이브 데이터 수집 + 계산기 호출.
|
||||||
|
- 주입: `IFeedforwardConfigStore`, `IExperionDbService`, **`ISimOverrideStore`(WP0)**.
|
||||||
|
- `LoadAllAsync`로 cfg 찾기 → 필요한 태그 목록(feed/streams/pica-6111/pi-6111b/ti-6103/ficq-6115/tica-6111a.op) 구성 → `GetRealtimeRecordsByTagNamesAsync` → `PvSnapshot`+`RampExtraInputs` 빌드(스냅샷 빌드는 `FeedforwardSupervisor.BuildSnapshotAsync` 패턴 참고, **단 복붙 말고 필요한 태그만**) → `FeedRampCalculator.Compute` 호출.
|
||||||
|
- **태그 read 헬퍼 단일 분기**: `SimOverrideStore.Enabled && TryGet(tag)` 면 오버라이드값(ts=now), 아니면 live. 응답에 `simOverrideActive` 플래그 전달.
|
||||||
|
- 신선도: timestamp가 stale_sec 초과면 해당 태그 Good=false → 계산기에서 HOLD/warning.
|
||||||
|
|
||||||
|
#### (D) 엔드포인트 — `FeedforwardController`
|
||||||
|
신규 `[HttpGet("ramp-advisor")]`:
|
||||||
|
```
|
||||||
|
GET /api/ff/ramp-advisor?columnId=1&targetFeed=1100&deltaIAllow=50&floodLimit=&n=1.8&sensibleGain=&feedTempRef=
|
||||||
|
→ FeedRampAdvisory (JSON camelCase)
|
||||||
|
- sensibleGain·feedTempRef: 미전달 시 현열보정 off(+warning). config 필드화는 후속(현재 query/기본).
|
||||||
|
- ⚠ `floodLimit` query param과 `ColumnConfig.DeltaPFloodLimit`(DB 저장) 중복: query param이 config보다 우선(config 있으면 config 값이 기본; query param 전달 시 override). 문서화 필수.
|
||||||
|
```
|
||||||
|
- 읽기 전용. 컨트롤러에 `FeedRampAdvisorService` 주입(생성자 추가).
|
||||||
|
|
||||||
|
#### (E) DI 등록 — `Program.cs`
|
||||||
|
`FeedRampAdvisorService`를 scoped 등록(다른 FF 서비스 등록부 근처).
|
||||||
|
|
||||||
|
#### (F) 단위테스트 — `tests/ExperionCrawler.Tests/FeedRampCalculatorTests.cs`
|
||||||
|
- WP1 시나리오 S1~S5를 `FeedRampCalculator.Compute`에 대한 단위테스트로 작성(합성 ColumnConfig + PvSnapshot 직접 구성, 라이브 불요).
|
||||||
|
- **S5는 `sensibleGain`·`feedTempRef` 인자를 명시 전달**해 현열보정 검증(부록A S5 예제: sensibleGain=0.001, feedTempRef=150, ti6103=140 → steam +9.0).
|
||||||
|
- S7(물질수지 불일치)은 **`FeedRampCalculator` 대상 아님** — mbState는 `FeedforwardEngine`에서만 산출. S7은 WP2(현행엔진 프로빙) 전용. WP3에 포함하려면 통합테스트(`FeedforwardEngine` 경유)로 별도 작성.
|
||||||
|
- 예) S1: C-6111 config + currentFeed=900, targetFeed=1100, ΔI=50 → `rampRate.value≈3.29`(허용오차), `rampRate.binding=="dynamic"`, `rampTimeMin≈60.8`, `ceiling.value≈2105`, `ceiling.binding` P 관련, `steam.fiq6115To≈fiq6115From×1.2222`.
|
||||||
|
|
||||||
|
### 상세 단계 (순서)
|
||||||
|
1. (B) DTO 작성 → 빌드.
|
||||||
|
2. (A) 계산기 작성 → 빌드.
|
||||||
|
3. (F) 단위테스트 작성 → `dotnet test` 통과(= WP1 충족) 까지 (A) 보정.
|
||||||
|
4. (C) 서비스 → (E) DI → (D) 엔드포인트.
|
||||||
|
5. 빌드 경고 0/에러 0.
|
||||||
|
6. (시뮬레이션) 운전원에 S1 값 주입 요청 → `GET /api/ff/ramp-advisor?columnId=1&targetFeed=1100` 응답이 WP1 기대치와 일치 확인.
|
||||||
|
7. (선택, WP3b) `ff.js`에 "피드 램프 계산기" 패널(입력칸+결과표) 추가 — 별도 승인 후.
|
||||||
|
|
||||||
|
### 합격기준
|
||||||
|
- `dotnet build` 경고 0 / 에러 0, `dotnet test` 전건 통과.
|
||||||
|
- WP1 시나리오 S1~S5 단위테스트 통과. (S7은 Engine 레벨 통합테스트로 별도 — 이 문서 범위 외.)
|
||||||
|
- 엔드포인트가 S1 라이브 주입에 대해 기대 JSON 반환(rampRate binding=dynamic, time≈61min, steam ×1.22).
|
||||||
|
- 쓰기(OPC/DB) 호출 **0건** (코드 grep으로 확인: WriteTagAsync/Insert/Update 미사용).
|
||||||
|
- 모든 미산정 항목이 `warnings[]`에 노출(은폐 금지).
|
||||||
|
|
||||||
|
### 비범위 (이번 WP3 제외 — 후속)
|
||||||
|
- 편차 trim / sensitive tray 2-point / 압력 서브시스템 깨우기 / 에너지루프 시상수 식별 / 자동쓰기. (브레인스토밍 §7.5·§8·§9 — 별도 작업지시서.)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 부록 A. 공식 요약 (재현용)
|
||||||
|
|
||||||
|
```
|
||||||
|
[Ceiling]
|
||||||
|
valveCeiling = min_i( sp_max_i / K_i )
|
||||||
|
floodingCeiling = currentFeed × (floodLimit / ΔPnow)^(1/n), ΔPnow = pi6111b − pica6111
|
||||||
|
ceiling = min(available)
|
||||||
|
|
||||||
|
[Ramp rate, kg/hr per min]
|
||||||
|
(a) valveSlew = min_i( rate_up_i / K_i ) (Commanded)
|
||||||
|
(b) dynamic = ΔI_allow × 60 / (K_P × (τ_P + θ_P)) (P=ProductKey, 초 단위 τ,θ)
|
||||||
|
(c) energyLoop= (에너지루프 시상수 기반, 입력시)
|
||||||
|
R_feed = min(available)
|
||||||
|
|
||||||
|
[Time] rampTimeMin = (clampedTarget − currentFeed) / R_feed
|
||||||
|
[Steam] fiq6115To = fiq6115Cur × (clampedTarget/currentFeed)
|
||||||
|
+ sensibleGain × clampedTarget × (feedTempRef − ti6103Now) // (a) 현열보정
|
||||||
|
sensibleGain ≈ Cp_feed/λ_steam [kg스팀/(kg피드·°C)]; feedTempRef=앵커 feed온도
|
||||||
|
```
|
||||||
|
|
||||||
|
### C-6111 worked example (S1: 900→1100, ΔI=50)
|
||||||
|
```
|
||||||
|
valveSlew = 30/0.95 = 31.6
|
||||||
|
dynamic = 50×60 / (0.95×(900+60)) = 3000/912 = 3.29 ← binding
|
||||||
|
R_feed = 3.29 kg/hr·min
|
||||||
|
rampTime = (1100−900)/3.29 = 60.8 min
|
||||||
|
valveCeiling = min(2000/0.95, 2000/0.8, 1000/0.02, 500/0.03) = 2105 (P)
|
||||||
|
steam = fiq6115Cur × 1100/900 = ×1.2222 (S1: ti6103=feedTempRef → 현열항 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
### C-6111 worked example (S5: 피드 900 고정, TI-6103 150→140, sensibleGain=0.001, feedTempRef=150)
|
||||||
|
```
|
||||||
|
처리량비례 = fiq6115Cur × 900/900 = fiq6115Cur (변화 0)
|
||||||
|
현열보정 = 0.001 × 900 × (150 − 140) = 9.0 kg/hr
|
||||||
|
fiq6115To = fiq6115Cur + 9.0 ← steam↑ (피드 변화 없이 TI-6103 외란만으로)
|
||||||
|
※ sensibleGain=0.001은 DEMO placeholder. 실제는 Cp_feed/λ_steam로 캘리브레이션.
|
||||||
|
```
|
||||||
|
|
||||||
|
## 부록 B. 진단 결과 (2026-06-01, diagnosis-checklist.md §1~§8 수행)
|
||||||
|
|
||||||
|
### 발견된 문제점
|
||||||
|
|
||||||
|
| # | 항목 | 등급 | 상태 |
|
||||||
|
|---|------|------|------|
|
||||||
|
| 1 | `SimOverrideStore`에 `ConcurrentDictionary` + `volatile bool` 미명시 — Singleton 동시성 경합 위험(ARM64) | 🟠 MED | WP0 §96에 수정 반영 |
|
||||||
|
| 2 | S7(mbState)를 `FeedRampCalculator.Compute` 단위테스트 대상으로 지정 — S7은 Engine 전용, Calculator로 테스트 불가 | 🟠 MED | WP3 §253·§267 수정 반영 |
|
||||||
|
| 3 | `floodLimit` query param과 `ColumnConfig.DeltaPFloodLimit`(DB) 이중 소스 — 우선순위 불명확 | 🟡 LOW | WP3 §244에 주석 추가 |
|
||||||
|
| 4 | `appsettings.json`에 `Feedforward:SimOverrideEnabled` 섹션 없음 — 구현 시 누락 주의 | 🟡 LOW | 사전 공유로 대체 |
|
||||||
|
| 5 | `RampExtraInputs`가 C-6111 태그 hardcode — 타 컬럼 확장 시 ColumnConfig 확장 필요 | 🟡 LOW | 현 스코프(C-6111) 한정 |
|
||||||
|
| 6 | **S5(스팀/TI-6103)가 #2와 동형 모순** — 스팀 1차식은 피드 고정 시 변화=0인데 S5는 steam↑ 기대. 현열부하는 앵커링으로 소거 불가 → 별도 게인 필수 | 🟠 MED | **해소 (a 확정)** |
|
||||||
|
|
||||||
|
### #6 해소 = (a) 확정 (2026-06-01)
|
||||||
|
- **`sensibleGain`(≈Cp/λ_steam) + `feedTempRef`(앵커 feed온도) 파라미터 도입**. 현열보정 = `sensibleGain × clampedTarget × (feedTempRef − ti6103Now)`.
|
||||||
|
- **T_b 소거 유도**: 전량식에서 처리량비례항을 빼면 잔차 = `(Cp/λs)·F·(T0−T1)` → 비점 불필요, 게인 1개로 충분.
|
||||||
|
- S5 mandatory 유지(WP3-F·§270). 두 파라미터 NaN/0이면 현열항 0 + warning(안전 기본).
|
||||||
|
- 반영: Compute 시그니처(§198~), step6(§220~), 엔드포인트 query param, 부록A 공식·S5 예제.
|
||||||
|
|
||||||
|
### 진단 보강 (Opus 재검토)
|
||||||
|
- **#1 보강**: `ConcurrentDictionary`는 per-key 안전만 보장. `SetMany`+`Snapshot` 그룹 원자성은 미보장 → 일관된 다중태그 스냅샷이 필요하면 lock 또는 immutable-dict swap. (순차 테스트 사용엔 무방.)
|
||||||
|
- **#5 보강**: `steam_op_tag`는 ColumnConfig에 이미 존재 → 그건 config에서 읽고, config에 없는 태그(pi-6111b/ti-6103/ficq-6115)만 하드코딩+TODO.
|
||||||
|
- **(b) 공식 일반화(minor)**: dynamic 제약은 P만이 아니라 lagging Commanded 전체 합 `ΔI×60/Σ K_i(τ_i+θ_i)`이 정확. C-6111은 P만 τ≠0이라 결과 동일.
|
||||||
|
|
||||||
|
### 교차 검증 결과 (STEP 6)
|
||||||
|
- 이미 수정된 문제(Q1): 없음
|
||||||
|
- 다른 레이어에서 처리(Q2): 없음
|
||||||
|
- 의도적 설계(Q3): #4·#5는 Phase I 스코프 한정으로 의도적
|
||||||
|
- 재현 불가(Q4): 없음
|
||||||
|
- **누락(Opus 추가)**: #6 (S5/스팀 현열항 모순) — 진단 체크리스트가 #2(S7)는 잡았으나 동형인 S5는 놓침
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 부록 C. 참조 문서
|
||||||
|
- `docs/안전피드램프-한계치-브레인스토밍.md` (설계 전문 §0~§9)
|
||||||
|
- 메모리: `project_safe_feed_ramp_brainstorm`, `project_demo_system_synthetic_data`, `reference_json_serializer_pascalcase`, `project_sidedraw_ff_advisory`
|
||||||
Reference in New Issue
Block a user