🔍【教學】為什麼 TXT 跟 Excel 數字對不起來?一次看懂晶圓測試 BIN 統計與程式設計觀念

一、故事背景:TXT 看起來對了,Excel 卻顯示錯誤?

假設你在做晶圓測試資料處理,系統會輸出:

  1. 一個文字檔(TXT)

  2. 一個 Excel 報表

這兩個檔案裡,都會出現類似下面幾個數字:

  • TOTAL_TEST:總測試顆數

  • TOTAL_PASS:通過顆數

  • TOTAL_FAIL:失敗顆數

  • TEST_YIELD:良率

  • BIN01(1)BIN04(4)…:各個 BIN 的顆數

理論上:

TOTAL_PASS 應該要等於「Bin1 的顆數」,

TOTAL_TEST 應該要等於「所有 BIN 顆數加總」。


實際情況卻是:

  • TXT 檔裡 TOTAL_PASS 已經跟 BIN01(1) 對得起來

  • Excel 報表裡的「Pass Q’ty」卻跟 Bin1 不一致

也就是說:同一顆晶圓、兩份報表,數字卻不同。
這在跟客戶對帳或查良率問題時,超級尷尬。

接下來就用軟體工程師的角度,把整件事拆開來講,但會盡量用「白話」方式,讓完全不懂程式的人也看得懂。


二、資料從哪來?兩條不同的數字來源

在系統裡,可以把資料想成有兩個階段:

  1. 讀取原始資料(舊的數字)

    • 從原始檔案或資料庫讀到一份「Header 資料」,裡面已經有 TOTAL_PASSTOTAL_FAIL

    • 這些數字可能是設備或前一套系統算好的。

  2. 重新統計 BIN 顆數(新的數字)

    • 系統逐顆 die 去看它是 Bin1、Bin4、Bin5…

    • 再做一份 Bin 統計表,例如:

      • Bin1:3309 顆

      • Bin4:3 顆

      • Bin5:96 顆

問題就出在:TXT 跟 Excel 用到的「數字來源不一樣」。


三、TXT 部分:已經有做「重新計算」

先看 TXT 的輸出流程(用改寫過的假想程式來說明):

// 代表「晶圓摘要」的物件 class WaferSummary { int totalPass; int totalFail; int totalTest; double yield; // ✅ 用 BIN 統計結果重新計算 void recalcFrom(BinStatistics bins) { int pass = bins.getCount("BIN1"); int all = bins.getTotal(); // 把所有 BIN 顆數加總 this.totalPass = pass; this.totalTest = all; this.totalFail = all - pass; this.yield = (all == 0) ? 0.0 : (pass * 100.0 / all); } }

TXT 匯出的時候會這樣做:

