August 17, 2026 in LIBS 与光谱分析5 minutes
介绍实现CF-LIBS的详细步骤
本文定位:记录具体实现中的测温、密度估计、配分函数、Saha 合并、谱线筛选与后处理。
CF-LIBS(Calibration-Free LIBS,GB/T 38257—2019 第 9.2.3 条)的核心逻辑位于 libs_analysis/src/libs_analyzer/models/cf_libs.py 的 CFLIBS 类中。整个多元素全成分输出由 predict_composition() 编排,依次执行以下 5 个核心步骤 + 1 个后处理步骤。
方法: _estimate_temperature(X)
物理原理: LTE 假设下,同一元素多条谱线强度遵循 Boltzmann 分布。对目标元素(默认 Fe I)的各谱线取对数:
$$\ln\left(\frac{I_j}{g_j \cdot A_j}\right) = \ln\left(\frac{F \cdot n_s}{Z_s(T)}\right) - \frac{E_j}{k_B T}$$以 $E_j$ 为自变量做线性回归,斜率 $= -1/(k_B T) \Rightarrow T$。
代码流程:
temp_element(默认 Fe)temp_ion(默认 I)的谱线表;若 temp_min_wl_nm > 0(默认 400nm),剔除紫外区谱线(避免 Fe 密集谱区宽窗背景被邻线抬高导致 T 虚高)。max(min_lines_for_boltzmann, 4) 条线: 4 条是统计稳定的下限(2 点拟合 R² 恒为 1,门控失效)。不足则全部样品回退 t_ref_k。_multi_line_net_and_snr() 提取净强度/SNR/对比度:
(peak − bg) / noise。peak / shoulder_median,shoulder 为紧邻峰窗两侧的局部中位强度,用于过滤连续背景上的伪峰。snr_threshold(默认 5.0)且对比度 ≥ min_peak_contrast(默认 2.0)。temp_line_quantile(默认 0.3,即最弱 30%)分位数的弱线子集。物理依据:线光学深 τ ∝ 线强,强线被自吸收压低 → Boltzmann 斜率变浅 → T 虚高 5000–10000K。弱线不足 4 条时回退全部有效线。min_boltzmann_delta_e_ev(默认 1.2 eV)时回退(斜率对误差过度敏感)。_boltzmann_fit(E, y) → (slope, R², intercept)。self_absorb_sigma × RMSE),最多移除 30% 且移除后 ≥ 4 条。仅移除向下偏离(自吸收只压低强度),不删向上离群点(避免旧贪心算法过拟合到 2 点拟合的退化问题)。max(min_boltzmann_r2, r2_sig)。scipy 缺失时退化为固定门槛。t_min_k, t_boltzmann_max_k $]$(默认 [3000, 20000] K)。此判定在删线结束后才执行,不参与删线决策,避免"删线直到温度过线"的过拟合。t_ref_k(默认 10000 K)。[t_min_k, t_max_k]。方法: _estimate_electron_density(X, T) → 调用 electron_density.estimate_ne()
物理原理: 等离子体中带电粒子间的电场导致谱线 Stark 展宽,Lorentzian 分量 FWHM 与电子密度成正比:
$$N_e = 10^{17} \times \frac{\text{FWHM}_{\text{Stark}}}{w} \quad (\text{cm}^{-3})$$其中 $w$ 为 Stark 展宽参数(nm)。
代码流程:
electron_density 为 float → 用户指定固定值(最高优先,不受 enable_stark_density 开关影响)。enable_stark_density=False(消融实验)→ 固定 DEFAULT_NE_CM3 = 1×10^{17} cm⁻³。estimate_ne()):
fit_window_nm(默认 1.0nm)窗内拟合 Voigt + 线性背景(_voigt_bg()),提取 Lorentzian HWHM $\gamma$。instrument_width_nm,默认 0.08nm),得到纯 Stark FWHM。self_absorption_tolerance(默认 0.4)的样品标记为自吸收,该线不参与 $N_e$ 计算。1×10^{17}。1×10^{17} cm⁻³。(Ne (n,), diagnostics: {ne_source, per_line, n_lines_used, ...})。方法: _Z(element, ion, T) → 调用 partition_function.partition_function()
物理原理: 配分函数 $Z_{s,\text{ion}}(T)$ 是元素在不同能级上布居的统计权重之和,是 CF-LIBS 浓度公式中消去 $F$ 后唯一与温度相关的修正因子。不同元素、不同电离态的 $Z(T)$ 差异显著(如 Fe I 在 10000K ≈ 28,Fe II ≈ 42)。
代码流程:
partition_functions(旧格式 {Fe: 8.0} 固定值)且未指定 partition_functions_path → 直接返回固定值,忽略 ion 与 T(向后兼容)。partition_function()):
load_partition_table() 从 configs/partition_functions.yaml 读取 {T_points: [...], elements: {elem: {ion: {T: Z}}}},校验 Z ∈ [0.5, 1000] 且随温度单调递增。fallback=1.0。ndarray。方法: 在 _compute_relative_concentrations() 内部执行 → 调用 saha.saha_ratio()
物理原理: Saha 方程描述相邻电离态的浓度比:
$$\frac{n_{s,\text{II}}}{n_{s,\text{I}}} = \frac{2}{N_e} \cdot \frac{Z_{s,\text{II}}(T)}{Z_{s,\text{I}}(T)} \cdot \left(\frac{2\pi m_e k_B T}{h^2}\right)^{3/2} \cdot \exp\left(-\frac{E_{\text{ion}}}{k_B T}\right)$$CF-LIBS 浓度公式对每个电离态分别给出 $q_{\text{ion}} = F \cdot C_{s,\text{ion}} / Z_{s,\text{ion}}(T)$,需合并得到元素总浓度 $C_s = C_{s,\text{I}} + C_{s,\text{II}}$。
代码流程(在 _compute_relative_concentrations() 中对每个元素执行):
_available_ions(elem) 返回原子参数表中存在的 I/II 态(跳过 III 及以上,LIBS 温度下占比 <1%)。_pick_reference_ion(ions) 优先选 I(中性原子谱线更全),单态则直接用。enable_saha_merge=True 时):
saha_max_amplification(默认 $10^4$)。T 过高/Ne 过低时放大倍数可达 $10^3$–$10^4$,超限时钳位并记录诊断(saha_clipped)。方法: _compute_relative_concentrations(X, T, Ne)
这是整个流程中最复杂的步骤,包含谱线质量筛选、浓度计算、降级检测和归一化。
物理原理:
$$C_s \propto Z_s(T) \cdot \left\langle \frac{I_j}{g_j \cdot A_j \cdot \exp(-E_j / k_B T)} \right\rangle_{j \in s}$$归一化消去总比例因子 $F$:$x_s = C_{s,\text{raw}} / \sum_{s'} C_{s',\text{raw}}$。
代码流程:
对每个元素的每个电离态,执行以下 五层过滤(每层可由 enable_* 开关独立关闭,用于消融实验):
| 层 | 过滤 | 物理目的 |
|---|---|---|
| ① 高激发能过滤 | $E \leq$ max_E_ev(默认 12.0 eV) |
高 E 线在典型温度下 Boltzmann 因子极小(<10⁻⁷),1/boltz 放大噪声致浓度虚高 |
| ② 三重过滤(SNR + 对比度 + 备选通道) | SNR ≥ 5.0 且 contrast ≥ 2.0;备选:SNR ≥ 3.0 且 contrast ≥ 1.3 | 过滤噪声峰和连续背景伪峰,恢复 Fe 密集区真实强峰 |
| ③ 光谱干扰检测 | 两级:窗内混合(|Δλ|≤window_nm)+ 近邻强线(实测强度比 > ratio) | 排除被其他元素近邻线污染的线(如 Na D 线污染 S I 589.6nm) |
| ④ 弱线过滤 | $gA \cdot \exp(-E/k_BT) \geq$ min_gA_boltz(默认 2×10⁶) |
gA·boltz 过小时 1/(gA·boltz) 放大因子过大,噪声被放大致浓度失真 |
| ⑤ 相对强度过滤 | net ≥ min_line_intensity × 全谱最大值(默认 1%) |
过除低于检测限的极弱噪声线 |
对每个样品 $i$,统计通过所有过滤的有效线数 $n_{\text{valid}}$:
| 路径 | 条件 | 计算方式 |
|---|---|---|
| 主路径 | $n_{\text{valid}} \geq$ min_lines_for_concentration(默认 4) |
$q = \text{percentile}_{75}(q_{\text{all, valid}})$(上四分位,规避自吸收压低的强线) |
| 降级路径 1 | 1–3 条有效线 | $q = \text{percentile}_{50}(q_{\text{all, valid}})$(中位数,少量线时更鲁棒) |
| 降级路径 2 | 0 条有效线但有非弱线 | 从非弱线中 gA·boltz 最大的最灵敏线推算检测下限:$q_{\text{limit}} = q_{\text{measured}} \times \min(1, 3/\text{SNR})$ |
| 降级路径 3 | 所有线均为弱线 | 赋占位值 floor × 100(代表"低于检测下限") |
对走了降级路径的元素(且未被任一电离态主路径覆盖的样品),施加地质合理浓度上限(trace_concentration_caps,如 Mn ≤ 0.5%、S ≤ 0.8% 等),防止噪声/干扰放大致过估。仅约束降级元素,主量元素不受影响。 钳位后重新归一化保持总和为 1。
$x_s = C_{s,\text{raw}} / \sum_{s'} C_{s',\text{raw}}$,消去未知总比例因子 $F$,得到各元素原子摩尔分数。
方法: mcwhirter_check() + atomic_to_composition()
调用: mcwhirter_check(Ne, T, delta_E)
物理原理: LTE 假设成立需满足 McWhirter 判据:
$$N_e \geq 1.6 \times 10^{12} \times T^{1/2} \times \Delta E^3 \quad (\text{cm}^{-3})$$其中 $\Delta E$ 取参与浓度计算的谱线中最大上能级 $E_{\text{upper}}$(保守上界,因跃迁能量 ≤ $E_{\text{upper}}$)。
代码流程:
{satisfied: (n,) bool, threshold: (n,), min_ne: float, delta_E_ev: float}。调用: atomic_to_composition(C_atomic, feo_fe_ratio)
物理原理: CF-LIBS 输出原子摩尔分数,但铁矿石分析报告要求氧化物/元素质量分数。转换需:
feo_fe_ratio(磁铁矿 ≈ 0.333,赤铁矿 ≈ 0)。代码流程:
atomic_to_element_mass(): 原子摩尔分数 → 含氧元素质量分数(氧按化学计量比分配到各金属元素的分母中)。element_mass_to_composition(): 元素质量分数 → 10 组分 wt% 报告(TFe、FeO、SiO₂、Al₂O₃、CaO、MgO、TiO₂、MnO、P、S)。predict_composition(X)
│
├── Step 1: _estimate_temperature(X)
│ Boltzmann 图法逐样品测温 → T (n,)
│ 核心机制:弱线选择规避自吸收 + 向下离群点移除 + F 检验 R² 门控
│
├── Step 2: _estimate_electron_density(X, T)
│ Stark 展宽法估计 → Ne (n,)
│ 核心机制:Voigt 拟合 + 仪器展宽扣除 + 共振线自吸收检测 + 中位数聚合
│
├── Step 3: _Z(element, ion, T) [在 Step 5 内逐元素调用]
│ NIST 表插值 → Z(T) (n,)
│ 核心机制:离散温度点线性插值,缺失回退 1.0
│
├── Step 4: Saha 合并 [在 Step 5 内逐元素执行]
│ saha_ratio() → C_II/C_I → C_total
│ 核心机制:两态直接相加 or 单态 Saha 推算 + 放大钳位
│
├── Step 5: _compute_relative_concentrations(X, T, Ne)
│ 五层过滤 + 三条浓度路径 + Saha 合并 + 降级上限 + 归一化
│ → {element: 原子摩尔分数 (n,)}
│
└── Step 6: 后处理
├── mcwhirter_check(Ne, T, ΔE) → LTE 判据
└── atomic_to_composition(C_atomic) → 10 组分 wt% 报告
若 calibrated=True,在 fit(X, y) 阶段用已知浓度 $y$ 对目标元素(默认 Fe)的相对浓度 $c_{\text{rel}}$ 做线性校正 $y = a \cdot c_{\text{rel}} + b$。predict_composition() 中以该校正比等比缩放全部元素后重新归一化——即国标 9.2.3 允许的"单点/多点定标 CF-LIBS"模式。