不確定性與單位 是做什麼的?
範圍
當計算涉及物理單位,或報告的數值需要不確定度時,請使用此技能。具體而言:
- 在單位之間進行轉換,包括需要物理背景的轉換(波長到光子能量、質量到物質的量、能量到溫度);
- 透過測量模型傳播不確定度,無論輸入是否相關;
- 從校準證書、規格書和重複性數據建立 GUM 不確定度預算;
- 選擇覆蓋因子,並決定
k = 2是否合理; - 進行四捨五入並撰寫結果,讓讀者清楚瞭解
±的意義; - 從曲線擬合中提取參數不確定度,而不丟棄相關性;
- 審查現有的分析程式碼,找出隱藏的單位和不確定度缺陷;
- 檢查維度一致的答案是否在物理上可能——考慮其數量級、無因次群及其所指涉的流態。
此技能涵蓋計量學以及實現它的兩個庫。它不涵蓋統計推論、模型選擇或研究設計——請參閱 statistical-analysis、statistical-power 和 experimental-design。
當前版本與安裝
驗證日期:2026-07-26:
- pint 0.25.3,發佈於 2026-03-19;需要 Python 3.11+。
- uncertainties 3.2.3,發佈於 2025-04-21;需要 Python 3.8+。
- NumPy 2.5.1 和 SciPy 1.18.0;都需要 Python 3.12+。
- SciPy 1.18.0 中的
scipy.constants使用 CODATA 2022。SciPy 1.11 及更早版本使用 CODATA 2018,兩者之間有幾個推薦值不同。
uv venv --python 3.13
source .venv/bin/activate
uv pip install "pint==0.25.3" "uncertainties==3.2.3" "numpy==2.5.1" "scipy==1.18.0"
pint-pandas 和 pint-xarray 可添加單位感知的列和陣列,需另外安裝。
不可協商的工作流程
- 在輸入時附加單位,僅在輸出時移除單位。 在函數邊界使用
ureg.wraps或m_as("unit")進行轉換,絕不在計算中途進行。 - 在計算任何東西之前,明確寫出測量模型,包括其估計值為零的修正項。模型中遺漏的修正項,其不確定度也將從預算中遺漏。
- 為每個輸入提供四項資訊:估計值、標準不確定度、不確定度的來源分佈,以及其自由度。
- 使用正確的除數轉換 Type B 陳述。 證書中的擴展不確定度除以其聲明的
k;矩形分佈的極限除以sqrt(3)。 - 在合併前識別相關性。 針對同一標準校準、在同一儀器上測量或來自同一擬合的輸入是相關的。
- 計算靈敏度係數,並從
c_i * u(x_i)而非原始不確定度讀取預算。 - 檢查線性化。 將蒙地卡羅法與 GUM 框架並行運行,並應用 JCGM 101 第 8 條的比較。若失敗,則報告蒙地卡羅結果。
- 根據有效自由度選擇
k,而不是憑習慣。 - 先對不確定度進行四捨五入,然後將數值四捨五入到相同的小數位數。
- 說明
±的含義——是標準還是擴展,附上k、覆蓋概率和方法。 - 在報告前進行數量級合理性檢查。 維度一致的結果仍可能是不可能的。將其與已知尺度或無因次群進行比較,並確認你所依賴的每個假設在該流態中仍然成立。
此技能旨在防止的失敗
以下每個範例都能無錯運行並產生看似合理的數值。
在未知尺度下移除單位
length = (12.7 * ureg.mm).magnitude # 12.7 -- 什麼的?
length = (12.7 * ureg.mm).m_as("m") # 0.0127 米,明確聲明
.magnitude 返回的是量值當前攜帶的任何數值。在提取點每次都指明單位。
偏移溫度算術
Q(20, "degC") + Q(5, "degC") # OffsetUnitCalculusError -- 正確拒絕
Q(20, "degC") + Q(5, "delta_degC") # 25 degree_Celsius
Q(25, "degC") - Q(20, "degC") # 5 delta_degree_Celsius
攝氏度和華氏度是區間尺度。溫度上的不確定度始終是一個差值,應屬於 delta_ 單位:將 20 ± 0.5 degC 轉換為華氏度得到 68 degF ± 0.9 delta_degF,一行內進行兩次不同的轉換。
透過乘法相加的對數單位
Q(10, "dBm") + Q(10, "dBm") # 0.0001 kilogram**2 * meter**4 / second**6
這是 10 mW × 10 mW,不是 20 mW,也不是 13 dBm。沒有引發任何錯誤。在進行任何算術運算之前,請轉換為線性單位。
因往返轉換而破壞的相關性
x = ufloat(1.0, 0.1)
x - x # 0.0+/-0
x - ufloat(x.nominal_value, x.std_dev) # 0.00+/-0.14
從其名義值和標準差重建一個變量會建立一個獨立的變量。任何透過一對浮點數進行序列化的操作也是如此。使用 correlated_values(values, covariance_matrix) 來重建一組相關變量。
被默默重新縮放的協方差矩陣
popt, pcov = curve_fit(f, x, y, sigma=sigma) # 預設
popt, pcov = curve_fit(f, x, y, sigma=sigma, absolute_sigma=True)
預設情況下,pcov 會按歸約卡方值進行重新縮放,因此參數不確定度會吸收擬合優度,並與不傳遞任何 sigma 時得到的結果相匹配。在一次合成的直線擬合中,兩者分別得到 [0.0364, 0.2154] 和 [0.0477, 0.2820]——相差 31%。只要 sigma 包含真實的標準不確定度,就傳遞 absolute_sigma=True。
從未檢查的線性化
對於 y = x² 且 x = 1.0 ± 0.5,GUM 框架給出 y = 1.0、u_c = 1.0 和 95% 區間 [-0.96, 2.96]——對於一個平方量,這個區間大部分是負數。蒙地卡羅法給出平均值 1.25、u_c = 1.06 和最短 95% 區間 [0, 3.32]。線性傳播庫中的任何東西都不會告訴你發生了這種情況。
內建本地 CLI
所有輔助工具均可離線運行,拒絕 URL 和符號連結,對輸入進行綁定,以私有權限原子性地寫入輸出,並且未經 --force 參數拒絕覆寫。
python skills/uncertainty-and-units/scripts/propagate_uncertainty.py --help
python skills/uncertainty-and-units/scripts/uncertainty_budget.py --help
python skills/uncertainty-and-units/scripts/format_result.py --help
python skills/uncertainty-and-units/scripts/convert_units.py --help
python skills/uncertainty-and-units/scripts/audit_units.py --help
python skills/uncertainty-and-units/scripts/check_plausibility.py --help
propagate_uncertainty.py
在同一個模型上運行兩種傳播方法,並應用 JCGM 101 第 8 條驗證測試。
python skills/uncertainty-and-units/scripts/propagate_uncertainty.py \
--expression "m / (pi * (d / 2) ** 2 * h)" \
--variable "m=250.0,0.05" \
--variable "d=20.0,0.02,rectangular" \
--variable "h=40.0,0.05,rectangular" \
--measurand density --unit "g/cm3" --format markdown
每個 --variable 的格式為 name=value,standard_uncertainty[,distribution[,dof]],其中分佈為 normal、rectangular、triangular、arcsine 或 exact,僅控制蒙地卡羅抽樣。相關性以 --correlation "a,b=0.9" 的形式輸入。對於任何長期使用的模型,可以使用 JSON --spec 檔案來保存。
表達式被解析為抽象語法樹,並通過對 + - * / ** 和一個固定函數列表的顯式走訪來化簡。它從未被編譯或執行。
報告會給出估計值、u_c、靈敏度係數、百分比預算、有效自由度、k、U、兩個蒙地卡羅覆蓋區間,以及關於線性化結果是否可以報告的裁決。
uncertainty_budget.py
以證書和數據表聲明的方式組合不確定度分量。
python skills/uncertainty-and-units/scripts/uncertainty_budget.py --template > budget.json
python skills/uncertainty-and-units/scripts/uncertainty_budget.py --spec budget.json --format markdown
每個分量都指定了一個 distribution,它決定了其除數——expanded 除以其 coverage_factor、rectangular 除以 sqrt(3)、triangular 除以 sqrt(6)、arcsine 除以 sqrt(2)、normal 除以 1——並可選地帶有 sensitivity、dof 和 relative: true。該工具會計算 u_c、Welch-Satterthwaite 有效自由度、來自 t 分佈的 k 和 U,並在 Type A 分量沒有自由度時、nu_eff 小到使 k = 2 不正確時、某個分量佔主導時,以及聲明為 normal 的 Type B 分量可能是一個未經除法的擴展不確定度時發出警告。
format_result.py
python skills/uncertainty-and-units/scripts/format_result.py \
--value 12.34567 --uncertainty 0.02345 --unit mm \
--coverage-factor 2.26 --coverage-probability 0.95
返回 12.346 ± 0.023 mm、12.346(23) mm、科學記號和 LaTeX 形式,以及必須伴隨數值的說明文字。當為以 1 或 2 開頭的不確定度請求一位有效數字時,以及當不確定度超過估計值時,會發出警告。
convert_units.py
python skills/uncertainty-and-units/scripts/convert_units.py \
--value 532 --unit nm --to eV --context spectroscopy --uncertainty 0.5
python skills/uncertainty-and-units/scripts/convert_units.py \
--value 1.0 --unit g --to mol --context chemistry --context-parameter "mw=180.156 g/mol"
透過轉換的局部導數來傳遞不確定度,這點很重要,因為上下文轉換是互為倒數而非成正比的。當轉換需要上下文時,會在錯誤訊息中指明上下文名稱,並標記偏移單位和對數單位。--list-contexts 會顯示登錄檔中定義的內容。
audit_units.py
對現有分析程式碼進行靜態審查。進行解析,從不匯入或執行。
python skills/uncertainty-and-units/scripts/audit_units.py \
--input analysis.py --format markdown --fail-on medium
| 規則 | 嚴重性 | 偵測內容 |
|---|---|---|
UNIT001 | 中 | 一個模組中的第二個 UnitRegistry——跨註冊表的 ValueError |
UNIT002 | 中 | 任何地方都沒有 delta_ 單位的偏移溫度單位 |
UNIT003 | 高 | .magnitude 前面沒有 .to(...) 或 .m_as(...) |
UNIT004 | 中 | 對數單位,其 + 操作實際上是乘法 |
UNC001 | 高 | 沒有 absolute_sigma 的 curve_fit |
UNC002 | 中 | 沒有 ddof 的 np.std / np.var |
UNC003 | 中 | 在使用 uncertainties 的模組中使用了 math 或 numpy 函數 |
UNC004 | 高 | 從 .nominal_value 和 .std_dev 重建的 ufloat |
CONST001 | 低 | 與 CODATA 常數差異在 0.1% 以內的常數字面值 |
當發現的問題符合 --fail-on(預設為 high)時,退出狀態為 1,這使其可用作 pre-commit 或 CI 檢查。
這些規則是啟發式的,因此可以使用指令註解來抑制誤報——尾隨註解涵蓋其所在行,單獨一行的註解則涵蓋下一行:
value = quantity.magnitude # audit-units: ignore UNIT003 -- already converted upstream
# audit-units: ignore UNC003 -- the argument here is a plain float array
scaled = np.log10(counts)
# audit-units: ignore-file CONST001 涵蓋整個模組,不指定任何規則名稱則會抑制所有規則。抑制操作會在報告中被計數而非隱藏,因此一個沉默所有內容的檔案仍然會說出這一點。
check_plausibility.py
維度一致性不等於物理可能性。一個直徑 2 米的細胞和毛細血管中 4e7 的雷諾數都能通過所有單位檢查。此工具針對無因次群、特徵尺度和精選的量級帶測試一組量值,並在報告數值前驗證每個公式的維度。
python skills/uncertainty-and-units/scripts/check_plausibility.py \
--quantity "density=1060 kg/m**3" --quantity "velocity=0.5 mm/s" \
--quantity "length=8 um" --quantity "viscosity=3.5 mPa*s" \
--group reynolds --format markdown
# Re = 0.001211 -- 層流 (圓形管道,長度 = 直徑)
python skills/uncertainty-and-units/scripts/check_plausibility.py \
--quantity "diameter=2 m" --band "eukaryotic_cell_diameter=diameter"
# 不合理:超出 5-100 um 範圍 4.3 個數量級
--group 評估 14 個無因次群中的一個,並命名系統所處的流態;--scale 計算一個特徵尺度,如擴散時間、德拜長度或斯托克斯沉降速度;--band 將提供的量值與觀測到的範圍進行比較。--list 會列印整個目錄以及每個公式所需的輸入。
物理常數(k_B、N_A、R_gas、g_earth 等)無需提供即可用於每個公式,並且在運行時從 scipy.constants 讀取,而不是作為字面值寫入,因此它們會跟隨 SciPy 所搭載的 CODATA 版本。
維度檢查是關鍵。當一個公式需要動力黏度,但傳入的是運動黏度時——兩者都稱為 "viscosity",都在水的表格中,相差一個因子 ρ——在計算任何數值之前就會被拒絕:
error: viscosity must have dimensionality [mass] / ([length] * [time]),
but m²/s is [length] ** 2 / [time]
當裁決符合 --fail-on(預設為 implausible;在一個帶的十倍以內的值被視為 questionable)時,退出狀態為 1。這些閾值是具有軟邊界的慣例,並假設其相關性所擬合的幾何形狀——請參閱 references/plausibility-scales.md 以了解每種情況下應使用的特徵長度。
選擇傳播方法
| 情況 | 方法 |
|---|---|
| 線性或接近線性模型,接近正態的輸入,大自由度 | 僅 GUM 框架 |
| 輸入 ±2u 範圍內有任何非線性 | 同時運行兩種方法,應用第 8 條測試 |
| 任何輸入上的相對不確定度高於 ~20% | 使用蒙地卡羅法 |
…(因翻譯而截斷)