# Feedforward Advisory — 과도상태(Transient) 메커니즘
## 운전원 교육 자료

> 대상: C-6111 PGMEA 측류추출 증류탑 FF(Feedforward Advisory) 시스템
> 버전: 2026-05 Phase I

---

## 1. 개요

FF 시스템은 Feed(공급유량) 변동 시 각 스트림(P/R/D/B)의 **권장 SP(Setpoint)를 실시간 계산**하여 운전원에게 제시합니다. 그러나 Feed나 압력이 불안정할 때는 권장값을 곧바로 신뢰할 수 없습니다. 이때 **과도상태(Transient)** 메커니즘이 작동하여 권장값을 "참고용"으로 전환하고, 안정화될 때까지 기다립니다.

### ⚠️ 중요: FF는 Advisory(보조지표)입니다

**FF 시스템은 DCS의 실제 Setpoint(SP)를 절대 변경하지 않습니다.** Transient 여부와 관계없이:
- DCS SP는 운전원이 설정한 값 그대로 유지됨
- FF는 권장값(Recommended SP)을 화면에 표시만 함
- 운전원이 권장값을 검토한 후 **직접 DCS에 입력**해야 적용됨
- Transient 중에는 권장값에 `valid=false`(신뢰도 낮음) 플래그만 추가됨

즉, FF가 transient 상태라고 해서 **공정에 실제 변화가 일어나지는 않습니다.** 단지 운전원이 참고할 권장 숫자가 "아직 믿을 만한 상태가 아니다"라는 신호일 뿐입니다.

---

## 2. Transient 진입 조건

Transient는 다음 **3가지 조건** 중 하나라도 만족하면 발동합니다.

| 조건 | 감지 방식 | 파라미터 | 기본값 |
|:----|:---------|:---------|:------|
| **① FEED 이동** | Feed 유량의 순간변화율(미분)이 임계 초과 | `FeedMoveThreshold` | **5%/분** |
| **② 압력 불안정** | 압력PV가 필터 추종 범위 이탈 | `PressureBand` | **3.0** |
| **③ 정착 대기 중** | 위 조건이 해제된 후 SettleTimer가 0이 아님 | `SettleSec` | **1800초(30분)** |

### 2.1 FEED 이동 감지 — 상세

```
FeedFilter: 1차 저역통과필터 (τ=300초, 시정수 5분)
  목적: 공급유량의 순간 노이즈 제거, 실질적인 변화만 포착

FeedDeriv: 필터 출력의 미분값 (틱당 변화량 → 분당 변화율)
  moving = |dF| × 60 > FeedMoveThreshold (기본 5%/분)
```

예:
- Feed가 820→1000으로 180만큼 변화
- FeedFilter가 300초 시정수로 부드럽게 추종
- 1차 틱(2초)에서 dF ≈ (821.2-820)/2 = 0.6/sec = 36/min
- **36 > 5 → moving = true**

### 2.2 압력 불안정 감지 — 상세

```
PressFilter: 1차 저역통과필터 (τ=60초)
  목적: 압력 신호의 고주파 진동 제거

pUnstable = |압력PV - PressFilter출력| > PressureBand (기본 3.0)
```

의미: 필터가 추종 가능한 범위를 실제 압력이 벗어나면 "불안정"으로 판단.

### 2.3 정착 대기(SettleTimer) — 상세

```
if (moving || pUnstable)
    SettleTimer = SettleSec (1800초)  // ← 리셋
else
    SettleTimer = max(0, SettleTimer - ScanSec)
```

Transient 조건이 해제되어도 **SettleTimer가 0이 될 때까지(최대 30분) transient 유지.**

---

## 3. Transient 상태에서의 동작

### 3.1 UI 표시

```
┌─────────────────────────────────────────────────────┐
│  과도상태: 압력 불안정 — 권장값 정착 대기            │
│                                                     │
│  스트림 │ PV    │ 권장 SP   │ Δ     │ 신뢰         │
│  P      │ 780.2 │ 779.0    │ -1.2  │ A (흐림)     │
│  R      │ 620.0 │ 623.2    │ +3.2  │ A (흐림)     │
│  D      │ 16.5  │ 16.4     │ -0.1  │ B (흐림)     │
│  B      │ 24.8  │ 24.6     │ -0.2  │ B (흐림)     │
│                                                     │
│  물질수지: 정착 대기 (1795s)                         │
└─────────────────────────────────────────────────────┘
```

