不确定性与单位
范围
当计算涉及物理单位或报告的数字需要不确定性时,使用本技能。具体包括:
- 单位转换,包括需要物理上下文的转换(如波长转光子能量、质量转物质量、能量转温度);
- 通过测量模型传播不确定性,无论输入是否相关;
- 从校准证书、技术规格和重复性数据构建 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")进行转换,切勿在计算中间进行。 - 在计算任何内容之前,显式写出测量模型,包括估计值为零的修正项。被遗漏的修正项会从预算中丢失其不确定性。
- 为每个输入提供四项信息:估计值、标准不确定度、不确定度的来源分布及其自由度。
- 使用正确的除数进行 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)
默认情况下,curve_fit 会使用缩减卡方值缩放 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,并在以下情况下发出警告:A 类分量没有自由度、nu_eff 小到足以使 k = 2 错误、一个分量占主导地位,以及声明为 normal 的 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 | medium | 一个模块中存在第二个 UnitRegistry——可能导致跨注册表的 ValueError |
UNIT002 | medium | 偏移温度单位,且任何地方都没有 delta_ 单位 |
UNIT003 | high | .magnitude 后面没有紧跟 .to(...) 或 .m_as(...) |
UNIT004 | medium | 对数单位,其 + 运算实际是乘法 |
UNC001 | high | curve_fit 没有使用 absolute_sigma |
UNC002 | medium | np.std / np.var 没有使用 ddof |
UNC003 | medium | 在不安全使用 uncertainties 的模块中使用了 math 或 numpy 函数 |
UNC004 | high | 从 .nominal_value 和 .std_dev 重建的 ufloat |
CONST001 | low | 字面量接近 CODATA 常数的 0.1% 以内 |
退出状态为 1 表示存在满足 --fail-on(默认为 high)条件的发现,这使得它可以用作 pre-commit 或 CI 检查。
这些规则是基于启发式的,因此可以使用指令注释来抑制误报——注释位于行尾则仅覆盖该行,单独占一行则覆盖下一行:
value = quantity.magnitude # audit-units: ignore UNIT003 -- 已在上游转换
# audit-units: ignore UNC003 -- 这里的参数是纯浮点数组
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 版本而更新。
量纲检查是核心功能。当公式需要动力粘度而传入的却是运动粘度(两者都称为“粘度”,都在水表中可查到,相差一个密度因子 ρ)时,在计算任何数字之前就会遭到拒绝:
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% |
…
[翻译时已截断]