docs: 任务书 03 医生核对包;TIC 拟合约束文献核查记录
来源:负责人 2026-10-17 要求把 29 例处理结果整理成医生能看的格式并做成长期入口(表格 CSV、文字 PDF、视频不压缩、不向医生提问、问题清单只写现象);文献核查为负责人要求的质量门依据核对,结论待医生看过后再定。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# Lognormal 拟合质量门参数:旧项目溯源
|
||||
|
||||
路径前缀:`OLD` = `/home/iomgaa/Projects/CADx-4/reference/CADx-4-CAD`。旧代码行号指当前 HEAD 的 `OLD/app/domain/ceus_roi/tic_fitting.py`。
|
||||
|
||||
## 结论
|
||||
|
||||
`tic_analysis.fitting` 里的每一个数,旧项目里都找不到论文出处,也找不到临床方出处,全部是工程侧在第一轮四段视频工程验收时定的占位值。旧 design/0043、0044 明确写了:这些数**不进决策记录**,要等「代表性开发集」标定后才锁定;而旧项目直到结束也没有做这次标定。两个引入提交(`6630872`、`5d83603`)的提交说明只有标题,没有正文。现在 yaml 注释写的「出自旧项目 design/0044」只说明这些数是在 0044 那次提交引入的,0044 正文里一个数都没有。
|
||||
|
||||
旧仓库的临床规范抄本(`535c387` 里的 08-16 重写稿)给多峰判据和主峰判据定了**另一组数**(0.80 / 3.0 秒),和拟合段的 `multi_peak_*`、`minimum_peak_distance_s` 对不上。见第 6 行和「没把握的地方」。
|
||||
|
||||
## 一、逐条溯源表
|
||||
|
||||
| # | 约束 | 当前值 | 引入提交 | 出处原文(文件:行号) | 出处类别 |
|
||||
|---|---|---|---|---|---|
|
||||
| 1a | 峰高上界 = 幅度 × 10 | `height_upper = max(amplitude*10.0, 1.0)` | `5d83603`(2026-09-18,「收紧双曲线拟合与截图就绪门」,无正文)。v1 `6630872` 用的是面积上界 `amplitude*duration*100`(`git show 6630872:app/domain/ceus_roi/tic_fitting.py` 第 352 行) | 旧代码 `tic_fitting.py:457`,没有注释。0043:154-155「约束至少保证 `A > 0`、`σ > 0`……边界的数值不在本文重复,最终进入工程配置并由标定数据决定」 | 工程侧自定(写死在代码里,没进配置) |
|
||||
| 1b | 峰时刻窗:候选峰 ±`candidate_long_window_s`(5 s),并且离拟合区间头尾各 `boundary_margin_s`(0.25 s) | 5.0 / 0.25 | `candidate_long_window_s` 是 `5d83603` 引入的;`boundary_margin_s` 是 `6630872` 引入的,`5d83603` 起才用作峰窗 | 旧代码 `tic_fitting.py:807-814`。旧 yaml 注释:`candidate_long_window_s: 5.0 # 宏观 bolus 候选,抑制逐帧掩膜与压缩波动`(`OLD/config/ceus_roi_default.yaml:117`)。0044:133-134「峰值必须位于第一遍 bolus 的实际观察区间」只讲原则,没有给数 | 工程侧自定 |
|
||||
| 1c | σ 区间 [0.08, 2.5] | 0.08 / 2.5 | `6630872` | `OLD/config/ceus_roi_default.yaml:127-128`,没有注释。0044:141-142「否决"放宽形状参数上界直到现有样本通过"。贴边解说明参数空间或数据支持有问题」。0049:18-20 记录一次 `roi_pan` 拟合「`sigma` 到达配置上限,质量门以 `parameter_on_boundary` 拒绝」;0049:47「不提高 `sigma_max`,不为参考区另造一套未标定的拟合阈值」 | 工程侧自定(0049 自己写了「未标定」) |
|
||||
| 1d | t0 区间:观察到基线时不早于拟合起点;估计基线时可早 `estimated_baseline_lookback_s`(10 s) | 10.0 | `5d83603` | 旧代码 `tic_fitting.py:815-819`。旧 yaml `:136` `estimated_baseline_lookback_s: 10.0 # 允许 t0 位于视频起点前,但截图不外推`。**注意**:旧 `research_config.py:488` 里 pydantic 的默认值是 `5.0`,和 yaml 的 10.0 不一致(yaml 覆盖默认值,所以实际跑的是 10.0)。0044:90-93 讲联合估计基线的道理,没有给数 | 工程侧自定 |
|
||||
| 1e | 基线区间:观察基线 ±max(3×噪声, 5%幅度);估计基线时下界 max(0, P1−0.25×幅度),上界 min(P45, 基线+0.35×幅度);正则尺度 max(0.2×幅度, 噪声) | 3.0 / 0.05 / P1 / P45 / 0.25 / 0.35 / 0.2,全写死在代码里 | `5d83603`(`amplitude*0.05` 最早出现在 `6630872`,当时用作残差尺度) | 旧代码 `tic_fitting.py:458-469`,没有注释。0044:91-92「估计范围由曲线低分位、局部噪声和显示灰度范围共同约束,并用正则项阻止基线……任意漂移」只讲原则。这里的 3×噪声和临床契约的到达判据 3×σ0 是两回事(契约见 `ceus.yaml` 的 `anchor_frames.arrival`),代码里没有任何地方把两者关联起来 | 工程侧自定 |
|
||||
| 2 | `parameter_boundary_fraction=0.001`:参数贴边即拒绝 | 0.001 | `5d83603` | 旧 yaml `:138` `# 形状参数贴边判据占允许区间的比例`。拒绝这一规则的出处是 0044:138-140「形状参数贴近边界、峰值落在观察边缘时,即使残差门通过也不能成为正式拟合」。0.001 这个数本身找不到出处 | 规则:工程侧设计(0044)。数值:工程侧自定 |
|
||||
| 3 | 模型峰不得落在拟合区间头尾(`model_peak_on_boundary`,余量 0.25 s) | 0.25 | `6630872`(v1 已有这一拒绝;`5d83603` 起改用拟合区间头尾) | 旧代码 `tic_fitting.py:864-870`。0043:206-207 失败语义「峰值落在观测边界」;0043:154「模型峰值落在观测到的有效时间范围」;0044:138-139。0.25 s 的数值找不到出处 | 规则:工程侧设计(0043/0044)。数值:工程侧自定 |
|
||||
| 4 | `minimum_r2=0.35`、`maximum_nrmse=0.45`、`maximum_residual_noise_ratio=2.0`;判据是 nRMSE 必须过,R² 和残差噪声比二者过一个即可 | 0.35 / 0.45 / 2.0 | `minimum_r2`、`maximum_nrmse` 是 `6630872` 引入的;`maximum_residual_noise_ratio` 是 `5d83603` 引入的 | 旧代码 `tic_fitting.py:871-876`。旧 yaml `:133` `# 残差不高于基线噪声同量级时允许低 R²`。0043:248-250「`1.5 s` 平滑窗、某个固定 `R²`、`nRMSE` 或信噪比门槛都可以作为实验起点,不能在只有一例真实交付时成为正式口径」。0044:168-170「具体数值进入版本化配置并由代表性开发集锁定,不在决策记录中复制」。旧 `explanation/tic-quantification-encoding.md:594`「Lognormal 的 `fit_R2`、`fit_nRMSE` 与残差质量门 \| 工程侧占位,代表性开发集标定后固定 \| 工程侧」。「二者过一个」的理由见旧 `explanation/ceus-roi-pipeline.md:510-512`「让低动态范围但残差已落入观测噪声的曲线不因 `R²` 单项被误杀」。临床规范抄本只要求「`fit_R2` 与 `fit_nRMSE` 各自过门槛时记 1」,没有给门槛值(`git show 535c387:"research-wiki/scratch/2026-08-16-ceus-tic规范重写稿.md"` 第 899 行) | 工程侧自定(文档自己写明是占位)。临床方只定了这两个字段,没给数值 |
|
||||
| 5 | `roi_all` 和 `roi_perf` 两条都成功,才取 D1–D4 | — | `5d83603`(`lesion_fit_ready` 由它引入) | 0044:30-31「项目负责人确认了本轮交付目标:`roi_all` 与 `roi_perf` 都要得到可用于取值的 Lognormal 拟合,关键截图由 `roi_perf` 的连续拟合曲线定位」。0044:53-54「一次病灶截图任务只有在两条拟合都通过后才进入关键时刻提取」。旧代码 `OLD/app/domain/ceus_roi/service.py:482`、`OLD/debugs/tic_lognormal_replay.py:514`。本仓库对应位置是 `src/cadx/ceus/_pipeline.py:300` 和 `_anchor_frames.py:234`,不在 `_tic.py` | 负责人决定(工程侧 design 记录),不是临床方,也不是论文 |
|
||||
| 6a | `candidate_window_s=1.5`、`candidate_polyorder=2`、`max_candidate_gap_s=0.5`、`minimum_valid_samples=20`、`duplicate_mean_absdiff_threshold=0.25`、`max_nfev=4000`、`robust_loss=soft_l1` | 同左 | 全部是 `6630872` | 旧 yaml `:116-130`。0043:126-128「阶数固定为 2,因为一阶导数需要表达峰附近的曲率;具体窗口时长必须通过代表性视频标定」。0043:100-101 重复帧阈值「属于待标定参数」。0043:109-110 短缺口「不能在没有批量素材时拍一个固定秒数」。0043:157-158 损失函数「Huber 或 `soft_l1`……实现前的开发集比较负责在两者中固定一个」,但找不到任何比较记录。旧 encoding.md:595-597 把候选窗、重复帧、短缺口列为「工程侧占位」 | 工程侧自定(文档自己写明待标定) |
|
||||
| 6b | `minimum_peak_distance_s=1.0`、`minimum_relative_peak_height=0.10` | 1.0 / 0.10 | `6630872` | 旧 yaml `:122-123`,没有注释。**对照临床规范抄本 §7.1**:「候选峰的高度要达到全局峰值的 0.80」「峰的突出度要超过"峰高的 0.10 倍"与"基线噪声 σ0 的 3 倍"中较大的那一个」「多个候选彼此要隔开多远才算两个峰,规范给的是 3.0 秒」(`535c387` 重写稿第 213-219 行)。拟合段的候选检测没有用这组数 | 工程侧自定,和临床规范 §7.1 的数不一致 |
|
||||
| 6c | `multi_peak_minimum_separation_s=5.0`、`multi_peak_minimum_relative_height=0.50`、`multi_peak_maximum_valley_fraction=0.25` | 5.0 / 0.50 / 0.25 | `6630872` | 旧 yaml `:124-126`,没有注释。**对照临床规范抄本 §15**:「第二峰高度达到第一主峰的 0.80、且两峰间距达到 3.0 秒时,记下一条"这条曲线有两个峰"的提示」(`535c387` 重写稿第 448 行)。旧 encoding.md:578-579 把「多峰判据:第二峰占第一主峰的高度比例 / 两峰最小间距」的取值权威列为《临床口径契约》(临床方原规范 §15)。谷深比 0.25 是工程侧另加的条件,理由见 ceus-roi-pipeline.md:506-507「否则呼吸和 ROI 跟踪造成的周期振荡会被误判成再次推注」 | 工程侧自定,和临床规范 §15 的数不一致 |
|
||||
| 6d | `estimated_baseline_percentile=15.0`(另有写死的 `min(2×15, 45)` 分位低值集) | 15.0 | `5d83603` | 旧 yaml `:135` `# 无稳定开头时的有界基线先验`。旧代码 `tic_fitting.py:245-248` | 工程侧自定 |
|
||||
| 6e | `maximum_perf_area_step_fraction=0.15` | 0.15 | `5d83603` | 旧 yaml `:137`。0044:71-73 讲规则(相邻帧去暗区面积比例突变就排除),没有给数 | 规则:工程侧设计。数值:工程侧自定 |
|
||||
|
||||
旧文档里明确写出「这些数是占位」的总括引文:
|
||||
- 0043:268-269「拟合质量门槛、Savitzky-Golay 候选窗口、重复帧阈值、短缺口上限和参数边界只在开发集上确定一次,锁定后用于整个队列」
|
||||
- 0043:281-282「参数在更大开发集上锁定前不得描述成临床阈值」
|
||||
- 0044:193-194「正式门槛仍需在代表性开发集上评价……」
|
||||
- 旧 `explanation/tic-quantification-encoding.md:600-603`「当前值是首轮工程占位,四段本地 MP4 只验证失败可见性、帧率差异和回放链路,不能代替代表性开发集标定」
|
||||
- 旧 `explanation/ceus-roi-pipeline.md:727-728`「尚未在代表性开发集上锁定,不能视为临床标定」
|
||||
- 旧 `research_config.py:456-459` docstring「这些值只用于第一轮工程验收,不是临床阈值」
|
||||
- 旧 `guides/replaying-lognormal-tic.md:167`「四例只构成工程冒烟集,不足以锁定候选窗口、重复帧、多峰和质量阈值」
|
||||
|
||||
临床方唯一规定过的拟合相关内容:曲线处理方法从四种里选一种(gamma-variate 拟合、lognormal 拟合、Savitzky-Golay、local regression),全队列统一、参数固定(旧 design/0030:288、encoding.md:521;原规范 §3.5);另外列了 `fit_QC` / `fit_R2` / `fit_nRMSE` 三个字段(原规范 §17)。临床方没有给任何门槛值。
|
||||
|
||||
## 二、旧项目提到过的 TIC 相关文献
|
||||
|
||||
全部集中在旧 `research-wiki/design/0043-mp4-tic-lognormal-fitting.md` §13(289-310 行)。没有一篇被引来支撑具体数值,只用来支撑路线选择。下表年份是我从 URL 和期刊 ID 推的,文件里没有写年份。
|
||||
|
||||
| 作者 / 来源 | 年份(推断) | 被引位置 | 引来支撑什么 |
|
||||
|---|---|---|---|
|
||||
| Bracco,VueBox® Instructions for Use(v7.7,VBO.8.20) | 2025-06-06(0042:22-23 写明) | 0043:291-292;0042:22-25;原件在 `OLD/debugs/VueBox说明书.pdf` | 删重复帧、bolus/replenishment 两种模型、保留拟合信号、输出 QOF。0043:62-63 明说说明书没有公开函数、优化器、初始化、边界和 QOF 公式 |
|
||||
| Bracco 产品页 VueBox Quantification Toolbox | — | 0043:293-294 | bolus 与 replenishment 用的是专有拟合模型 |
|
||||
| Cooley 等,nanobubble 微流控(RSC Lab Chip,D3LC00514C) | 约 2023 | 0043:295-297 | 能从 MP4 灰度矩阵生成 TIC(体外实验,0043:65-66) |
|
||||
| Hoyt 等,pixel-by-pixel CEUS perfusion kinetics(PMC3463888) | 约 2012 | 0043:298-300 | 有损压缩 CEUS 视频可以做半定量时序分析,同时说明压缩带来的局限(0043:68-70) |
|
||||
| Gheonea 等,quantitative low-MI CE-EUS,胰腺(PMC3548695) | 约 2013 | 0043:301-303 | 胰腺 CE-EUS 视频逐帧 ROI 灰度并加参照曲线,作为临床先例(0043:72-74) |
|
||||
| Harabis 等,indicator dilution models for UCA bolus(PMID 23348425) | 约 2013 | 0043:304-305 | 拟合残差最小,不代表参数最接近真值(0043:76-78) |
|
||||
| Kuenen 等,multi-model framework(PMC6615468) | 约 2019 | 0043:306-308 | Lognormal、Gamma-variate、LDRW 等模型之间的差异,以及逐模型的拟合比较 |
|
||||
| Fujioka 等,Ceusia-Breast(PMC10466705) | 约 2023 | 0043:309-310 | 被否决的 Logistic 洗入加指数洗出方案的来源(0043:240-244) |
|
||||
|
||||
本仓库 `reference-pdf/INDEX.md`(50 个 PDF)里没有一篇 TIC、Lognormal 或灌注建模方法学论文。2018 年的 EFSUMB 非肝 CEUS 指南只是临床检查规范,也没有被引来支撑拟合参数。旧仓库的 `research-wiki/reference/roi-tic-parameters.md` 和 `glossary.md` 里完全没有 Lognormal 拟合的内容。
|
||||
|
||||
## 三、我没把握的地方
|
||||
|
||||
1. **临床规范抄本只到 08-16 重写稿为止。** 旧 yaml 里的 anchor_frames 镜像的是《临床口径契约》2026-08-25 版,而契约本身在 Linear 上,旧仓库没有它的全文。我拿来对照的 §7.1 / §15 数值(0.80、3.0 秒)出自 `535c387` 的 08-16 重写稿。08-25 版或之后有没有改这几个数,我没有核到;要核得去 Linear 读契约原文。拟合段的 `multi_peak_*` 和 `minimum_peak_distance_s` 是不是有意偏离临床口径(只用于找候选、不直接当临床多峰判据),旧文档没有写;我在旧文档里只看到 encoding.md:578-579 把多峰判据的权威归到契约。
|
||||
2. **`fit_quality ≥ 85%` 的来历查不出。** 旧 `debugs/TIC关键帧与定量质检指标_计算方式.md:78` 和 `debugs/TIC指标_LLM输入清单.md:42` 都写着「当前质量门不是单一的 `R² ≥ 85%`」,看上去有人(可能是临床方)提过 85% 这个口径,但旧仓库里找不到最早出处。最早出现在提交 `2351e69`,提交说明没有正文。VueBox 说明书里 QOF 的单位是 %,我在它的文本里没有找到 85% 这个门槛。
|
||||
3. **`6630872` 和 `5d83603` 两个提交的说明都只有标题**,所以「为什么取 0.35 / 0.45 / 2.0 / 0.001 / ×10」只能从 design 和代码注释里推断。四段工程视频上有没有试过别的取值,旧仓库没有留下记录;我也没有翻 `debugs/` 下的日志。
|
||||
4. 上表的年份是从 URL 和 ID 推断的,没有逐篇打开核对。
|
||||
5. 旧 `research_config.py:488` 里 `estimated_baseline_lookback_s` 的默认值 5.0 和 yaml 的 10.0 不一致。按 pydantic 的读法实际生效的是 yaml 的 10.0,但我没有在旧项目里跑代码确认。
|
||||
Reference in New Issue
Block a user