Files
STM32F4-Base/docs/images/采样有效性判定时间轴.svg
wandering1 790e153cd6 fix(adc_input): 丢帧计数改按帧点数累计,与 TPAFE 侧 tgap 同单位
读码确认的口径缺陷:两片转换器的丢帧计数单位不一致——TPAFE 侧
adc_health_tpafe_gaps() 按 (d-1) 加权记「帧点数」,STM32 侧
adc_input_stm32_gaps() 每次事件只 +1 记「次数」。两者都被当作心跳字段
并排打印(adc1_gap / tgap),一次跨多帧时数值就分叉:同样丢 3 帧,
一边记 2、一边记 1。跨字段对比或做除法会得出错误结论。

选 A(改代码,真对称)而不是只改字段名:
- 单拍超一帧(d=2)时两者数值相同,历史上绝大多数样本本来就等价,
  换单位对既有判读习惯冲击很小;
- 只在一次跨 ≥2 帧时分叉,而那正是心跳日志突发期最常见的形态,
  留在文档里当"注意点"迟早还会读错一次。

改动:
- adc_input.c:s_stm32_gaps += (d - 1u)(d = seq - s_dma_seq_seen,
  顺带把已算过的差值提成局部变量 d,不再重复算一遍)
- adc_input.h / adc_input.c 函数头:单位写明「Σ 每次前进的超出部分」,
  并点名 2026-10-21 之前固件该字段是次数口径,跨版本日志不可直接对比
- 用例:原两档只跨 1 帧(前进 2 记 1),钉不出单位;补第二档——连投
  3 帧不消费(一次跨 2 帧)必须记 2 点、累计 1+2=3。补充断言沿用所属
  用例覆盖点,不另立新编号,也不在文档外复制用例号(编号门禁按文件内
  实例数比对台账豁免,多写一处即被判新债)
