refactor(编号·批次二): 文档侧 194 处保护功能号改成功能名,定义表 7 张首格改语义标识

批次二文档半(道 gate-docs 执行)。先纠三个数的口径账,别再拿任何旧数当准:**234 处是准数** —— 卡片写
52(Lead 用了门禁 Checker 的引用集合,它**刻意排除属主文档内部的定义位**)、道里先报 265(裸正则把
`SDL2-2.32.10` 里的 `L2-2` 当成功能号,误报 10 处)。最终边界口径 = 带左边界 + 跳过反引号代码段。

· 19 只文件 HEAD 共 234 处 → 现 40 处,**40 处 100% 落在变更记录行**(冻结历史,按 Q3 一条没动),
  非变更记录残留 **0**;改写 163 行 / 16 只文档。站点最多:规划文档 110→37、相量层单测说明 25→1、
  采集与数据处理短板评测 21→0、App/algo/README 26→0。
  (`App/algo/README.md` 由上一笔代码提交带上车,路径归属已在该笔正文注明,内容是本批改写)
· **定义表首列由编号改成语义标识**(编号规范 §3.3「表首格就是短语」的完全形态):首列原为编号的表
  共 **7 张**(不是 5 张),删掉与之重复的「语义名」列;表头标签按域词区分——三张 L3 保护**元件**表
  保留 `| 元件 |`,四张 L1/L2 表用 `| 功能名 |`(把「元件」统一洗成功能名会丢掉领域信息)。
  七张表逐张核:表头竖线数 == 分隔行 == 首条数据行 == 列数+1;与 HEAD 逐块对拍**净新增不一致块 0**,
  并且正是这个对拍抓到第一版「三张表数据行已删列、表头没删」的破表。
· 7 处删号留下的残词/重复解释括号人工收口(如「L1-5(通道标定)」→「通道标定(一次系数 + 零漂)」),
  复扫待收口站点 0;措辞逐字取自映射表,无第二种说法。
· tools/arch_diagram 三只生成器 4 处(3 处 docstring + 1 处图形文案)与产物同批:重跑后**只有位图那张
  变 2 个 text 节点的换行位置**,画布 1580x740 与总行数不变,另两张逐字节未变;改前先干跑对照证明三张
  svg 原本与生成器一致(不在 stale 基线里)——`check_generated_fresh --only docs-svg` PASS。

本笔另含 **F-* 半批的文档面**(同一轮 `git add docs tools/arch_diagram AGENTS.md` 一并收进
,非误伤):BSD
函数调用关系里 9 处反引号紧邻指针、属主文档 §7 的停发句与导读行(**12 条定义行原样保留、不删登记族**)、
以及 `gen_net_instability_svg.py` 与它的产物 `网络不稳根因总览.svg`(「唯一读者红线」那条的框宽自适应
526 → 551,右缘 1411 未越界,画布 1560x1468 不变)——该半批的**代码注释面**在下一笔。

