修复:适应视图不跟随时间轴偏移 + 派生信号构造成空信号

## 为什么

用户 2026-10-29 报告两条功能异常:

1. 给某条信号设置「调整 → 时间轴」偏移后,再点「适应视图」,视界没有跟着平移,
   曲线整体跑到视界之外;
2. 用「均值滤波 / 弱峰调整」的「构建为新信号」派生出来的信号是**空的**(有一个网格但画不出任何东西)。

## 根因

### ① 时间边界没有叠加 offsetTime

采样实际画在 `t + SignalStyle::offsetTime` 处,但"取景用的时间范围"只统计了时间轴的
源时刻下限/上限(`axis.minTime/maxTime`),三处都漏了偏移:

- `TabConfig::ComputeVisibleTimeBounds`(「适应视图」/视图裁剪的时间范围来源)
- `PlotView::CollectFitContributions`(`minTime`/`maxTime` 与单值点的 `pointTime`)
- `PlotView::FitTimeToLane`(网格右键「按网格时间轴展开」)

于是偏移后取景仍停留在原始时间范围。

### ② 派生信号把时间偏移"烘"进采样值

`Application::BuildDerivedSignal` 的 2c 步按 `time[i] - offsetTime` 重采样,把平移写进采样值。
派生信号与源信号**共用同一条文件时间轴**,所以平移出轴范围的那一段只能写成 NaN:
偏移 ≥ 数据跨度时整条信号变成全 NaN(= 空信号),偏移很小时也会在两端留下与实际曲线不符的空洞。

预览曲线本来就用**源样式的 `offsetTime`** 绘制(`PaintDerivedCurve` 里 `TimeToX(time + offsetTime)`),
因此把偏移留在派生信号的样式上,显示与预览一致,且采样数据一点都不会丢。

## 改了什么

1. `Utilities/Src/DataModelTab.cpp`:`ComputeVisibleTimeBounds` 逐信号叠加 `style->offsetTime`
   (`low = min(low, axis.minTime + off)`、`high = max(...)`)。
2. `Components/PlotView/Src/PlotViewFeatures.cpp`:
   - `CollectFitContributions` 的 `minTime/maxTime` 叠加偏移;单值点的 `pointTime` 改为**显示时刻**
     (`time + offsetTime`),视界居中与边界让位都以它为准;
   - `FitTimeToLane` 同样叠加偏移。
3. `Components/Application/Src/ApplicationCommands.cpp`:
   - 删除 2c(重采样烘值),时间偏移改由**新信号样式**表达(3b 变成唯一路径);
   - 同步重写两处注释说明"为什么不再烘值"。
4. 文档:`DataModel.hpp::ComputeVisibleTimeBounds`、`PlotView.hpp::{TimeBounds,FitContribution}`
   的注释更新为"显示时间(含 offsetTime)"。
5. `Documents/agent_mem.md`:追加第十四轮,并把两条旧规则显式标注为**已作废**
   (时间边界只取源时刻 / 派生信号烘值),写明现行做法与理由。

## 副作用(有意为之)

派生信号若源自"带时间轴偏移"的信号,它的「调整」面板里「时间轴」会显示该偏移值。
旧实现为了让面板显示默认值而烘值,代价是数据被裁掉甚至整条变空 —— 这个取舍不可接受。

## 怎么验证

新增离屏探针 `.preflight/derivecheck`(16 条断言,不占鼠标/键盘/屏幕):

```
INFO signals=10 axis=[0.000000, 1.260000] span=1.260000
mean:     values=1009 finiteCount=1009      -> 有数据、范围不越界
weakPeak: values=1009 finiteCount=1009      -> 有数据
offset=0.126000 fitView=[0.126000, 1.386000] (期望 [0.126, 1.386])-> 适应视图跟随偏移
offset-derived:  values=1009 finite=1009    (修复前 908)
huge-offset-derived: values=1009 finite=1009 styleOffset=2.520000 (修复前全 NaN)
16 passed, 0 failed
```

回归(全部通过):

```
make release / make debug                 零 error / 零 warning
uicheck 69/69   lbcheck 21/21   lbresid 5/5   lbzorder 4/4
lbcovr   7/7    lbpanel 10/10   derivecheck 16/16
rendercheck: 8 个场景哈希与上一轮逐一相同 + FUNC 7/7, exit=0
  A FAED59DF284153DB  B E6443BFE4E3955F8  C 96A0AA8C402F1729  D E3D5DBD998E43720
  E DA0583CB13C26A6F  F FFB822159F604D1D  G 19F8DE8FE3A8DF18  H DBBDDE4CB2C97C92
```

