246 lines
11 KiB
Markdown
246 lines
11 KiB
Markdown
# 判定逻辑补全设计(二期)
|
||
|
||
> 关联文档:一期设计 `2026-05-15-rust-tauri-mvp-design.md`;需求来源 `docs/建材放射性检测结果分析软件开发计算逻辑(1).pdf`。
|
||
|
||
## 1. 目标
|
||
|
||
一期已完成算法骨架(IRa/Ir、A/B 类不确定度、GUM 合成、MCM 仿真)。本期补齐 PDF 第 3、6 节缺失的**判定层与输出层**,使软件能给出最终交付给用户的"有效性 + 合格/不合格 + 材料分级"结论,而不只是中间量。
|
||
|
||
补齐范围:
|
||
|
||
- 1.3 样品信息:材料类型选择与对应限值集。
|
||
- 2.2.4–2.2.6:扩展不确定度 U、k=1/k=2 相对扩展不确定度、GUM 解析真值区间 P2.5/P97.5。
|
||
- 3.1 有效性判定(37 Bq/kg 低活度豁免 + Ur(IRa) 阈值)。
|
||
- 3.2 临界值判定(真值区间是否跨越极限值 → 合格/不合格/建议增加次数)。
|
||
- 3.2.3 装饰装修材料 A/B/C 三级分类。
|
||
- 单次测量(n=1)主流程支持。
|
||
- 6.1 输出元信息(样品编号、计算日期)。
|
||
- 修正合成不确定度中 A 类项缺少校准因子 `a` 的问题。
|
||
|
||
非目标(仍延后):SQLite 历史、Excel/PDF 报告导出。本期只在内存结构和界面上给出完整结论,导出留三期。
|
||
|
||
## 2. 与现状的差距映射
|
||
|
||
| PDF 节 | 现状 | 本期动作 |
|
||
|---|---|---|
|
||
| 1.3 材料类型 | 无,仅手填 limit | 新增 `MaterialType`,按类型派生限值 |
|
||
| 2.2.4 扩展不确定度 | 无 | `IndexResult` 增 `expanded_uncertainty` |
|
||
| 2.2.5 k=1/k=2 相对 | 仅一套(k=1) | 增 `relative_expanded_uncertainty_percent` |
|
||
| 2.2.6 GUM 真值区间 | 仅 MCM 百分位 | `IndexResult` 增 `p2_5/p97_5 = value ± U` |
|
||
| 3.1 有效性 | 仅 Ur≤20% 双指数 | 实现 37 Bq/kg 豁免,仅看 Ur(IRa) |
|
||
| 3.2 临界值判定 | 无 | 新增 `Verdict` 判定函数 |
|
||
| 3.2.3 A/B/C | 无 | 装饰材料级联分类 |
|
||
| 单次测量 | `count<2` 报错 | n=1 时 uA=0 放行 |
|
||
| 6.1 元信息 | 无 | 输入/输出增 `sample_id`、`calculation_date` |
|
||
| 合成不确定度 A 类项 | 漏 `a` 因子 | 修正为 `a·uA` |
|
||
|
||
## 3. 领域模型变更(`domain.rs`)
|
||
|
||
### 3.1 输入
|
||
|
||
```rust
|
||
pub struct SampleInput {
|
||
pub ra: NuclideMeasurements,
|
||
pub th: NuclideMeasurements,
|
||
pub k: NuclideMeasurements,
|
||
#[serde(default)]
|
||
pub material_type: MaterialType, // 新增,默认 BuildingMainBody
|
||
#[serde(default)]
|
||
pub sample_id: Option<String>, // 新增 6.1
|
||
#[serde(default)]
|
||
pub calculation_date: Option<String>, // 新增 6.1,前端传 ISO 字符串
|
||
}
|
||
|
||
#[derive(Default)]
|
||
pub enum MaterialType {
|
||
#[default]
|
||
BuildingMainBody, // 建筑主体材料 IRa≤1.0, Ir≤1.0
|
||
HollowBuildingMainBody, // 空心率>25%主体材料 IRa≤1.0, Ir≤1.3
|
||
DecorativeMaterial, // 装饰装修材料 A/B/C 分级
|
||
}
|
||
```
|
||
|
||
`AcceptanceLimits` 不再由前端手填,改为由 `MaterialType` 派生(保留结构体用于 MCM 比较)。装饰材料有多级限值,用一张分级表表达:
|
||
|
||
```rust
|
||
pub struct LimitTier { pub label: &'static str, pub ira_limit: Option<f64>, pub ir_limit: Option<f64> }
|
||
|
||
impl MaterialType {
|
||
/// 返回从严到宽的限值阶梯。主体材料/空心材料各 1 级;装饰材料 A/B/C 三级。
|
||
pub fn tiers(&self) -> &'static [LimitTier] { /* 见下表 */ }
|
||
}
|
||
```
|
||
|
||
限值表(来自 PDF 3.2):
|
||
|
||
| 材料类型 | 级别 | IRa 限 | Ir 限 |
|
||
|---|---|---|---|
|
||
| 主体材料 | 合格 | 1.0 | 1.0 |
|
||
| 空心率>25% | 合格 | 1.0 | 1.3 |
|
||
| 装饰装修 | A | 1.0 | 1.3 |
|
||
| 装饰装修 | B | 1.3 | 1.9 |
|
||
| 装饰装修 | C | — | 2.8 |
|
||
|
||
> C 类只约束 Ir(`ira_limit = None`)。
|
||
|
||
### 3.2 指数结果扩展
|
||
|
||
```rust
|
||
pub struct IndexResult {
|
||
pub value: f64,
|
||
pub standard_uncertainty: f64, // u, 已有
|
||
pub expanded_uncertainty: f64, // U = u·k (k=2),新增
|
||
pub relative_uncertainty_percent: f64, // k=1,已有
|
||
pub relative_expanded_uncertainty_percent: f64, // k=2,新增
|
||
pub p2_5: f64, // value - U,新增(GUM 解析区间)
|
||
pub p97_5: f64, // value + U,新增
|
||
}
|
||
```
|
||
|
||
指数包含因子固定 `k = 2`(PDF 2.2.4/2.2.6)。
|
||
|
||
### 3.3 判定结果
|
||
|
||
```rust
|
||
pub struct CalculationResult {
|
||
/* 既有字段 ... */
|
||
pub analysis: AnalysisResult, // 新增
|
||
}
|
||
|
||
pub struct AnalysisResult {
|
||
pub total_calibrated_activity: f64, // A1·a+A2·b+A3·c
|
||
pub validity: Validity,
|
||
pub verdict: Verdict,
|
||
}
|
||
|
||
pub enum Validity {
|
||
LowActivityExempt, // ≤37 Bq/kg,直接有效
|
||
UncertaintyAcceptable, // >37 且 Ur(IRa)≤20%
|
||
Invalid, // >37 且 Ur(IRa)>20%
|
||
}
|
||
|
||
pub enum Verdict {
|
||
Qualified, // 主体/空心:合格
|
||
Unqualified, // 不合格
|
||
DecorativeClass(DecorClass), // 装饰:A/B/C
|
||
NeedMoreMeasurements, // 真值区间跨越极限值,建议增加到 6 次
|
||
InvalidResult, // 有效性不成立
|
||
}
|
||
|
||
pub enum DecorClass { A, B, C, Unqualified }
|
||
```
|
||
|
||
`Conclusion` 枚举保留(向后兼容),但 UI 主结论改用 `Verdict`。
|
||
|
||
## 4. 计算逻辑变更(`calculator.rs`)
|
||
|
||
### 4.1 单次测量支持
|
||
|
||
`validate_input`:`count` 下限由 2 改为 1,且三核素次数一致。`type_a_uncertainty`:`n == 1` 时返回 `0.0`(PDF 2.2.1 uA=0),`n>=6` 走标准差法,`2<=n<6` 走极差法,`n` 其它非法值仍报错。
|
||
|
||
### 4.2 合成不确定度修正
|
||
|
||
校准比活度 `C = mean·a`,对测量值 A 的灵敏系数是 `a`:
|
||
|
||
```rust
|
||
// 修正前: combined = sqrt(uA² + (mean·uB)²)
|
||
// 修正后: combined = sqrt((a·uA)² + (mean·uB)²)
|
||
let combined = ((factor*type_a).powi(2) + (mean*type_b_uncertainty).powi(2)).sqrt();
|
||
```
|
||
|
||
n=1(uA=0)时与现状一致,可与 PDF 单次算例对齐校验。
|
||
|
||
### 4.3 GUM 真值区间
|
||
|
||
每个 `IndexResult` 计算 `U = u·2`,`p2_5 = value - U`,`p97_5 = value + U`,相对量两套(u/value 与 U/value)。
|
||
|
||
### 4.4 有效性判定(3.1)
|
||
|
||
```rust
|
||
let total = ra.mean_calibrated + th.mean_calibrated + k.mean_calibrated; // A1·a+A2·b+A3·c
|
||
let validity = if total <= 37.0 {
|
||
Validity::LowActivityExempt
|
||
} else if ira.relative_expanded_uncertainty_percent <= 20.0 {
|
||
Validity::UncertaintyAcceptable
|
||
} else {
|
||
Validity::Invalid
|
||
};
|
||
```
|
||
|
||
> **待确认 1**:3.1 的 `Ur(IRa)≤20%` 用 k=2 的相对扩展不确定度(与 2.2.5 命名一致)还是 k=1。本设计先取 k=2,见第 7 节。
|
||
|
||
### 4.5 临界值判定(3.2)
|
||
|
||
核心是"真值区间 [P2.5,P97.5] 相对极限值 L 的位置"的三态函数:
|
||
|
||
```rust
|
||
enum TierCheck { Pass, Fail, Straddle } // 全在限下 / 全在限上 / 跨越
|
||
|
||
fn check(idx: &IndexResult, limit: Option<f64>) -> TierCheck {
|
||
let Some(l) = limit else { return TierCheck::Pass }; // 无约束(如 C 类的 IRa)
|
||
if idx.p97_5 < l { TierCheck::Pass } // 区间不含 L 且值 < L
|
||
else if idx.p2_5 > l { TierCheck::Fail } // 区间不含 L 且值 > L
|
||
else { TierCheck::Straddle } // 区间含 L → 建议增加次数
|
||
}
|
||
```
|
||
|
||
组合规则:
|
||
|
||
- 若 `validity == Invalid` → `Verdict::InvalidResult`。
|
||
- **主体/空心材料**(单级):IRa、Ir 两项 `check`。
|
||
- 任一 `Straddle` → `NeedMoreMeasurements`。
|
||
- 两项均 `Pass` → `Qualified`。
|
||
- 否则(存在 `Fail`)→ `Unqualified`。
|
||
- **装饰材料**(A→B→C 级联):自严到宽逐级判断。
|
||
- 某级两项(C 级仅 Ir)均 `Pass` → 归该级(`DecorClass::A/B/C`)。
|
||
- 某级存在 `Straddle` 且尚未在更严级别通过 → `NeedMoreMeasurements`。
|
||
- 全部级别都不通过且 C 级 `Fail` → `DecorClass::Unqualified`(不可用于建材)。
|
||
|
||
### 4.6 与 MCM 的衔接
|
||
|
||
GUM 路径给出确定性 `Verdict`;当 `Verdict::NeedMoreMeasurements`(区间跨越极限值)时,MCM 的 `overall_fail_probability` 即 PDF 6.3 的"95% 置信概率下不符合概率",作为补充量化结论展示。MCM 仍每次都算(用当前限值),无需新增接口。
|
||
|
||
> **待确认 2**:6 次测量后若仍跨越极限值,最终合格判据用 MCM 不符合概率阈值(如 <5% 判合格)还是仅展示概率由人判断。现有代码用 `pass_probability>=0.95`,本设计沿用并在第 7 节标注。
|
||
|
||
## 5. 界面变更(`App.tsx`)
|
||
|
||
- 顶部输入区:新增**材料类型**下拉(三选一)、**样品编号**输入、**计算日期**选择(默认今日)。移除手填 IRa/Ir 限值,改为根据材料类型只读展示当前限值表。
|
||
- 结果区新增"**分析判定**"卡片:
|
||
- 有效性标签(有效/低活度豁免/无效)+ 总比活度 `A1·a+A2·b+A3·c` 与 37 对比。
|
||
- 最终判定标签:合格 / 不合格 / A 类·B 类·C 类 / 建议增加至 6 次 / 结果无效。
|
||
- 各指数 GUM 真值区间 `[P2.5, P97.5]`、U、相对扩展不确定度(k=1/k=2)。
|
||
- 报告头展示样品编号与计算日期,为三期导出做准备。
|
||
|
||
类型定义(TS)同步扩展 `MaterialType`、`AnalysisResult`、`Verdict`、`IndexResult` 新字段。
|
||
|
||
## 6. 测试(`tests/calculator_tests.rs`)
|
||
|
||
新增:
|
||
|
||
- **单次测量对齐 PDF 算例**:A1=83.439/a=0.916 等,断言 IRa≈0.38、Ir≈0.73、u(IRa)≈0.012、U(IRa)≈0.024、P2.5≈0.36、P97.5≈0.40、Ur(IRa,k=2)≈6.3%。
|
||
- **有效性**:total≤37 → `LowActivityExempt`;total>37 且 Ur 大 → `Invalid`。
|
||
- **临界值三态**:构造区间全低/全高/跨越,断言 `Qualified`/`Unqualified`/`NeedMoreMeasurements`。
|
||
- **装饰材料级联**:分别命中 A、B、C 与 Unqualified。
|
||
- **合成不确定度修正**:多次测量下 A 类项含 `a` 因子(与手算对比)。
|
||
- 既有 6 次测量与 MCM 测试保持通过(注意修正后数值会有小幅变化,需更新期望值)。
|
||
|
||
## 7. 已确认决策
|
||
|
||
1. **3.1 的 Ur(IRa) 取 k=2 的相对扩展不确定度**(`relative_expanded_uncertainty_percent`),与 2.2.5 命名一致。✅ 已定
|
||
2. **6 次测量后的最终合格判据**:用 MCM 不符合概率,`overall_fail_probability < 5%`(即 `pass_probability ≥ 0.95`)自动判合格/不合格。✅ 已定
|
||
3. **材料类型限值只读**:移除前端手填 IRa/Ir 限值,严格按材料类型派生。✅ 已定
|
||
|
||
仍按本设计默认处理、无需进一步确认:
|
||
|
||
4. **计算日期来源**:由前端生成 ISO 字符串传入(本地时区可控,Rust 侧不引入 `chrono`)。
|
||
5. **单次测量仍跑 MCM**:n=1 时 uA=0,MCM 仅传播 B 类不确定度,仍有意义,默认保留。
|
||
|
||
## 8. 实施顺序
|
||
|
||
1. `domain.rs`:`MaterialType`/限值表 + `IndexResult` 扩展 + `AnalysisResult/Verdict`。
|
||
2. `calculator.rs`:单次测量、合成不确定度修正、GUM 区间、有效性、临界值判定。
|
||
3. 补充/更新 Rust 测试至全绿(先对齐 PDF 单次算例)。
|
||
4. `lib.rs` 导出新类型;`main.rs` 命令签名无需变更(结构体透传)。
|
||
5. `App.tsx`:材料类型/样品信息输入 + 分析判定卡片。
|
||
6. 端到端手测三类材料的合格/不合格/分级/建议增加次数路径。
|