⚠ 因 `docs/任务规划/登记簿.md` 与 `docs/任务规划/UI补齐.md` 正被另一张卡(UI 叶数复核)改动,本笔**不含
那两只文件**,批次二的 §9 存量收尾与它们同批提交。
This commit is contained in:
2026-10-27 09:01:51 +08:00
parent b7c0889cc7
commit 4c74cfa825
26 changed files with 175 additions and 170 deletions
+1 -1
View File
@@ -46,7 +46,7 @@
- netTask:`net_stack_bring_up`(配置已由 defaultTask 在屏障前加载,本任务只读 RAM 副本)→ 置 NET_READY → 循环 `net_poll` + `net_process_messages`;消费 `SYS_EVT_NET_RECONFIG` → 按网络代次号重建监听(新 IP 免重启生效)
- defaultTask:`f_mount` forced(无卷自动 `f_mkfs`;挂载后卷健康探针,FAT 区陈旧时自愈重格式化)→ 加载网络配置 → STORAGE_READY → LED 闪烁;同时是 syslog(`/log/run.log`·`selftest.log`,定长 64B 记录)的**唯一写者**与**配置引擎属主**(netTask/uiTask 不得直接触碰配置引擎)
- adcTask:**纯消费者**——每拍 `adc_input_poll()`(TPAFE 原子快照 + 消费一帧 STM32 ADC1 DMA 双缓冲),只取数不做保护运算;**节拍与唤醒同源**(TIM3 ISR 内触发 CONVST + 同一更新事件经 TRGO 触发 ADC1,并调 `adc_tick_irq_notify()` 置位,任务 `osThreadFlagsWait` 等唤醒)。⚠ ISR 侧**只能**走 `adc_tick_irq_notify()`(内含"消费者就绪"门,TIM3 比调度器早 ≈100 ms 启动);手写于 `Src/freertos.c` 的 `USER CODE` 区,纳入 IWDG `required_mask`(`TASK_WD_ADC`)
- **采集与算法层(L1/L2/L3)落在 `App/algo/`**:`adc_input`/`adc_health` = L1,`sample_ring`/`phasor` = L2,`freq` = L2.5 测频(B8,自适应窗),`prot_set`/`prot_elm` = L3。板端消费者 = **protectTask**(B5,2026-10-12):20 ms 节拍 `prot_elm_run()` + L5-4 采样故障闭锁 + L5-1 定值校验和巡检;跨上下文复归(104 YK11)经 `prot_elm_request_reset()` 落请求。纳入 IWDG `required_mask`(`TASK_WD_PROTECT`,产品 `0x1F7`)。→ `docs/算法/采集与算法层设计说明.md`(设计与判据)、`App/algo/README.md`(目录索引)
- **采集与算法层(L1/L2/L3)落在 `App/algo/`**:`adc_input`/`adc_health` = L1,`sample_ring`/`phasor` = L2,`freq` = L2.5 测频(B8,自适应窗),`prot_set`/`prot_elm` = L3。板端消费者 = **protectTask**(B5,2026-10-12):20 ms 节拍 `prot_elm_run()` + 自检失败闭锁(采样故障闭锁)+ 定值校验和巡检;跨上下文复归(104 YK11)经 `prot_elm_request_reset()` 落请求。纳入 IWDG `required_mask`(`TASK_WD_PROTECT`,产品 `0x1F7`)。→ `docs/算法/采集与算法层设计说明.md`(设计与判据)、`App/algo/README.md`(目录索引)
- 全景 → `docs/架构设计/项目架构总览.md`;启动时序与内核前模式 → `docs/架构设计/项目启动顺序管理.md`
<!-- TASK_TABLE:BEGIN generated by scripts/gen_task_table.py -->
+1 -1
View File
@@ -216,7 +216,7 @@ typedef struct {
| 字段 | 真源 | 说的是什么事 | 屏上落点 | 还能改定值吗 |
|---|---|---|---|---|
| `locked` | `prot_set_locked()`(L5-1 校验和自检失配) | 这台装置现在**写不进去** | 整定页保存行值列 `LOCK`,且 ENTER 一律不消费(禁编辑) | ❌ |
| `locked` | `prot_set_locked()`(定值校验和自检失配) | 这台装置现在**写不进去** | 整定页保存行值列 `LOCK`,且 ENTER 一律不消费(禁编辑) | ❌ |
| `cal_block` | `adc_cal_prot_blocked()`(`App/algo/adc_cal.c`:UA/UN/IA 三路 `ADC_CAL_F_VALID` 全齐才放行。**判据停走用的是同一个函数**——`App/task/protect_task.c` 也调它,道F task-16 起全仓一份判定、`DTU_BENCH` 旁路也只有这一处;机器证据 = `test/host/adc_cal` 的 TC-ADCCAL-018) | 定值能改,但**改了也不会动作**(判据停走) | 整定页标题右侧「未标定」徽标 | ✅ |
合成一个词就等于互相冒充:现场看到 `LOCK` 会以为"改了白改"而不去标定,看到「未标定」
+1 -1
View File
@@ -73,7 +73,7 @@
| 相量 Ia | `phasor_get(0, &p)` | ✅ 真(码值) | 过流/过负荷判据源 |
| 相量 Ia-2 次 | `phasor_get(3, &p)` | ✅ 真(码值) | 涌流制动用,页面可显示 |
| 相量 Ia-5 次 | `phasor_get(4, &p)` | ✅ 真(码值) | 选线用 |
| 频率 | `freq_get(&f)` + `freq_valid()` | 🔶 有条件 | 等周波未闭环(`docs/算法/继电保护功能复现规划.md` L1-7),104 点 `0x401D` 仍标 IV |
| 频率 | `freq_get(&f)` + `freq_valid()` | 🔶 有条件 | 等周波未闭环(`docs/算法/继电保护功能复现规划.md` 「等周波采样(软件测频 + 调频闭环)」),104 点 `0x401D` 仍标 IV |
| 温度 | `adc_input_raw(ADC_SEM_TEMP, &raw)` | 🔶 仅码值 | 无换算 API |
| 遥信 6 点 | `iec104_pts_yx_read(idx, &v)` | ✅ 真 | YX15/16/17/18/23/31(`YX_VALID_MASK`) |
| 遥信 27 点 | 同上 | ❌ 恒无效 | 无硬件来源(开入未配置) |
+1 -1
View File
@@ -27,7 +27,7 @@
### 2.1 规模
> ⚠ **本表是 2026-10-23 立项当天快照**(节点 42 / 有内容页叶子 6 / 空叶子 27 / 黄金参考 11 份均为当日实数,按"完成即冻结"不回改)。
> 页面扩充落地后现值已变——黄金参考现为 40 份(`simulator/tests/ref/` 入库的 `shot_*.bin` 实数),现状口径见
> 页面扩充落地后现值已变——黄金参考现为 47 份(`simulator/tests/ref/` 入库的 `shot_*.bin` 实数),现状口径见
> `docs/UI设计/页面扩充详细方案.md` 与 `docs/UI设计/UI_数据供给设计说明.md`。
| 项 | 数 |
+2 -2
View File
@@ -27,8 +27,8 @@
<text x="294" y="333.6" font-size="13" fill="#1e293b" text-anchor="middle">机制:全局中断寄存器整体读即清,open/relisten 丢弃式读一遍=拔全楼门铃线</text>
<rect x="844" y="238.0" width="690" height="120.0" rx="10" fill="#f0fdf4" stroke="#16a34a" stroke-opacity="0.45"/>
<text x="860" y="260.0" font-size="15" font-weight="700" fill="#16a34a">总闸唯一读者</text>
<rect x="860" y="270.0" width="526" height="34" rx="7" fill="#ffffff" stroke="#16a34a" stroke-opacity="0.55"/>
<text x="1123" y="291.6" font-size="13" fill="#1e293b" text-anchor="middle">F-NET-7:全局寄存器唯一读者=net_poll;open/relisten 只清本 Socket SINT</text>
<rect x="860" y="270.0" width="551" height="34" rx="7" fill="#ffffff" stroke="#16a34a" stroke-opacity="0.55"/>
<text x="1135" y="291.6" font-size="13" fill="#1e293b" text-anchor="middle">唯一读者红线:全局寄存器唯一读者=net_poll;open/relisten 只清本 Socket SINT</text>
<rect x="860" y="312.0" width="223" height="34" rx="7" fill="#ffffff" stroke="#16a34a" stroke-opacity="0.55"/>
<text x="971" y="333.6" font-size="13" fill="#1e293b" text-anchor="middle">查自己门铃时,不许拔别人家的线</text>
<line x1="722" y1="298.0" x2="834" y2="298.0" stroke="#94a3b8" stroke-width="2.5"/>

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

@@ -33,8 +33,8 @@
<text x="1104" y="219" font-size="11" font-weight="700" fill="#0d9488">bit8</text>
<text x="1104" y="236" font-size="10" fill="#334155">STALE</text>
<rect x="1204" y="200" width="320" height="46" rx="8" fill="#f8fafc" stroke="#64748b" stroke-opacity="0.25"/>
<text x="1216" y="217" font-size="11" fill="#475569">protectTask 每 20 ms 读它做 L5-4 闭锁;bit8 由</text>
<text x="1216" y="232" font-size="11" fill="#475569">本任务自己判老后 OR 入(判定层不写)</text>
<text x="1216" y="217" font-size="11" fill="#475569">protectTask 每 20 ms 读它做自检失败闭锁;bit8 </text>
<text x="1216" y="232" font-size="11" fill="#475569">由本任务自己判老后 OR 入(判定层不写)</text>
<text x="40" y="276" font-size="12" font-weight="700" fill="#0f172a">sticky 锁存位</text>
<text x="40" y="294" font-size="10" fill="#64748b">adc_health_sticky(),直到 init 才清</text>
<rect x="310" y="256" width="94" height="46" rx="8" fill="#fff1f2" stroke="#e11d48" stroke-opacity="0.55"/>

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

@@ -446,7 +446,7 @@ sequenceDiagram
### 5.9 ADC 采集(FR-ADC)🔶 采集链路已实现(B1);保护/遥测算法与上行待实现
- **需求(B0 已确认,2026-10-10)**:**持续采集** 8 路电气量(Ua/Ub/Uc/U0、Ia/Ib/Ic/I0,**1000 Hz / 20 点/周波**),经保护/遥测算法后**上送 IEC 60870-5-104**(以太网 TCP 2404;遥测上送短浮点、采集上传系数 = 1)。
- **现状(采集链路 B1 + L1 已实现,2026-10-10)**:启动序列调用一次 `tpafe5160_init()`;**运行期周期 CONVST 重触发已由 TIM6 更新中断(1 kHz)接管**(`Src/main.c` 的 `HAL_TIM_PeriodElapsedCallback`,2026-10-10)+ `adcTask` 经 L1 层 `adc_input_poll()` 消费(`tpafe5160_snapshot()` 8 通道 + STM32 ADC1 9 通道扫描)+ 帧统计,台架 `@test` 确认 `frame_seq` 严格 1000 Hz 递增、`frst_err=0`、`adc1_rc=0` / `adc1_err=0`;STM32 侧 ADC1 **消费者已落地**(`App/algo/adc_input.c` 的 `stm32_scan()`,L1-3/L1-4,2026-10-10),受双转换器无共同采样触发所限,仅逐通道独立监视。
- **现状(采集链路 B1 + L1 已实现,2026-10-10)**:启动序列调用一次 `tpafe5160_init()`;**运行期周期 CONVST 重触发已由 TIM6 更新中断(1 kHz)接管**(`Src/main.c` 的 `HAL_TIM_PeriodElapsedCallback`,2026-10-10)+ `adcTask` 经 L1 层 `adc_input_poll()` 消费(`tpafe5160_snapshot()` 8 通道 + STM32 ADC1 9 通道扫描)+ 帧统计,台架 `@test` 确认 `frame_seq` 严格 1000 Hz 递增、`frst_err=0`、`adc1_rc=0` / `adc1_err=0`;STM32 侧 ADC1 **消费者已落地**(`App/algo/adc_input.c` 的 `stm32_scan()`,「STM32 ADC1 启动与扫描」/L1-4,2026-10-10),受双转换器无共同采样触发所限,仅逐通道独立监视。
- **后果**:上电后仅采集 1 个样本,此后数据永久陈旧。
- **B0 结论**(2026-10-10,详见 `docs/算法/继电保护功能复现规划.md` §1.5):① 持续采集 ② 1000 Hz(20 点/周波),通道 = 4U+4I(点表 `4011~4018`)③ 上行 **IEC 60870-5-104**(2404,非 ModBus RTU 上行)④ ADC 采集链路为遥测/保护的必需来源 → **常驻编译**;原 `APP_ADC_ENABLE` 占位宏零消费点,已于 2026-10-22 删除(将来若要裁剪,需在真实初始化点接入门控并登记进 `App/app/app_cfg.h`)。
- **实现约束**(见 §9):周期 CONVST 重触发 + `adc_task` 消费 `tpafe5160_snapshot()`;**原子快照 API 已就位**(2026-10-10 修三条采集契约缺陷,旧的 `get_buf` / `data_ready` / `clear_ready` 已删 → 取数不再撕裂、重触发不再丢帧、芯片不驱动总线会被 `init()` 首帧自检抓到);栈预算核算;V0.1 通道映射已固化 → `docs/硬件平台/ADC通道映射说明.md`(13/17 路置换;语义 UA/UB/UC/UN、IA/IB/IC/IN、V_ZL2=温度,其余备用;网名 ADC17 = PC4 用 `ADC_CHANNEL_14`,**不是** `ADC_CHANNEL_12`)。⚠ **8 路电气量分属 TPAFE / STM32 两片转换器属 V0.1 硬件缺陷**(跨转换器无同一时刻性、精度与量程不一致,登记簿条目「双转换器无共同采样触发」,V0.2 改版要求全部走 TPAFE)→ 在 V0.1 上主板侧只做**逐通道独立监视**,功率 / 功率因数 / 相角 / 矢量类量一律取子板计量模块结果,不得由主板混算。
@@ -772,7 +772,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
| 缺口 | 现状 | 影响 |
|---|---|---|
| **ADC 采集链路** | ✅ **采集链路已实现(B1 + L1,2026-10-10)**:采样节拍由 TIM6 更新中断(1 kHz)硬件触发;`adcTask` 经 L1 层 `adc_input_poll()` 消费(TPAFE 8 通道快照 + **STM32 ADC1 9 通道扫描**),台架 `@test` 闭环(1000 Hz、`adc1_rc=0`);取数按语义(L1-3/L1-4,双转换器无共同采样触发下逐通道独立监视) | 数据路径已通;剩余为上层保护/遥测算法与 104 上行 |
| **ADC 采集链路** | ✅ **采集链路已实现(B1 + L1,2026-10-10)**:采样节拍由 TIM6 更新中断(1 kHz)硬件触发;`adcTask` 经 L1 层 `adc_input_poll()` 消费(TPAFE 8 通道快照 + **STM32 ADC1 9 通道扫描**),台架 `@test` 闭环(1000 Hz、`adc1_rc=0`);取数按语义(「STM32 ADC1 启动与扫描」/L1-4,双转换器无共同采样触发下逐通道独立监视) | 数据路径已通;剩余为上层保护/遥测算法与 104 上行 |
| **RS-485 采集链路** | `rs485_task.c` 空桩;`App/protocol/` 仅 README | 无 RS-485 数据收发(B0 定:**对下 ModBus RTU 采集**) |
| **DTU 核心转发职责** | **B0 已定(2026-10-10)**:上行 **IEC 60870-5-104**(以太网 TCP 2404,遥测短浮点系数 1);RS-485 对下 ModBus RTU 采集 | 转发目标已明确,待实现 |
+4 -4
View File
@@ -60,7 +60,7 @@
| 证据 | 说明 |
|---|---|
| L1-3 台架判据(2026-10-10) | 只验了"9 通道全部转换成功 + 零超时 + 互异非饱和 + 跨次开机读数不同"——证明**通路活**,不证明**读数对**,连极性都没证 |
| 「STM32 ADC1 启动与扫描」台架判据(2026-10-10) | 只验了"9 通道全部转换成功 + 零超时 + 互异非饱和 + 跨次开机读数不同"——证明**通路活**,不证明**读数对**,连极性都没证 |
| `docs/硬件平台/ADC通道映射说明.md` §8 | 步骤 2(STM32 引脚注 0.5 V)**明标"尚未执行"**;步骤 1(TPAFE 注 1 V DC)**无执行记录**。两项挂账自 2026-10-09 |
| `docs/硬件平台/V0.0_网表详细分析报告.md` §5.1 第 6 条 | "AIN1 注入 1 V 直流 → UI ADC1 值变化 + U3.14 BUSY 脉冲(**首次功能级 ADC 验证**)"——**无执行记录**(该清单整体未跑) |
| 台架设备 | 无信号源、无示波器(`docs/测试说明/相量层单元测试说明.md` 已写明板端无信号源) |
@@ -91,7 +91,7 @@
头注释与 §4.5;M5 的"104 上送值与**工程量**一致"仍挂卡 0 / 卡 12(工程量口径尚未成立)。
> **不进本波退出判据的两项增强**:谐波**方和根真有效值**(挂
> `docs/算法/继电保护功能复现规划.md` L2-8)与快照**4 点平均平滑**——随谐波轨立项一起做;
> `docs/算法/继电保护功能复现规划.md` 「遥测谐波轨(可选)」)与快照**4 点平均平滑**——随谐波轨立项一起做;
> 快照保持「基波有效值 + 直取相量」口径(§4.5 原文)。
---
@@ -147,7 +147,7 @@ UI 快照的 `qds`)。
保护判据拿"ADC 引脚电压"跟"二次值定值"比,必然误动作。所以 M4 必须让
`protect_task` 多一个闭锁源:**UA/UN/IA 的 `VALID` 位未全置位 → 判据停走**。
- 与 L5-4 采样故障闭锁同构(`PROT_HF_LOCK_MASK` 那一套),不新增机制。
- 与「自检失败闭锁」采样故障闭锁同构(`PROT_HF_LOCK_MASK` 那一套),不新增机制。
- 现有台架 `@test` 的期望会因此变化——**这是有意的**,需要在任务卡里同步更新判据。
- 台架调试需要旁路时,走编译期开关(仅 `DTU_BENCH` 构建),不进 cfg、不进 104。
@@ -271,7 +271,7 @@ typedef struct {
| 不做 | 理由 / 归属 |
|---|---|
| 录波 + 104 文件传输 | 独立立项;且录波通道必须先有工程量,排在本波之后 |
| 等周波调频(`docs/算法/继电保护功能复现规划.md` §3.1 的 L1-7) | 与标定正交;无标准源时判据不可达 |
| 等周波调频(`docs/算法/继电保护功能复现规划.md` §3.1 的「等周波采样(软件测频 + 调频闭环)」) | 与标定正交;无标准源时判据不可达 |
| 功率 / 相位 / 功率因数 | **V0.1 硬件禁止**(`docs/硬件平台/ADC通道映射说明.md` §7 通道归属行:跨转换器无同一时刻性) |
| PT 断线判据 | 需要 `flags` 与遥信配合,而 V0.1 **无开入硬件** → 与下一行同归开入波次 |
| 开入 / 开出固件 | 固件里**完全没有**这两类代码(`docs/问题记录/采集与数据处理短板评测.md` 登记),是另一个波次的量级 |
@@ -106,7 +106,7 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1`
> 同日**增列 `adcTask`**(B1:ADC 采集消费者,512 words,静态最坏链 504 B / 余 75%)。
> **2026-10-11 L2 相量层接入后复测**:adcTask 静态 **832 B** / 台架实测峰值 **928 B / 2048(余 54%)**,
> 增量为压环 + `phasor_run()`(`win[20]` 80 B)+ `log_phasors` 日志链;仍高于 1024 B 底线,7 任务全 PASS。
> **同日 L1-6 有效性校验后抬栈 512→640 words**:`adc_health_report`→`syslog_post` 控制台回显尾把静态
> **同日采样有效性校验后抬栈 512→640 words**:`adc_health_report`→`syslog_post` 控制台回显尾把静态
> 最坏链推到 **1080 B**(512 words 时余 968 B < 1024 B ISR 底线)→ 抬至 2.5 KB,余 **1480 B / 57%**;
> 堆 `min_ever` 7152 → **6640 B**(-512 B,符合预算)。
> 此前 2026-10-04 的 V5 30 min 重采曾把 defaultTask 推到 **3664B/4096(余量 432B ≈ 10%,曾登记在案)**;
@@ -126,9 +126,9 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1`
| testTask | `2048*4` | 8KB | 测试套件(产品构建不创建;存储套件深链需要) | 未创建 / 静态 496 B |
| defaultTask | `1280*4` | 5KB | FatFS 挂载/探针 + 配置引擎 + syslog + 栈水位探针 | 2152 B(余 41%)/ 静态 **3016 B**(栈余量收口时抬栈 1024→1280,2026-10-12) |
| timeSyncTask | `640*4` | 2.5KB | TCP 时间同步 | 616 B(余 50%)/ 静态 **1264 B**(栈余量收口时抬栈 512→640,2026-10-12) |
| adcTask | `640*4` | 2.5KB | TPAFE5160 采样消费 + L2 相量 + L1-6 有效性校验(TIM3 1 kHz 节拍,B1→L2→L1-6 2026-10-11) | **952 / 2560**(余 1608 B / 62%,台架 `@test` 实测 2026-10-11);静态 **1320 B**(2026-10-12 复测,L3 接线后) |
| adcTask | `640*4` | 2.5KB | TPAFE5160 采样消费 + L2 相量 + 有效性校验(TIM3 1 kHz 节拍,B1→L2→「采样有效性校验」 2026-10-11) | **952 / 2560**(余 1608 B / 62%,台架 `@test` 实测 2026-10-11);静态 **1320 B**(2026-10-12 复测,L3 接线后) |
| iec104Task | `640*4` | 2.5KB | IEC104 上行服务(2404 监听 + link 状态机,B4 2026-10-12) | 未上板 / 静态 **1456 B**(拆链→重建监听→net_bind→SPI 故障→日志尾,日志主导;512 words 时余 592 B < ISR 底线 → 抬至 640,余 1104 B / 43%) |
| protectTask | `512*4` | 2KB | 保护判据节拍(prot_elm_run 消费者 + L5-4 采样闭锁,B5 2026-10-12) | 未上板 / 静态 **872 B**(float 判据 + phasor 快照 + 日志尾,余 1176 B / 57%) |
| protectTask | `512*4` | 2KB | 保护判据节拍(prot_elm_run 消费者 + 「自检失败闭锁」采样闭锁,B5 2026-10-12) | 未上板 / 静态 **872 B**(float 判据 + phasor 快照 + 日志尾,余 1176 B / 57%) |
| idle(内核) | `configMINIMAL_STACK_SIZE=128` | 0.5KB | 空闲 | 未观测(未取句柄) |
| timer(内核) | `configTIMER_TASK_STACK_DEPTH=256` | 1KB | 软定时器 | 未观测 |
@@ -8,7 +8,7 @@
> **状态**:已落地并经真机验证;下游 = L2 相量 / 测频 → L3 保护判据(`docs/算法/采集与算法层设计说明.md`)。
> **相关文档**:
> `docs/硬件平台/ADC通道映射说明.md`(网名 ↔ 板级 `ADCn` ↔ 转换器通道号,唯一权威)
> `docs/算法/继电保护功能复现规划.md` §3.1 L1-1(上位需求:1000 Hz 周期 CONVST 重触发)
> `docs/算法/继电保护功能复现规划.md` §3.1「周期 CONVST 重触发」
> `Drivers/BSP/TPAFE5160/README.md`(驱动契约:`BUSY` / `FRSTDATA` / 原子快照)
> `docs/子系统设计/看门狗设计说明.md` §11.4(`[PROF]` 字段语义与耗时基线)
>
@@ -285,7 +285,7 @@ t = 1000 µs 下一个更新事件
| `adc1_gap` | Σ(`seq` 每次前进的超出部分) = **丢掉的帧点数**(2026-10-21 起;此前固件为"次数") | 每 10 s 心跳 +1 点 | 快速上涨 → 本任务单拍 > 1 ms(看 `adcm`) |
| `adc1_err` | **连续 ≥ 2 拍**无新帧 | 0 | > 0 → 节拍源 / DMA 真停 |
| `adc1_hw` | `HAL_ADC_ErrorCallback()` 次数 | 0 | > 0 → ADC / DMA 硬件报错 |
| `tgap` | `adc_health_tpafe_gaps()`(L1-6) | 极少 | TPAFE 侧丢帧,与 `adc1_gap` **同单位(帧点数)**,可直接对比 |
| `tgap` | `adc_health_tpafe_gaps()`(「采样有效性校验」) | 极少 | TPAFE 侧丢帧,与 `adc1_gap` **同单位(帧点数)**,可直接对比 |
单拍耗时(`adcp` = `TASK_PROF_ADC_POLL`)与整拍耗时(`adcm` = `TASK_PROF_ADC_BEAT`)不在心跳里,
由 DWT 探针的 `[PROF]` 行给出,字段语义与基线 → `docs/子系统设计/看门狗设计说明.md` §11.4。
@@ -12,8 +12,8 @@
| 面 | 本期做 | 本期不做(登记 §8) |
|---|---|---|
| 链路 | APCI U/S/I、STARTDT/STOPDT/TESTFR、k/w 窗、t1/t2/t3 | 多主站并发(单连接语义,见 §5) |
| 遥测 YC | 短浮点 M_ME_NC_1(系数 1):背景/周期/死区上送 | 归一化/标度、谐波轨(L2-8) |
| 遥信 YX | 单点 M_SP + 双点 M_DP:背景 + 突发(COT=3);**突发单点带 CP56 时标 = M_SP_TB_1(B9,随 L4-4 SOE 落地)** | 双点带时标(V0.1 双点恒 IV,无意义) |
| 遥测 YC | 短浮点 M_ME_NC_1(系数 1):背景/周期/死区上送 | 归一化/标度、谐波轨(「遥测谐波轨(可选)」) |
| 遥信 YX | 单点 M_SP + 双点 M_DP:背景 + 突发(COT=3);**突发单点带 CP56 时标 = M_SP_TB_1(B9,随「SOE 记录」 SOE 落地)** | 双点带时标(V0.1 双点恒 IV,无意义) |
| 遥控 YK | 双点 C_DC 两段式(选择 82H/执行 02H) | 带时标、升降/步位 |
| 定值 | C_RD 读 + C_SE_NC 两段写(地址 = prot_set `comm_addr`) | 定值区切换/下装文件 |
| 其他 | C_CS 对时(→ `sys_clock`)、C_TS、C_RP | 固有参数 8001H~800AH(字符串类)、C_CI 电度、文件传输(录波) |
@@ -66,7 +66,7 @@
| 5~14 | 预留 | — | ❌ IV |
| 15 | 故障总 | OC1∨OC2∨OC3∨3U0(`prot_elm`) | ✅ |
| 16~18 | 过流 Ⅰ/Ⅱ/Ⅲ 段 | `PE_OC1/2/3` asserted | ✅ |
| 19~20 | 零序过流 Ⅰ/Ⅱ | L3-2 未实现 | ❌ IV |
| 19~20 | 零序过流 Ⅰ/Ⅱ | 「三段式零序过流」未实现 | ❌ IV |
| 21~22 | 接地故障/重载 | 未实现 | ❌ IV |
| 23 | 过载 | `PE_OL` asserted | ✅ |
| 24~30 | 外部遥信(RS-485) | B2 暂缓(`docs/任务规划/暂缓-RS485.md`) | ❌ IV |
@@ -105,7 +105,7 @@
**点表不另立地址表**,prot_set 即单一事实源。`comm_addr = 0` 的本地项(投退/返回系数/
全局软压板)不可经 C_RD/C_SE 寻址(B7 起显式排除,防 IOA=0 误命中首个本地项)。
- 写两段式:选择 = 范围校验;执行 = `prot_set_set_sealed`(**原子写+封存**:影子区
写好后单字交换活跃区,protectTask 的 L5-1 巡检任何时刻都看到自洽快照,
写好后单字交换活跃区,protectTask 的「定值校验和」巡检任何时刻都看到自洽快照,
B5 登记的 µs 级竞态窗口就此收口)。
- 持久化(B7):执行段置 prot_set 脏标志 → iec104Task 每轮 poll `dirty_peek` 投递
`SYS_EVT_PROT_SET_SAVE` → **defaultTask(配置引擎属主)** 经 `App/cfg/prot_set_store.c`
+1 -1
View File
@@ -61,7 +61,7 @@
| `timeSyncTask` | 2560 | Normal | 等网络 → TCP :8888 收 PC 推送时间 → 写 RTC | `time_sync_task` |
| `adcTask` | 2560 | AboveNormal | 纯消费者:`osThreadFlagsWait` 等 TIM3 1kHz 唤醒(ISR 内 `adc_tick_irq_notify` 置位)→ `adc_input_poll()`(TPAFE 原子快照 + STM32 ADC1 DMA 双缓冲)→ L1/L2 消费,不取数不做保护运算 | `adc_task_func` |
| `iec104Task` | 2560 | Normal | 等网络 → IEC 60870-5-104 上行(:2404 监听 + link 状态机,遥信/遥测/定值区,B4) | `iec104_serv_task` |
| `protectTask` | 2048 | Normal | 保护判据 20ms 节拍:`prot_elm_run()` + L5-4 采样故障闭锁 + L5-1 定值校验和巡检(B5);不依赖网络,纳入 IWDG `required_mask` | `protect_task` |
| `protectTask` | 2048 | Normal | 保护判据 20ms 节拍:`prot_elm_run()` + 「自检失败闭锁」采样故障闭锁 + 定值校验和巡检(B5);不依赖网络,纳入 IWDG `required_mask` | `protect_task` |
> `idle`(128 words)/ `timer`(256 words)由 FreeRTOS 内核创建。所有任务栈从 FreeRTOS `heap_4` 堆分配(**已迁 CCM**,2026-10-12 扩容至 56 KB,见 `docs/内存管理/RAM使用分析与优化方案.md` §4.1.2/§2.3)。
> **栈实测与预算**(2026-10-10~14,工具 `scripts/stack_report.py` = Keil 静态调用图 + 串口 `[STACK]` 水位;详见 `docs/内存管理/RAM使用分析与优化方案.md` §4.0.6/§2.3):
@@ -12,7 +12,7 @@
> [`配置文件单元测试说明.md`](配置文件单元测试说明.md)(同层"强符号桩"范本)、
> [`相量层单元测试说明.md`](相量层单元测试说明.md)(同批落地的 L2 姊妹篇)、
> [`../硬件平台/ADC通道映射说明.md`](../硬件平台/ADC通道映射说明.md)(**语义映射权威口径**)、
> [`../算法/继电保护功能复现规划.md`](../算法/继电保护功能复现规划.md)(L1-3 / L1-4 设计依据)、
> [`../算法/继电保护功能复现规划.md`](../算法/继电保护功能复现规划.md)(「STM32 ADC1 启动与扫描」/「通道语义映射」设计依据)、
> 快照语义约定的历史审计(属主文档已于 2026-10-15 删除)
---
@@ -25,7 +25,7 @@
| 半边 | 内容 | 可测性 |
|---|---|---|
| **纯逻辑**(被测) | ① 语义通道映射表(L1-4):`UA/UB/UC/UN/IA/IB/IC/IN/TEMP` → `(来源, 下标)`;② STM32 ADC1 帧消费(L1-3,v2.0 DMA 模型):**Rank 顺序 ↔ ADC1 通道号 ↔ 语义** + **乒乓半区选择**;③ 取数守卫与 poll 契约;④ 状态码与四类故障计数(`seq`/`gap`/`err`/`hw`) | 纯查表 + 状态机,与硬件无关 → **可在 PC 上位穷举** |
| **纯逻辑**(被测) | ① 语义通道映射表(「通道语义映射」):`UA/UB/UC/UN/IA/IB/IC/IN/TEMP` → `(来源, 下标)`;② STM32 ADC1 帧消费(「STM32 ADC1 启动与扫描」,v2.0 DMA 模型):**Rank 顺序 ↔ ADC1 通道号 ↔ 语义** + **乒乓半区选择**;③ 取数守卫与 poll 契约;④ 状态码与四类故障计数(`seq`/`gap`/`err`/`hw`) | 纯查表 + 状态机,与硬件无关 → **可在 PC 上位穷举** |
| **硬件副作用** | `HAL_ADC_Start_DMA()`(挂载)与被测代码自己实现的三个 HAL 弱回调 `HAL_ADC_Conv[Half]CpltCallback` / `HAL_ADC_ErrorCallback`;`tpafe5160_snapshot()`(临界区) | 挂载是**外部符号** → 主机侧给同名强符号桩;三个回调由**被测代码**定义 → 测试直接调用它们注入"DMA 完成" |
板端套件(`test/board/`)**无法验证本层的核心判据**:
@@ -41,8 +41,8 @@
"Rank 顺序 ↔ ADC1 通道号 ↔ 语义"整条链路**逐通道钉死**;"DMA 完成"由测试直接调用被测代码
实现的半传输/传输完成回调注入(`dma_beat()`),故障路径用可注入桩一次覆盖。
> ⚠ 本单测**只覆盖 L1-3 / L1-4**。L1-5(通道标定)本层不做,故取到的是**未标定原始码值**;
> L1-1 / L1-2(周期触发与 TPAFE 快照链路)由 `adc_task` + TPAFE 驱动承担,板端套件覆盖。
> ⚠ 本单测**只覆盖「STM32 ADC1 启动与扫描」与「通道语义映射」**。「通道标定(一次系数 + 零漂)」本层不做,故取到的是**未标定原始码值**;
> 「周期 CONVST 重触发」与「TPAFE 快照消费」由 `adc_task` + TPAFE 驱动承担,板端套件覆盖。
### 1.2 被测对象与桩(**不改生产代码**)
@@ -255,15 +255,15 @@ test/host/adc_input/adc_input_test.c
因此本单测**只覆盖正向路径**(`map_check() == 0`);反向路径的等效保障是
`adc_input_init()` 的返回值——它在开机时自检并留痕(见 `app_main.c`)。
### 4.2 本层不做标定(L1-5 待办)
### 4.2 本层不做标定(「通道标定(一次系数 + 零漂)」待办)
`adc_input_raw()` 返回的是**未标定原始码值**(TPAFE = 16 位补码,STM32 = 0..4095)。
一次系数 / 零漂标定属 **L1-5,尚未实现**,故本单测不对"物理量换算"做任何断言。
一次系数 / 零漂标定属 **「通道标定(一次系数 + 零漂)」,尚未实现**,故本单测不对"物理量换算"做任何断言。
### 4.3 不覆盖 V0.1 的硬件缺陷(双转换器无共同采样触发)
V0.1 上 8 路电气量分属两片转换器且**无共同采样触发**(登记簿条目「双转换器无共同采样触发」),本层只做**逐通道独立监视**。
"跨转换器相量合成"(线 / 负序 / 零序)不得在本层或 L2 上做——属 L2-5 且 V0.1 受限
"跨转换器相量合成"(线 / 负序 / 零序)不得在本层或 L2 上做——属「线/负序/零序合成」且 V0.1 受限
(见 `docs/算法/继电保护功能复现规划.md` §1.6)。
---
@@ -372,8 +372,8 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
| 层 | 载体 | 抓住什么 |
|---|---|---|
| 文本层 | `check_content_pages.py` 字形模板匹配(310 条、覆盖 37 页,解析字体 cmap / glyph_dsc / bitmap) | 缺字显示空白 / 标签写错等**静默失败**(不依赖 `ref/`,先于像素比对运行、失败即中止防误刷参考) |
| 像素层 | 40 内容页 + 菜单 8 状态,与黄金参考逐字节比对 | 几何 / 样式 / 光标反显 / 整体外观 |
| 文本层 | `check_content_pages.py` 字形模板匹配(310 条、覆盖当时 37 页,解析字体 cmap / glyph_dsc / bitmap) | 缺字显示空白 / 标签写错等**静默失败**(不依赖 `ref/`,先于像素比对运行、失败即中止防误刷参考) |
| 像素层 | 47 内容页 + 菜单 8 状态,与黄金参考逐字节比对 | 几何 / 样式 / 光标反显 / 整体外观 |
| 池水位层 | `MENU_POOL_BASELINE=5368 B` / `POOL_AFTER_ROUNDTRIP=5448 B` | LVGL 内存池泄漏 / 结构性漂移(量的是 `used`,与 `LV_MEM_SIZE` 总大小无关) |
### 5.3 黄金参考与字体纪律
@@ -644,3 +644,4 @@ CI 就静默停摆(2026-10-11 实测 run 16~21 共 12 个 job 零日志)。
| 2026-10-26 | 像素层页数口径修正为 **27 内容页**(判据 = `simulator/tests/ref/` 入库的 27 个 `shot_*.bin`;旧写「11」是页面扩充前的数字)。同类陈述同步在 `UI_自动化测试流程.md` 等六处改正 |
| 2026-10-26 | 三层断言表的文本层规模由「50 条」修正为 **242 条、覆盖 24 页**(现值取自 `simulator/tests/check_content_pages.py` 的 TEXTS 实跑计数;三张密码态无文本断言)|
| 2026-10-26 | 三层断言表同步 UI 三页落地后的真值:像素层 **27 → 40 内容页**、文本层 **242 → 310 条(覆盖 37 页)**;上方变更记录里的 27 / 242 属当日事实,保留不动 |
| 2026-10-27 | 三层断言表的像素层计数同步真值:**40 → 47 内容页**(判据 = `simulator/tests/ref/` 入库 `shot_*.bin` 实数 47 张 + `check_content_pages.py` 的 `PAGES` 47 项);文本层 310 条 / 覆盖 37 页仍是 2026-10-26 实跑口径,未随新增页重测,留待下次实跑回填;本条只加新行,历史行 27 → 40 原样保留 |
@@ -23,7 +23,7 @@
因此天然适合离线穷举。板端套件(`test/board/`)**无法验证本层的核心判据**:
- 板端**无信号源**,无法注入已知**幅值 / 相位 / 频率**的标准波形,因而无法验证
"读数 = 设定值"这一根本判据(同 L1-3 的替代口径,见 `docs/硬件平台/ADC通道映射说明.md` §8);
"读数 = 设定值"这一根本判据(同「STM32 ADC1 启动与扫描」的替代口径,见 `docs/硬件平台/ADC通道映射说明.md` §8);
- 谐波抑制、频率敏感度、滑动窗恒定性、双区无撕裂等特性在板上**无稳定激励源**可造。
主机侧可**合成任意波形**(含直流、任意次谐波、频偏、任意初相),把上述特性一次性钉死,
@@ -87,7 +87,7 @@ test/host/phasor/phasor_test.c
| **门禁层级** | **L0.5 层**(介于 L0 静态门禁与 L1 板端套件之间):主机侧、秒级、纯逻辑 |
| **pre-commit 钩子** | `phasor-unit-test`(本地钩子,`.pre-commit-config.yaml` §7d) |
| **汇总行** | `=== Phasor Tests: 57/57 PASSED (failed=0) ===` |
| **与板端测试的关系** | 互补:本单测保证**算法正确性**;板端保证 **1 kHz 采样节拍与 TPAFE 快照链路**(L1-1 / L1-2)正常 |
| **与板端测试的关系** | 互补:本单测保证**算法正确性**;板端保证 **1 kHz 采样节拍与 TPAFE 快照链路**(「周期 CONVST 重触发」/「TPAFE 快照消费」)正常 |
---
@@ -96,32 +96,32 @@ test/host/phasor/phasor_test.c
> 命名 `TC-PH-NNN`(PH = PHasor)。用例内的输出标签使用 `L2-x` 前缀,对应
> `docs/算法/继电保护功能复现规划.md` §3.2 的设计点编号。部分用例直接观测静态量(白盒)。
### 2.1 L2-1 全周傅氏系数表
### 2.1 全周傅氏系数表
| 用例 | 断言 | 设计点 |
|---|---|---|
| **TC-PHASOR-001** | 逐项:`sin[k] == sin(2πk/N)·(√2/N)`、`cos[k] == cos(2πk/N)·(√2/N)`(k = 0..19) | L2-1 防转录错 |
| **TC-PHASOR-002** | 归一化 `Σsin² == Σcos² == 1/N`;精确零点 `sin@0,10`、`cos@5,15`;`sin[5] == √2/N` | L2-1 判据基础 |
| **TC-PHASOR-001** | 逐项:`sin[k] == sin(2πk/N)·(√2/N)`、`cos[k] == cos(2πk/N)·(√2/N)`(k = 0..19) | 「全周傅氏系数表」防转录错 |
| **TC-PHASOR-002** | 归一化 `Σsin² == Σcos² == 1/N`;精确零点 `sin@0,10`、`cos@5,15`;`sin[5] == √2/N` | 「全周傅氏系数表」判据基础 |
### 2.2 L2-3 / L2-4 基波幅值 / 有效值 / 相位
### 2.2 「相量有效值输出」/「相位输出」基波幅值 / 有效值 / 相位
| 用例 | 断言 | 设计点 |
|---|---|---|
| **TC-PHASOR-003** | 纯基波:`fAmSQ == A/√2`(**有效值**)、`fAm == √2·fAmSQ`(幅值),误差 ≤ 1% | L2-3 |
| **TC-PHASOR-004** | `atan2(fIm, fRe)` == 注入相角(6 组幅值 / 相位) | L2-4 |
| **TC-PHASOR-003** | 纯基波:`fAmSQ == A/√2`(**有效值**)、`fAm == √2·fAmSQ`(幅值),误差 ≤ 1% | 相量有效值输出 |
| **TC-PHASOR-004** | `atan2(fIm, fRe)` == 注入相角(6 组幅值 / 相位) | 相位输出 |
### 2.3 直流与谐波抑制 / 任意次谐波提取
| 用例 | 断言 | 设计点 |
|---|---|---|
| **TC-PHASOR-005** | 直流 + 2 / 3 / 5 次谐波被**完全滤除**(基波读数不变,误差 ≤ 1%,5 例) | L2-1 |
| **TC-PHASOR-006** | 任意次谐波提取(**索引步进 = 谐波次数**):k = 1 / 2 / 5 从混合信号中提取;纯基波下 2 / 5 次分量 ≈ 0 | L2-1 / L1-9 入口 |
| **TC-PHASOR-005** | 直流 + 2 / 3 / 5 次谐波被**完全滤除**(基波读数不变,误差 ≤ 1%,5 例) | 全周傅氏系数表 |
| **TC-PHASOR-006** | 任意次谐波提取(**索引步进 = 谐波次数**):k = 1 / 2 / 5 从混合信号中提取;纯基波下 2 / 5 次分量 ≈ 0 | 「全周傅氏系数表」/「二次谐波/五次谐波提取入口」入口 |
### 2.4 频率敏感度
| 用例 | 断言 | 设计点 |
|---|---|---|
| **TC-PHASOR-007** | 幅值误差:50 Hz ≤ 0.1%、±1 Hz ≤ 1.5%、±2 Hz ≤ 3%(**最坏相位**) | L2-3 / L1-7 依据 |
| **TC-PHASOR-007** | 幅值误差:50 Hz ≤ 0.1%、±1 Hz ≤ 1.5%、±2 Hz ≤ 3%(**最坏相位**) | 「相量有效值输出」/「等周波采样(软件测频 + 调频闭环)」依据 |
### 2.5 L2 输入采样环(`sample_ring.c`)
@@ -129,23 +129,23 @@ test/host/phasor/phasor_test.c
|---|---|---|
| **TC-PHASOR-010** | `init` 清填充与帧计数;未攒满取窗 → -2;入环后取窗**按时序**(老 → 新);通道之间**互相独立**;填充量饱和于 `DEPTH` 但帧计数**不**饱和;回绕后取窗 == 最后 N 个值(有序);参数守卫:`n=0` / `n>DEPTH` / 越界通道 / `NULL out` / `NULL frame` / 错帧长 均拒绝 | L2 输入 |
### 2.6 L2-2 实例层
### 2.6 「基波相量实例」实例层
| 用例 | 断言 | 设计点 |
|---|---|---|
| **TC-PHASOR-020** | 实例数 == 5;实例表可取 `name`;越界实例 → `NULL`;未攒满一周波 `phasor_get()` → -2;越界 index / `NULL out` → -1;攒满 20 帧后 `get()` == 0 且实例 0 的 RMS == `A/√2`;谐波实例(`C04-IA-F2` / `C05-IA-F5`)在纯基波下 ≈ 0;**逐实例复核"实例窗 == 独立 `phasor_calc()` 结果"** | L2-2 |
| **TC-PHASOR-020** | 实例数 == 5;实例表可取 `name`;越界实例 → `NULL`;未攒满一周波 `phasor_get()` → -2;越界 index / `NULL out` → -1;攒满 20 帧后 `get()` == 0 且实例 0 的 RMS == `A/√2`;谐波实例(`C04-IA-F2` / `C05-IA-F5`)在纯基波下 ≈ 0;**逐实例复核"实例窗 == 独立 `phasor_calc()` 结果"** | 基波相量实例 |
### 2.7 L2-6 滑动窗
### 2.7 「每 1 ms 滑动窗刷新」滑动窗
| 用例 | 断言 | 设计点 |
|---|---|---|
| **TC-PHASOR-021** | 连续滑动 20 拍,基波读数**恒定**(误差 ≤ 1%) | L2-6 |
| **TC-PHASOR-021** | 连续滑动 20 拍,基波读数**恒定**(误差 ≤ 1%) | 每 1 ms 滑动窗刷新 |
### 2.8 L2-7 双区指针原子交换
### 2.8 双区指针原子交换
| 用例 | 断言 | 设计点 |
|---|---|---|
| **TC-PHASOR-022** | 使用区逐次产出**交替** 0 → 1 → 0 → 1;**连测 60 拍**:每拍 `get()` == 当前环窗的独立重算(幅值每 20 拍在 100 / 10 之间切换 → 读到陈旧区会立刻不相等);扫描后结果仍可读 | L2-7 |
| **TC-PHASOR-022** | 使用区逐次产出**交替** 0 → 1 → 0 → 1;**连测 60 拍**:每拍 `get()` == 当前环窗的独立重算(幅值每 20 拍在 100 / 10 之间切换 → 读到陈旧区会立刻不相等);扫描后结果仍可读 | 双区指针原子交换 |
### 2.9 `phasor_zero` / `phasor_init` 清零与幂等
@@ -185,7 +185,7 @@ test/host/phasor/phasor_test.c
`frame_at()` 给 9 路语义通道灌的是**同值**波形,仅为驱动 L2 本身。V0.1 上各通道**不同刻**
(V0.1 硬件缺陷:TPAFE 与 STM32 无共同采样触发),跨通道相量运算在本平台上不成立——本单测**不**做
任何跨通道合成断言(L2-5 受限,见 `docs/算法/继电保护功能复现规划.md` §1.6)。
任何跨通道合成断言(「线/负序/零序合成」受限,见 `docs/算法/继电保护功能复现规划.md` §1.6)。
### 4.3 实例数 4 → 5:规划表已对齐(2026-10-10)
@@ -194,14 +194,14 @@ C03 二次谐波、C04 五次谐波;**本项目**按 V0.1 **有效通道**(`
`UB/UC/IB/IC/IN` 无中点偏置 → 削顶不可用)展开为 **5 个实例**
(`C01-IA-F1` / `C02-UA-F1` / `C03-UN-F1` / `C04-IA-F2` / `C05-IA-F5`)。
`docs/算法/继电保护功能复现规划.md` §3.2 的 L2-2 行已于 2026-10-10 同步为 **5 个实例**
`docs/算法/继电保护功能复现规划.md` §3.2 的「基波相量实例」行已于 2026-10-10 同步为 **5 个实例**
(并加注说明 4 → 5 的来历);本单测按**实现**断言(实例数 == 5),两者口径现已一致。
`docs/算法/傅氏算法详解.md` §7 的"4 个实例"已标注为**参考项目**口径。
### 4.4 实例表用"数据驱动"而非硬编码
`k_inst[]` 每项为 `{name, sem, harm}`,`phasor_run()` 遍历该表取窗并计算。因此新增一个
相量实例(如 L2-8 的遥测谐波轨)**只需在表里加一行**,本单测的"实例数 == 5"与
相量实例(如「遥测谐波轨(可选)」的遥测谐波轨)**只需在表里加一行**,本单测的"实例数 == 5"与
"逐实例复核"两条断言会**自动扩展到新实例**——但需同步更新该常量断言。
---
+2 -2
View File
@@ -129,7 +129,7 @@ STM32(U17)为 LQFP144 脚号。
| 项 | 现状 | 影响 |
|---|---|---|
| **通道归属(硬件缺陷)** | 8 路电气量分属两片转换器:UA/UN/IA → TPAFE,UB/UC/IB/IC/IN → STM32 ADC | **V0.1 硬件缺陷**(非有意分配,理由见 §1)→ V0.1 上禁止跨转换器做相位/功率/功率因数/矢量类运算;**V0.2 改版要求 8 路电气量全部走 TPAFE**(登记簿 N-18) |
| STM32 ADC 外设 | **已生成(2026-10-09,CubeMX 6.17 + FW_F4)**:`Src/adc.c`/`Inc/adc.h` 已入库并挂进 `MDK-ARM/*.uvprojx`;`Inc/stm32f4xx_hal_conf.h` 的 `HAL_ADC_MODULE_ENABLED` 已生效;HAL `stm32f4xx_hal_adc.c/_ex.c` + `stm32f4xx_ll_adc.h` 已补入仓库(HAL 原本是裁剪子集);`Src/main.c` 里 `MX_ADC1_Init()` 排在 `MX_IWDG_Init()` 之后。生成配置核对无误:9 通道 / Rank 1~9 / 全部 144 cycles / `ScanConvMode=ENABLE` / `ContinuousConvMode=DISABLE` / `ExternalTrigConv=ADC_SOFTWARE_START` + `EDGE_NONE` / `EOCSelection=ADC_EOC_SINGLE_CONV` / `DataAlign=RIGHT` / 12 位;`HAL_ADC_MspInit()` 已把 PA0~PA7+PC4 配成 `GPIO_MODE_ANALOG` | 硬件通路已打通(`hadc1` 可用);**消费者已落地**——`App/algo/adc_input.c` 的 `stm32_take()`(L1-3,v2.0,2026-10-10):ADC1 由 **TIM3 TRGO 硬件触发**一轮 9 通道 + **DMA2_Stream4 循环搬运**进乒乓双缓冲,任务侧只消费刚完成的半区(零忙等),9 通道一轮 ≈ 67 µs |
| STM32 ADC 外设 | **已生成(2026-10-09,CubeMX 6.17 + FW_F4)**:`Src/adc.c`/`Inc/adc.h` 已入库并挂进 `MDK-ARM/*.uvprojx`;`Inc/stm32f4xx_hal_conf.h` 的 `HAL_ADC_MODULE_ENABLED` 已生效;HAL `stm32f4xx_hal_adc.c/_ex.c` + `stm32f4xx_ll_adc.h` 已补入仓库(HAL 原本是裁剪子集);`Src/main.c` 里 `MX_ADC1_Init()` 排在 `MX_IWDG_Init()` 之后。生成配置核对无误:9 通道 / Rank 1~9 / 全部 144 cycles / `ScanConvMode=ENABLE` / `ContinuousConvMode=DISABLE` / `ExternalTrigConv=ADC_SOFTWARE_START` + `EDGE_NONE` / `EOCSelection=ADC_EOC_SINGLE_CONV` / `DataAlign=RIGHT` / 12 位;`HAL_ADC_MspInit()` 已把 PA0~PA7+PC4 配成 `GPIO_MODE_ANALOG` | 硬件通路已打通(`hadc1` 可用);**消费者已落地**——`App/algo/adc_input.c` 的 `stm32_take()`(「STM32 ADC1 启动与扫描」,v2.0,2026-10-10):ADC1 由 **TIM3 TRGO 硬件触发**一轮 9 通道 + **DMA2_Stream4 循环搬运**进乒乓双缓冲,任务侧只消费刚完成的半区(零忙等),9 通道一轮 ≈ 67 µs |
| ADC1 上电自校准 | **已补(2026-10-10)**:`Src/adc.c` 的 `USER CODE BEGIN ADC1_Init 2` 调用 `adc1_calibrate()`(实现同文件 `USER CODE BEGIN 1`,按 RM0090 §13.3.6:清 ADON→等生效→置 ADON→置 CAL→等 CAL 由硬件清零)。⚠ **CubeMX 不生成这一步**,且本仓库裁剪版 HAL **没有** `HAL_ADCEx_Calibration_Start`、裁剪版 CMSIS 头**没有** `ADC_CR2_CAL`(bit3,代码里按 RM 自建 `ADC1_CAL_BIT`)→ 属 L2 手工定制,审计项 `adc1-calibration-call` / `adc1-calibration-impl` 兜底 | 实测有效:校准前后同一拍 STM32 侧 6 路**同向**变化 `UB 898→961`、`UC 978→1038`、`IB 906→922`、`IC 1061→1071`、`IN 1017→1055`、`T 790→846`(+10~+63 LSB ≈ 0.2~1.5 % FS);TPAFE 侧 `UA/UN/IA` 一字不变 → 变化确来自 ADC1 校准。缺这一步不报错,只是**读数带失调** |
| ADC 时钟 | CubeMX 的 F4 ADC 面板**有** Clock Prescaler 一项(此前"面板没有该项、固定 DIV2"的判断有误),已选 **PCLK2/4 → ADCCLK = 21 MHz** ✓。面板里 **DIV2 是灰的、选不到**:DB 里 `FadcConstraint Max=36000000`,APB2 = 84 MHz → DIV2 = 42 MHz 超限,该候选值被 `Action="DISABLE"` 禁掉,超规值进不来 | **不设额外防护(2026-10-09 决定)**:约束已由 CubeMX 把关;`.ioc` 虽不保存 `ADC1.ClockPrescaler` 键,重生成也只会回落到约束允许的值。按 144+12 cycles 算 ≈ 7.4 µs/通道、9 通道一轮 ≈ 67 µs |
| `adc_task` | **已实现(B1,2026-10-10;L1 层 v2.3;P1-5 事件驱动消费,2026-10-10)**:`App/task/adc_task.c` 每拍调 `adc_input_poll()`(`App/algo/adc_input.c`)= TPAFE `tpafe5160_snapshot()` 原子快照(8 通道)+ 消费一帧 STM32 ADC1 DMA 乒乓缓冲,**经 `adc_input_raw()` 按语义取数**(不再直接索引驱动缓冲);**消费唤醒由 TIM3 ISR 置位 `ADC_WAKE_FLAG`**(不再 1 ms 轮询);任务在 `Src/freertos.c` 的 `USER CODE` 区创建为 `adcTask`(512 words / **AboveNormal**) | 数据路径已通(台架 `@test`:`frames` 严格 1000 Hz 递增、**`idle=0`**、`adc1_rc=0` / `adc1_err=0`) |
@@ -175,7 +175,7 @@ STM32(U17)为 LQFP144 脚号。
## 8. 逐通道验证方法(上板自检口径)
1. **TPAFE 侧**:对目标 `AIN` 注入 1 V DC → 观察对应 `buf[i]` 变化(UA→`buf[6]`、UN→`buf[5]`、IA→`buf[2]`),同时 U3.14 `BUSY` 有脉冲;**语义与下标不符即映射错**。⚠ **本步无执行记录**(2026-10-23 核查;`V0.0_网表详细分析报告.md` §5.1 第 6 条的同一验证也从未执行)。已排入 `docs/任务规划/数据可信.md` 卡 0,并把两条判据降为**不需要示波器**的口径:① "`BUSY` 有脉冲"改用固件帧计数——注入前后 `tpafe5160_frame_seq()` 仍严格 1000 Hz 递增即等价;② 幅值判据改用万用表读注入点实际电压 + 同时读 `adc_input_raw()` 码值,三点线性拟合(R² ≥ 0.999)。
2. **STM32 侧**:对目标引脚(如 PC4=UB)注入 0.5 V → 读 `ADC_CHANNEL_14` 应变化;若不变而相邻通道变化 → 通道宏写错(见 §5 警告)。⚠ **本步尚未执行**(2026-10-10 L1-3 台架只验证了"9 通道全部转换成功 + 零超时 + 互异非饱和 + 跨次开机读数不同",台架无信号源);映射的**代码侧**一致性有两道保证:① `App/algo/adc_input.c` 的 `k_adc_map[]` 与 CubeMX 标签(`ADC17_UB`=PC4 等)逐条对齐;② 开机自检 `adc_input_init()` 校验每个 STM32 语义通道都落在 `k_stm32_rank_ch[]` 扫描序列内(挡"映射到不扫描的通道 → 恒读陈旧值")。
2. **STM32 侧**:对目标引脚(如 PC4=UB)注入 0.5 V → 读 `ADC_CHANNEL_14` 应变化;若不变而相邻通道变化 → 通道宏写错(见 §5 警告)。⚠ **本步尚未执行**(2026-10-10 「STM32 ADC1 启动与扫描」台架只验证了"9 通道全部转换成功 + 零超时 + 互异非饱和 + 跨次开机读数不同",台架无信号源);映射的**代码侧**一致性有两道保证:① `App/algo/adc_input.c` 的 `k_adc_map[]` 与 CubeMX 标签(`ADC17_UB`=PC4 等)逐条对齐;② 开机自检 `adc_input_init()` 校验每个 STM32 语义通道都落在 `k_stm32_rank_ch[]` 扫描序列内(挡"映射到不扫描的通道 → 恒读陈旧值")。
3. **备用通道**:RESERVED 路不接入任何语义,UI 与上报里不得出现;若实测有读数漂移,只记录不消费。
4. **端子侧变比(2026-10-23 补)**:上面 1/2 两条都只到 **ADC 引脚**。**"端子电压 → ADC 引脚电压"的变比在仓库里没有任何文档给出**(`docs/硬件平台/` 只有 `.tel` 网表与分析报告,无子板原理图),而 `V0.0_网表详细分析报告.md` §4.7 已把 `1k 串联 + 1k 到地` 这组网络定性为"**源阻抗匹配(手册推荐做法,非分压)**"。故**不得**用"2:1 分压"直接换算出二次值;该变比由 `docs/任务规划/数据可信.md` 卡 0b 实测确认。
+69 -69
View File
@@ -4,7 +4,7 @@
> **参考来源**:`D:\Code\DTU\参考资料\huaiyuan\huaiyuan\Scatter_P_HV03.01_SV01.01\项目分析文档\04-算法与采样专题\ADC采集至数据使用全流程详解`(同专题另有《项目详细分析-交流采样与有效值计算》《傅氏算法详解》《项目详细分析-阶段6-继电器保护单元分析》)。
> **阅读前提**:先读 `docs/算法/傅氏算法详解.md`(算法原理)与 `docs/硬件平台/ADC通道映射说明.md`(采样通道权威口径)。
> **相关文档**:`docs/产品需求/产品需求设计文档.md`、`docs/任务规划/README.md`、`docs/内存管理/RAM使用分析与优化方案.md`。
> **状态**:**P0 采样与相量底座已台架闭环(2026-10-11)**——L1 采集链路(B1,2026-10-10)、L1-6 采样有效性校验与 L2 相量层(`sample_ring` + `phasor`,57 项主机单测 + 台架 `@test` 含 `phasor(first)/phasor(hb)` 标记闭环)均已落地;**P1/P2 保护元件与定值模型软件侧完成(2026-10-11,`prot_set` + `prot_elm`,57 项主机单测)**;**B5 板端接线完成(2026-10-12)**——`protectTask`(20 ms 判据节拍 + L5-4 采样故障闭锁 + L5-1 定值校验和巡检,IWDG `TASK_WD_PROTECT` bit8,栈 512 words 静态链 872 B / 余 57%),判据结果经 B4 IEC104 遥信(YX15~23/31)上送;**B7 定值持久化 + 全局软压板 + 竞态收口完成(2026-10-12,含台架腿验证)**;**出口记录(L4)与标准源注入验收为下一步**(见 §7)。
> **状态**:**P0 采样与相量底座已台架闭环(2026-10-11)**——L1 采集链路(B1,2026-10-10)、 采样有效性校验与 L2 相量层(`sample_ring` + `phasor`,57 项主机单测 + 台架 `@test` 含 `phasor(first)/phasor(hb)` 标记闭环)均已落地;**P1/P2 保护元件与定值模型软件侧完成(2026-10-11,`prot_set` + `prot_elm`,57 项主机单测)**;**B5 板端接线完成(2026-10-12)**——`protectTask`(20 ms 判据节拍 + 「自检失败闭锁」采样故障闭锁 + 定值校验和巡检,IWDG `TASK_WD_PROTECT` bit8,栈 512 words 静态链 872 B / 余 57%),判据结果经 B4 IEC104 遥信(YX15~23/31)上送;**B7 定值持久化 + 全局软压板 + 竞态收口完成(2026-10-12,含台架腿验证)**;**出口记录(L4)与标准源注入验收为下一步**(见 §7)。
---
@@ -37,7 +37,7 @@
| 操作系统 | FreeRTOS V10.3.1(CMSIS-RTOS v2) |
| 已实现子系统 | 网络(CH395F)、存储(GD5F2GQ5UE SPI NAND + dhara FTL + FatFs)、时间(SD2506 RTC + `sys_clock`)、配置(cfg_file)、日志、UI(远端显示)、看门狗(IWDG)、FTP |
| 采样硬件 | TPAFE5160(16 位、8 通道**同步**、±5 V 双极性、并行 `GPIOG[15:0]`)+ STM32 内部 ADC1(12 位、9 通道**顺序**扫描、0~3.3 V 单极性) |
| 采样软件 | `Drivers/BSP/TPAFE5160/tpafe5160.h` 驱动就绪(原子快照 API);`App/task/adc_task.c` **已实现真实消费者(B1,2026-10-10)**——`tpafe5160_snapshot()` 取数 + 帧统计;**采样节拍由 TIM3 更新事件(1 kHz)硬件触发**(2026-10-10;同一事件经 TRGO 触发 ADC1 + DMA);STM32 侧 **`App/algo/adc_input.c` 已实现语义映射 + ADC1 DMA 乒乓帧消费(L1-3/L1-4,v2.0)**,`HAL_ADC_Start_DMA` 已出现 |
| 采样软件 | `Drivers/BSP/TPAFE5160/tpafe5160.h` 驱动就绪(原子快照 API);`App/task/adc_task.c` **已实现真实消费者(B1,2026-10-10)**——`tpafe5160_snapshot()` 取数 + 帧统计;**采样节拍由 TIM3 更新事件(1 kHz)硬件触发**(2026-10-10;同一事件经 TRGO 触发 ADC1 + DMA);STM32 侧 **`App/algo/adc_input.c` 已实现语义映射 + ADC1 DMA 乒乓帧消费(「STM32 ADC1 启动与扫描」/L1-4,v2.0)**,`HAL_ADC_Start_DMA` 已出现 |
| 保护算法层 | **L2 相量层已实现并台架闭环**(`App/algo/sample_ring.c` + `phasor.c`:全周傅氏 5 实例、双区交换、每 1 ms 刷新,2026-10-11 `@test`);**L3 元件框架 + 过流/过负荷/过压/欠压/零序过压 + 定值模型软件侧完成**(`prot_elm.c` + `prot_set.c`,2026-10-11,57 项主机单测);**出口 / SOE 记录仍缺失**(P4) |
| 已知硬件缺陷 | 登记簿条目「双转换器无共同采样触发」:8 路电气量分属两片转换器 → V0.1 上禁止跨转换器做相位/功率/矢量运算 |
@@ -67,7 +67,7 @@
| **B0 产品定义** | 采集是否持续 / 采样率与通道 / 转发目标 / 保护元件清单——决定 B1 与保护层的**规模** | ✅ 已确认(2026-10-10,见 §1.5) |
| **B1 ADC 采集链路** | 周期 CONVST + `adc_task` 消费 `tpafe5160_snapshot()` + 建任务 + 栈预算 | ✅ 已实现并 `@test` 实机闭环(2026-10-10;`adcTask` 512 words,台架 1000 Hz) |
| **双转换器无共同采样触发(硬件缺陷)** | V0.1 跨转换器无同一时刻性 → 限定 V0.1 可实现的保护范围 | ⚠️ 硬件改版项(V0.2) |
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | ✅ 两任务均已核算:`adcTask`(**L1-6 后:栈抬至 640 words,静态 1080 B / 台架实测峰值 952/2560 / 余 57%**);`protectTask`(B5,2026-10-12:**512 words,静态链 872 B / 余 1176 B / 57%**,台架水位待 `@test`) |
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | ✅ 两任务均已核算:`adcTask`(**「采样有效性校验」后:栈抬至 640 words,静态 1080 B / 台架实测峰值 952/2560 / 余 57%**);`protectTask`(B5,2026-10-12:**512 words,静态链 872 B / 余 1176 B / 57%**,台架水位待 `@test`) |
### 1.5 B0 产品定义(2026-10-10 确认)
@@ -236,38 +236,38 @@
### 3.1 L1 采集与预处理
| # | 功能点 | 关键参数 | 完成判据 | 状态 |
| --- | --- | --- | --- | --- |
| L1-1 | 周期 CONVST 重触发 | 1000 Hz(与保护节拍同源) | 示波器见 U3 `BUSY` 连续脉冲;`tpafe5160_frame_seq()` 持续递增 | ✅ 2026-10-10:**TIM3 更新事件(1 kHz)硬件触发**(ISR 内 `tpafe5160_start_conv_irq()`;方案 A,零引脚/零驱动改动。⚠ 节拍源**不能**是 TIM6/TIM7——F4 上 ADC1 收不到它们的 TRGO,见 `docs/子系统设计/ADC采样节拍设计说明.md` §3.2);台架 `@test` PASS——`seq` 每 10 s 精确 +10000 = 1000.0 Hz、`frst_err=0`(早期证据 `boot_log_data/20261010_prod_adc_tim6_boot_log.txt`,节拍源当时为 TIM6) |
| L1-2 | TPAFE 快照消费 | 8 通道 / 帧 | `adc_task` 每拍调 `tpafe5160_snapshot()`,返回 1/0/-1 有处理 | ✅ B1 已实现并 `@test` 闭环(`adc_task.c`;台架 `idle=0`、`frst_err=0`) |
| L1-3 | STM32 ADC1 启动与扫描 | 9 通道、144 cycles、**TIM3 TRGO 硬件触发 + DMA** | 全库出现 `HAL_ADC_Start_DMA`;9 通道码值随注入变化 | ✅ 2026-10-10(v2.0):`App/algo/adc_input.c` 的 `stm32_take()`——ADC1 由 TIM3 更新事件经 TRGO 触发一轮 9 通道,`HAL_ADC_Start_DMA(&hadc1, buf, 18)` + DMA2_Stream4 循环模式把码值自动搬进**乒乓双缓冲**,任务侧只消费刚完成的半区(**零忙等**,实测单拍 `adcp` 122 µs → **8 µs**);台架 `@test` PASS——`adc1_seq` 每拍 +1、`adc1_err=0`、`adc1_hw=0`。⚠ 判据"随注入变化"以"逐通道独立读数 + 零停摆 + 跨次开机读数不同"替代(台架无信号源,同 §7.1 无示波器口径);**引脚级注入验证(`ADC通道映射说明.md` §8 步骤 2)仍为待做项** |
| L1-4 | 通道语义映射 | 见 `docs/硬件平台/ADC通道映射说明.md`(**按语义取数,不写死下标**) | `UA→buf[6]`、`UN→buf[5]`、`IA→buf[2]`;STM32 侧 `UB→ADC_CHANNEL_14` | ✅ 2026-10-10:`App/algo/adc_input.c` 的 `k_adc_map[]` 语义表(`UA/UN/IA`→TPAFE `buf[6]/[5]/[2]`,`UB/UC/IB/IC/IN/TEMP`→ADC1 `CH14/3/6/1/2/5`)+ `adc_input_raw()` 按语义取数;开机**映射自检**(`adc_input_init()` 校验 STM32 映射通道必落在扫描序列内 → 挡住"映射到不扫描的通道"静默错)通过(`ADC input layer init: OK`)。台架首帧日志 8 路 + 温度全部读出:`UA=11429 UN=11454 IA=11452`(与 TIM3 轮次一致)、`UB=1018 UC=1044 IB=943 IC=1069 IN=1052 T=850`(互异、非饱和;**两次开机读数不同** → 确为实时转换而非常量) |
| L1-5 | 通道标定(一次系数 + 零漂) | 每通道 `k`、`b`;系数定点 `2^10` | 注入标准源,读数误差 ≤ 目标精度 | ⬜ |
| L1-6 | 采样有效性校验 | FRSTDATA 跳变、帧序号单调、丢帧计数 | 芯片静默/丢帧被检出并置告警 | ✅ 2026-10-11:新增 `App/algo/adc_health.c/h`(纯逻辑判定层:静默 100 ms 门限 / 丢帧边沿 / 序号倒退锁存 / FRSTDATA·HAL 错误·STM32 停摆计数增量)+ `adc_task.c` 告警编排(严重事件与故障上升沿 `DBG_ERROR` + 每类每次开机一次 `SYSLOG_SELFTEST`,恢复 `DBG_INFO`;gap 不告警只计数,心跳增 `tgap`);主机单测 `test/host/adc_health/` **31 用例全绿**(`adc-health-unit-test` 钩子);台架 `@test` PASS 零 `[ERR]`(健康不误报,`boot_log_data/20261011_prod_adc_health_boot_log.txt`)。⚠ 抬栈:判定链 `adc_health_report`→`syslog_post` 回显尾使 adcTask 静态最坏链 832→**1080 B** → 栈 512→**640 words**(余 1480 B / 57%) |
| L1-7 | 等周波采样(软件测频 + 调频闭环) | 20 点/周波;测频范围建议 **45~55 Hz**(参考 40.5~60.5) | 频率偏移 ±2 Hz 时幅值误差 ≤ 1% | ⬜ |
| L1-8 | 零序通道接入(外部专用 / 自产切换) | 外部 `UN`/`IN`;自产 `3I0 = Ia+Ib+Ic`(V0.2 起) | 零序通道可切换来源,值正确 | ⬜ |
| L1-9 | 二次谐波/五次谐波提取入口 | k=2(涌流)、k=5(选线) | 相量层可产出对应谐波相量 | ✅ 2026-10-11:`phasor.c` 实例表 `C04-IA-F2`(k=2)/ `C05-IA-F5`(k=5)随每拍重算产出,台架心跳日志 `phasor(hb) C04/C05` 行可见(`boot_log_data/20261011_prod_phasor_boot_log.txt`);谐波**抑制/提取正确性**已由主机单测覆盖(`test/host/phasor/`) |
| 功能名 | 关键参数 | 完成判据 | 状态 |
| --- | --- | --- | --- |
| 周期 CONVST 重触发 | 1000 Hz(与保护节拍同源) | 示波器见 U3 `BUSY` 连续脉冲;`tpafe5160_frame_seq()` 持续递增 | ✅ 2026-10-10:**TIM3 更新事件(1 kHz)硬件触发**(ISR 内 `tpafe5160_start_conv_irq()`;方案 A,零引脚/零驱动改动。⚠ 节拍源**不能**是 TIM6/TIM7——F4 上 ADC1 收不到它们的 TRGO,见 `docs/子系统设计/ADC采样节拍设计说明.md` §3.2);台架 `@test` PASS——`seq` 每 10 s 精确 +10000 = 1000.0 Hz、`frst_err=0`(早期证据 `boot_log_data/20261010_prod_adc_tim6_boot_log.txt`,节拍源当时为 TIM6) |
| TPAFE 快照消费 | 8 通道 / 帧 | `adc_task` 每拍调 `tpafe5160_snapshot()`,返回 1/0/-1 有处理 | ✅ B1 已实现并 `@test` 闭环(`adc_task.c`;台架 `idle=0`、`frst_err=0`) |
| STM32 ADC1 启动与扫描 | 9 通道、144 cycles、**TIM3 TRGO 硬件触发 + DMA** | 全库出现 `HAL_ADC_Start_DMA`;9 通道码值随注入变化 | ✅ 2026-10-10(v2.0):`App/algo/adc_input.c` 的 `stm32_take()`——ADC1 由 TIM3 更新事件经 TRGO 触发一轮 9 通道,`HAL_ADC_Start_DMA(&hadc1, buf, 18)` + DMA2_Stream4 循环模式把码值自动搬进**乒乓双缓冲**,任务侧只消费刚完成的半区(**零忙等**,实测单拍 `adcp` 122 µs → **8 µs**);台架 `@test` PASS——`adc1_seq` 每拍 +1、`adc1_err=0`、`adc1_hw=0`。⚠ 判据"随注入变化"以"逐通道独立读数 + 零停摆 + 跨次开机读数不同"替代(台架无信号源,同 §7.1 无示波器口径);**引脚级注入验证(`ADC通道映射说明.md` §8 步骤 2)仍为待做项** |
| 通道语义映射 | 见 `docs/硬件平台/ADC通道映射说明.md`(**按语义取数,不写死下标**) | `UA→buf[6]`、`UN→buf[5]`、`IA→buf[2]`;STM32 侧 `UB→ADC_CHANNEL_14` | ✅ 2026-10-10:`App/algo/adc_input.c` 的 `k_adc_map[]` 语义表(`UA/UN/IA`→TPAFE `buf[6]/[5]/[2]`,`UB/UC/IB/IC/IN/TEMP`→ADC1 `CH14/3/6/1/2/5`)+ `adc_input_raw()` 按语义取数;开机**映射自检**(`adc_input_init()` 校验 STM32 映射通道必落在扫描序列内 → 挡住"映射到不扫描的通道"静默错)通过(`ADC input layer init: OK`)。台架首帧日志 8 路 + 温度全部读出:`UA=11429 UN=11454 IA=11452`(与 TIM3 轮次一致)、`UB=1018 UC=1044 IB=943 IC=1069 IN=1052 T=850`(互异、非饱和;**两次开机读数不同** → 确为实时转换而非常量) |
| 通道标定(一次系数 + 零漂) | 每通道 `k`、`b`;系数定点 `2^10` | 注入标准源,读数误差 ≤ 目标精度 | ⬜ |
| 采样有效性校验 | FRSTDATA 跳变、帧序号单调、丢帧计数 | 芯片静默/丢帧被检出并置告警 | ✅ 2026-10-11:新增 `App/algo/adc_health.c/h`(纯逻辑判定层:静默 100 ms 门限 / 丢帧边沿 / 序号倒退锁存 / FRSTDATA·HAL 错误·STM32 停摆计数增量)+ `adc_task.c` 告警编排(严重事件与故障上升沿 `DBG_ERROR` + 每类每次开机一次 `SYSLOG_SELFTEST`,恢复 `DBG_INFO`;gap 不告警只计数,心跳增 `tgap`);主机单测 `test/host/adc_health/` **31 用例全绿**(`adc-health-unit-test` 钩子);台架 `@test` PASS 零 `[ERR]`(健康不误报,`boot_log_data/20261011_prod_adc_health_boot_log.txt`)。⚠ 抬栈:判定链 `adc_health_report`→`syslog_post` 回显尾使 adcTask 静态最坏链 832→**1080 B** → 栈 512→**640 words**(余 1480 B / 57%) |
| 等周波采样(软件测频 + 调频闭环) | 20 点/周波;测频范围建议 **45~55 Hz**(参考 40.5~60.5) | 频率偏移 ±2 Hz 时幅值误差 ≤ 1% | ⬜ |
| 零序通道接入(外部专用 / 自产切换) | 外部 `UN`/`IN`;自产 `3I0 = Ia+Ib+Ic`(V0.2 起) | 零序通道可切换来源,值正确 | ⬜ |
| 二次谐波/五次谐波提取入口 | k=2(涌流)、k=5(选线) | 相量层可产出对应谐波相量 | ✅ 2026-10-11:`phasor.c` 实例表 `C04-IA-F2`(k=2)/ `C05-IA-F5`(k=5)随每拍重算产出,台架心跳日志 `phasor(hb) C04/C05` 行可见(`boot_log_data/20261011_prod_phasor_boot_log.txt`);谐波**抑制/提取正确性**已由主机单测覆盖(`test/host/phasor/`) |
> ⚠️ **「双转换器无共同采样触发」约束**:L1-4 中 `UA/UN/IA` 在 TPAFE、`UB/UC/IB/IC/IN` 在 STM32 ADC。V0.1 上 L1 只做**逐通道独立监视**,不得假设同族量同刻(`UA` 与 `UB` 无共同采样触发)。
> ⚠️ **「双转换器无共同采样触发」约束**:「通道语义映射」中 `UA/UN/IA` 在 TPAFE、`UB/UC/IB/IC/IN` 在 STM32 ADC。V0.1 上 L1 只做**逐通道独立监视**,不得假设同族量同刻(`UA` 与 `UB` 无共同采样触发)。
### 3.2 L2 相量计算
| # | 功能点 | 关键参数 | 完成判据 | 状态 |
| --- | --- | --- | --- | --- |
| L2-1 | 全周傅氏系数表 | `sin(2πk/N)·(√2/N)`、`cos(2πk/N)·(√2/N)`,N=20 | 系数表与 `docs/算法/傅氏算法详解.md` §2.3 一致 | ✅ 2026-10-11:`phasor.c` 离线系数表**预乘 √2/N**;主机单测逐项复核(`test/host/phasor/` 系数表用例) |
| L2-2 | 基波相量实例 | **5 个实例**(参考项目 4 个,见下方注):`C01-IA-F1` / `C02-UA-F1` / `C03-UN-F1` / `C04-IA-F2` / `C05-IA-F5` | 每实例输出 `{fRe, fIm, fAm, fAmSQ}` | ✅ 2026-10-11:`k_inst[]` 数据驱动 5 实例;台架开机即产出 `phasor(first)` 5 行(`boot_log_data/20261011_prod_phasor_boot_log.txt`) |
| L2-3 | 相量有效值输出 | `fAmSQ = √(fRe²+fIm²)` 直接为**有效值**(系数已折算) | 标准源读数 = 设定有效值 | ✅ 2026-10-11(链路级):`fAmSQ` 口径实现 + 单测合成正弦幅值误差 ≤1%;**"标准源读数"判据在无信号源台架不可达**(同 §7.1),待 L1-5 标定后复核 |
| L2-4 | 相位输出 | `φ = atan2(fIm, fRe)` | 相位误差 ≤ 目标值 | ✅ 2026-10-11(链路级):`fRe/fIm` 常驻双区、每拍产出,φ 由消费侧 `atan2f` 现算(不常驻结构体,见 `docs/算法/采集与算法层设计说明.md` §6);单测覆盖相位;**目标值待产品定义 + 标准源复核** |
| L2-5 | 线/负序/零序合成 | 线电压 `Uab=Ua−Ub` 等;负序 `3U2`/`3I2`;零序 `3U0`/`3I0` | 合成相量可复用于保护元件(**V0.1 仅同转换器内可合成**,见 §1.6) | ⬜ **V0.1 不适用**:跨转换器合成被「双转换器无共同采样触发」禁止;零序走**外部专用通道** `UN`/`IN`(§6.4),无需自产 → 随 V0.2 启用 |
| L2-6 | 每 1 ms 滑动窗刷新 | 每来新点,窗滑动一格、20 点重算(暴力法) | 相量每拍更新 | ✅ 2026-10-11:`sample_ring` 40 点环 + `phasor_run()` 每拍整窗重算(仅 `r==1` 新帧压环,P0 修复);台架 `ring` 随 `frames` 同步递增、`idle=0` |
| L2-7 | 双区指针原子交换 | 计算区/使用区切换 | 保护元件读使用区,无撕裂 | ✅ 2026-10-11:`s_zone[2][5]` + 单字节 `volatile` 切换(Cortex-M 原子);单测覆盖双区交换;为独立 L3 任务预留无锁读 |
| L2-8 | 遥测谐波轨(可选) | k=1~9,方和根 `√(ΣHk²)` | 与基波轨并行,供 UI/上送 | ⬜ |
| 功能名 | 关键参数 | 完成判据 | 状态 |
| --- | --- | --- | --- |
| 全周傅氏系数表 | `sin(2πk/N)·(√2/N)`、`cos(2πk/N)·(√2/N)`,N=20 | 系数表与 `docs/算法/傅氏算法详解.md` §2.3 一致 | ✅ 2026-10-11:`phasor.c` 离线系数表**预乘 √2/N**;主机单测逐项复核(`test/host/phasor/` 系数表用例) |
| 基波相量实例 | **5 个实例**(参考项目 4 个,见下方注):`C01-IA-F1` / `C02-UA-F1` / `C03-UN-F1` / `C04-IA-F2` / `C05-IA-F5` | 每实例输出 `{fRe, fIm, fAm, fAmSQ}` | ✅ 2026-10-11:`k_inst[]` 数据驱动 5 实例;台架开机即产出 `phasor(first)` 5 行(`boot_log_data/20261011_prod_phasor_boot_log.txt`) |
| 相量有效值输出 | `fAmSQ = √(fRe²+fIm²)` 直接为**有效值**(系数已折算) | 标准源读数 = 设定有效值 | ✅ 2026-10-11(链路级):`fAmSQ` 口径实现 + 单测合成正弦幅值误差 ≤1%;**"标准源读数"判据在无信号源台架不可达**(同 §7.1),待「通道标定(一次系数 + 零漂)」标定后复核 |
| 相位输出 | `φ = atan2(fIm, fRe)` | 相位误差 ≤ 目标值 | ✅ 2026-10-11(链路级):`fRe/fIm` 常驻双区、每拍产出,φ 由消费侧 `atan2f` 现算(不常驻结构体,见 `docs/算法/采集与算法层设计说明.md` §6);单测覆盖相位;**目标值待产品定义 + 标准源复核** |
| 线/负序/零序合成 | 线电压 `Uab=Ua−Ub` 等;负序 `3U2`/`3I2`;零序 `3U0`/`3I0` | 合成相量可复用于保护元件(**V0.1 仅同转换器内可合成**,见 §1.6) | ⬜ **V0.1 不适用**:跨转换器合成被「双转换器无共同采样触发」禁止;零序走**外部专用通道** `UN`/`IN`(§6.4),无需自产 → 随 V0.2 启用 |
| 每 1 ms 滑动窗刷新 | 每来新点,窗滑动一格、20 点重算(暴力法) | 相量每拍更新 | ✅ 2026-10-11:`sample_ring` 40 点环 + `phasor_run()` 每拍整窗重算(仅 `r==1` 新帧压环,P0 修复);台架 `ring` 随 `frames` 同步递增、`idle=0` |
| 双区指针原子交换 | 计算区/使用区切换 | 保护元件读使用区,无撕裂 | ✅ 2026-10-11:`s_zone[2][5]` + 单字节 `volatile` 切换(Cortex-M 原子);单测覆盖双区交换;为独立 L3 任务预留无锁读 |
| 遥测谐波轨(可选) | k=1~9,方和根 `√(ΣHk²)` | 与基波轨并行,供 UI/上送 | ⬜ |
> **双轨有效值**:保护要"基波有效值 + 相位"(抗衰减直流、抗谐波误动);计量/遥测要"真有效值"(谐波方和根)。两者**不可混用**——这是参考系统 `CN_ANA_VEC_SQRT=FALSE` 与遥测谐波轨并存的根本原因。
> **L2-2 实例数 4 → 5 的来历**:参考项目(`APP/CLS100_Dsp/InstCalCell.c`)为 **4 个实例**——C01 基波 I/U、C02 零序基波、C03 二次谐波、C04 五次谐波。本项目按 V0.1 **有效通道**(`UA`/`UN`/`IA`,见 §1.6:`UB/UC/IB/IC/IN` 无中点偏置 → 削顶不可用)展开:C01 的"I/U"拆为两行(`C01-IA-F1` 电流 / `C02-UA-F1` 电压),其余顺延为 `C03-UN-F1` 零序、`C04-IA-F2` 二次、`C05-IA-F5` 五次。实现见 `App/algo/phasor.c` 的 `k_inst[]`;判据按 **5** 个实例断言(见 `docs/测试说明/相量层单元测试说明.md` §2.6)。
> **「基波相量实例」实例数 4 → 5 的来历**:参考项目(`APP/CLS100_Dsp/InstCalCell.c`)为 **4 个实例**——C01 基波 I/U、C02 零序基波、C03 二次谐波、C04 五次谐波。本项目按 V0.1 **有效通道**(`UA`/`UN`/`IA`,见 §1.6:`UB/UC/IB/IC/IN` 无中点偏置 → 削顶不可用)展开:C01 的"I/U"拆为两行(`C01-IA-F1` 电流 / `C02-UA-F1` 电压),其余顺延为 `C03-UN-F1` 零序、`C04-IA-F2` 二次、`C05-IA-F5` 五次。实现见 `App/algo/phasor.c` 的 `k_inst[]`;判据按 **5** 个实例断言(见 `docs/测试说明/相量层单元测试说明.md` §2.6)。
> **本表状态列口径**(2026-10-11 更新):L2-1~L2-4 / L2-6 / L2-7 已**实现 + 主机单测(57 用例)+ 台架 `@test` 闭环**——闭环命令 `run_boot_test.py --required "...;phasor(first);phasor(hb)" --require-order "App init OK>phasor(first)>phasor(hb)"`,证据 `boot_log_data/20261011_prod_phasor_boot_log.txt`(`fw build` 身份戳匹配、回读一致、锚点 ×1、零 `[ERR]`)。⚠ **幅值/相位精度判据(标准源)在无信号源台架上不可达**(同 §7.1 无示波器口径),且 L1-5 标定未实现 → 现读数为**原始码值**,只证明链路通;精度复核排在标定之后。L2-5 随 V0.2(双转换器无共同采样触发),L2-8 可选项未做。
> **本表状态列口径**(2026-10-11 更新):「全周傅氏系数表」~「相位输出」/「每 1 ms 滑动窗刷新」/「双区指针原子交换」已**实现 + 主机单测(57 用例)+ 台架 `@test` 闭环**——闭环命令 `run_boot_test.py --required "...;phasor(first);phasor(hb)" --require-order "App init OK>phasor(first)>phasor(hb)"`,证据 `boot_log_data/20261011_prod_phasor_boot_log.txt`(`fw build` 身份戳匹配、回读一致、锚点 ×1、零 `[ERR]`)。⚠ **幅值/相位精度判据(标准源)在无信号源台架上不可达**(同 §7.1 无示波器口径),且「通道标定(一次系数 + 零漂)」标定未实现 → 现读数为**原始码值**,只证明链路通;精度复核排在标定之后。「线/负序/零序合成」随 V0.2(双转换器无共同采样触发),「遥测谐波轨(可选)」可选项未做。
### 3.3 L3 保护元件
@@ -275,55 +275,55 @@
**核心集(P0/P1)**
| # | 元件 | 判据要点 | 关键定值 | 状态 |
| --- | --- | --- | --- | --- |
| L3-1 | 三段式相间过流 | 相电流基波 > 定值,经延时出口;返回系数滞回 | Ⅰ/Ⅱ/Ⅲ 段电流 + 延时 | 🔶 2026-10-11 主机实现:`App/algo/prot_elm.c` 通用"滞回+定时限"核 + `prot_set.c` 定值(Ⅰ/Ⅱ/Ⅲ 段,A 相 `IA`),单测 27 用例含 1.01× 启动/100 ms 到点/滞回保持/返回释放;**板端接线已落地(B5,2026-10-12:protectTask 20 ms 节拍,动作经 104 YX16~18 上送)**;出口(L4)待做 |
| L3-2 | 三段式零序过流 | 零序电流 > 定值,经延时出口 | Ⅰ/Ⅱ/Ⅲ 段零序电流 + 延时 | ⬜(双转换器无共同采样触发:`IN` 走 STM32,V0.2 使能;框架已就绪,加实例表一行即可) |
| L3-3 | 过负荷 | 相电流 > 定值,告警/跳闸可整定 | 过负荷电流 + 延时 | 🔶 同 L3-1(`OL-IA` 实例,默认告警不跳闸;板端接线随 B5 落地,YX23 上送) |
| L3-4 | 过压 / 欠压 | 相/线电压越限,经延时出口 | 过压定值、失压定值 + 延时 | 🔶 同 L3-1(`OV-UA`/`UV-UA`,欠量方向单测覆盖;沿用参考告警段 0x8027/0x8029) |
| L3-5 | 过频 / 低频 | 频率越限,经延时出口 | 过频、低频定值 + 延时 | ✅ 软件侧完成(B8,2026-10-12):`freq` 层测频(自适应窗,45~55 Hz 扫频最坏 **0.0101 Hz** / 1% 噪声 0.0160 Hz)+ `OF/UF` 实例(51.0/49.0 Hz、dly 1000 ms、返回系数 0.99/1.01,本地定值 8 项);OF/UF 暂无独立遥信点,动作仅经 YX15 总聚合可见(独立分点 + 注入验收 = B10) |
| L3-6 | 零序过压 | 零序电压 > 定值 | 零序过压定值 + 延时 | 🔶 同 L3-1(`3U0-UN` 实例,外部零序电压通道,不受双转换器无共同采样触发限制) |
| 元件 | 判据要点 | 关键定值 | 状态 |
| --- | --- | --- | --- |
| 三段式相间过流 | 相电流基波 > 定值,经延时出口;返回系数滞回 | Ⅰ/Ⅱ/Ⅲ 段电流 + 延时 | 🔶 2026-10-11 主机实现:`App/algo/prot_elm.c` 通用"滞回+定时限"核 + `prot_set.c` 定值(Ⅰ/Ⅱ/Ⅲ 段,A 相 `IA`),单测 27 用例含 1.01× 启动/100 ms 到点/滞回保持/返回释放;**板端接线已落地(B5,2026-10-12:protectTask 20 ms 节拍,动作经 104 YX16~18 上送)**;出口(L4)待做 |
| 三段式零序过流 | 零序电流 > 定值,经延时出口 | Ⅰ/Ⅱ/Ⅲ 段零序电流 + 延时 | ⬜(双转换器无共同采样触发:`IN` 走 STM32,V0.2 使能;框架已就绪,加实例表一行即可) |
| 过负荷 | 相电流 > 定值,告警/跳闸可整定 | 过负荷电流 + 延时 | 🔶 同「三段式相间过流」(`OL-IA` 实例,默认告警不跳闸;板端接线随 B5 落地,YX23 上送) |
| 过压 / 欠压 | 相/线电压越限,经延时出口 | 过压定值、失压定值 + 延时 | 🔶 同「三段式相间过流」(`OV-UA`/`UV-UA`,欠量方向单测覆盖;沿用参考告警段 0x8027/0x8029) |
| 过频 / 低频 | 频率越限,经延时出口 | 过频、低频定值 + 延时 | ✅ 软件侧完成(B8,2026-10-12):`freq` 层测频(自适应窗,45~55 Hz 扫频最坏 **0.0101 Hz** / 1% 噪声 0.0160 Hz)+ `OF/UF` 实例(51.0/49.0 Hz、dly 1000 ms、返回系数 0.99/1.01,本地定值 8 项);OF/UF 暂无独立遥信点,动作仅经 YX15 总聚合可见(独立分点 + 注入验收 = B10) |
| 零序过压 | 零序电压 > 定值 | 零序过压定值 + 延时 | 🔶 同「三段式相间过流」(`3U0-UN` 实例,外部零序电压通道,不受双转换器无共同采样触发限制) |
**扩展集(P2/P3)**
| # | 元件 | 判据要点 | 状态 |
| --- | --- | --- | --- |
| L3-7 | 涌流制动 | 二次谐波占比 > 制动系数,闭锁差动/过流 | ⬜ |
| L3-8 | PT 断线 | 电压突变/负序判据,闭锁电压类保护 | ⬜ |
| L3-9 | CT 断线 | 电流不平衡判据,闭锁 | ⬜ |
| L3-10 | 母线接地告警 | 零序电压 + 零序电流组合 | ⬜ |
| L3-11 | 故障启动(波形启动) | 突变量启动,触发录波/启动元件 | ⬜ |
| L3-12 | 无压/无流闭锁 | 低电压或低电流时闭锁过流 | ⬜ |
| 元件 | 判据要点 | 状态 |
| --- | --- | --- |
| 涌流制动 | 二次谐波占比 > 制动系数,闭锁差动/过流 | ⬜ |
| PT 断线 | 电压突变/负序判据,闭锁电压类保护 | ⬜ |
| CT 断线 | 电流不平衡判据,闭锁 | ⬜ |
| 母线接地告警 | 零序电压 + 零序电流组合 | ⬜ |
| 故障启动(波形启动) | 突变量启动,触发录波/启动元件 | ⬜ |
| 无压/无流闭锁 | 低电压或低电流时闭锁过流 | ⬜ |
**延后集(受双转换器无共同采样触发 / 产品定义制约)**
| # | 元件 | 制约 |
| --- | --- | --- |
| L3-13 | 方向元件 / 功率方向 | 需跨转换器相位一致 → V0.1 不可做 |
| L3-14 | 重合闸 | FTU 专有,视 B0 产品定义 |
| L3-15 | 手动跳闸 / 遥控 | 依赖出口硬件与协议定义 |
| 元件 | 制约 |
| --- | --- |
| 方向元件 / 功率方向 | 需跨转换器相位一致 → V0.1 不可做 |
| 重合闸 | FTU 专有,视 B0 产品定义 |
| 手动跳闸 / 遥控 | 依赖出口硬件与协议定义 |
> **V0.1 可行性**:上表按元件类型分组,但**V0.1 上能否闭环**取决于通道(见 **§1.6**)——核心集中 `IA`/`UA`/`UN` 可做(A 相过流、过负荷、过压/欠压、零序过压),**L3-2 零序过流与 B/C 相过流本期不可做**(`IN`/`IB`/`IC` 削顶);扩展集 L3-7~L3-12 多依赖三相,本期**建接口不使能**。
> **V0.1 可行性**:上表按元件类型分组,但**V0.1 上能否闭环**取决于通道(见 **§1.6**)——核心集中 `IA`/`UA`/`UN` 可做(A 相过流、过负荷、过压/欠压、零序过压),**三段式零序过流与 B/C 相过流本期不可做**(`IN`/`IB`/`IC` 削顶);扩展集「涌流制动」~「无压/无流闭锁」多依赖三相,本期**建接口不使能**。
### 3.4 L4 出口与记录
| # | 功能点 | 说明 | 状态 |
| --- | --- | --- | --- |
| L4-1 | 跳闸出口(KO) | 判据满足 → 驱动出口继电器,带保持/脉冲 | ⬜ |
| L4-2 | 告警出口 / 信号 | 告警类动作驱动信号灯/继电器 | ⬜ |
| L4-3 | 出口自检 | 出口回路检测(若有回读) | ⬜ |
| L4-4 | SOE 记录 | 带时标的事件顺序记录 | ✅(B9,2026-10-12:`/log/soe.log` 64 B 定长记录 = 类型 + 元件号 + seq(u32) + CP56Time2a + epoch + 校验和;台架 FTP 下载解码 PASS,时标与 104 CP56 交叉一致) |
| L4-5 | 动作记录 | 保护动作/返回记录,落 `/log/soe.log` | ✅(B9,2026-10-12:六类边沿全覆盖——元件动作/复归、软压板投/退、采样数据块/恢复;protectTask 只投递(SPSC 环,post 禁 DBG),defaultTask `syslog_drain()` 落盘,动作路径无 NAND I/O) |
| L4-6 | 故障录波(可选) | 4000 Hz 内部节拍预留 | ⬜ |
| 功能名 | 说明 | 状态 |
| --- | --- | --- |
| 跳闸出口(KO) | 判据满足 → 驱动出口继电器,带保持/脉冲 | ⬜ |
| 告警出口 / 信号 | 告警类动作驱动信号灯/继电器 | ⬜ |
| 出口自检 | 出口回路检测(若有回读) | ⬜ |
| SOE 记录 | 带时标的事件顺序记录 | ✅(B9,2026-10-12:`/log/soe.log` 64 B 定长记录 = 类型 + 元件号 + seq(u32) + CP56Time2a + epoch + 校验和;台架 FTP 下载解码 PASS,时标与 104 CP56 交叉一致) |
| 动作记录 | 保护动作/返回记录,落 `/log/soe.log` | ✅(B9,2026-10-12:六类边沿全覆盖——元件动作/复归、软压板投/退、采样数据块/恢复;protectTask 只投递(SPSC 环,post 禁 DBG),defaultTask `syslog_drain()` 落盘,动作路径无 NAND I/O) |
| 故障录波(可选) | 4000 Hz 内部节拍预留 | ⬜ |
### 3.5 L5 自检与闭锁
| # | 功能点 | 说明 | 状态 |
| --- | --- | --- | --- |
| L5-1 | 定值校验和 | `tagPRS_XXX` 的 `dwTagSum` 自检,定值非法闭锁 | 🔶 2026-10-11:`prot_set.c` 已实现 sum32 正/反码封存 + selfcheck 失配置闭锁(参考 `dwTagSum/dwTagSumN` 模式);**B7(2026-10-12)竞态收口**:104 定值写改 `prot_set_set_sealed`(影子区写+封存后单字交换)+ selfcheck seqlock 式复核(提交撞见 = 本轮跳过),B5 登记的 µs 级误锁窗口消除;定值持久化 `/prot_set.bin`(blob 带 sum32 正/反码对,整表原子装载);元件级 tagPRS 常量表校验仍待补 |
| L5-2 | 采样通道自检 | 通道码值越界/静默检出 | 🔶 静默/丢帧/序号倒退/错误增量已由 L1-6 `adc_health` 检出(2026-10-11);码值越界待做 |
| L5-3 | 硬件自检 | 出口回路、电源、时钟 | ⬜ |
| L5-4 | 自检失败闭锁 | 任一项失败 → 闭锁相关保护并告警 | 🔶 定值闭锁 → 全元件复位已联动(`prot_elm_eval` 读 `prot_set_locked()`,单测覆盖);**采样故障闭锁已落地(B5,2026-10-12)**:protectTask 每拍读 `adc_health_flags()` 电平位(TPAFE/STM32 stall + 序号倒退)→ 命中即 `prot_elm_init()` 复位 + 本拍不判据,自愈后自动恢复;锁存类事件位(FRSTDATA/HW_ERR)不构成"当前测量不可信"→ 不闭锁,如实登记 |
| 功能名 | 说明 | 状态 |
| --- | --- | --- |
| 定值校验和 | `tagPRS_XXX` 的 `dwTagSum` 自检,定值非法闭锁 | 🔶 2026-10-11:`prot_set.c` 已实现 sum32 正/反码封存 + selfcheck 失配置闭锁(参考 `dwTagSum/dwTagSumN` 模式);**B7(2026-10-12)竞态收口**:104 定值写改 `prot_set_set_sealed`(影子区写+封存后单字交换)+ selfcheck seqlock 式复核(提交撞见 = 本轮跳过),B5 登记的 µs 级误锁窗口消除;定值持久化 `/prot_set.bin`(blob 带 sum32 正/反码对,整表原子装载);元件级 tagPRS 常量表校验仍待补 |
| 采样通道自检 | 通道码值越界/静默检出 | 🔶 静默/丢帧/序号倒退/错误增量已由「采样有效性校验」 `adc_health` 检出(2026-10-11);码值越界待做 |
| 硬件自检 | 出口回路、电源、时钟 | ⬜ |
| 自检失败闭锁 | 任一项失败 → 闭锁相关保护并告警 | 🔶 定值闭锁 → 全元件复位已联动(`prot_elm_eval` 读 `prot_set_locked()`,单测覆盖);**采样故障闭锁已落地(B5,2026-10-12)**:protectTask 每拍读 `adc_health_flags()` 电平位(TPAFE/STM32 stall + 序号倒退)→ 命中即 `prot_elm_init()` 复位 + 本拍不判据,自愈后自动恢复;锁存类事件位(FRSTDATA/HW_ERR)不构成"当前测量不可信"→ 不闭锁,如实登记 |
---
@@ -386,7 +386,7 @@
### 5.2 定值项模型(`tagPRS_XXX`)
每元件一个配置结构:**定值号 / 模拟通道号 / KI·KO 标志 / 校验和** + `Init` / `Main` / 出口函数。定值项与元件一一绑定,便于逐元件自检(L5-1)。
每元件一个配置结构:**定值号 / 模拟通道号 / KI·KO 标志 / 校验和** + `Init` / `Main` / 出口函数。定值项与元件一一绑定,便于逐元件自检(「定值校验和」)。
### 5.3 折算与存储
@@ -432,7 +432,7 @@
### 6.2 双转换器无共同采样触发:影响与降级口径
- **V0.1 现板**:主板侧只做**逐通道独立监视**(有效值/越限/温度);**禁止**跨转换器的同周期相位、功率、功率因数、矢量类运算。
- **受影响功能**:方向元件、功率方向、差动类——延后(L3-13)。
- **受影响功能**:方向元件、功率方向、差动类——延后(「方向元件 / 功率方向」)。
- **V0.2 改版后**:8 路电气量全部接 TPAFE(与 5 路备用路对调串联电阻目的地,BOM 不变),上层语义与代码**不动**,只改映射表内容 → 保护层无需重构。
- **接口设计启示**:**按语义取数、不写死下标**,是 V0.2 平滑升级的前提。
@@ -452,7 +452,7 @@
- **自产零序在 V0.1 不可行**:`Ia` 在 TPAFE、`Ib`/`Ic` 在 STM32,求和属**跨转换器**(双转换器无共同采样触发)。
- 于是本期:**零序过压**(`UN`,TPAFE,测量有效)可做;**零序过流**(`IN`,STM32 削顶 → 无有效值)不可做。
- V0.2(8 路电气量全上 TPAFE)后可自产,外部/自产可切换(恢复 TLV13 语义)。
- 落点:L1-8。
- 落点:「零序通道接入(外部专用 / 自产切换)」。
### 6.5 定值存储
@@ -470,12 +470,12 @@
| 阶段 | 名称 | 内容 | 前置 | 里程碑 |
| --- | --- | --- | --- | --- |
| **P0** | 采样与相量底座 | B1(周期 CONVST + `adcTask` 消费 + 建任务 + 栈预算)+ L1 + L2 | B0 + B1 ✅ | 每 1 ms 产出正确的基波相量 —— **✅ 2026-10-11 台架闭环**(L1-6 同日落地 ✅;L1-5 标定 / L1-7 等周波为 P0 遗留项,精度复核依赖标准源) |
| **P0** | 采样与相量底座 | B1(周期 CONVST + `adcTask` 消费 + 建任务 + 栈预算)+ L1 + L2 | B0 + B1 ✅ | 每 1 ms 产出正确的基波相量 —— **✅ 2026-10-11 台架闭环**(「采样有效性校验」同日落地 ✅;「通道标定(一次系数 + 零漂)」标定 / 「等周波采样(软件测频 + 调频闭环)」等周波为 P0 遗留项,精度复核依赖标准源) |
| **P1** | 基础保护元件 | **V0.1 有效子集**:过流(A 相,`IA`)、过负荷(A 相)+ 定值模型;B/C 相过流**建接口不使能** | P0 | 标准源注入 A 相可正确动作 —— 🔶 **软件侧 2026-10-11 完成**(`prot_set` 定值模型 30 用例 + `prot_elm` 元件框架/过流三段/过负荷 27 用例,主机全绿);**板端接线已落地(B5,2026-10-12:protectTask + IWDG bit8 + 栈核算 + 104 YX 上送)**;标准源注入验收待做 |
| **P2** | 电压/频率类保护 | 过压/欠压(`UA`)、过频/低频、零序过压(`UN`) | P0 | 电压/频率越限正确动作 —— 🔶 过压/欠压/零序过压随 P1 同批主机完成(同框架实例);过频/低频 ✅ **B8 已落地(2026-10-12)**:freq 层(自适应窗,扫频最坏 0.0101 Hz)+ OF/UF 实例;出口独立遥信点与注入验收归 B10 |
| **P3** | 异常检测与闭锁 | L5 自检闭锁、采样通道自检;三相类(涌流/PT·CT 断线/母线接地)**建接口不使能** | P1/P2 | 自检失败闭锁;未使能元件不误动 |
| **P4** | 出口、记录与定值集成 | L4 出口与记录、§5 定值模型落 cfg_file、UI 显示、上送 | P1 | 动作出口 + SOE 记录 + UI 显示闭环(**定值持久化 + 软压板 + 竞态收口 = B7 完成 2026-10-12,台架腿已验 ✅**;**SOE/动作记录 = B9 完成 2026-10-12 ✅**:protectTask 边沿→SPSC 环→defaultTask 落盘 `/log/soe.log`,protectTask 静态链 872 B 不变,自发 YX 上送 M_SP_TB_1 带时标;出口继电器 L4-1~L4-3 仍 ⬜——V0.1 无出口硬件,跳闸维持否定确认 R7 口径) |
| **P5** | 方向/功率类(延后) | L3-13 方向元件等 | V0.2 硬件 / 子板计量 | 跨转换器相位一致后实现 |
| **P4** | 出口、记录与定值集成 | L4 出口与记录、§5 定值模型落 cfg_file、UI 显示、上送 | P1 | 动作出口 + SOE 记录 + UI 显示闭环(**定值持久化 + 软压板 + 竞态收口 = B7 完成 2026-10-12,台架腿已验 ✅**;**SOE/动作记录 = B9 完成 2026-10-12 ✅**:protectTask 边沿→SPSC 环→defaultTask 落盘 `/log/soe.log`,protectTask 静态链 872 B 不变,自发 YX 上送 M_SP_TB_1 带时标;出口继电器「跳闸出口(KO)」~「出口自检」仍 ⬜——V0.1 无出口硬件,跳闸维持否定确认 R7 口径) |
| **P5** | 方向/功率类(延后) | 「方向元件 / 功率方向」方向元件等 | V0.2 硬件 / 子板计量 | 跨转换器相位一致后实现 |
> ⚠️ **V0.1 硬件裁剪**(2026-10-10,详见 §1.6):V0.1 上只有 TPAFE 三路(`UA`/`UN`/`IA`)测量有效。故 **P0 骨架全做**(与通道无关),**P1/P2 只做有效通道子集**——A 相过流、A 相过负荷、过压/欠压、零序过压、过频/低频;**三相过流(B/C 相)、零序过流、方向/功率类、PT/CT 断线**依赖 V0.2 硬件(修复「双转换器无共同采样触发」+ 中点偏置),本期**建接口不使能**。
@@ -5,7 +5,7 @@
> **阅读前提**:采样节拍与乒乓双缓冲 → `docs/子系统设计/ADC采样节拍设计说明.md`;
> 8 路电气量为何分属两片转换器 → `docs/硬件平台/ADC通道映射说明.md`。
> **不在本文范围**:接口签名与全层约定速览在 `docs/算法/采集与算法层设计说明.md`,本文不重复其接口表;
> 需求与验收口径登记在 `docs/算法/继电保护功能复现规划.md` §3.1(功能项 L1-6)与同文档 §3.5(L5 自检与闭锁)。
> 需求与验收口径登记在 `docs/算法/继电保护功能复现规划.md` §3.1(功能项「采样有效性校验」)与同文档 §3.5(L5 自检与闭锁)。
> **配图**:三张 SVG 的生成器在 `tools/arch_diagram/`(改图 = 改脚本顶部数据后重跑,勿手改 `.svg`)。
## 目录
@@ -88,7 +88,7 @@
| 快照装配 | `App/task/adc_task.c` | **本拍 poll 之后**把 6 个计数 + 一份 `now_ms` 填进 `adc_health_in_t` |
| 判定 | `App/algo/adc_health.c` | 只做判定与位图维护;不知道寄存器、不知道日志 |
| 编排 | `App/task/adc_task.c` | 按位分级:`DBG_ERROR` / `SYSLOG_SELFTEST` / `DBG_INFO`(恢复) |
| 闭锁 | `App/task/protect_task.c` | 每 20 ms 读 `adc_health_flags()`,命中掩码即复位元件并停判据(L5-4) |
| 闭锁 | `App/task/protect_task.c` | 每 20 ms 读 `adc_health_flags()`,命中掩码即复位元件并停判据(「自检失败闭锁」) |
两条边界是刻意的,破坏它们的代价写在右边:
@@ -106,8 +106,8 @@
| 候选判据 | 为什么不用 |
|---|---|
| 码值越界 / 超量程 | L1-5 通道标定未实现(`docs/算法/继电保护功能复现规划.md` §3.1),码值还没有工程量含义;且两片转换器增益不同(TPAFE 16 位双极性 / STM32 12 位单极性),不存在统一阈值 |
| 波形合理性(方差、过零、单调) | 这是「信号对不对」,属 L5-2 的另一半;空载与零值都是合法工况,判据只能靠猜阈值 |
| 码值越界 / 超量程 | 「通道标定(一次系数 + 零漂)」通道标定未实现(`docs/算法/继电保护功能复现规划.md` §3.1),码值还没有工程量含义;且两片转换器增益不同(TPAFE 16 位双极性 / STM32 12 位单极性),不存在统一阈值 |
| 波形合理性(方差、过零、单调) | 这是「信号对不对」,属「采样通道自检」的另一半;空载与零值都是合法工况,判据只能靠猜阈值 |
| **序号是否前进** | 唯一与信号内容无关的新鲜度证据:不管输入是正弦、零值还是断线,正常态就是每拍 +1 |
于是本层只看 5 个计数器加 1 个时基。这也是它能保持纯逻辑、能被穷举测试的根因——**判据越朴素,
@@ -645,8 +645,8 @@ stateDiagram-v2
- `docs/子系统设计/看门狗设计说明.md` §4.3 —— 长耗时窗口的三类处置(瞬态静默的候选来源)
- `docs/子系统设计/看门狗设计说明.md` §11.4 —— `[PROF]` 探针字段与耗时基线(判「超拍」要看它)
- `docs/硬件平台/ADC通道映射说明.md` —— 语义映射唯一权威口径(与「哪一侧静默」直接相关)
- `docs/算法/继电保护功能复现规划.md` §3.1 —— L1 功能项与验收口径(本层 = L1-6 行)
- `docs/算法/继电保护功能复现规划.md` §3.5 —— L5 自检与闭锁(本层供数的 L5-4 在此登记)
- `docs/算法/继电保护功能复现规划.md` §3.1 —— L1 功能项与验收口径(本层 = 「采样有效性校验」行)
- `docs/算法/继电保护功能复现规划.md` §3.5 —— L5 自检与闭锁(本层供数的「自检失败闭锁」在此登记)
- `docs/内存管理/RAM使用分析与优化方案.md` §2.3 与 §4.0.6 —— `adcTask` 栈配置、最坏链与余量台账
- `App/algo/README.md` —— 目录级文件清单与构建测试入口
- `docs/子系统设计/ADC采样节拍设计说明.md` §3.4 —— TIM3 启动位置与顺序(兜底门开机不误锁的前提)
@@ -76,7 +76,7 @@ flowchart TD
|---|---|
| `app_main_init()`(内核启动前) | `adc_input_init()`(映射自检 + 挂 DMA 缓冲)→ `phasor_init()`(内部连带 `sample_ring_init()`)→ `freq_init()` → `prot_set_init()` → `prot_elm_init()` |
| `adcTask`(每拍) | `adc_input_poll()` → `adc_input_raw()` ×9 → `sample_ring_push_frame()` → `phasor_run()` → `freq_run()` → 心跳与健康判定 `adc_health_check()` |
| `protectTask`(20 ms) | 取 `phasor_get()` rms 与 `freq_get()` → `prot_elm_run()`;L5-4 采样故障闭锁、L5-1 定值校验和巡检 |
| `protectTask`(20 ms) | 取 `phasor_get()` rms 与 `freq_get()` → `prot_elm_run()`;「自检失败闭锁」采样故障闭锁、 定值校验和巡检 |
`prot_elm_init()` 须在 `phasor_init()` **之后**(它按名前缀解析相量实例索引);`prot_set` 独立
(只依赖 `stdint.h`),可在任意点初始化。
@@ -122,7 +122,7 @@ flowchart TD
|---|---|
| `adc_health_init()` | 清状态;**首拍 `check()` 只建基线、不判定** |
| `adc_health_check(&in, &out)` | 吃"计数快照"做一次判定(每拍调,常数次整数运算);差值法 `(int32_t)(now - prev)` → 计数与 tick 回绕都安全 |
| `adc_health_flags()` | **电平**故障位:`TPAFE_STALL` / `STM32_STALL`(≥100 ms 无前进,可自愈)/ `SEQ_BACKWARD`(锁存)——为 L5-4 闭锁供数 |
| `adc_health_flags()` | **电平**故障位:`TPAFE_STALL` / `STM32_STALL`(≥100 ms 无前进,可自愈)/ `SEQ_BACKWARD`(锁存)——为「自检失败闭锁」闭锁供数 |
| `adc_health_sticky()` | **锁存**位:`FRSTDATA` / `STM32_ERR` / `HW_ERR` 的增量痕迹,自愈后仍留痕 |
| `adc_health_tpafe_gaps()` | TPAFE 累计丢帧点数(序号前进 >1 的超出部分),与 STM32 侧 `adc_input_stm32_gaps()` **同单位**(心跳字段 `tgap` / `adc1_gap` 可直接对比) |
@@ -195,12 +195,12 @@ flowchart TD
"部分新部分旧"的混合结果。
- **每拍 20 点全部重算**(暴力法)。不用"加尾项去头项"的增量式:增量递推会累积误差,
暴力法每次都是干净的一周波。代价 = 每拍 20 × 实例数次乘加,相量刷新周期 1 ms。
- **相位(L2-4)不常驻结构体**:需要时自行 `atan2f(fIm, fRe)`(`φ` 约定 = 窗首初相,见 §7)。
- **相位(「相位输出」)不常驻结构体**:需要时自行 `atan2f(fIm, fRe)`(`φ` 约定 = 窗首初相,见 §7)。
---
## 7. L2 派生量:频率测量 `freq.c`
**解决的问题**:过频 / 低频(`docs/算法/继电保护功能复现规划.md` §3.3 L3-5)需要系统频率读数,
**解决的问题**:过频 / 低频(`docs/算法/继电保护功能复现规划.md` §3.3 「过频 / 低频」)需要系统频率读数,
而 L2 只出相量。本层把"相邻两拍基波相量的相位差"变成"频率",并解决**非整周波窗长的 DFT 泄漏纹波**
——这是决定精度的关键问题。
@@ -271,7 +271,7 @@ UA 无幅值落 IA → 0.0020 Hz。
| `prot_set_dirty_peek()` / `_take()` / `_mark()` | 脏标志三件套(落盘握手) | peek = 通知 iec104Task;take = 属主落盘前消费;mark = 写失败回置重试 |
| `prot_set_store_serialize()` / `_parse()` | 持久化 blob:`PSET` + 版本 + 值区 + sum32 正 / 反码对 | parse **整表原子**:magic / 版本 / 长度 / 校验对 / 范围任一失败 = **一字不动** |
| `prot_set_get_f()` / `get_ctl()` | 工程量浮点 / 投退读取 | 单字读原子 |
| `prot_set_selfcheck()` | 重算 sum32 与封存正 / 反码比对,失配 → 闭锁(L5-1) | seqlock 式复核:提交时撞见改写 = 本轮跳过而**不误锁**;`prot_set_seal()` 是解锁的**唯一**合法路径 |
| `prot_set_selfcheck()` | 重算 sum32 与封存正 / 反码比对,失配 → 闭锁(「定值校验和」) | seqlock 式复核:提交时撞见改写 = 本轮跳过而**不误锁**;`prot_set_seal()` 是解锁的**唯一**合法路径 |
**要点**
@@ -316,7 +316,7 @@ UA 无幅值落 IA → 0.0020 Hz。
`over` 位统一处理(`UV` / `UF` 是欠量实例)。
- **定时限**用差值法 `(uint32_t)(int32_t)(now - t0) >= dly` → tick 回绕安全;`dly = 0` =
启动同拍即动作。**返回是即时的**(参考系统带 10 ms 返回延时,接出口硬件时再补)。
- **闭锁联动**:`prot_set_locked()`(L5-1)或该元件投退 = 0 → 状态整体复位、不再判据。
- **闭锁联动**:`prot_set_locked()`(「定值校验和」)或该元件投退 = 0 → 状态整体复位、不再判据。
- **数据缺失时的两种处理刻意不同**(这是本层最容易改错的一处):
- 相量类**任一未就绪 → 整拍跳过**(不给判据喂陈旧值);
- 频率类**无有效读数 → 按方向填"必不启动"值**(过量填 `0`、欠量填 `1e30` → 滞回比较恒假 →
@@ -329,7 +329,7 @@ UA 无幅值落 IA → 0.0020 Hz。
(`iec104_pts` 的 fault-total 掩码含 OC / 3U0;OF / UF 置总位但无独立分点)。
**文档与代码都必须按此口径,勿写"独立遥信"。**
- **板端接线**:`App/task/protect_task.c`(protectTask,20 ms)消费 `prot_elm_run()` +
L5-4 采样故障闭锁 + L5-1 校验和巡检;判据结果经 104 遥信上送(`iec104_pts` YX15~23 / 31)
自检失败闭锁 + 定值校验和巡检;判据结果经 104 遥信上送(`iec104_pts` YX15~23 / 31)
→ `docs/算法/继电保护功能复现规划.md` §7。实例数变化会同时改变启动锚点 `elm=` 数字与
`prot_elm_active_mask()` 位宽(B8:7 → 9 实例),串口锚点表若含该数字须同步核对。
@@ -412,7 +412,7 @@ adcTask 静态最坏链与余量的**台账在** `docs/内存管理/RAM使用分
## 13. 相关文档
- 目录索引与构建 / 测试入口:`App/algo/README.md`
- L1-6 判定层深设计(判据推导 / 盲区 / 验证分工):`docs/算法/采样有效性校验设计说明.md`
- 「采样有效性校验」判定层深设计(判据推导 / 盲区 / 验证分工):`docs/算法/采样有效性校验设计说明.md`
- 分层与功能项清单(L1~L5 的属主登记处):`docs/算法/继电保护功能复现规划.md`
- 通道映射权威口径:`docs/硬件平台/ADC通道映射说明.md`
- 采样节拍与 DMA 搬运:`docs/子系统设计/ADC采样节拍设计说明.md`
@@ -134,14 +134,14 @@ flowchart TB
| 公共 API | 消息 | netTask 侧实现 | 关键芯片命令 | 返回语义 | 设计意图 / 注意 |
|---|---|---|---|---|---|
| `net_listen` | `NET_MSG_LISTEN` | `net_listen_locked` | `set_proto_type` + `set_sour_port` + `open_socket`(**open 重试 3×,失败走 `net_sock_reset_sync` 确定性排渣**)+ `tcp_listen` + 清**本 Socket** 中断状态 | 0 / -1 | **初次**监听允许有界重试(启动期无竞争);成功后置 `auto_relisten=1`——监听常驻的源头;启动前只清本 Socket SINT(B3/F-NET-7:全局寄存器唯一读者 = `net_poll`,全量读清会焊死其它 Socket 事件位);open 失败重试原"close+盲等 500ms"已换 sock_reset(GRACEFUL 100ms 底,E4 定案复位后 open 必成) |
| `net_listen` | `NET_MSG_LISTEN` | `net_listen_locked` | `set_proto_type` + `set_sour_port` + `open_socket`(**open 重试 3×,失败走 `net_sock_reset_sync` 确定性排渣**)+ `tcp_listen` + 清**本 Socket** 中断状态 | 0 / -1 | **初次**监听允许有界重试(启动期无竞争);成功后置 `auto_relisten=1`——监听常驻的源头;启动前只清本 Socket SINT(唯一读者红线:全局寄存器唯一读者 = `net_poll`,全量读清会焊死其它 Socket 事件位,见 `docs/网络/网络自愈架构设计.md` §4.10);open 失败重试原"close+盲等 500ms"已换 sock_reset(GRACEFUL 100ms 底,E4 定案复位后 open 必成) |
| `net_accept` | `NET_MSG_ACCEPT` | `net_accept_locked` | 无(先 `net_poll` 泵一次 + 状态判定) | 监听 fd 自身(单连接)/ -1(WOULDBLOCK) | 单连接:监听 Socket 在 CONNECT 后**自身即数据通道**,返回的就是它;CLOSED + auto_relisten 时触发**非阻塞** `net_listener_request`;**accept 路径不做自愈**——单次状态读会误判"刚 listen 未生效"致重建风暴(2026-09-23 实测),统一交给 `net_reconcile_tick` 形态③④(合并后的单一重建入口) |
| `net_connect` | `NET_MSG_CONNECT` | `net_connect_locked` | `set_proto_type` + `open_socket`(open 重试 3× + `net_sock_reset_sync` 排渣)+ 清残留中断(只清本 Socket SINT,`ch395f_sock_events`)+ `set_sour_port` / `set_des_ip`(大端数组)/ `set_des_port` + `tcp_connect` | 0 = 请求已发出(**异步**)/ -1 | open **先于**寄存器写入(open 会复位寄存器);open 后清残留 DISCONNECT,防新连接秒断(TRAP-NET-12);目的 IP 字节序写反 = CONNECT TIMEOUT(TRAP-NET-14);返回 0 ≠ 已建立——调用方以 `net_sock_state` 轮询等 ESTABLISHED |
| `net_send` | `NET_MSG_SEND` | `net_send_locked` | `ch395f_write_send_buf`(分块)+ 等 SENBUF_FREE(`net_poll` 轮询,**有界自旋 ≤ `NET_SEND_SPIN_MS`**);超预算登记挂起 send(`net_send_pending_register`) | 实际字节数 / -1 | 分块 ≤ `NET_SEND_CHUNK_MAX` = 1KB(**硬件发送 FIFO 硬上限**,TRAP-NET-16:写穿 FIFO = 数据错位);`send_ready` 门控用 `net_poll` 轮询而非 osDelay,**自旋超 `NET_SEND_SPIN_MS`(2ms)即转挂起**(netTask 最坏停滞由 1s 压到 2ms);短写**必须**告警——静默截断会让对端永久等待剩余字节(2026-09-21 实证:UI 推流应答截断 → 客户端失联) |
| `net_recv` | `NET_MSG_RECV`(timeout=0→**无限等待**,无 30s 默认预算) | `net_recv_locked` | `net_poll` + `get_recv_len` / `read_recv_buf` | >0 / 0(EOF) / -1(errno = WOULDBLOCK / CONNRESET;阻塞形态无 TIMEDOUT 一档) | 快路径:数据已在 → 立即读出返回(允许部分读);无数据 + 阻塞(`blocking` 属性=1 且未 DONTWAIT)→ **登记挂起后立即返回**(挂起登记,netTask 零占用),唤醒源=数据/EOF/close/网络重建;DONTWAIT / `blocking=0` + CLOSED/session_dead → EOF + 触发重监听;⚠ IWDG 受监控任务禁用无限形态(`net_socket.h` 文档契约) |
| `net_recv_nb` | `NET_MSG_RECV`(flags=DONTWAIT) | `net_recv_locked` | 同上 | >0 / 0 / -1(WOULDBLOCK 等) | 原 `NET_MSG_DONTWAIT` 路径转正的具名入口;不改变 `blocking` 属性;受 IWDG 监控 / 有周期职责任务的推荐默认(ui_net_sink / iec104_serv 已迁) |
| `net_recv_to` | `NET_MSG_RECV`(timeout>0) | `net_recv_locked` | 同上 | >0 / 0 / -1 / **-2(本片超时无数据)** | 队头阻塞修复配套 + **显式预算**入口(等价 Python settimeout,无隐藏默认值):调用方把长等待切成有界片(如剩余预算),**总超时语义不变、单次占用有界**;`timeout_ms=0` 直接拒(0 = 无限等待,与本接口"有界"存在理由相反);超时**只凭 -2 判定、不得依赖 errno**(`s_net_errno` 是跨任务共享全局量,随时被别的任务覆盖) |
| `net_close` | `NET_MSG_CLOSE` | `net_close_locked` | `ch395f_cmd_done(CLOSE)` 快路径(芯片已 CLOSED → 只清本 Socket 残留事件)/ `net_sock_reset_sync(GRACEFUL)` 确定性排渣 | 0 / -1 | **先**结束本 fd 挂起 recv(排空/取消 + 必通知,关不得让等待者悬挂);排空只碰本 Socket SINT,**不再读清全局中断寄存器**(F-NET-7:全局唯一读者 = `net_poll`);原"close + 500ms 盲等排空循环"已换 sock_reset(内置 LISTEN 态二段 CLOSE 补发,E2 补充发现);控制块整体清零(`last_peer_port` 幽灵基准跨 fd 保留,属「relisten 沉降段原语化受阻」) |
| `net_close` | `NET_MSG_CLOSE` | `net_close_locked` | `ch395f_cmd_done(CLOSE)` 快路径(芯片已 CLOSED → 只清本 Socket 残留事件)/ `net_sock_reset_sync(GRACEFUL)` 确定性排渣 | 0 / -1 | **先**结束本 fd 挂起 recv(排空/取消 + 必通知,关不得让等待者悬挂);排空只碰本 Socket SINT,**不再读清全局中断寄存器**(唯一读者红线:全局唯一读者 = `net_poll`,见 `docs/网络/网络自愈架构设计.md` §4.10);原"close + 500ms 盲等排空循环"已换 sock_reset(内置 LISTEN 态二段 CLOSE 补发,E2 补充发现);控制块整体清零(`last_peer_port` 幽灵基准跨 fd 保留,属「relisten 沉降段原语化受阻」) |
| `net_drop_conn` | `NET_MSG_DROP_CONN` | `net_drop_conn_locked` | `net_pending_settle_close` + `net_sock_reset_sync(QUARANTINE)` +(auto_relisten)`net_listener_request` | 0(含幂等)/ -1 | **拆会话保监听**(队头阻塞收口):应用放弃会话(对时 30s 预算耗尽 / 协议超时)而单连接监听被挂起对端永久占住时的应用侧出口;EOF 路径**不得**调(`auto_relisten` 已接管);非 ESTABLISHED/CONNECTING 直接返 0 不动监听;本层收口 CLOSED 不清 fd(保留 local_port/auto_relisten),监听型 fd 登记重监听、失败交 D10 + reconciler 形态④ |
| ~~`net_relisten`~~ | ~~`NET_MSG_RELISTEN`~~ | **已删除**(消息类型同删) | — | — | 原"无条件芯片侧重建"与 pump/D10 完全重叠,且对健康监听器是 footgun(open→USE→close 自毁 ~1s);生产零调用。历史实现见 `net_socket.c` git 历史 |
| ~~`net_resync_listen`~~ | ~~`NET_MSG_RESYNC_LISTEN`~~ | **已删除**(语义并入对账⑤) | — | — | D14 静默回收(芯片自行回监听、不发 DISCONNECT)现由 `net_reconcile_tick` 判据⑤自动认领:本层 ESTABLISHED 且芯片 0x05/0x01 → 只修本层(state→LISTENING + 转登 `last_peer_port` + 清 `lost_conn_seen` + 取消挂起 recv),**不发芯片命令**(纪律原样保留,run8 实证 170s 拒绝);去抖/冷却沿用对账框架 |
@@ -233,14 +233,14 @@ flowchart TB
> 认领门槛见 §4.7(在用 + `auto_relisten` + TCP + 已绑端口)——少了它"本层 CLOSED + 已绑端口"的
> 出向连接会被误判为监听器并 relisten。
**去抖 + 冷却(缺一不可)**:单次状态读可能落在"刚 open/listen 尚未生效"的瞬态——**2026-09-23 实测**:无去抖的 accept 路径自愈把监听反复重建直至 `relisten give up`(三服务口全死、89 行 ERROR)。故**分级去抖**(单位=轮,100ms/轮):②=1 轮(`NET_RECON_STABLE_ACCEPT`,幽灵甄别兜底假阳性);③④⑤=2 轮(`NET_RECON_STABLE_RELISTEN`);①=4 轮(`NET_RECON_STABLE_DEATH`,**勿改小**——F-NET-17 M3 可疑电平让位再入的 400ms 租约,E9a 实证);同一 Socket 动手后**冷却 1s**(`NET_RECONCILE_COOLDOWN_MS`;U11 被动重同步不去抖不占冷却)。开销:每 100ms 每在用 Socket 的状态回读已收拢在 `net_poll`(≈100µs/轮),本 tick 本身零额外 SPI。
**去抖 + 冷却(缺一不可)**:单次状态读可能落在"刚 open/listen 尚未生效"的瞬态——**2026-09-23 实测**:无去抖的 accept 路径自愈把监听反复重建直至 `relisten give up`(三服务口全死、89 行 ERROR)。故**分级去抖**(单位=轮,100ms/轮):②=1 轮(`NET_RECON_STABLE_ACCEPT`,幽灵甄别兜底假阳性);③④⑤=2 轮(`NET_RECON_STABLE_RELISTEN`);①=4 轮(`NET_RECON_STABLE_DEATH`,**勿改小**——风暴态三机制里 M3 可疑门的让位再入 400ms 租约,见 `docs/网络/网络自愈架构设计.md` §4.1.6,E9a 实证);同一 Socket 动手后**冷却 1s**(`NET_RECONCILE_COOLDOWN_MS`;U11 被动重同步不去抖不占冷却)。开销:每 100ms 每在用 Socket 的状态回读已收拢在 `net_poll`(≈100µs/轮),本 tick 本身零额外 SPI。
### 4.9 事件处理器(netTask 上下文;由 `net_poll` 驱动,对账 tick 可再入)
| 函数 | 设计作用 | 主要调用 | 意图 / 注意 |
|---|---|---|---|
| `handle_connect_event` | LISTENING → standalone accept(回读对端地址 → ESTABLISHED + `send_ready=1` + 清残留 TIMEOUT + 回调);CONNECTING → 客户端连接成功(回读对端 + 使能 KeepAlive + 回调) | `ch395f_get_remot_ipp` + `get_sock_int_status` +(client)`set_keepalive_enable` + `fire_event` | GET_REMOT_IPP 为**小端**输出(与 set_des_ip 的大端相反)——解析别抄反;`session_dead` 的**唯一清零点** |
| `handle_disconnect_event` | 状态机迁移 + 陈旧事件甄别 + **登记沉降事实**(不再自己重建) | `ch395f_get_socket_status`(事件路径**主动 SPI**,不用缓存——缓存刷新在 net_poll 末尾,事件路径上必然滞后)→(LISTENING:只回读留痕,监听失位交 **reconciler 形态③** 重建;仍在监听 → 判陈旧丢弃)/(ESTABLISHED:芯片仍 ESTABLISHED → 判陈旧丢弃;F-NET-17 M3 可疑门 → 置可疑电平让位对账①) | ① **陈旧 DISCONNECT 甄别**(D20):同一 fd"关闭→重监听→再连接"循环复用,上一条连接的 FIN/ACK 可能在 fd 已复用时才上报 → 不甄别则新连接秒断(实测:FTP 同会话第二个数据连接必 425);② 正常释放(FIN)→ **GRACEFUL 沉降 100ms**(只置事实,重建由 `net_reconcile_tick` 形态③④ 做);③ 置 CLOSED 后**不立即关芯片 Socket**——留给 `net_recv_locked` 排空剩余数据(FIN 可能先于数据到达) |
| `handle_disconnect_event` | 状态机迁移 + 陈旧事件甄别 + **登记沉降事实**(不再自己重建) | `ch395f_get_socket_status`(事件路径**主动 SPI**,不用缓存——缓存刷新在 net_poll 末尾,事件路径上必然滞后)→(LISTENING:只回读留痕,监听失位交 **reconciler 形态③** 重建;仍在监听 → 判陈旧丢弃)/(ESTABLISHED:芯片仍 ESTABLISHED → 判陈旧丢弃;M3 可疑门 → 置可疑电平让位对账①,见 `docs/网络/网络自愈架构设计.md` §4.1.6) | ① **陈旧 DISCONNECT 甄别**(D20):同一 fd"关闭→重监听→再连接"循环复用,上一条连接的 FIN/ACK 可能在 fd 已复用时才上报 → 不甄别则新连接秒断(实测:FTP 同会话第二个数据连接必 425);② 正常释放(FIN)→ **GRACEFUL 沉降 100ms**(只置事实,重建由 `net_reconcile_tick` 形态③④ 做);③ 置 CLOSED 后**不立即关芯片 Socket**——留给 `net_recv_locked` 排空剩余数据(FIN 可能先于数据到达) |
| `handle_recv_event` | 置 `readable` + 回调;**不读 recv_len** | `fire_event` | 不读长度是为了避免与 `net_recv_locked` 的 `ch395f_get_recv_len` 竞争(旧"分批读归零"机理,未证实);`readable` 供 `net_select` 无 SPI 访问判读 |
| `handle_send_event` | 发送缓冲已空:触发回调(`send_ready` 由 SENBUF_FREE 前置位) | `fire_event` | — |
| `handle_timeout_event` | CONNECTING → CREATED(连接超时);**ESTABLISHED → 登记隔离 + CLOSED**(TRAP-NET-18);LISTENING → 仅记日志 | **`net_listener_settle(fd, NET_LISTENER_SETTLE_QUARANTINE)`** + `fire_event` | TIMEOUT = 异常释放(如客户端中止上传):对端在途数据随后落进 RX 缓冲 → 必须隔离(400ms)后才许复监听;正常 FIN 释放走 disconnect 路径(GRACEFUL 100ms),**不走**隔离 |
@@ -410,9 +410,9 @@ sequenceDiagram
| `ch395f_set_ip_addr` / `set_gwip_addr` / `set_mask_addr` / `set_dhcp` | `net_init`(**均须在 `ch395f_init` 之前**) | 固定 IP 或 DHCP |
| `ch395f_init` / `ch395f_ping_enable` | `net_init` | 协议栈初始化(INIT_CH395)/ PING(须在 init 之后) |
| `ch395f_set_send_buf` / `ch395f_set_recv_buf` | `net_init`(8 Socket 布局);`net_bind`(UDP)(Socket 4~7 兜底) | 每 Socket 收 4 块 + 发 2 块 |
| `ch395f_get_glob_int_status_all` | **仅 `net_poll`**(F-NET-7 / B3:全局寄存器唯一读者;`net_listen_locked` / `net_connect_locked` / `net_close_locked` / `net_relisten_locked` 的原全局读清已全部删除) | **读 = 清**(中断清除机制,无按位手段)——其他位置读清会焊死 net_poll 的按 Socket 门控 |
| `ch395f_get_glob_int_status_all` | **仅 `net_poll`**(唯一读者红线:全局寄存器唯一读者,见 `docs/网络/网络自愈架构设计.md` §4.10;`net_listen_locked` / `net_connect_locked` / `net_close_locked` / `net_relisten_locked` 的原全局读清已全部删除) | **读 = 清**(中断清除机制,无按位手段)——其他位置读清会焊死 net_poll 的按 Socket 门控 |
| `ch395f_get_sock_int_status` | `net_poll`(逐 Socket SINT);各 open 路径后清残留;事件处理器清 TIMEOUT | **读 = 清** |
| `ch395f_sock_events` | `net_connect_locked`(open 后清残留,F-NET-7 护栏原语);`net_close_locked`(芯片已 CLOSED 快路径只清本 Socket 残留事件) | 只碰**本 Socket** SINT 的护栏原语 |
| `ch395f_sock_events` | `net_connect_locked`(open 后清残留,唯一读者红线的护栏原语,见 `docs/网络/网络自愈架构设计.md` §4.10);`net_close_locked`(芯片已 CLOSED 快路径只清本 Socket 残留事件) | 只碰**本 Socket** SINT 的护栏原语 |
| `ch395f_open_socket` / `ch395f_close_socket` | `net_bind`(UDP)、`net_listen_locked`、`net_connect_locked`、`net_relisten_locked`(含沉降期主动 close);`net_close_locked` 的 CLOSE 已改经 `ch395f_cmd_done` / `ch395f_sock_reset_*` | TRAP-NET-09:close 后需沉降才能重开 |
| `ch395f_tcp_listen` / `ch395f_tcp_connect` | `net_listen_locked` / `net_relisten_locked`;`net_connect_locked` | — |
| `ch395f_set_proto_type` / `set_sour_port` / `set_des_ip` / `set_des_port` | `net_bind`(UDP)、`net_listen_locked`、`net_connect_locked`、`net_relisten_locked`、`net_sendto` | open 之后写端口/IP(open 会复位寄存器);set_des_ip 期望**大端数组** |
@@ -422,7 +422,7 @@ sequenceDiagram
| `ch395f_get_sock_state` / `ch395f_sock_state_cached` | 刷新**仅 `net_poll`** 每轮对在用 Socket 调 `get_sock_state`(唯一刷新点);`sock_state_cached` 读缓存 = `net_reconcile_tick`(形态①②③④⑤/U11 判据) | 芯片状态唯一事实源;E2 实测单次回读 18.1µs,缓存新鲜度 ≤1ms |
| `ch395f_sock_reset_begin` / `ch395f_sock_reset_poll` | `net_sock_reset_sync`(`net_listen_locked` / `net_connect_locked` open 重试、`net_close_locked`、`net_drop_conn_locked`);`net_poll` 每轮对在用 Socket **步进**(IDLE 槽纯 RAM 判零 SPI) | 驱动复位状态机:读空 RX → CLOSE → 排空事件(quiescent) → 等 byte0=00H;内置 LISTEN 态二段 CLOSE 补发(E2 补充发现);GRACEFUL 100ms 底 / QUARANTINE 400ms 底 |
| `ch395f_cmd_done` | `net_close_locked`(CLOSED 快路径判据) | 命令完成判定(OPEN/LISTEN/CLOSE 三形态,读缓存不额外发 SPI) |
| `ch395f_link_up_cached` / `ch395f_link_change_count` | `net_reconcile_tick`(链路态订阅留痕,F-DRV-13) | 驱动 link 变化计数,net_poll 喂 |
| `ch395f_link_up_cached` / `ch395f_link_change_count` | `net_reconcile_tick`(链路态订阅留痕,见 `docs/网络/网络自愈架构设计.md` §4.4 链路态喂料缓存) | 驱动 link 变化计数,net_poll 喂 |
| `ch395f_get_remot_ipp` | `handle_connect_event`、`net_reconcile_tick`(幽灵甄别,形态② 命中时唯一按需 SPI)、`net_connect_locked`(诊断) | **小端**输出(与 set_des_ip 相反) |
| `ch395f_set_keepalive_enable` | `handle_connect_event`(client 连接成功时) | — |
+6 -2
View File
@@ -13,7 +13,7 @@
|---|---|---|
| `I1`~`I8` | 本架构的**不变量**(Invariant)——违反即有实测后果 | §2 |
| `E0`~`E19` | **台架实验**编号(E = Experiment):每个实验是「假设 → 方法 → 判据 → 门禁哪个决策」 | §5.2(原始记录已归档,见 §12) |
| `F-NET-nn` / `F-DRV-nn` / `F-MS-nn` | 审计的**编号发现**:NET 层 / 驱动层 / 状态镜像层 | §7(只保留仍被引用的 12 条) |
| `F-NET-nn` / `F-DRV-nn` / `F-MS-nn` | 审计的**编号发现**:NET 层 / 驱动层 / 状态镜像层(**2026-10-27 停发**,指代一律用 §7 表的「一句话结论」条目名) | §7(保留 12 条历史对照) |
| `M1`~`M5` | 实验固件里的**候选修改代号**:M1 沉降无条件化 · M2 门控换 `net_listener_armed` · M3 可疑门 · M4/M4-lite 删沉降段全局读即清 · M5 `sock_reset` quiescent 排空 | §4.1、§4.3 |
| `形态①`~`形态⑤` | `net_reconcile_tick` 的五类**失同步判据** | §4.1 |
| `U1`~`U15` | 状态迁移的**"无人负责"组合**(架构欠债清单) | `docs/问题记录/CH395F_Trap_Records.md` 审计遗留章节 |
@@ -659,7 +659,11 @@ DISCONNECT 会被 `(void)` 丢掉。但 RECV_OK 是条件位(下轮补回)
——走 `sock_reset`(内置补发)或保留 TRAP-NET-09 式重试。
10. **不把监听重建接进 `sock_reset` 原语**:三条前置语义未补齐(§8 延后项 1,E16)。
## 7. 编号发现速查(仍被代码/文档引用的 12 条)
## 7. 编号发现速查(12 条,历史对照表)
> ⚠ **本节的条目号已于 2026-10-27 停发(编号规范 §9 批次一),正文改用条目名指代**;
> 下表保留编号列仅作历史对照(删表会让历史行的引用报「未登记前缀」假错),
> 全仓不得再新增对这些号的引用——代码注释与关联文档已改写为「一句话结论 + 本表落点」的语义形式。
| 编号 | 一句话结论 | 收口落点 |
|---|---|---|
@@ -57,14 +57,14 @@
| 层 | 项 | 证据 |
|---|---|---|
| L1 | 1 kHz 硬件节拍、TPAFE 快照、ADC1 DMA 乒乓、语义映射 | `docs/算法/继电保护功能复现规划.md` §3.1 的 L1-1~L1-4 |
| L1 | 采样有效性(静默/丢帧/倒退/错误增量) | 复现规划 §3.1(L1-6);`docs/算法/采样有效性校验设计说明.md` |
| L1 | 谐波相量入口(IA 的 2/5 次) | 复现规划 §3.1(L1-9) |
| L2 | 全周傅氏 5 实例、双区原子切换、每拍重算 | 复现规划 §3.2(L2-1~L2-4/L2-6/L2-7) |
| L2.5 | 测频(自适应窗,45~55 Hz 最坏 0.0101 Hz) | 复现规划 §3.3(L3-5) |
| L3 | 9 元件(三段过流/过负荷/过压/欠压/零序过压/过频/低频) | 复现规划 §3.3(L3-1/L3-3~L3-6) |
| L4 | SOE + 动作记录(64 B 定长、CP56 时标、SPSC 环异步落盘) | 复现规划 §3.4(L4-4/L4-5) |
| L5 | 定值校验和 + 持久化 + 全局软压板 + 采样故障闭锁 | 复现规划 §3.5(L5-1/L5-4) |
| L1 | 1 kHz 硬件节拍、TPAFE 快照、ADC1 DMA 乒乓、语义映射 | `docs/算法/继电保护功能复现规划.md` §3.1 的「周期 CONVST 重触发」~「通道语义映射」 |
| L1 | 采样有效性(静默/丢帧/倒退/错误增量) | 复现规划 §3.1(「采样有效性校验」);`docs/算法/采样有效性校验设计说明.md` |
| L1 | 谐波相量入口(IA 的 2/5 次) | 复现规划 §3.1(「二次谐波/五次谐波提取入口」) |
| L2 | 全周傅氏 5 实例、双区原子切换、每拍重算 | 复现规划 §3.2(「全周傅氏系数表」~「相位输出」/L2-6/L2-7) |
| L2.5 | 测频(自适应窗,45~55 Hz 最坏 0.0101 Hz) | 复现规划 §3.3(「过频 / 低频」) |
| L3 | 9 元件(三段过流/过负荷/过压/欠压/零序过压/过频/低频) | 复现规划 §3.3(「三段式相间过流」/L3-3~「零序过压」) |
| L4 | SOE + 动作记录(64 B 定长、CP56 时标、SPSC 环异步落盘) | 复现规划 §3.4(「SOE 记录」/L4-5) |
| L5 | 定值校验和 + 持久化 + 全局软压板 + 采样故障闭锁 | 复现规划 §3.5(「定值校验和」/L5-4) |
| 上行 | 104 总召/变位/遥控/定值读写/时钟同步 | `docs/子系统设计/IEC104上行设计说明.md` |
### 3.2 部分闭环
@@ -93,7 +93,7 @@
- `App/algo/adc_input.c` 的 `adc_input_raw()` 明确只搬原始码值、不做标定(见其头文件注释)。
- `App/algo/phasor.c` 的系数表只含 √2/N 折算,**不含通道增益**——`fAmSQ` 的数值量纲是"码值",不是 V/A。
- `App/algo/prot_elm.h` 与 `App/algo/freq.h` 均注明"工程量↔码值换算系数 = 1(L1-5 标定未实现)"。
- `App/algo/prot_elm.h` 与 `App/algo/freq.h` 均注明"工程量↔码值换算系数 = 1(「通道标定(一次系数 + 零漂)」标定未实现)"。
- `App/protocol/iec104/iec104_pts.c` 的遥测源直接返回 `p.fAmSQ`;死区 10.0 也是码值口径。
**参考做法**:`DataPre.c` 每拍做 `fValue = iVal * pfSamCoe[dwPinNo]`,每通道一个定点(2^10)系数,把码值换成二次侧工程量;再由 PT/CT 变比换一次值。
@@ -203,7 +203,7 @@
- **建议**:硬件确认出口回路后,做 `ko.c` 抽象(脉冲宽度用 `0x8031/0x8032`)+ 出口自检。软件侧可先建接口不使能。
- **规模**:M / 依赖硬件。
### 5.3 派生量(L2-5)
### 5.3 派生量(「线/负序/零序合成」)
- **现状**:只有 3 个基波实例 + 2 个谐波实例,无线电压、无负序/正序/零序合成、无差分、无直流分量。
- **为什么现在做**:V0.1 受双转换器无共同采样触发限制,跨转换器合成**不成立**(`UA` 与 `UB` 无同一时刻性);但**代码与单测可以先就绪**,V0.2 只改映射表就能使能。参考侧 `CalfLineVec`/`CalfNegVec`/`CalfPosVec`/`CalfSeqVec`/`CalfZeroVec`/`CalfAnaDC`/`CalfAnaDif` 是七个小模块,逻辑清晰、天然可主机单测。
@@ -230,14 +230,14 @@
## 6. 精度与数据质量
### 6.1 等周波采样未闭环(L1-7)
### 6.1 等周波采样未闭环(「等周波采样(软件测频 + 调频闭环)」)
- **现状**:TIM3 固定 1 kHz。`freq.c` 已能出 0.0101 Hz 的测频结果,但**没人用它调采样率**。
- **后果**:频偏 ±2 Hz 时窗长偏离整周波,基波幅值误差 1~2%,相位误差更大;2 次/5 次谐波相量(涌流、选线)误差被放大。参考侧靠"测频 → 调 EHRPWM 周期"把窗长锁死在 20 点/周波。
- **建议**:闭环 = `freq_get()` → 查表/PI → TIM3 ARR 微调(1 kHz ±2%)。注意三点:① 调 ARR 会同时改变 ADC1 触发与 TPAFE CONVST 节拍,要核算 ADC1 9 通道扫描(≈67 µs)与 TPAFE 转换时间在最短周期内仍有余量;② 先开环验证固定 50 Hz 精度,再上闭环;③ 调频期间相量窗会短暂不整周波,保护侧要有过渡处理(或仅在频率稳定时调)。
- **规模**:M。
### 6.2 削顶/越界检测缺失(L5-2 残余)
### 6.2 削顶/越界检测缺失(「采样通道自检」残余)
- **现状**:`adc_health` 只判"前进量"(静默/丢帧/倒退/错误增量),**不判数据合理性**。STM32 侧交流量负半周削顶(R5)在代码里无法被检出。
- **后果**:V0.1 的 `UB/UC/IB/IC/IN` 读数"看起来有值",实际是削顶后的假值。现在靠"在点表里标 IV"规避——那是**配置**,不是**检测**。一旦有人把点表改回有效,或者 V0.2 上线后某一路前端失效,系统不会告警。
@@ -329,14 +329,14 @@
| 短板 | 既有登记位置 | 本报告补充了什么 |
|---|---|---|
| 标定 | `docs/算法/继电保护功能复现规划.md` §3.1 的 L1-5(⬜) | 明确它是**遥测链的前置**,且给出落点(`adc_input_raw()` 与采样环之间) |
| 等周波 | 同 §3.1 的 L1-7(⬜) | 补三条实施约束(ARR 联动、开环先行、过渡处理) |
| 遥测链 | 复现规划 §3.2(L2-8,标"可选") | **建议从"可选"升为"必做"**——它是遥测、电度、越限、畸变率的共同底座 |
| 派生量 | 复现规划 §3.2(L2-5,V0.1 不适用) | 建议代码与单测先就绪,V0.2 只改映射 |
| 录波 | 复现规划 §3.4(L4-6,⬜) | 补"104 文件服务"这一半(原登记只写录波) |
| 标定 | `docs/算法/继电保护功能复现规划.md` §3.1 的「通道标定(一次系数 + 零漂)」(⬜) | 明确它是**遥测链的前置**,且给出落点(`adc_input_raw()` 与采样环之间) |
| 等周波 | 同 §3.1 的「等周波采样(软件测频 + 调频闭环)」(⬜) | 补三条实施约束(ARR 联动、开环先行、过渡处理) |
| 遥测链 | 复现规划 §3.2(「遥测谐波轨(可选)」,标"可选") | **建议从"可选"升为"必做"**——它是遥测、电度、越限、畸变率的共同底座 |
| 派生量 | 复现规划 §3.2(「线/负序/零序合成」,V0.1 不适用) | 建议代码与单测先就绪,V0.2 只改映射 |
| 录波 | 复现规划 §3.4(「故障录波(可选)」,⬜) | 补"104 文件服务"这一半(原登记只写录波) |
| 运行参数段 | 未登记 | **新发现**,建议按语义标识登记("运行参数段 0x8020~0x8058") |
| 开入开出 | 未登记 | **新发现**,建议登记("开入量采集与遥信"、"遥控与出口") |
| 削顶检测 | 复现规划 §3.5(L5-2 残余,"码值越界待做") | 给出两条具体判据 |
| 削顶检测 | 复现规划 §3.5(「采样通道自检」残余,"码值越界待做") | 给出两条具体判据 |
| 频率点 | `docs/子系统设计/IEC104上行设计说明.md` §8 第 4 条 | 明确它现在就能做(算法已就绪,只差绑定) |
---
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成 docs/images/采样有效性位图与掩码.svg —— L1-6 出口位图与消费者掩码对照(纯标准库)。
"""生成 docs/images/采样有效性位图与掩码.svg —— 采样有效性校验出口位图与消费者掩码对照(纯标准库)。
为什么不用 Mermaid:本图的核心信息是**位号对齐**(同一 bit 在三张位图与四个消费者掩码
里落在同一列),必须等宽网格逐列对齐;Mermaid 无法控制列位。
@@ -47,7 +47,7 @@ C_NONE = ("#94a3b8", "#f8fafc") # 未使用 / 不适用
GROUPS = [
dict(head="判定层写出的三张位图(adc_health.c)", rows=[
dict(label="flags 电平位", sub="adc_health_flags(),当前活跃",
note="protectTask 每 20 ms 读它做 L5-4 闭锁;bit8 由本任务自己判老后 OR 入(判定层不写)",
note="protectTask 每 20 ms 读它做自检失败闭锁;bit8 由本任务自己判老后 OR 入(判定层不写)",
bits=[("bit0", "TPAFE_STALL", "level"), ("bit1", "STM32_STALL", "level"),
("bit2", "SEQ_BACKWARD", "latch"), ("bit3", "—", "none"),
("bit4", "—", "none"), ("bit5", "—", "none"),
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成 docs/images/采样有效性校验数据流.svg —— L1-6「观测计数 → 快照 → 判定 → 位图 → 消费者」(纯标准库)。
"""生成 docs/images/采样有效性校验数据流.svg —— 采样有效性校验「观测计数 → 快照 → 判定 → 位图 → 消费者」(纯标准库)。
为什么不用 Mermaid:本图要表达**三条量车道(TPAFE / STM32 / 时基)平行流过五个阶段**,
Mermaid 自动布局会把三条车道挤成交叉线、也保不住"同一拍取数"的横向对齐。
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成 docs/images/采样有效性判定时间轴.svg —— L1-6 四个工况的时序与门限(纯标准库)。
"""生成 docs/images/采样有效性判定时间轴.svg —— 采样有效性校验四个工况的时序与门限(纯标准库)。
为什么不用 Mermaid:本图要表达**时间与门限的比例关系**(100 ms 门限线、静默计时线、
电平位/锁存位的存续区间),必须按比例画坐标与条形;Mermaid 只画拓扑、不保比例。
@@ -59,7 +59,7 @@ RINGS = [
["症状:别的 Socket 的 CONNECT/DISCONNECT 从此永久失踪",
"机制:全局中断寄存器整体读即清,open/relisten 丢弃式读一遍=拔全楼门铃线"],
"总闸唯一读者",
["F-NET-7:全局寄存器唯一读者=net_poll;open/relisten 只清本 Socket SINT",
["唯一读者红线:全局寄存器唯一读者=net_poll;open/relisten 只清本 Socket SINT",
"查自己门铃时,不许拔别人家的线"]),
("③ 柜台和货梯是同一台", "单连接模型",
["症状:会话 EOF 之后端口「连接被拒」",