"相机误差 0.2 mm、标定误差 0.3 mm,所以总误差 0.5 mm"看起来直观,却缺少方向、统计定义与相关性。误差预算需要先写清测量模型,再让输入的不确定性通过模型传播。把每个模块的宣传数字直接相加,很难得到可信的目标位置结论。
**阅读范围:**本文是三维视觉与医学影像软件工程系列的独立技术教程。数据和数值实验均为合成示例,不读取患者数据,不代表实际设备性能或临床精度。文中长度按示例明确的单位解释。资料核对日期:2026 年 10 月 16 日。

图 1:误差预算:先写模型,再谈合成误差(原创教学配图)
一、先定义输出量与扰动模型
本篇输出是一个三维目标点的位置。基准旋转为单位旋转,目标点在 (0,0,150) mm;平移扰动与小旋转向量扰动都按目标参考系表达。不同扰动施加方向会改变雅可比,因此不能在任意坐标约定下照抄同一公式。
位置误差、每坐标标准差、三维 RMS、径向 P95 和最大误差是不同统计量。零均值并不意味着没有随机误差;标准差小也不意味着没有固定偏差。报告时需要把中心偏移与散布分别记录。
二、小角度雅可比怎样得到?
对接近单位旋转的扰动 δθ,有 R(δθ)p≈p+δθ×p=p−p×δθ。加上平移 δt 后,位置误差近似为 δy=δt−p×δθ。因此 J=I,−\[p×],输入六维协方差 Σ 传播为 Σ_y≈JΣJᵀ。
角度必须按弧度输入。位于旋转中心附近的点对旋转扰动不敏感,远处目标则因杆长放大而敏感;沿目标方向的旋转分量可能不产生一阶位置变化。这也是单纯用一个杆长乘一个角误差,只能作为有方向假设的近似。
三、相关性与系统偏差不能省略
若平移与旋转由同一套数据估计,它们可能相关;完整协方差中的交叉项可能增加也可能减少输出方差。各模块共享参考或数据时,也不应默认独立。平方和开根号只在相应独立或不相关及统计口径条件成立时才适用。
固定偏差不能通过增加随机样本自然消失。把所有 Monte Carlo 样本都平移 1 mm,协方差保持不变,输出均值与 RMS 却明显变化。本篇用这个反例说明:只画误差椭球,可能遗漏整个椭球中心已经偏了。
四、蒙特卡洛是传播模型,不是制造真值
按照假设的输入分布抽样,通过完整非线性模型计算输出,再估计均值、协方差和分位数。它能检查线性近似是否适合当前范围,也能处理某些复杂模型,但结果质量取决于输入分布与相关性是否可信。
样本多只减少模拟统计误差,不会修复遗漏的弯曲、时间延迟或参考偏差。径向 P95 是当前模型样本中误差长度的第 95 百分位,不自动等于临床成功率,也不能拿每坐标 1.96σ 直接替代三维半径阈值。
五、可运行的完整合成实验
抽样十万次,平移每坐标标准差 0.2 mm,旋转向量每坐标标准差 0.1°,假设独立零均值高斯。使用 SciPy 完整旋转作用于 150 mm 处目标,比较实际样本协方差与一阶雅可比结果;再加入固定 1 mm 的 x 方向偏差。
环境说明:代码在本机 Python 3.14 环境中实际执行。为便于复现,请保存为 demo.py,在支持这些库的独立环境中安装依赖;若目标解释器没有兼容 wheel,应先选择受支持的解释器。环境差异可能影响最后几位数值,不影响本文所检查的几何或统计关系。
python -m pip install numpy scipy
python demo.py
import numpy as np
from scipy.spatial.transform import Rotation
rng=np.random.default_rng(16)
n=100000;sigma_t=.2;sigma_angle=np.deg2rad(.1)
dt=rng.normal(0,sigma_t,(n,3))
dr=rng.normal(0,sigma_angle,(n,3))
point=np.array([0.,0.,150.])
error=Rotation.from_rotvec(dr).apply(point)+dt-point
cov=np.cov(error,rowvar=False)
def skew(v):
x,y,z=v
return np.array([[0,-z,y],[z,0,-x],[-y,x,0.]])
J=np.column_stack([np.eye(3),-skew(point)])
input_cov=np.diag([sigma_t**2]*3+[sigma_angle**2]*3)
linear=J@input_cov@J.T
assert np.allclose(np.diag(cov),np.diag(linear),rtol=.03)
length=np.linalg.norm(error,axis=1)
biased=error+np.array([1.,0,0])
np.testing.assert_allclose(np.cov(biased,rowvar=False),cov,atol=1e-12)
assert np.linalg.norm(biased.mean(0))>.9
print('empirical_coordinate_SD_mm',np.sqrt(np.diag(cov)))
print('linear_coordinate_SD_mm',np.sqrt(np.diag(linear)))
print('radial_RMS_mm',np.sqrt(np.mean(length**2)),'radial_P95_mm',np.percentile(length,95))
print('biased_radial_RMS_mm',np.sqrt(np.mean(np.sum(biased**2,axis=1))))
print('PASS: small-angle covariance and constant-bias counterexample')
六、运行结果与应该怎样解读
经验坐标标准差约 (0.32959,0.32930,0.19938) mm,线性预测约 (0.32945,0.32945,0.2) mm。径向 RMS 约 0.50677 mm,P95 约 0.83555 mm。加入固定偏差后 RMS 约 1.12092 mm,协方差不变。

图 2:杆长与小扰动标准差关系(原创教学配图)
代码中的断言验证了本篇明确描述的性质。配图中标为原理示意的部分用于解释模型,不是实测截图;由公式生成的曲线只在图注与正文列出的假设下成立。不要把合成实验输出当成真实产品的性能报告。
七、常见现象与排查方向
| 现象 | 优先检查 | 处理方向 |
|---|---|---|
| 角度误差大了几十倍 | 度与弧度混用 | 在模型边界统一单位 |
| 总误差比预期大 | 遗漏杆长或相关项 | 写出目标点与完整雅可比 |
| 标准差很好但整体偏移 | 固定系统偏差未建模 | 同时报告均值和散布 |
| 模拟很稳定却对不上实测 | 输入模型缺少真实因素 | 用独立观测检查模型假设 |
八、独立验证与适用边界
误差预算应标明每个输入的来源、统计定义、坐标系、相关性假设与有效范围。将预算结果与独立参考下的实际目标误差分布比较,分析偏差、尾部和随工作距离变化的趋势。BIPM 的 JCGM 指南提供不确定度表达与蒙特卡洛传播的参考入口;本文不是对完整指南的替代,也未覆盖真实设备或合规验证。
建议把原始输入、参数、软件版本、输出结果和失败状态一起保留。若把同一份检查数据反复用于选择参数,它就不再是完全独立的最终验证集。将算法演示接入真实系统时,应另行验证输入质量、参考不确定性和完整处理链路。
参考资料
上述资料用于核对相关接口与基本约定;本文的合成数据、推导示例与代码不声称复刻库内全部实现。
写在最后
"不积小流,无以成江海。"
------ 荀子,《劝学》
先写明假设,再解释数字,误差预算才会成为可检验的工程判断。