- 모든 스트림의 권장값이 **valid = false** (회색/흐리게 표시, `.ff-stale`)
- 권장값 계산은 **내부적으로 계속 진행**되지만, 운전원 화면에서는 "참고용" 표시
- 물질수지(V_loss, 수율) 계산 **중단**
- 우측 하단에 정착 대기 시간 카운트다운

### 3.2 Transient 중 Recommended SP는 어떻게 되나?

**Recommended SP는 계속 업데이트됩니다. 이전값에 고정되지 않습니다.**

```
예: Feed 820→1000 step, P stream 기준

t=0min  Feed step, transient 시작
        P_rec = 779 (deadtime 중, 이전 Feed≈820 기준)
t=1min  P_rec = 781 (deadtime 끝나며 새 Feed 반영 시작)
t=5min  P_rec = 799 (Lag τ=900s로 서서히 상승)
t=15min P_rec = 861
t=30min P_rec = 916 (transient 해제, valid=true 전환)
t=45min P_rec = 950 (정상상태 도달)
```

계산 자체는 멈추지 않습니다:
- FeedFilter, PressFilter, DeadTimeBuffer, Lag, RateLimiter 모두 **정상 작동**
- Recommended SP도 매 틱(2초)마다 **계속 재계산되어 갱신됨**
- **단, `valid=false` 플래그만 붙어서 화면에 흐리게 출력**

즉, transient가 풀리는 순간 **이미 최신 Feed를 반영한 권장값이 valid=true로 전환**됩니다.

---

## 4. Transient 종료 후 — 정상 상태 전환

### 조건
```
moving = false AND pUnstable = false AND SettleTimer = 0
```

### 전환 효과
1. 모든 스트림 `valid = true` — 권장값 본격 표시
2. 물질수지 계산 재개:
   ```
   V_loss = FeedFilter출력 - (D_PV + P_PV + B_PV)
   수율   = 100 × P_PV / FeedFilter출력
   ```
3. MassBalanceState 평가:
   - `|V_loss| > 0.03 × Feed` → **"물질수지 불일치(계측 점검)"**
   - `V_loss < 0` → **"음의 손실(스팬 오류 의심)"**
   - else → **"정상"**

### 주의: Transient 해제 ≠ 정상상태 도달

Transient가 풀려도 P stream의 Lag(τ=900초=15분)가 아직 정착 중일 수 있음:

```
예) Feed 820→1000 변경 시:
  t=0분    Feed step, transient 시작
  t=30분   SettleTimer=0, transient 해제
           → P 권장은 아직 950(최종값)에 도달 전 (약 910~920)
  t=45분   P 권장 95% 도달 (3τ)
```

운전원은 transient 해제 후에도 **권장값이 서서히 움직이는 것**을 정상으로 이해해야 함.

---

## 5. 스트림별 동작 차이

| 역할 | Deadtime | Lag | Rate Limit | Transient 영향 |
|:----|:---------|:----|:-----------|:---------------|
| **P** (Commanded) | θ=60초 | τ=900초 | 30/min | valid=false만 적용, 계산은 계속 |
| **R** (Reflux) | P 경유(상속) | P 경유 | 30/min | P와 동일 |
| **D** (LevelDriven) | 없음 | 없음 | 없음 | `K×Feed` 즉시 반영, valid=false |
| **B** (LevelDriven) | 없음 | 없음 | 없음 | `K×Feed` 즉시 반영, valid=false |

**LevelDriven**은 단순 비례식:
```
D_rec = 0.02 × FeedFilter출력
B_rec = 0.03 × FeedFilter출력
```
deadtime/lag이 없으므로 Feed 변동에 즉시 반응하지만, 어디까지나 **기대치(Feedforward bias)**입니다. 실제 SP는 레벨 제어기(LIC)가 결정합니다.

---

## 6. 설정 파라미터 튜닝 가이드

| 파라미터 | 현재값 | 느슨하게 | 엄격하게 | 영향 |
|:---------|:-------|:---------|:---------|:-----|
| `FeedMoveThreshold` | 5/분 | ↑ 증가 | ↓ 감소 | 크면 Feed 변동 둔감, 작으면 민감 |
| `PressureBand` | 3.0 | ↑ 증가 | ↓ 감소 | 크면 압력 둔감, 작으면 민감 |
| `SettleSec` | 1800초 | ↓ 감소 | ↑ 증가 | 작으면 빨리 해제, 크면 오래 대기 |
| `FeedFilterTauSec` | 300초 | ↓ 감소 | ↑ 증가 | 작으면 빠른 반응, 크면 늦은 반응 |
| `PressFilterTauSec` | 60초 | ↓ 감소 | ↑ 증가 | 작으면 압력 빠른 추종, 크면 늦음 |