- 文档同步:ADC采样节拍设计说明 §8/§9 字段口径与稳态基线、采集与算法
  层设计说明 §3/§4、采样有效性校验设计说明 §6.2/§10/§11(并把"两车道
  单位不同"从观测盲区降级为"历史日志口径差异")、ADC输入层单元测试
  说明用例表该行;两张配图生成器文案同步

实测:
- @build 0 错 0 警;Program Size 与上一提交**逐字节相同**(Code=213520
  RW=1184 ZI=131504)——编译器早已为半区推导算过同一差值并复用,
  故本次净增 0 B,不产生新的台账漂移
- 主机单测:ADC 输入层 103/103、ADC 有效性 45/45
- stack_report:adcTask 1320 B / protectTask 872 B 均不变
- 字节卫生:BOM 无 / CR 0 / U+FFFD 0 / 文件尾换行齐
- id-check:Passed(曾因新增用例号实例触发"台账之外 +2",已按不复制
  用例号的方式消除,未动 id_known_backlog.json 台账)

gate: only mem-budget/mem-numbers pending lead ledger backfill
pre-commit run --all-files 失败仅这两条,漂移量来自上一条提交 6f90600
(+96 B Code / +24 B ZI);本条自身 0 B。按并行分支约定本分支不跑
--write,台账由 Lead 合并后统一回填。
2026-10-22 00:43:32 +08:00

194 lines
18 KiB
XML
Raw Permalink 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.
<svg xmlns="http://www.w3.org/2000/svg" width="1580" height="1038" viewBox="0 0 1580 1038" font-family="Microsoft YaHei, Segoe UI, PingFang SC, sans-serif">
<rect x="0" y="0" width="1580" height="1038" fill="#ffffff"/>
<text x="40" y="44" font-size="21" font-weight="700" fill="#0f172a">采样有效性判定时间轴 · 四个工况的 elapsed 与位存续区间</text>
<text x="40" y="70" font-size="13" fill="#64748b">elapsed = (int32_t)(now_ms - 最后一次序号前进的时刻);条带 = 位为 1 的存续区间</text>
<rect x="430" y="106" width="16" height="12" rx="3" fill="#0d9488"/>
<text x="452" y="116" font-size="12" fill="#475569">电平位 flags(可自愈)</text>
<rect x="619" y="106" width="16" height="12" rx="3" fill="#e11d48"/>
<text x="641" y="116" font-size="12" fill="#475569">锁存位 sticky / 不自愈</text>
<rect x="813" y="106" width="16" height="12" rx="3" fill="#d97706"/>
<text x="835" y="116" font-size="12" fill="#475569">边沿事件 events(仅当拍)</text>
<rect x="1022" y="106" width="16" height="12" rx="3" fill="#e11d48"/>
<text x="1044" y="116" font-size="12" fill="#475569">静默门限 100 ms</text>
<text x="40" y="178" font-size="13" font-weight="700" fill="#334155">工况与计数</text>
<text x="430" y="178" font-size="13" font-weight="700" fill="#334155">静默计时 elapsed(ms)与位存续</text>
<text x="1150" y="178" font-size="13" font-weight="700" fill="#334155">关键时刻与判读</text>
<rect x="40" y="220" width="370" height="142" rx="10" fill="#f8fafc" stroke="#64748b" stroke-opacity="0.25"/>
<text x="54" y="246" font-size="13" font-weight="700" fill="#0f172a">A 对照:健康 1 kHz(d 恒为 1)</text>
<text x="54" y="270" font-size="11" fill="#475569">seq: 1000 1001 1002 ... 每拍恰好 +1</text>
<text x="54" y="287" font-size="11" fill="#475569">每拍都刷新最后前进时刻 adv_ms</text>
<text x="54" y="310" font-size="11" font-weight="700" fill="#0d9488">elapsed = now - adv_ms 恒为 0 → 永不进门限带</text>
<rect x="430" y="224" width="690" height="96" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="430" y1="316.0" x2="1120" y2="316.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="320.0" font-size="10" fill="#64748b" text-anchor="end">0</text>
<line x1="430" y1="284.0" x2="1120" y2="284.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="288.0" font-size="10" fill="#64748b" text-anchor="end">50</text>
<line x1="430" y1="252.0" x2="1120" y2="252.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="256.0" font-size="10" fill="#64748b" text-anchor="end">100</text>
<line x1="430" y1="220.0" x2="1120" y2="220.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="224.0" font-size="10" fill="#64748b" text-anchor="end">150</text>
<line x1="430.0" y1="316" x2="430.0" y2="320" stroke="#cbd5e1" stroke-width="1"/>
<text x="430.0" y="332" font-size="10" fill="#64748b" text-anchor="middle">0</text>
<line x1="602.5" y1="316" x2="602.5" y2="320" stroke="#cbd5e1" stroke-width="1"/>
<text x="602.5" y="332" font-size="10" fill="#64748b" text-anchor="middle">50</text>
<line x1="775.0" y1="316" x2="775.0" y2="320" stroke="#cbd5e1" stroke-width="1"/>
<text x="775.0" y="332" font-size="10" fill="#64748b" text-anchor="middle">100</text>
<line x1="947.5" y1="316" x2="947.5" y2="320" stroke="#cbd5e1" stroke-width="1"/>
<text x="947.5" y="332" font-size="10" fill="#64748b" text-anchor="middle">150</text>
<line x1="1120.0" y1="316" x2="1120.0" y2="320" stroke="#cbd5e1" stroke-width="1"/>
<text x="1120.0" y="332" font-size="10" fill="#64748b" text-anchor="middle">200</text>
<line x1="430" y1="252.0" x2="1120" y2="252.0" stroke="#e11d48" stroke-width="2" stroke-dasharray="8 5"/>
<text x="944" y="246.0" font-size="10" fill="#e11d48">ADC_HEALTH_STALL_MS = 100</text>
<polyline points="430.0,316.0 1120.0,316.0" fill="none" stroke="#0d9488" stroke-width="2.6" stroke-linejoin="round"/>
<rect x="430" y="328" width="690" height="15" rx="4" fill="#f1f5f9" stroke-opacity="0"/>
<rect x="430" y="347" width="690" height="15" rx="4" fill="#f1f5f9" stroke-opacity="0"/>
<text x="424" y="339" font-size="10" fill="#64748b" text-anchor="end">flags</text>
<text x="424" y="358" font-size="10" fill="#64748b" text-anchor="end">sticky/events</text>
<text x="1150" y="238" font-size="11" fill="#334155">判定层对健康态**零输出**:events=0、flags=0、</text>
<text x="1150" y="255" font-size="11" fill="#334155">sticky=0。主机单测 TC-ADCHEALTH-002 用 2000 拍</text>
<text x="1150" y="272" font-size="11" fill="#334155">扫描把这个结论钉死(健康不误报)。</text>
<rect x="40" y="406" width="370" height="142" rx="10" fill="#f8fafc" stroke="#64748b" stroke-opacity="0.25"/>
<text x="54" y="432" font-size="13" font-weight="700" fill="#0f172a">B TPAFE 静默:100 ms 检出,恢复只清电平位</text>
<text x="54" y="456" font-size="11" fill="#475569">seq: 1000 1001 ... 冻结在 1050</text>
<text x="54" y="473" font-size="11" fill="#475569">STM32 车道照常前进(分车道独立判定)</text>
<text x="54" y="496" font-size="11" font-weight="700" fill="#0d9488">elapsed 每拍 +1,达到 100 ms 那拍即置位</text>
<rect x="430" y="410" width="690" height="96" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="430" y1="502.0" x2="1120" y2="502.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="506.0" font-size="10" fill="#64748b" text-anchor="end">0</text>
<line x1="430" y1="470.0" x2="1120" y2="470.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="474.0" font-size="10" fill="#64748b" text-anchor="end">50</text>
<line x1="430" y1="438.0" x2="1120" y2="438.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="442.0" font-size="10" fill="#64748b" text-anchor="end">100</text>
<line x1="430" y1="406.0" x2="1120" y2="406.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="410.0" font-size="10" fill="#64748b" text-anchor="end">150</text>
<line x1="430.0" y1="502" x2="430.0" y2="506" stroke="#cbd5e1" stroke-width="1"/>
<text x="430.0" y="518" font-size="10" fill="#64748b" text-anchor="middle">0</text>
<line x1="602.5" y1="502" x2="602.5" y2="506" stroke="#cbd5e1" stroke-width="1"/>
<text x="602.5" y="518" font-size="10" fill="#64748b" text-anchor="middle">50</text>
<line x1="775.0" y1="502" x2="775.0" y2="506" stroke="#cbd5e1" stroke-width="1"/>
<text x="775.0" y="518" font-size="10" fill="#64748b" text-anchor="middle">100</text>
<line x1="947.5" y1="502" x2="947.5" y2="506" stroke="#cbd5e1" stroke-width="1"/>
<text x="947.5" y="518" font-size="10" fill="#64748b" text-anchor="middle">150</text>
<line x1="1120.0" y1="502" x2="1120.0" y2="506" stroke="#cbd5e1" stroke-width="1"/>
<text x="1120.0" y="518" font-size="10" fill="#64748b" text-anchor="middle">200</text>
<line x1="430" y1="438.0" x2="1120" y2="438.0" stroke="#e11d48" stroke-width="2" stroke-dasharray="8 5"/>
<text x="944" y="432.0" font-size="10" fill="#e11d48">ADC_HEALTH_STALL_MS = 100</text>
<polyline points="430.0,502.0 775.0,438.0 947.5,406.0" fill="none" stroke="#0d9488" stroke-width="2.6" stroke-linejoin="round"/>
<polyline points="947.5,502.0 1120.0,502.0" fill="none" stroke="#0d9488" stroke-width="2.6" stroke-linejoin="round"/>
<line x1="775.0" y1="438.0" x2="775.0" y2="506" stroke="#64748b" stroke-width="1" stroke-dasharray="3 3"/>
<circle cx="775.0" cy="438.0" r="9" fill="#0f172a"/>
<text x="775.0" y="441.6" font-size="10.5" font-weight="700" fill="#ffffff" text-anchor="middle">1</text>
<line x1="947.5" y1="406.0" x2="947.5" y2="506" stroke="#64748b" stroke-width="1" stroke-dasharray="3 3"/>
<circle cx="947.5" cy="406.0" r="9" fill="#0f172a"/>
<text x="947.5" y="409.6" font-size="10.5" font-weight="700" fill="#ffffff" text-anchor="middle">2</text>
<rect x="430" y="514" width="690" height="15" rx="4" fill="#f1f5f9" stroke-opacity="0"/>
<rect x="430" y="533" width="690" height="15" rx="4" fill="#f1f5f9" stroke-opacity="0"/>
<text x="424" y="525" font-size="10" fill="#64748b" text-anchor="end">flags</text>
<text x="424" y="544" font-size="10" fill="#64748b" text-anchor="end">sticky/events</text>
<rect x="775.0" y="514.0" width="172.5" height="15" rx="4" fill="#0d9488" fill-opacity="0.85"/>
<text x="955.5" y="525.0" font-size="10" fill="#0d9488">TPAFE_STALL 电平</text>
<rect x="775.0" y="533.0" width="345.0" height="15" rx="4" fill="#e11d48" fill-opacity="0.85"/>
<text x="651.9" y="544.0" font-size="10" fill="#e11d48">TPAFE_STALL 锁存留痕</text>
<text x="1150" y="424" font-size="11" fill="#334155">1 t=100 ms:ADC_HF_TPAFE_STALL 置位 + 进 sticky;</text>
<text x="1150" y="441" font-size="11" fill="#334155"> 闭锁路径 = protectTask 下一拍(间隔 &lt;= 20 ms)</text>
<text x="1150" y="458" font-size="11" fill="#334155"> 命中掩码 → prot_elm_init() + 本拍不 eval</text>
<text x="1150" y="475" font-size="11" fill="#334155">2 t=150 ms:序号重新前进 → 电平位清、sticky 仍留痕</text>
<rect x="40" y="592" width="370" height="142" rx="10" fill="#f8fafc" stroke="#64748b" stroke-opacity="0.25"/>
<text x="54" y="618" font-size="13" font-weight="700" fill="#0f172a">C 消费者超拍:d=3 只算丢帧,永不判静默</text>
<text x="54" y="642" font-size="11" fill="#475569">seq: 1000 1003 1006 ... 每拍 +3</text>
<text x="54" y="659" font-size="11" fill="#475569">生产者活着,消费者没跟上</text>
<text x="54" y="682" font-size="11" font-weight="700" fill="#0d9488">d &gt;= 1 → 刷新 adv_ms,elapsed 恒 0;tgap += d-1</text>
<rect x="430" y="596" width="690" height="96" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="430" y1="688.0" x2="1120" y2="688.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="692.0" font-size="10" fill="#64748b" text-anchor="end">0</text>
<line x1="430" y1="656.0" x2="1120" y2="656.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="660.0" font-size="10" fill="#64748b" text-anchor="end">50</text>
<line x1="430" y1="624.0" x2="1120" y2="624.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="628.0" font-size="10" fill="#64748b" text-anchor="end">100</text>
<line x1="430" y1="592.0" x2="1120" y2="592.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="596.0" font-size="10" fill="#64748b" text-anchor="end">150</text>
<line x1="430.0" y1="688" x2="430.0" y2="692" stroke="#cbd5e1" stroke-width="1"/>
<text x="430.0" y="704" font-size="10" fill="#64748b" text-anchor="middle">0</text>
<line x1="602.5" y1="688" x2="602.5" y2="692" stroke="#cbd5e1" stroke-width="1"/>
<text x="602.5" y="704" font-size="10" fill="#64748b" text-anchor="middle">50</text>
<line x1="775.0" y1="688" x2="775.0" y2="692" stroke="#cbd5e1" stroke-width="1"/>
<text x="775.0" y="704" font-size="10" fill="#64748b" text-anchor="middle">100</text>
<line x1="947.5" y1="688" x2="947.5" y2="692" stroke="#cbd5e1" stroke-width="1"/>
<text x="947.5" y="704" font-size="10" fill="#64748b" text-anchor="middle">150</text>
<line x1="1120.0" y1="688" x2="1120.0" y2="692" stroke="#cbd5e1" stroke-width="1"/>
<text x="1120.0" y="704" font-size="10" fill="#64748b" text-anchor="middle">200</text>
<line x1="430" y1="624.0" x2="1120" y2="624.0" stroke="#e11d48" stroke-width="2" stroke-dasharray="8 5"/>
<text x="944" y="618.0" font-size="10" fill="#e11d48">ADC_HEALTH_STALL_MS = 100</text>
<polyline points="430.0,688.0 1120.0,688.0" fill="none" stroke="#0d9488" stroke-width="2.6" stroke-linejoin="round"/>
<polyline points="430.0,688.0 499.0,688.0 499.0,660.2 637.0,660.2 637.0,632.3 775.0,632.3 775.0,604.5 1120.0,604.5" fill="none" stroke="#d97706" stroke-width="2.4" stroke-linejoin="round"/>
<text x="438" y="612" font-size="10" fill="#d97706">tpafe_gaps 累计点数(右轴 0~8)</text>
<line x1="499.0" y1="682.2" x2="499.0" y2="692" stroke="#64748b" stroke-width="1" stroke-dasharray="3 3"/>
<circle cx="499.0" cy="682.2" r="9" fill="#0f172a"/>
<text x="499.0" y="685.8" font-size="10.5" font-weight="700" fill="#ffffff" text-anchor="middle">1</text>
<line x1="637.0" y1="682.2" x2="637.0" y2="692" stroke="#64748b" stroke-width="1" stroke-dasharray="3 3"/>
<circle cx="637.0" cy="682.2" r="9" fill="#0f172a"/>
<text x="637.0" y="685.8" font-size="10.5" font-weight="700" fill="#ffffff" text-anchor="middle">2</text>
<rect x="430" y="700" width="690" height="15" rx="4" fill="#f1f5f9" stroke-opacity="0"/>
<rect x="430" y="719" width="690" height="15" rx="4" fill="#f1f5f9" stroke-opacity="0"/>
<text x="424" y="711" font-size="10" fill="#64748b" text-anchor="end">flags</text>
<text x="424" y="730" font-size="10" fill="#64748b" text-anchor="end">sticky/events</text>
<rect x="499.0" y="719.0" width="6.9" height="15" rx="4" fill="#d97706" fill-opacity="0.85"/>
<text x="513.9" y="730.0" font-size="10" fill="#d97706">ADC_HE_TPAFE_GAP 仅当拍</text>
<rect x="637.0" y="719.0" width="6.9" height="15" rx="4" fill="#d97706" fill-opacity="0.85"/>
<text x="651.9" y="730.0" font-size="10" fill="#d97706">同上</text>
<rect x="775.0" y="719.0" width="6.9" height="15" rx="4" fill="#d97706" fill-opacity="0.85"/>
<text x="789.9" y="730.0" font-size="10" fill="#d97706">同上</text>
<text x="1150" y="610" font-size="11" fill="#334155">1 t=20 ms:d=3 → tgap += 2 + 当拍事件,下一拍事件消失</text>
<text x="1150" y="627" font-size="11" fill="#334155"> (边沿语义,不是电平)</text>
<text x="1150" y="644" font-size="11" fill="#334155">2 丢帧不入锁存、不告警、不闭锁;两条车道同单位:</text>
<text x="1150" y="661" font-size="11" fill="#334155"> tgap 与 adc1_gap 都按帧点数(d-1 加权)累计,心跳里可</text>
<text x="1150" y="678" font-size="11" fill="#334155"> 直接对比。台架日志:启动突发期 23 点,稳态每 10 s +1~2 点</text>
<rect x="40" y="778" width="370" height="142" rx="10" fill="#f8fafc" stroke="#64748b" stroke-opacity="0.25"/>
<text x="54" y="804" font-size="13" font-weight="700" fill="#0f172a">D 序号倒退:锁存不可自愈,代价是永久闭锁</text>
<text x="54" y="828" font-size="11" fill="#475569">seq: 1050 1051 ... 跳到 995</text>
<text x="54" y="845" font-size="11" fill="#475569">d = 995 - 1051 &lt; 0(有符号差)</text>
<text x="54" y="868" font-size="11" font-weight="700" fill="#0d9488">置位后重新对齐基线,不重复触发;位永不自动清</text>
<rect x="430" y="782" width="690" height="96" fill="#ffffff" stroke="#cbd5e1" stroke-width="1"/>
<line x1="430" y1="874.0" x2="1120" y2="874.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="878.0" font-size="10" fill="#64748b" text-anchor="end">0</text>
<line x1="430" y1="842.0" x2="1120" y2="842.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="846.0" font-size="10" fill="#64748b" text-anchor="end">50</text>
<line x1="430" y1="810.0" x2="1120" y2="810.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="814.0" font-size="10" fill="#64748b" text-anchor="end">100</text>
<line x1="430" y1="778.0" x2="1120" y2="778.0" stroke="#cbd5e1" stroke-width="0.8" stroke-dasharray="3 4"/>
<text x="424" y="782.0" font-size="10" fill="#64748b" text-anchor="end">150</text>
<line x1="430.0" y1="874" x2="430.0" y2="878" stroke="#cbd5e1" stroke-width="1"/>
<text x="430.0" y="890" font-size="10" fill="#64748b" text-anchor="middle">0</text>
<line x1="602.5" y1="874" x2="602.5" y2="878" stroke="#cbd5e1" stroke-width="1"/>
<text x="602.5" y="890" font-size="10" fill="#64748b" text-anchor="middle">50</text>
<line x1="775.0" y1="874" x2="775.0" y2="878" stroke="#cbd5e1" stroke-width="1"/>
<text x="775.0" y="890" font-size="10" fill="#64748b" text-anchor="middle">100</text>
<line x1="947.5" y1="874" x2="947.5" y2="878" stroke="#cbd5e1" stroke-width="1"/>
<text x="947.5" y="890" font-size="10" fill="#64748b" text-anchor="middle">150</text>
<line x1="1120.0" y1="874" x2="1120.0" y2="878" stroke="#cbd5e1" stroke-width="1"/>
<text x="1120.0" y="890" font-size="10" fill="#64748b" text-anchor="middle">200</text>
<line x1="430" y1="810.0" x2="1120" y2="810.0" stroke="#e11d48" stroke-width="2" stroke-dasharray="8 5"/>
<text x="944" y="804.0" font-size="10" fill="#e11d48">ADC_HEALTH_STALL_MS = 100</text>
<polyline points="430.0,874.0 1120.0,874.0" fill="none" stroke="#0d9488" stroke-width="2.6" stroke-linejoin="round"/>
<line x1="637.0" y1="868.2" x2="637.0" y2="878" stroke="#64748b" stroke-width="1" stroke-dasharray="3 3"/>
<circle cx="637.0" cy="868.2" r="9" fill="#0f172a"/>
<text x="637.0" y="871.8" font-size="10.5" font-weight="700" fill="#ffffff" text-anchor="middle">1</text>
<line x1="1099.3" y1="868.2" x2="1099.3" y2="878" stroke="#64748b" stroke-width="1" stroke-dasharray="3 3"/>
<circle cx="1099.3" cy="868.2" r="9" fill="#0f172a"/>
<text x="1099.3" y="871.8" font-size="10.5" font-weight="700" fill="#ffffff" text-anchor="middle">2</text>
<rect x="430" y="886" width="690" height="15" rx="4" fill="#f1f5f9" stroke-opacity="0"/>
<rect x="430" y="905" width="690" height="15" rx="4" fill="#f1f5f9" stroke-opacity="0"/>
<text x="424" y="897" font-size="10" fill="#64748b" text-anchor="end">flags</text>
<text x="424" y="916" font-size="10" fill="#64748b" text-anchor="end">sticky/events</text>
<rect x="637.0" y="886.0" width="483.0" height="15" rx="4" fill="#e11d48" fill-opacity="0.85"/>
<text x="507.8" y="897.0" font-size="10" fill="#e11d48">SEQ_BACKWARD 不自动清</text>
<rect x="637.0" y="905.0" width="483.0" height="15" rx="4" fill="#e11d48" fill-opacity="0.85"/>
<text x="528.8" y="916.0" font-size="10" fill="#e11d48">SEQ_BACKWARD 锁存</text>
<text x="1150" y="796" font-size="11" fill="#334155">1 t=60 ms:倒退被检出 → 重新对齐避免每拍重复置位</text>
<text x="1150" y="813" font-size="11" fill="#334155">2 电平位与锁存位同时置位 → 保护永久退出,直到</text>
<text x="1150" y="830" font-size="11" fill="#334155"> 复位或显式 adc_health_init();这是刻意取舍:</text>
<text x="1150" y="847" font-size="11" fill="#334155"> 计数被改写时相量不可信,宁可拒动不误动</text>
<rect x="40" y="982" width="1500" height="42" rx="10" fill="#fffbeb" stroke="#d97706" stroke-opacity="0.45"/>
<text x="56" y="1008" font-size="11" fill="#7c2d12">横轴 = 距最后一次序号前进的时间(ms,tick 回绕由有符号差值吸收);红线 = ADC_HEALTH_STALL_MS = 100 ms。详见 docs/算法/采样有效性校验设计说明.md</text>
</svg>