2026-W33 週報:把 10 秒缺口的兩端補起來¶
第三份週報,本週 5 張卡,是目前為止產量最高的一週(五個工作日五張,佇列沒有落後)。
W32 建立了 NFPA 110 的 10 秒預算,但留了一個沒回答的問題:那 10 秒,誰在撐? 本週前後兩端一起補上——dc-08 / dc-09 補前端(電池撐住那 10 秒),dc-06 補後端(燃油決定發電機接手後能撐多久),中間夾著把電分出去的兩張盤卡(dc-07 / dc-07b)。
節奏備註:
dc-07原稿 14238 字元、dc-09原稿 11929 字元,兩張都超過 10000 上限被迫就地拆出dc-07b與dc-09b。W32 週報說過「排dc-08前先想清楚要不要主動拆」——結果拆的不是dc-08,是它的前後鄰居。規律開始清楚了:只要一張卡同時包含「額定語意」與「測試/合規制度」,就是兩張。 佇列剩餘項目請照這個規則預先掃一遍,不要每次都在寫到一半才發現。
本週卡片¶
| 卡 | 標題 | 這張卡最關鍵的一個事實 |
|---|---|---|
dc-06 |
日用油箱與儲油槽 | 續航不是把油量加總除以耗油率——燃油是一張圖不是一個總和。移走任一元件後的最小值才是可用數字(本週實例:31.78 h 的總量,逐一移除後只剩 16.40 h;共用一顆泵時剩 1.03 h) |
dc-07 |
低壓主配電盤 — 額定電流體系 | 同一個物理量有四個合法數值(InA / Inc / Ing / RDF)。任何叫 rated_current 的單一欄位都會在某次容量檢討時害到人——它到底是哪一個? |
dc-07b |
短路耐受與保護協調 | Icc 是「一對設備共同擁有的屬性」,不是這面盤的屬性。上游斷路器一換,那 65 kA 就該失效,而現行直覺(額定放在 device 上)沒有任何機制做得到 |
dc-08 |
UPS 不斷電系統(雙轉換式) | 負載率告警的分母是 n_required × 最小成員容量,不是單機銘牌。同一組 UPS,67.5% 與 90% 都是「正確」的負載率,但只有後者會讓你在故障前就知道要擴容 |
dc-09 |
UPS 電池組(VRLA vs 鋰電) | runtime 的四個數字差 1.8 倍(規格 8 / 現況 13.1 / N−1 後 9.1 / N−1 且 EOL 7.3 分鐘),而儀表板通常顯示的是第一個 |
串起來¶
一、全鏈第一次出現「時間」這個容量維度¶
dc-01 ~ dc-05 的容量單位全部是功率:kVA、kW、A。它們回答的是「同時能供多少」。本週兩張卡換了單位:
| 卡 | 容量單位 | 換算成時間的方式 |
|---|---|---|
dc-06 |
公升(能量的代理) | 可達油量 ÷ 耗油率(負載率) → 小時級 |
dc-09 |
W/cell 曲線 → kWh | 查表 × Peukert × 老化 × 溫度 → 分鐘級 |
於是整條備援鏈第一次可以畫在時間軸上,而不是拓撲圖上:
市電消失
│
├─ 0 s ────────────── 11.09 s ─────────────────── 12 h ────────→ 補油卡車
│ ↑ ↑ ↑
│ 電池 dc-09 發電機 dc-05 儲油 dc-06
│ 分鐘級(7.3–13.1) 小時級 Uptime Tier 要求
│
└─ UPS dc-08 是決定「現在用哪一段」的那台機器——它自己不儲能
兩段之間有一個必須明寫的不變式:電池 runtime(最壞情況) > 發電機起動到穩定帶載的時間 × 安全係數。本週 dc-09 的加分題就是把它寫成告警規則(10 s × 20 = 200 s)。用本週的數字驗算:N−1 且 EOL 時 7.3 min = 438 s,過關,但餘裕來自運氣不是設計——沒有人算過這條式子,它只是碰巧成立。
這也是模型第一次需要一條「跨三個實體」的規則(BatteryBank × RedundancyGroup × Genset)。告警掛在任何單一設備上都寫不出來——這是「DCIM 不能只做設備清單」的第一個具體證據。
二、電力路徑上,誰在誰上游¶
市電 dc-01 → MV dc-03 → 變壓器 dc-02 ─┐
├→ ATS dc-04 → LV 主盤 dc-07 ──→ UPS dc-08 ──→(dc-10 STS / dc-11 PDU)
燃料 dc-06 → 發電機 dc-05 ─────────────┘ ↑ ↑
[保護層 dc-07b] [電池 dc-09]
疊在盤上的邊 掛在直流匯流排
三件事值得停下來看:
(1)dc-06 與 dc-09 是同一種形狀,但過去三週沒被認出來。
兩者都是儲能節點:不在電力路徑上(電不從油箱流過、也不從電池流過),但決定了路徑能中斷多久。W32 說「發電機是全鏈唯一一台上游不是電的設備」——本週補完:它的上游是 dc-06,而 dc-08 的上游除了電還有 dc-09。
FuelTank 與 BatteryString 應該共用一個抽象(capacity / usable(非全部可取)/ depletion_rate(load) / autonomy() 為推導值 / EOL 或補充機制)。兩張卡各自發明了一套算法,但骨架幾乎同構——見下面連貫性檢視第 2 點。
(2)dc-07b 是全鏈第一張「不是節點也不是設備」的卡。
Icw / Icc 掛在盤上勉強算屬性,但 SelectivityPair 明確是邊的屬性:選擇性是「上游這顆與下游那顆的關係」,換掉任一端就整格失效。W32 從 (genset, ats) 輪替第一次碰到邊上的約束,本週是第二次,而且更根本——保護協調整層都住在邊上。 現在的 DeviceRegistry 設計(節點字典 + upstream_id)沒有地方掛它,因為邊還沒有身分。這件事已經被三張卡點名(dc-03b 互鎖規則、dc-05c ATS 輪替、dc-07b 選擇性),不能再拖。
(3)冷卻鏈這週沒被點名,但欠款還在。
W32 留下的問題(冰水主機/CRAH 接 UPS 後面還是直吃發電機)本週沒有新資訊,因為五張卡全在電力鏈上。但 dc-08 給了一個新的判準:接在 UPS 後面的東西,其 kW 全數計入 n_minus_1_kw() 的分子。1 MW 機房把冷卻掛進 UPS,UPS 群組要大一輪(且電池 runtime 全部重算)。這不再只是「切換時會不會跳」的可靠度問題,而是直接改變 UPS 採購容量的成本問題——問 facility 的急迫度因此升一級。
三、本週母題:上限有多個競爭來源,而「誰綁死的」比「上限是多少」更有用¶
三週三個母題,一次比一次抽象:
| 週次 | 母題 |
|---|---|
| W31 | 單一欄位裝不下一個事實(數字要帶著量測條件) |
| W32 | 有些事實根本不住在欄位裡(住在序列、存量、事實與規則的多對多裡) |
| W33 | 上限是多個候選取 min/max,回傳裸數字就丟掉了最有用的資訊 |
本週五張卡全部是這個形狀,沒有例外:
| 卡 | 上限 | 候選來源 | 取 |
|---|---|---|---|
dc-06 |
autonomy_hours |
逐一移除每個 tank/component 的情境 | min |
dc-07 |
max_continuous |
元件額定×80%×溫度降額 / 群組 Ing = Inc × RDF |
min |
dc-07b |
available_fault_ka |
每個合法 SystemConfig(tie 開/閉、幾台並聯) |
max |
dc-08 |
usable_kw |
rating_kw / rating_kva × output_pf |
min |
dc-09 |
runtime_min |
曲線查表 → Peukert → 老化 → 溫度(連乘不是取 min,但同樣多來源) | 連乘 |
只有 dc-07 的骨架明確要求回傳 (284.0, "assembly_ing") 而非裸浮點數,理由講得最清楚:
「怎麼放寬」取決於誰綁死的。
這句話對另外四張同樣成立,但另外四張都回傳裸數字。這是本週最該立刻推廣的一個模式,而且它有一個立即可驗證的好處——dc-07 驗收表裡那四行:
rdf=0.8, MCCB → (284.0, "assembly_ing")
rdf=0.8, LVPCB → (284.0, "assembly_ing") ← 花錢換 100% 額定斷路器,上限完全沒動
rdf=1.0, MCCB → (320.0, "device") ← 綁死的來源換人了
rdf=1.0, LVPCB → (355.0, "device")
第二行是一張採購決策的成本表。 只回傳 284.0,你不會知道那筆升級的錢是白花的。
四、第三次撞上「只有故障當下才會被用到的功能」¶
| 卡 | 功能 | 平時可觀測嗎 | 模型只能存什麼 |
|---|---|---|---|
dc-05c |
發電機起動能力 | ❌ 停著的機所有讀值都正常 | last_test_at + 到期告警 |
dc-06 |
燃油品質 | ❌ 沒有感測器會叫你 | next_polish_due(純日期推導) |
dc-07b |
ZSI 邏輯正確性 | ❌ 正常運轉時不會動作 | last_zsi_functional_test_at |
三張卡,三個不同子系統,同一個結論:
凡是「只有故障當下才會被使用的功能」,都必須有一個測試日期欄位;沒有它,資料庫會沉默地說謊——而且所有儀表板都是綠的。
出現三次就不該再各自實作第四次。這已經夠格抽成一個共用結構(PeriodicVerification),細節見連貫性檢視第 1 點。
還有一個更尖銳的變形,本週第一次出現: dc-07b 演算 2 的 tie 閉合違規是事前可算的——不必等故障、不必做測試,只要枚舉配置就知道「這個配置本身違規」。這跟上面三個「必須靠測試才知道」剛好相反,而且更好:
可算型的正確歸宿不是告警,是互鎖——連回 dc-03b 那套 R1–R7 守衛規則。能在實體上封死的,不要放進監控系統當成一條會被人 ack 掉的告警。
五、「保護等級降級」是狀態不是屬性——第三次¶
| 卡 | 降級狀態 | 誰造成的 | 會不會忘記還原 |
|---|---|---|---|
dc-03b |
interlock_defeated |
人為,為了維修 | 會 |
dc-07b |
erms_engaged |
人為,為了人身安全 | 會(且會讓選擇性整層失效) |
dc-08 |
mode == STATIC_BYPASS / MAINTENANCE_BYPASS |
半自動/人為 | 會 |
三者共同的形狀完全一致:設備看起來正常、遙測全綠、但保護等級已經降級,而且降級是人為操作造成的、有正當理由、且極易忘記還原。
dc-08 的骨架把它做得最好(operating_mode 是狀態機不是布林,告警依 mode 分岔,MAINTENANCE_BYPASS 降為 INFO 但仍要計時),dc-07b 只寫了 erms_engaged: bool,dc-03b 至今沒有實作。
收斂方向:一個共用的「降級狀態」實體 —— engaged_at / engaged_by / work_order_id / expected_restore_at / 逾時升級規則。三次都自己寫一遍,第四次(dc-10 STS 的手動旁路)還是會再寫一遍。
六、本週兩張卡都有「來源分歧」,而且都指向同一種話術¶
本軌跡第一次連續兩張卡出現來源分歧段,值得並排看:
| 卡 | 分歧 | 分歧的本質 |
|---|---|---|
dc-08 |
ECO / eConversion 算不算不打折的保護?Schneider 說等同 Class 1,Vertiv 說是 marketing hype 且 VFD 保證不了 Class 1 | 兩邊可能在講不同的切換(高效模式→逆變器 vs 逆變器→旁路),毫秒數不可直接比 |
dc-09 |
VRLA 撐幾年?型錄 10 年 design life vs Schneider WP229 的 3–6 年 service life(TCO 取 4 年) | 兩邊講的是不同的量:理想條件的設計值 vs 含溫度/循環/DoD 的實際值 |
共同點不是「廠商在騙人」,是「兩個數字量的不是同一件事,而行銷語言剛好讓它們長得一樣」。 這正是 W31 母題(數字必須帶著量測條件)在採購場景的實戰版——也是為什麼 dc-09 要求 design_life_years 與 service_life_est_years 必須是兩個欄位。塞進同一欄的系統,連「我們是不是被坑了」都問不出口。
這兩個分歧本身就是下週最好的兩個提問(見下面 Q3)。
自我測驗¶
Q1(事實回憶). 一面 3200 A 低壓盤,某饋出迴路裝 400 A MCCB、Inc = 355 A、該區段實測 RDF = 0.8。這條迴路的設計連續電流 Ib = 300 A。過得了嗎?如果改用 100% 額定的 LVPCB 呢?
答案
過不了,而且換 LVPCB 也救不了。
候選 1(元件) :400 × 0.8(MCCB 的 80% 連續負載規則)× 1.0(35°C)= 320 A
候選 2(群組) :Ing = Inc × RDF = 355 × 0.8 = 284 A
max_continuous = min(320, 284) = 284 A ← 綁死的是「群組」
Ib = 300 > 284 → violation
換成 LVPCB(100% 額定)後候選 1 變成 400 A,但 min(400, 284) 還是 284——綁死的來源根本不是元件。這就是為什麼回傳值必須是 (284.0, "assembly_ing") 而不是 284.0:只有帶著來源鍵,你才知道那筆升級的錢是白花的。
把 RDF 提到 1.0(要求廠商逐路 Ib 做溫升驗證)才是有效的介入:min(320, 355) = (320.0, "device"),綁死的來源換人了。
再加一個容易忽略的方向——環境溫度會反超成為瓶頸:ambient_c = 45 且 rdf = 1.0 時,320 × 0.95 × 0.95 = (288.8, "device"),仍然擋不住 300 A。機電空間夏天沒做降額,跟 RDF 沒寫,是兩個獨立的坑。
對你的模型:Circuit 需要 in_a / inc_a / ing_a 三個電流欄位加上所屬 Section.rdf,並加 CHECK in_a >= inc_a >= ing_a。Assembly → Section → Circuit 三層不能扁平化,因為 RDF 與相互加熱是區段層級的性質——少了 Section,Σ(Inc × RDF) ≤ InA 這條唯一的容量真相根本寫不出來。
Q2(事實回憶). 廠商報「這組電池滿載 8 分鐘」。你的負載只有一半,能撐 16 分鐘嗎?
答案
不是 16,是 19.0 分鐘——比直覺多,而且方向是反的。
放得慢,電池的有效容量變大。很多人記得「電池不是線性的」,但把方向記反了——以為打折,其實是紅利。真正的打折在別的地方:
| 打折 | 係數 | 8 分鐘變成 |
|---|---|---|
| 老化(IEEE 485 aging factor 1.25 = 1/0.8) | ×0.8 | EOL 時全部再砍兩成 |
| 溫度(低溫內阻上升) | 再少幾 % | — |
| 負載率(Peukert) | 視方向 | 半載 19.0、90% 載 9.1 |
所以同一組電池有四個都「正確」的 runtime:規格 8 / 現況(67.5% 載)13.1 / N−1 後(90% 載)9.1 / N−1 且 EOL 7.3 分鐘。最大與最小差 1.8 倍,而儀表板通常顯示的是那個 8。
對你的模型:容量必須存曲線(discharge_rating: [(minutes, w_per_cell)])不是純量,runtime 是查表+插值+Peukert+老化的衍生值。而且插值不准外推(w_per_cell_at(60) 應該 raise)——外推放電曲線是實務大忌,表格外面的地方廠商沒測過。
Q3(應用). 一面 LV 盤標 Icw = 50 kA / 1 s,接在 2000 kVA / 380 V / Z = 6% 的變壓器下游。單台運轉時剛好過關。什麼情況下這面盤會超過額定?這件事需要等到故障才知道嗎?
答案
不需要等,事前純算就知道;而且正確的處置不是告警,是互鎖。
單台:Isc = 2,000,000 / (√3 × 380 × 0.06) = 2,000,000 / 39.49 ≈ 50.6 kA
50.6 kA vs Icw 50 kA → 勉強過(本身已經沒有餘裕)
tie 閉合、兩台變壓器並聯:≈ 101.2 kA
101.2 > 50 → 這面盤在該配置下「本身就是違規的」
冗餘在這一刻變成負債:平常 tie 閉合是為了維護時不斷電(dc-03b 的 concurrent maintainability),但它同時讓可用故障電流翻倍。你為了提高可用度做的事,讓保護裝置失去承受能力。
對你的模型:available_fault_ka 不是常數,是系統配置的函數。要有 SystemConfiguration 維度(tie 位置、幾台電源並聯),耐受檢查跑所有配置取 max:
這產生一條事前可算、不必等故障的告警——但更好的歸宿是把它交給 dc-03b 那套 R1–R7 守衛規則,用三選二互鎖從實體上封死該配置。能在硬體上封死的,不要放進監控系統當成一條會被人 ack 掉的告警。
第二層追問:若這面盤標的不是 Icw 而是 Icc(條件式短路耐受,例如 65 kA 但綁定上游 SCPD 型號 XYZ-1),現場換成 ABC-9 之後這個 65 kA 還算數嗎? 不算。而且模型必須回 ("UNKNOWN", 原因) 而非 fallback 到 65——條件式額定是一對設備共同擁有的屬性,Icc 這一列必須外鍵指向上游 SCPD 的型號,否則換一顆斷路器不會有任何機制讓那筆評等失效。
Q4(應用). 4 台 500 kW UPS 組成 N+1(n_required = 3),負載 1350 kW。監控畫面顯示每台 67.5%、一切正常。掉一台之後,電池還撐得住發電機起動嗎?把數字算完,然後說出這條規則為什麼不能掛在任何一台設備上。
答案
算得出來,也過得了關——但這個「過關」不是設計出來的,是碰巧的。
容量:capacity_kw = 4 × 500 = 2000 kW
n_minus_1_kw = n_required × 最小成員 usable_kw = 3 × 500 = 1500 kW
load_pct = 1350 / 1500 = 90.0% ← 不是 67.5%
per_unit_now = 1350 / 4 / 500 = 67.5% ← 畫面上顯示的那個
per_unit_after_fail = 1350 / 3 / 500 = 90.0%
電池:67.5% 載 → 8 × (1/0.675)^1.25 = 13.1 min
90.0% 載 → 8 × (1/0.900)^1.25 = 9.1 min
EOL 再 ×0.8 = 7.3 min = 438 s
對照 W32 的發電機時序:
開放轉換總時序 11.09 s
最壞情況(三次 crank 到 overcrank lockout)78 s
438 / 78 = 5.6 倍餘裕 → 過關
三個要點:
-
90.0%才是有用的數字,67.5%是安慰劑。 群組負載率的分母必須是n_required × 最小成員容量,因為 N+1 的意義就是「掉一台之後還要撐住」。用capacity_kw當分母的系統,會在容量真正見底的前一刻都顯示綠燈。順帶注意load_kw = 1200時load_pct恰為 80.0,而告警規則是> 80——邊界值不觸發,這是驗收表刻意埋的一行。 -
餘裕是運氣不是設計。 438 s vs 78 s 看起來很寬,但沒有人算過這條式子。三個獨立變化都會吃掉它:電池過了 EOL 沒換(
dc-09演算 2:32 °C 環境下 10 年設計壽命實際只有 5.8 年)、負載長高、或發電機起動時間隨電池老化變長(W32 的crank_time漂移)。三者都在往同一個方向走,而且互相獨立。 -
這條規則跨三個實體,所以不能掛在任何一台設備上。
RedundancyGroup.n_required ─┐
BatteryBank.discharge_rating ├→ 「N−1 時 EOL runtime < 起動時間 × 安全係數」→ CRITICAL
Genset.start_sequence ─┘
對你的模型:告警規則本身必須是一等公民(有 id、有輸入實體清單、有版本),而不是散在各個設備型別的 method 裡。這是 dc-05c 「規則必須是資料列不是 enum 值」的第二次出現,只是這次驅動它的不是合規制度,是物理。
Q5(建模判斷). 本週五張卡都在算 min / max,其中三個地方回傳裸數字會直接害到人。哪三個?該用什麼統一形狀取代?
答案
三個地方:
| 位置 | 現在回傳 | 丟掉了什麼 | 代價 |
|---|---|---|---|
dc-08 usable_kw() |
500.0 |
綁死的是 rating_kw 還是 rating_kva × pf? |
想擴容時不知道該換機還是改功因,可能買錯 |
dc-06 concurrently_maintainable_hours() |
16.40 |
是哪個元件被移走造成的? | 不知道該去修哪一顆泵——這正是這個數字唯一的用途 |
dc-09 runtime_min() |
7.3 |
是哪一層打折造成的(負載率/老化/溫度)? | 分不清「該換電池」還是「該降負載」還是「該修空調」 |
dc-07 的 max_continuous() 是唯一做對的(回 (284.0, "assembly_ing")),dc-07b 的 effective_withstand_ka() 做對了一半(有理由字串,但把 "UNKNOWN" 塞進 float 的位置)。
統一形狀——一個帶出處的量,同時解決「誰綁死的」與「這個值可能不存在」:
from dataclasses import dataclass
from enum import Enum
class Unknown(Enum):
UNKNOWN = "unknown" # 唯一的 sentinel,不要用字串
@dataclass(frozen=True)
class Bound:
value: float | Unknown
binding_source: str # "assembly_ing" / "pump-1_removed" / "aging" / ...
reason: str = "" # UNKNOWN 時必填
candidates: dict[str, float] | None = None # 全部候選,除錯與「放寬要花多少錢」用
def __float__(self): # 誘惑最大的一行,刻意不提供
raise TypeError("Bound 不可隱式轉 float——請顯式取 .value 並處理 UNKNOWN")
三個設計決定值得說清楚:
-
UNKNOWN必須是型別層級的東西,不是"UNKNOWN"字串也不是None。dc-07的verify_ina()在rdf is None時要回UNKNOWN而非True——未驗證不等於通過。台灣兩套盤體標準並行,代表模型必須能誠實表達「這面盤沒有這個數字」,而不是塞 0、塞in_a、或塞一個型錄猜來的值。用字串當 sentinel,早晚有人float()它。 -
拒絕隱式轉 float 是刻意的摩擦。 只要能隱式轉,呼叫端就會退化回裸數字,三個月後又是一堆
if x > y。 -
candidates不是除錯用的裝飾。 Q1 那四行對照表就是從它印出來的——「換 100% 額定斷路器上限完全沒動」這件事只有保留全部候選才看得見,而它是一筆採購決策。
一句話總結本週的建模躍遷:W31 教你「一個欄位裝不下一個事實」,W32 教你「有些事實不住在欄位裡」,W33 教你「有些答案不是一個數,是一個數加上它的來歷」。
間隔複習¶
本週正式排程生效——這是本軌跡第一次真的做間隔重複。
| 週次 | 抽兩週前 | 抽四週前 |
|---|---|---|
| W33(本週) | W31 的卡(dc-01 ~ dc-03b)✅ |
尚無(W29 無卡片) |
| W34 | W32 的卡(dc-04 ~ dc-05c) |
尚無(W30 無卡片) |
| W35 | W33 的卡(dc-06 ~ dc-09) |
W31 的卡(第二次) |
| W36 | W34 | W32 的卡(第二次) |
抽中的是 dc-02 變壓器(W31,2026-07-29)。挑它的理由不是隨機:它在 W31 留下的一個結論,本週才第一次真的兌現。
複習題(W31 dc-02 × 本週 dc-07b). dc-02 說 impedance_pct 是「跨設備約束的來源,不是裝飾欄位」。這句話在本週具體長成了什麼?如果有人把變壓器從 6% 阻抗換成 5%,你的系統該有什麼反應?
答案
兌現的方式是 Q3 那條式子——dc-07b 演算 1 整段就是 dc-02 那句話的可執行版本:
Isc = kVA / (√3 × V × Z%)
2000 kVA / 380 V / 6% → 50.6 kA
2000 kVA / 380 V / 5% → 60.8 kA ← 阻抗變小,故障電流變大
dc-02 的欄位,決定了 dc-07 那面盤的合法性。 這是全模型第一次「A 的欄位決定 B 的合法性」,W31 當時只能寫成一句叮嚀,本週才有第二個設備可以真的接上去。
換成 5% 阻抗後,系統該有的反應(三層,缺一不可):
- 立刻重算所有下游盤的耐受檢查,且要跑遍所有
SystemConfiguration:單台 60.8 kA 已經超過Icw = 50 kA——這面盤在單台運轉下就違規了,不必等 tie 閉合。 - 把所有
Icc(條件式額定)標記為 stale,因為條件式額定綁定的是特定上游 SCPD 與特定的預期故障電流。 - 把所有
SelectivityPair標記為invalidated_by這次變更——選擇性是在特定故障電流下驗證的,partial(limit_ka=35)在 60.8 kA 下當然也不成立。
反過來看更值得記:阻抗小的變壓器壓降小、效率看起來好,採購時容易被當成優點;但它同時把下游的短路電流頂上去,可能讓整面盤與所有斷路器規格失效。「更好的變壓器」讓下游變違規——這種反直覺的耦合,正是為什麼跨設備約束必須是可執行的驗證規則,而不是留在單線圖的註解裡。
對你的模型:需要一條「變更影響分析」的路徑——改一個欄位,能查出所有依賴它的推導值與驗證結論。這比告警更早一步:它作用在變更審查的當下,而不是事故的當下。
四週前(W29):尚無。 本軌跡起始於 2026-07-28,W29 無卡片。W35 起雙軌全開(同時抽兩週前與四週前),屆時每份週報會多兩題。
本週的 model code 連貫性檢視¶
先結算舊帳:
| 來源 | 項目 | 狀態 |
|---|---|---|
| W31 #2 | 邊存在兩端 | ⚠️ 仍未收斂,本週 SelectivityPair 讓它變成真正的痛點 |
| W31 #3 | id 參照 vs 物件內含 | ⚠️ 仍未收斂,本週又製造了兩種新用法(見下面 #3) |
| W32 #4 | DeviceRegistry 缺席 |
🔴 W32 說「必須在 dc-07/dc-08 之前」——期限已過,節點數如預期翻倍 |
| W32 #7 | Measured 值物件 |
⚠️ 本週出現第四、五個實例(w_per_cell_at 的量測條件、ambient_c_monthly_avg) |
本週新增六處。與前兩週不同的是:本週沒有任何一處會產生錯誤數字——五張卡的驗收表彼此對得上,dc-09 甚至主動接回 dc-08 演算 3 的 67.5% → 90%,數字一致。問題全部是結構性的,代價會在 dc-10 ~ dc-16 那七張卡(節點數再翻一倍)一次付清。
🔴 1. Assembly 這個名字現在指向兩個不同的類別¶
dc-07 定義 Assembly(id, ina_a, verified_to, sections);dc-07b 開頭寫「接續 dc-07 的 Assembly / Section / Circuit 往上疊保護層」,然後重新定義了一個 Assembly(id, ratings, upstream_scpd_model)——欄位完全不重疊。
兩張卡是同一天前後拆出來的,這個碰撞幾乎是拆卡的必然副作用,但它是本週唯一一個「兩份 code 直接無法合併」的地方。
收斂建議:一個 Assembly,兩組關注點分開掛:
@dataclass
class Assembly:
id: str
ina_a: float
verified_to: Verified
sections: list[Section] = field(default_factory=list)
# 保護層(dc-07b)
ratings: list[ShortCircuitRating] = field(default_factory=list)
upstream_scpd_model: str | None = None
effective_withstand_ka() 與 max_continuous() 是同一個物件的兩個問題——一個問「平常能過多少電」,一個問「出事時撐不撐得住」,本來就該在同一個型別上。
🔴 2. FuelTank 與 BatteryString 是同構的,卻各寫了一套¶
兩者的結構幾乎逐項對應,但沒有任何共用抽象:
| 概念 | dc-06 |
dc-09 |
|---|---|---|
| 銘牌容量 | capacity_l |
discharge_rating 曲線 |
| 可用量(≠ 全部) | usable_l()(DAY 扣 critical_low/BULK 扣沉積層) |
energy_kwh() 的 0.8 DoD |
| 抽取率 | consumption_lph()(負載率的函數) |
runtime_min() 的 Peukert |
| 續航 | autonomy_hours() |
runtime_min() |
| 劣化 | 燃油週轉/polishing | service_life_years() |
| 補充 | DayTankCycle 補油循環 |
充電(尚未建模) |
收斂建議:抽一個 EnergyStore 協定 —— usable() / depletion_rate(load) / autonomy()(一律推導,不存欄位)/ degradation_state()。好處具體有三個:
- 儀表板可以一視同仁畫「還能撐多久」,不必對每個型別寫一個分支;
dc-20儲冷槽(第二輪冷卻鏈)第三次撞上同一個形狀時,直接實作協定即可;- 「續航是推導值不是欄位」這條規則只需寫一次,而不是每張卡重新叮嚀一遍——它已經被叮嚀三次了。
🟡 3. 實體關聯的風格,本週又多了兩種¶
W31 #3 至今未收斂,本週把樣本數推到五種:
dc-06 : FuelPath.source / dest → 物件內含
dc-07 : Assembly.sections → 物件內含
dc-07b: SelectivityPair.upstream → 物件內含(Breaker)
dc-08 : RedundancyGroup.members → 物件內含(Ups)
dc-09 : BatteryBank.ups_id → 字串 id ← 第一個回到 id 參照的
dc-09 是本週唯一用 id 的,而且它是對的——電池與 UPS 是跨卡引用,物件內含在這裡會製造循環(Ups 要知道自己的電池、BatteryBank 要知道自己的 UPS)。
收斂建議:訂一條可以照著做的規則,不要再每張卡臨場決定——
持久化層一律 id 參照;
DeviceRegistry.resolve()產生的執行期圖才用物件參照。跨卡(跨子系統)的關聯永遠是 id。
DeviceRegistry 已經被 W31、W32 各點名一次,本週是第三次。它的缺席現在有了具體代價:SelectivityPair 需要邊有身分,BatteryBank.ups_id 是個沒有任何東西保證存在的裸字串,跟 W32 說的 TestEvent.initiating_ats_id 一模一樣。
🟡 4. 告警各自為政,形狀已經有三種¶
dc-06 : next_polish_due 到期 → 只在敘述裡,無 code
dc-07b: check() 回違規配置名稱清單 → list[str]
dc-08 : alarms() → list[tuple[str, str]](裸字串 severity)
dc-09 : 加分題的 CRITICAL 規則 → 只在敘述裡,無 code
收斂建議:Alarm(severity: Severity, code: str, message: str, entity_ids: list[str], raised_at)。三個理由:
severity用 Enum,否則"CRITICAL"與"Critical"遲早並存;code是穩定識別碼,message才是人看的——沒有 code 就沒辦法做去重、抑制與 runbook 對應,而dc-08已經有一條「同一件事分 CRITICAL / INFO 兩種嚴重度」的規則(static vs maintenance bypass),正是最需要穩定 code 的形狀;entity_ids是複數,因為 Q4 那條規則同時讀三個實體。單數entity_id現在就已經裝不下。
🟡 5. 「上限取 min」的回傳形狀不一致(=自我測驗 Q5)¶
不重複展開,結論是 Bound 值物件。與前四點的差別:這一點改動最小、收益最立即(Q1 那張採購對照表直接從 candidates 印出來),建議第一個做。
🟡 6. 命名漂移:usable_* 這個前綴已經有四種說法¶
W32 #6 講的是單位後綴(_s / _ms / _min),本週是動詞:
dc-06 : usable_l() ← 銘牌扣掉不可用
dc-07 : max_continuous() ← 同一件事
dc-08 : usable_kw() ← 同一件事
dc-09 : deliverable_kw() ← 同一件事
四個名字、一個概念。收斂建議:一律 usable_<unit>(),max_continuous 與 deliverable_kw 改名。同時把 W32 #6 的單位後綴一起補完——兩者都是純機械改動,合併成一次 rename 比分兩次便宜。
優先序(本週沒有會產生錯誤數字的項目,所以排序依據換成「拖下去多貴」):
本週該問 facility 的問題¶
五張卡共提出 15 個問題,去重後選 3 個下週真的拿去問人的。挑選標準沿用前兩週:「現在問還來得及改,晚問就固化了」。本週三題剛好落在三個不同的固化時點——採購(已快來不及)/ commissioning(唯一機會)/ 現在就能問(但沒人會主動說)。
Q1 — 問 盤體供應商 / 機電設計單位(⚠️ 採購階段,最急)¶
「低壓盤的驗證標準是 CNS 13542 還是 CNS 15783-1(IEC 61439)?請給溫升測試報告編號。 若是前者,
Inc/Ing/RDF這三個數字從哪裡拿?規格書裡有沒有寫 RDF、寫多少?當初有沒有逐路提供Ib,還是讓廠商套用假定負載係數? 各饋出斷路器是 80% 還是 100% 額定?機電空間夏季實測溫度多少,有沒有做過 35 °C 以上的降額? 另外短路側:每面盤標的是Icw(無條件)還是Icc(條件式)?若是Icc,指定的上游 SCPD 是哪個型號,現場裝的是不是那一顆?Icw標 1 s 還是 3 s?」
為什麼是這題:一次拿到決定整面盤能不能用的全部參數,而且每一個都是採購當下固化、事後改不了的。
- 驗證標準決定欄位是否存在。 台灣兩套標準並行,若是 CNS 13542,
Inc/Ing/RDF在制度上根本不存在——你的容量檢查只能回 UNKNOWN。這不是資料缺漏,是「這面盤沒有這個數字」,模型必須誠實表達,不能塞 0 或塞In。 - RDF 是唯一能事前介入的點。 Q1 的答案顯示
RDF = 0.8比1.0少 11% 的可用電流,而事後任何遙測都看不見它。正確的做法是把一行字寫進採購規格:「本盤所有饋出迴路須以 RDF = 1.0 驗證,或依附表逐路Ib進行溫升驗證」。這行字現在寫進去是免費的,蓋完之後是換盤。 Icc是一對設備的屬性。 若標的是Icc而現場上游換了型號,那個 65 kA 就該失效——但沒有任何機制會通知你。現在問,是為了知道要不要建那條外鍵。
Q2 — 問 控制系統承包商 / 電驛設定承包商(⚠️ commissioning 前,唯一機會)¶
「短路電流計算有沒有涵蓋 tie 閉合 + 兩台變壓器並聯?算出來幾 kA?有沒有三選二互鎖從實體上禁止該配置?電動機反饋算進去了嗎? 有沒有做過 arc flash study(IEEE 1584-2018)?主斷路器有 ERMS 或 ZSI 嗎?ZSI 做過注入電流的功能測試嗎(不是導通測試)?ERMS 有沒有就地狀態指示、有沒有進事件記錄? UPS 側:靜態旁路的過載額定跟上游斷路器協調過了嗎? UPS 供不出跳脫電流的情境(
dc-08演算 5)下,該跳的是下游分路,不是 UPS 旁路進線。」
為什麼是這題,而且為什麼期限最硬:
- tie 閉合的違規是純算的(Q3:50.6 → 101.2 kA),不必等故障。但互鎖必須在 commissioning 前設定進去——蓋完之後補裝要停整面盤。
- ZSI 的正確性在正常運轉時完全不可觀測,唯一的驗證機會是 commissioning 的注入電流測試。導通測試(量線通不通)與功能測試(注入電流看限制訊號有沒有發出去)完全不是同一件事,而承包商常只做前者。沒有這筆測試記錄,
last_zsi_functional_test_at這個欄位從第一天起就是空的。 - ERMS 與選擇性正面衝突:開了 ERMS,清除時間從 0.3 s 降到 0.05 s(入射能量 40 → 6 cal/cm²),但選擇性整層失效——一個下游故障會跳掉整面盤。這個取捨必須有人做決定並留下記錄,不能讓它變成「維修人員自己判斷、事後忘記還原」。
Q3 — 問 UPS 供應商 / 電池供應商 / 維運¶
「旁路輸入來自哪一面盤?跟整流器輸入同一面嗎? 若是,這台 UPS 的『兩個輸入』在故障域上其實是一個。 有沒有啟用 ECO / eConversion?誰有權切、有沒有進事件記錄? 另外——貴司報的切換毫秒數,是哪兩個模式之間的?(高效模式→逆變器,還是逆變器→旁路?) 電池:廠商報的 runtime 是幾分鐘率、在幾度、算不算老化係數(IEEE 485 的 1.25)? 電池間全年溫度曲線有紀錄嗎、月均幾度? 還有——你報的是 design life 還是 service life?請分開講。 最後:電池室的樓板承重上限是多少?」
為什麼是這題:本週兩個「來源分歧」都在這裡,而且兩個分歧都是問對問題就能當場化解的。
- ECO 模式:Schneider 說 eConversion 等同 Class 1,Vertiv 說傳統 ECO 是 marketing hype 且 VFD 保證不了 Class 1。兩邊很可能在講不同的切換,所以問法不是「ECO 安不安全」(會得到行銷答案),而是「你報的毫秒數是哪兩個模式之間的」。這句話問完,對方要嘛給你精確定義,要嘛答不出來——兩種結果都有用。
- design life vs service life:型錄 10 年、Schneider WP229 說 service life 3–6 年、TCO 模型取 4 年。這不是誰錯,是兩個不同的量。問清楚才能解釋「為什麼型錄寫 10 年、我們四年就要換」,也才知道
design_life_years與service_life_est_years各該填什麼。而 32 °C 環境下 10 年設計壽命實際只剩 5.8 年(10 × 2^(−7/9))——溫度曲線是這個計算唯一的輸入,沒有它就永遠只能吵。 - 旁路同源:這是稽核報表不是告警——它不會變化,但會讓「兩條 feed」的冗餘顯示成綠燈。跟 W32 補考題(
dc-01兩路市電同變電所、dc-05三台機共用油管)是同一個錯誤的第三次出現:用數量冒充獨立性。 - 樓板承重:11,340 kg 對舊建物翻新是真實限制,也是鋰電最常被選中的理由。這題決定的是選型,晚問就等於已經選好了。
這週沒選上、但別忘記的¶
- 儲油槽幾座、各多少公升?移走其中一座之後,全站在設計負載下還剩幾小時?(要這個數字,不是總和——本週實例:31.78 h 的總量,逐一移除後只剩 16.40 h。)
- 輸油泵與燃油控制盤的電源從哪來? 是不是全部吊在同一面盤或同一個 ATS 上?(共用一顆泵時續航從 16.40 h 掉到 1.03 h。)
- 燃油多久採樣化驗、多久 polishing?上次報告在哪、我們的油幾歲? critical low 是接成警報還是引擎停機?(年週轉率僅 11.8%,換完一輪要 8.5 年,而柴油可用期只有 6–12 個月——這是一個沒有感測器會叫你的故障。)
- UPS 的
upsOutputSource(RFC 1628)分不出 static bypass 與 maintenance bypass(都是4)。問廠商有沒有私有 OID 或 Modbus 暫存器能分辨——分不出來就等於「負載未受保護」這條 CRITICAL 告警會在計畫性維修時每次誤報,然後被人關掉。
下週¶
- 佇列下一張:
dc-09b電池測試制度與消防合規(IEEE 1188 內阻/容量門檻、commissioning baseline、NFPA 855 與 UL 9540A、熱失控偵測)。它會第四次撞上「只有故障當下才會被用到的功能需要測試日期欄位」——在寫它之前把PeriodicVerification抽出來,讓dc-09b成為第一個直接複用的卡,而不是第四次重寫。 - 連貫性檢視的 #1 與 #5 請在
dc-09b之前修完(各約 20 分鐘),#3DeviceRegistry必須在dc-10之前——那之後有七張卡在排隊,欠三週的帳每拖一張就多一份。 dc-09b之後是dc-10STS,它會第四次出現「保護等級降級是狀態不是屬性」(手動旁路)。第 5 節那個共用實體,最晚在那之前要有。- ⚠️ commissioning 隨時可能開始。 本週 Q2 已經把該在現場拿到的東西列清楚了——ZSI 注入電流功能測試、tie 閉合互鎖驗證、arc flash 標籤。加上 W32 的 Q3(ATS 五個計時器設定值 + NFPA 110 §7.13.4.1.4 分段時序記錄),這兩份清單合起來就是 commissioning 現場的驗收單,一次性且不可重現。