Files
CADx-4/research-wiki/scratch/2026-10-17-TIC拟合约束文献核查/D-old-sources.md
T
iomgaa 14d6f8e153 docs: 任务书 03 医生核对包;TIC 拟合约束文献核查记录
来源:负责人 2026-10-17 要求把 29 例处理结果整理成医生能看的格式并做成长期入口(表格 CSV、文字 PDF、视频不压缩、不向医生提问、问题清单只写现象);文献核查为负责人要求的质量门依据核对,结论待医生看过后再定。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 05:09:34 -04:00

65 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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,但我没有在旧项目里跑代码确认。