void exportAsTxt(WaferSummary header, BinStatistics bins, Writer out) { // ✅ 先用 bins 重新算一次 header 的數字 header.recalcFrom(bins); // 接著才把數字寫進 TXT out.write("TOTAL_TEST=" + header.totalTest); out.write("TOTAL_PASS=" + header.totalPass); out.write("TOTAL_FAIL=" + header.totalFail); out.write("TEST_YIELD=" + header.yield + "%"); // ... }

因此:

  • TOTAL_PASS 會等於 BIN1 顆數

  • TOTAL_TEST 會是所有 BIN 顆數加總

  • TOTAL_FAIL = TOTAL_TEST - TOTAL_PASS

也就是說,TXT 部分其實是對的


四、Excel 部分:忘記「重新計算」這一步

接著看 Excel 報表。

Excel 在填資料時,會準備一個「欄位對應表」,類似這樣:

Map<String, String> buildExcelFields(WaferSummary header, BinStatistics bins) { Map<String, String> map = new HashMap<>(); // 這幾個放在 Excel 摘要區 map.put("G_die", String.valueOf(header.totalTest)); map.put("Yield", String.format("%.2f%%", header.yield)); map.put("PassQty", String.valueOf(header.totalPass)); map.put("FailQty", String.valueOf(header.totalFail)); // 下面是各 BIN 顆數 map.put("Bin1", String.valueOf(bins.getCount("BIN1"))); map.put("Bin2", String.valueOf(bins.getCount("BIN2"))); // ... return map; }

看出問題了嗎?

  • PassQtyFailQtyG_dieYield
    → 拿的是 舊的 header 數字

  • 各個 Bin1Bin2
    → 拿的是 新的 bins 統計

TXT 已經有呼叫 recalcFrom(bins),Excel 卻沒有。
結果就變成:

  • Bin1 顆數 = 新統計結果(例如 3309)

  • PassQty 還是停留在舊的(例如 3313)

於是 Excel 就跟 TXT、也跟實際的 BIN 統計對不起來。

這就是典型的軟體工程問題:

同一份資料,系統裡存在兩個不同的「真相(source of truth)」,而且沒有同步更新。



五、修正觀念:只認「一個真相」,所有輸出都從這裡來

要讓 TXT 和 Excel 永遠一致,最重要的觀念只有一句話:

所有 summary 數字(TOTAL_PASS / TOTAL_TEST / YIELD…)

都應該「只」從 BIN 統計推回去,而不是各自算各自。


具體做法就是:

  1. 把「重新計算」寫成一個共用的方法(上面的 recalcFrom)。

  2. 只要有任何輸出(TXT、Excel、PDF…)要用到 summary 數字,全部都先呼叫一次。

修正版的 Excel 填值流程就會變成:

Map<String, String> buildExcelFields(WaferSummary header, BinStatistics bins) { // ✅ 先同步:用 bins 更新 header header.recalcFrom(bins); Map<String, String> map = new HashMap<>(); map.put("G_die", String.valueOf(header.totalTest)); map.put("Yield", String.format("%.2f%%", header.yield)); map.put("PassQty", String.valueOf(header.totalPass)); map.put("FailQty", String.valueOf(header.totalFail)); // ✅ 各 BIN 顆數依然直接用 bins for (int i = 1; i <= 64; i++) { String key = "Bin" + i; map.put(key, String.valueOf(bins.getCount(key))); } return map; }

這樣:

  • TXT:在輸出前呼叫 recalcFrom(bins)

  • Excel:在準備欄位前也呼叫 recalcFrom(bins)

兩邊都是以 BinStatistics 為唯一真相,自然就不會打架。


六、用非工程師也聽得懂的比喻

如果覺得以上程式碼還是有點抽象,我們換個比喻:

  • 想像你有一份成績單,上面寫:

    • 總分(TOTAL)

    • 及格總分(PASS)

    • 不及格總分(FAIL)

  • 同時你桌上也有一本「原始考卷」,每一題的分數都在裡面。

正確做法是:

  1. 先把每一題分數加總出「新的總分」。

  2. 再算出及格題、不及格題的總分。

  3. 最後才把這三個數字寫到成績單上。

錯誤做法是:

  • 成績單上的 TOTAL/PASS/FAIL 沿用舊數字

  • 但旁邊又根據「最新考卷」寫了一份「每題成績表」

結果就是:

  • 「每題成績表」是新的

  • 「總分欄位」是舊的

  • 兩個對不起來,學生一定會抗議。

晶圓測試、BIN 統計跟這個是一模一樣的道理。


七、實務建議:避免再踩一次坑

最後整理幾點實務上的小建議,給正在開發報表系統的工程師:

  1. 建立單一來源(Single Source of Truth)

    • 決定 summary 數字要以「哪一份資料」為準(這裡就是 BIN 統計)。

    • 其他所有輸出都只能從這裡算,不可以各自亂算。

  2. 把計算邏輯集中在一個方法

    • 比如 recalcFrom(bins)

    • 不要在 TXT 寫一套、在 Excel 再寫一套,日後一定會不同步。

  3. 在輸出前強制呼叫同步

    • 不管是 TXT、Excel、PDF,只要要用到 TOTAL_PASS 等欄位,先呼叫一次重算。

    • 這樣即使日後 bin 規則有變,只要改這一個方法就好。

  4. 做自動化檢查

    • 匯出報表後,可以跑一個簡單檢查:

      • TOTAL_PASS == Bin1 顆數

      • TOTAL_TEST == 所有 Bin 顆數加總

    • 發現不一致就丟錯誤或記 log,避免錯誤報表流到客戶手上。


結語

這篇文章用一個實際遇到的情境說明:

  • TXT 跟 Excel 報表數字不一致

  • 真正的根本原因是:
    兩邊使用不同的數字來源,而且沒有統一回到 BIN 統計去重算

只要掌握「單一真相 + 共用計算邏輯」這個核心觀念,不只是在晶圓測試系統,在任何需要輸出多種報表的系統(財報、銷售報表、庫存系統…)都能避免類似的對帳地獄。

如果你現在也遇到「TXT 數字正常、Excel 不正常」的情況,可以先從這幾個問題檢查起:

  1. 兩個輸出是不是用到不同的變數 / 資料來源?

  2. 有沒有一個共用的方法專門負責重算 summary?

  3. 在所有匯出流程裡,有沒有確定都呼叫到這個方法?

照這樣一步一步檢查,大部分「數字對不起來」的問題,其實都能很快找到答案。

留言

這個網誌中的熱門文章

🔍Vue.js 專案錯誤排查:解決 numericFields is not defined 與合併儲存格邏輯最佳化

🔎EF Core 連 Oracle 出現 ORA-00600 [kpp_concatq:2] 的完整排錯指南(含 EF Core ToString/CultureInfo 錯誤)

🛠【ASP.NET Core + Oracle】解決 ORA-00904 "FALSE": 無效的 ID 錯誤與資料欄位動態插入顯示問題