产物仍是 **788,992 B**(单一 exe,未拆 DLL,未改优化等级)。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-29 13:48:25 +08:00
1 parent 044b87383b
commit 71c6ff91cb
6 files changed
+91 -68

No files matched your search

+35
View File
@@ -8465,3 +8465,38 @@ rendercheck: A FAED59DF284153DB / B E6443BFE4E3955F8 / C 96A0AA8C402F1729 / D E3
"超在哪一段(`.text` / `.rdata` / `.xdata`+`.pdata` / `.rsrc`)、由哪个改动贡献"。
查段构成的标准命令:`objdump -h Build\Release\JustDataInspector.exe`。
当前 788,992 B,余量 259,584 B。
## 2026-10-29 第十四轮(本机):「适应视图」跟随时间轴偏移 + 派生信号不再为空
> 用户报告两条功能异常(都源于「调整 → 时间轴」偏移 + 派生信号烘值):
> ① 给信号设置时间轴偏移后点「适应视图」,视界没有跟着平移;
> ② 用「均值滤波 / 弱峰调整 → 构建为新信号」派生出来的信号是**空的**。
### 1. 硬规则变更(**推翻旧结论,务必按此**)
| # | 已作废的规则 | 现行做法 |
| --- | --- | --- |
| 1 | 时间边界只取 `axis.minTime/maxTime`(源时刻) | **必须叠加该信号自己的 `SignalStyle::offsetTime`**(采样画在 `t + offsetTime` 处)。三处入口:`TabConfig::ComputeVisibleTimeBounds`、`PlotView::CollectFitContributions`(`minTime/maxTime` 与 `pointTime`)、`PlotView::FitTimeToLane` |
| 2 | 派生信号把 `offsetTime` 按 `time[i] - offsetTime` **重采样烘进采样值**(2026-10-21 的"烘值"规则) | **不再烘值**:时间偏移一律写进**新信号的样式**(`derivedStyle->offsetTime`)。理由:烘值有损 —— 平移出时间轴范围的那一段只能写 NaN,偏移 ≥ 数据跨度时整条信号全 NaN(= 空信号);而且即便偏移很小,两端也会出现与预览不符的空洞 |
### 2. 根因与验证
* **①** `TimeBounds()` → `ComputeVisibleTimeBounds()` 只统计 `axis.minTime/maxTime`,
`FitContribution::{minTime,maxTime,pointTime}` 同样是源时刻 ⇒ 偏移后取景仍停留在原始时间范围,
曲线整体跑到视界之外。
* **②** `BuildDerivedSignal` 的 2c 步把偏移烘进采样值。派生信号与源信号**共用同一条文件时间轴**,
无法用采样值表达超出轴范围的平移 ⇒ 只能丢成 NaN。
预览曲线本来就用源样式的 `offsetTime` 绘制(`PaintDerivedCurve`:`TimeToX(time[index] + style->offsetTime)`),
所以**把偏移留在派生信号的样式上,显示与预览逐字节一致,且数据一点不丢**。
* 新探针 `.preflight/derivecheck`(16/16):无偏移的均值滤波/弱峰调整有数据且范围不越界;
单信号 +10% 偏移后 `FitAll` 视界 = `[min+off, max+off]`;偏移 10% 与 200% 时派生信号都保持
`finite == values.size()`,且样式上带着偏移。
* 回归:`uicheck` 69、`lbcheck` 21、`lbresid` 5、`lbzorder` 4、`lbcovr` 7、`lbpanel` 10、
`derivecheck` 16 全过;`rendercheck` 8 场景哈希**与上一轮逐一相同** + FUNC 7/7;零 warning;
产物仍是 **788,992 B**。
### 3. 副作用(已知、可接受)
派生信号如果源自一个"带时间轴偏移"的信号,它的「调整」面板里「时间轴」会显示该偏移值
(不再像以前那样强行"默认值")。这是**刻意**的:时间偏移无法无损地写进采样值,
把偏移诚实显示出来比"面板是默认值但数据被裁掉/变空"要好。