### 튜닝 예시

**"transient가 너무 자주 걸려요" →**
- `FeedMoveThreshold` 증가 (예: 5→8) — 미세 Feed 변동 무시
- `PressureBand` 증가 (예: 3→5) — 압력 진동 허용폭 확대
- 단, 너무 느슨하면 실제 불안정 상황을 놓칠 수 있음

**"transient가 너무 오래 가요" →**
- `SettleSec` 감소 (예: 1800→900) — 정착 대기시간 단축
- 단, 30분은 의도된 값 — 압력/Feed가 안정된 후에도 일정 시간 관찰하도록 설계

---

## 7. 실제 운전 시나리오 예시

### 시나리오 1: Feed 정상 증가 (의도적)

```
운전 조작: FICQ-6101 SP를 820→1000으로 변경
FF 반응:
  1. FeedDeriv 36/min → transient 시작
  2. 30분간 valid=false (흐림 표시)
  3. 30분 후 valid=true 전환
     - P 권장 ≈ 910 (아직 950 도달 전, Lag 진행 중)
     - D 권장 ≈ 20 (0.02 × 1000)
     - B 권장 ≈ 30 (0.03 × 1000)
  4. 약 45분 후 P 권장 950에 정착
```

운전원 행동:
- transient 중에는 권장값을 **참고**만 하고, 자신의 판단으로 SP 조정
- transient 해제 후 권장값이 합리적이면 추종
- P 권장이 최종값(950)에 도달하는 건 **15분 더 걸림** 인지

### 시나리오 2: 압력 진동 (진공펌프 기동)

```
현상: PICA-6111 압력이 3torr 이상 진동
FF 반응:
  1. pUnstable = true → transient 시작
  2. SettleTimer 1800초 리셋
  3. 압력 안정 후에도 30분간 transient 유지
```

운전원 행동:
- 진공계 안정화 확인
- transient가 불편하면 `SettleSec` 또는 `PressureBand` 조정 검토

### 시나리오 3: Feed 미세 변동 (transient 미진입)

```
Feed 820→830 (+10, 약 1.2% 변화)
FF 반응:
  1. FeedDeriv ≈ 2/min → 5 이하 → moving=false
  2. Transient 미진입 → 권장값 계속 유효
  3. P 권장: 0.95×830 ≈ 788.5 (lag/rate 적용)
```

---

## 8. FAQ

**Q: transient 중인데 권장값이 보이긴 하는데 흐려요. 왜죠?**
A: 계산은 계속되지만 운전원이 **아직 신뢰할 단계가 아니다**는 의미입니다. 압력이나 Feed가 안정된 후 30분이 지나면 선명하게 전환됩니다.

**Q: transient를 강제로 해제할 수 있나요?**
A: 현재 UI에는 강제 해제 기능이 없습니다. 설정에서 `SettleSec`을 0으로 줄이면 transient 시간을 없앨 수 있습니다. 단, 권장값의 신뢰성이 떨어질 수 있습니다.

**Q: transient 중에도 권장값을 SP에 반영해야 하나요?**
A: **아니요.** transient 중 권장값은 "참고용"입니다. 운전원의 경험과 판단으로 SP를 결정하세요. transient 해제 후 권장값을 검토하고 반영하세요.

**Q: P stream 권장값이 왜 이렇게 느리게 변하나요?**
A: Lag 시정수 τ=900초(15분) 때문입니다. Feed 변화가 Deadtime(60초)을 거쳐 Lag에 들어가면 15분에 걸쳐 서서히 정착합니다. 이는 공정의 실제 응답 특성을 모델링한 것입니다.

**Q: LevelDriven(D/B)은 왜 deadtime/lag이 없나요?**
A: D/B는 레벨 제어기(LIC)가 실제 SP를 결정합니다. FF가 계산하는 값은 **기대치(bias)**일 뿐입니다. 실제 레벨 제어 루프가 deadtime/lag을 처리하므로, FF 단에서는 즉시 반영해도 무방합니다.
