移除 OpenCode 配置与命令,技能与串口单一配置源迁移至 .dsh/skills 与 .serialtest,同步更新全部文档引用

This commit is contained in:
2026-10-10 14:05:36 +08:00
parent e89fe54a97
commit aac5f99fe9
44 changed files with 3868 additions and 180 deletions
+14
View File
@@ -15,6 +15,7 @@ docs/
├── 产品需求/ 产品需求设计文档(面向产品的需求基线)
├── 架构设计/ 全局架构与设计方法论
├── 子系统设计/ 各功能子系统的设计说明
├── 算法/ 傅氏算法与继电保护算法专题
├── 网络/ BSD Socket API 使用与内部实现
├── 测试说明/ 测试流程、模块测试指南、工具说明
├── 代码规范/ 编码规范与静态检查门禁
@@ -78,6 +79,8 @@ docs/
## 5. 子系统设计
### 5.1 功能子系统
| 文档 | 内容 |
|---|---|
| [`配置文件设计说明.md`](子系统设计/配置文件设计说明.md) | `/config.ini` 配置引擎:分层、解析、原子持久化(旧 NCFG 档已废弃) |
@@ -89,6 +92,16 @@ docs/
| [`网络/BSD_Socket_API_使用指南.md`](网络/BSD_Socket_API_使用指南.md) | **上层视图**:BSD Socket API 公开语义、示例、常见问题 |
| [`网络/BSD_Socket_API_函数调用关系.md`](网络/BSD_Socket_API_函数调用关系.md) | **内部视图**:netTask / 消息队列 / L3 挂起 / 重试对账的调用关系与设计意图 |
| [`网络/Net层阻塞模型架构设计.md`](网络/Net层阻塞模型架构设计.md) | **等待模型**:pending 请求架构、五路完成语义、设计边界与性能特征 |
---
### 5.2 算法专题
| 文档 | 内容 |
|---|---|
| [`傅氏算法详解.md`](算法/傅氏算法详解.md) | 全周波傅氏(单频 DFT)原理与工程实现:正交性、梳状带通、滑动窗、系数表折算有效值;保护/遥测双轨有效值的算法基础 |
| [`继电保护功能复现规划.md`](算法/继电保护功能复现规划.md) | **保护功能复现规划**:把参考系统(CLS100)保护链路映射到本项目(STM32F4)的分层功能/性能/参数清单、平台适配(N-18 等)与分阶段路线图 |
---
## 6. 测试说明
@@ -248,6 +261,7 @@ docs/
| 日期 | 变更 | 说明 |
|---|---|---|
| 2026-10-10 | 新增算法专题 | 新建 `docs/算法/继电保护功能复现规划.md`(保护链路复现总规划);本索引 §1 目录树补 `算法/`、§5 拆为 5.1 功能子系统 / 5.2 算法专题并登记 `算法/` 两篇文档 |
| 2026-10-05 | 新增产品需求文档 | 新建 `docs/产品需求/产品需求设计文档.md`(面向产品的需求基线);本索引新增 §3 产品需求、§2 推荐阅读顺序置顶、§1 目录树补 `产品需求/`;后续章节号顺延(架构设计 §4 … 变更记录 §12) |
| 2026-09-25 | 目录重组 + 索引建立 | 顶层 16 篇散落 md 归入 5 个新目录(`架构设计/` `子系统设计/` `网络/` `审查记录/` `环境与部署/`);全仓库 90 处引用同步;新建本索引(D-5) |
| 2026-09-25 | D-6 目录去空格 | `docs/UI 设计/` → `docs/UI设计/`;全仓库 67 处引用同步(含 URL 编码形态 `UI%20设计`);命名约定写入 §10 |
+12 -12
View File
@@ -445,17 +445,17 @@ sequenceDiagram
### 5.9 ADC 采集(FR-ADC)⬜ 待实现
- **需求(待产品定义确认)**:周期采集 TPAFE5160 多通道模拟量并转发。
- **需求(B0 已确认,2026-10-10)**:**持续采集** 8 路电气量(Ua/Ub/Uc/U0、Ia/Ib/Ic/I0,**1000 Hz / 20 点/周波**),经保护/遥测算法后**上送 IEC 60870-5-104**(以太网 TCP 2404;遥测上送短浮点、采集上传系数 = 1)。
- **现状**:`tpafe5160_init()` 与 `tpafe5160_start_conv_irq()` 在启动序列调用一次;**全仓库无周期性 CONVST 重触发**;`tpafe5160_snapshot()` 无消费者(`adc_task.c` 为空桩——2026-10-10 起已挂进 `uvprojx`,仍未在 `freertos.c` 创建);STM32 侧 ADC1 已生成但**全仓库无 `HAL_ADC_Start`**。
- **后果**:上电后仅采集 1 个样本,此后数据永久陈旧。
- **待确认(阻塞项 B0)**:① 采集是否持续 ② 采样率/通道 ③ 转发目标 ④ `APP_ADC_ENABLE` 语义。
- **B0 结论**(2026-10-10,详见 `docs/算法/继电保护功能复现规划.md` §1.5):① 持续采集 ② 1000 Hz(20 点/周波),通道 = 4U+4I(点表 `4011~4018`)③ 上行 **IEC 60870-5-104**(2404,非 ModBus RTU 上行)④ `APP_ADC_ENABLE` 语义 = 门控 ADC 采集链路(ADC 为遥测/保护必需来源;是否接线或删除占位宏待定)。
- **实现约束**(见 §9):周期 CONVST 重触发 + `adc_task` 消费 `tpafe5160_snapshot()`;**原子快照 API 已就位**(2026-10-10 修 E-44 / E-45 / E-58,旧的 `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 硬件缺陷**(跨转换器无同一时刻性、精度与量程不一致,登记簿 N-18,V0.2 改版要求全部走 TPAFE)→ 在 V0.1 上主板侧只做**逐通道独立监视**,功率 / 功率因数 / 相角 / 矢量类量一律取子板计量模块结果,不得由主板混算。
### 5.10 RS-485 采集(FR-RS485)⬜ 待实现
- **需求(待产品定义确认)**:半双工 RS-485 收发、协议帧解析、转发。
- **需求(B0 已确认,2026-10-10)**:半双工 RS-485 **对下 ModBus RTU 采集**(下行采集口,非上行口;上行走以太网 IEC 60870-5-104)。
- **现状**:`rs485_init()` 已调用;`rs485_task.c` 为空桩,未在 `freertos.c` 创建;`App/protocol/` 预留(仅 README + `.gitkeep`)。
- **实现约束**:双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ 协议状态机;解析必须与硬件 I/O 分离(`App/protocol/` 正为此预留)。
- **实现约束**:双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ 协议状态机;解析必须与硬件 I/O 分离(`App/protocol/` 正为此预留)。B0 结论详见 `docs/算法/继电保护功能复现规划.md` §1.5。
---
@@ -549,7 +549,7 @@ mac=00:00:00:00:00:00
|---|---|
| 端口 | USART1(PA9 TX / PA10 RX),115200 8N1 |
| 用途 | printf 日志 + `@test` 采集通道 |
| 配置源 | `.opencode/serial_config.json`(单一配置源) |
| 配置源 | `.serialtest/config.json`(单一配置源) |
| 工具 | 仓库内置 Python 串口助手(`tools/serial_tool/`,常驻 daemon + CLI) |
**启动标记(`@test` 判据)**:
@@ -771,16 +771,16 @@ cfg-file-unit-test、test-suite-switch、gitlint。
| 缺口 | 现状 | 影响 |
|---|---|---|
| **ADC 采集链路** | `adc_task.c` 空桩(已挂进 `uvprojx`、未建任务);无周期 CONVST 重触发;`tpafe5160_snapshot()` 无消费者;STM32 侧无 `HAL_ADC_Start` | 上电后仅采 1 个样本(驱动取数契约已于 2026-10-10 修好,接消费者不再有撕裂/丢样风险) |
| **RS-485 采集链路** | `rs485_task.c` 空桩;`App/protocol/` 仅 README | 无 RS-485 数据收发 |
| **DTU 核心转发职责** | 未定义 | 采集到数据后无处转发 |
| **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 采集 | 转发目标已明确,待实现 |
> **根因不是"缺陷难修",而是"功能没接"**——B1/B2 的规模完全取决于 B0 产品定义。
> **根因不是"缺陷难修",而是"功能没接"**——B1/B2 的规模取决于 B0 产品定义,**B0 已于 2026-10-10 确认**(见 `docs/算法/继电保护功能复现规划.md` §1.5)。
### 9.2 阶段路线图
```text
【阶段 B 功能】 B0 产品定义确认 ─┬─ B3 E-59 门禁固化(并行)
(当前最高优先) └─ E-58 原子快照 → B1 ADC → B2 RS485
【阶段 B 功能】 B0 产品定义确认 ✅ ─┬─ B3 E-59 门禁固化(并行)
(当前最高优先) └─ E-58 原子快照 → B1 ADC → B2 RS485
↓
【阶段 C 结构】 C1 pending 二期 ─ C3 日志管线 ─ C4 栈(S-1) ─ C5 收口 ─ C6 USART1 TX-only
↓
@@ -789,7 +789,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
| 阶段 | 关键任务 | 前置 |
|---|---|---|
| **B0** | 产品定义确认(阻塞项):采集是否持续 / 采样率通道 / 转发目标 / `APP_*_ENABLE` 语义 | — |
| **B0** | 产品定义确认 ✅(2026-10-10):持续采集 / 1000 Hz·20 点周波 / 上行 IEC 60870-5-104(2404)/ RS-485 对下 ModBus RTU;详见 `docs/算法/继电保护功能复现规划.md` §1.5 | — |
| **B1** | ADC 采集链路实现(周期 CONVST + `adc_task` 消费;**先修原子快照 API**) | B0 + E-59 门禁 |
| **B2** | RS-485 采集链路实现(双缓冲 + 序号 + DE 收尾 + 协议状态机) | B0 + E-59 门禁 |
| **B3** | E-59 门禁固化入 `AGENTS.md`(接消费者前先修缺陷 + 栈预算) | — |
@@ -801,7 +801,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
| 开关 | 位置 | 现状 |
|---|---|---|
| `APP_NET_ENABLE` / `APP_ADC_ENABLE` / `APP_RS485_ENABLE` | `App/app/app_cfg.h` | **未接线占位,不门控任何代码**——三宏全库零消费点,各模块一律编译进产品;是否/如何接线取决于 B0 产品定义。**不要把它们当开关用** |
| `APP_NET_ENABLE` / `APP_ADC_ENABLE` / `APP_RS485_ENABLE` | `App/app/app_cfg.h` | **未接线占位,不门控任何代码**——三宏全库零消费点,各模块一律编译进产品;B0 已确认 ADC / RS-485 均为必需链路(ADC=遥测/保护来源,RS-485=对下 ModBus RTU 采集)→ 建议在 B1/B2 落地时接线为真实门控(或删除占位宏)。**在接线前不要把它们当开关用** |
| `TEST_SUITE_*` | `test/board/test_config.h` | 测试套件**互斥**,一次构建只开一个;全注释 = 正常产品固件 |
---
+9 -7
View File
@@ -63,18 +63,20 @@
> 排序原则:**先降风险(产品级故障)→ 再补功能(核心链路)→ 再清结构债 → 最后卫生**。
> 本节只给「做什么 / 为什么现在 / 入口在哪 / 完成判据」,明细指向 §3 对应条目。
### 2.1 阶段 B:核心功能补齐(产品价值最高,需产品定义确认)
### 2.1 阶段 B:核心功能补齐(产品价值最高,产品定义已确认)
> 目标:让 DTU 真正采到数——这是当前**最大的功能空洞**,**当前最高优先级**。
> **B0 产品定义已于 2026-10-10 确认并销项**:上行 **IEC 60870-5-104**(以太网 TCP 2404)/
> 持续采集 / **1000 Hz(20 点/周波)** / RS-485 **对下 ModBus RTU 采集**;结论详见
> `docs/算法/继电保护功能复现规划.md` §1.5,并已同步 `docs/产品需求/产品需求设计文档.md` §5.9/§5.10/§9。
> **B3(纪律门禁)已于 2026-10-10 固化进 `AGENTS.md` 并销项**;同日 TPAFE 侧前置缺陷
> **E-44 / E-45 / E-58 全部修复** → **B1 现在只欠 B0 的产品定义 + 栈预算**;
> **E-44 / E-45 / E-58 全部修复** → **B1 现在只欠栈预算 + 建任务**;
> B2 仍欠 **E-50 / E-49**(RS485 驱动契约未修,门禁仍挡着)。
| 序 | 任务 | 前置 | 说明 |
|---|---|---|---|
| **B0** | **产品定义确认**(阻塞项) | — | 需甲方明确:① 采集是否持续 ② 采样率(**通道语义已于 2026-10-09 确认并固化 → `docs/硬件平台/ADC通道映射说明.md`**:UA/UB/UC/UN=`AIN1~4`、IA/IB/IC/IN=`AIN8~11`、V_ZL2=温度、其余 8 路备用;主板只做监视/辅助测量,计量在子板。**注意:8 路电气量分属 TPAFE/STM32 两片转换器属 V0.1 硬件缺陷 → N-18**,主板侧不得做跨转换器的相位/功率类运算) ③ 转发目标(MODBUS RTU?上行 TCP?)④ `APP_ADC_ENABLE`/`APP_RS485_ENABLE` 语义。**B1/B2 的规模完全取决于此** |
| **B1** | **ADC 采集链路实现**(消化 P1-1;E-58 已闭环) | B0 + **E-59 门禁**(TPAFE 侧已满足) | 周期 CONVST 重触发 + `adc_task` 消费 **`tpafe5160_snapshot()`**(**2026-10-10 驱动契约已修**:E-44 FRSTDATA 有效性校验 + `init()` 首帧自检返 `-3`、E-45 帧序号取代就绪电平标志、E-58 临界区原子快照;旧 `get_buf`/`data_ready`/`clear_ready` **已删**,删除前零调用者);`adc_task.c` **已挂进 `uvprojx`**(此前 Keil/模拟器两边都不注册 = 永不编译;simulator 无任务层,只挂 Keil);**仍欠**:栈预算核算(两任务未入 `freertos.c` 栈表,建任务前后各跑 `stack_report.py`;原 S-1 栈风险已于 2026-10-10 **削链销项**,defaultTask 现静态 2776/4096 余 32%、实测 2152 B)+ 消费者本体 + 建任务走 **L1(`.ioc` 的 `FREERTOS.Tasks01`)**;**取数必须按 `docs/硬件平台/ADC通道映射说明.md`**(TPAFE `buf[2]=IA`/`buf[5]=UN`/`buf[6]=UA`;STM32 侧 ADC1 **已于 2026-10-09 生成**:`hadc1` + `MX_ADC1_Init()`、9 通道 Rank1~9、144 cycles、ADCCLK=21 MHz、软件触发,网名 ADC17=PC4 用 `ADC_CHANNEL_14`;⚠ 全仓库至今**无 `HAL_ADC_Start`** → STM32 侧一路未跑) |
| **B2** | **RS-485 采集链路实现**(消化 E-50、E-49) | B0 + **E-59 门禁**(**尚未满足**:E-50 / E-49 未修) | 双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ 协议状态机(`App/protocol/` 正是为此预留) |
| **B1** | **ADC 采集链路实现**(消化 P1-1;E-58 已闭环) | B0 ✅ + **E-59 门禁**(TPAFE 侧已满足) | 周期 CONVST 重触发 + `adc_task` 消费 **`tpafe5160_snapshot()`**(**2026-10-10 驱动契约已修**:E-44 FRSTDATA 有效性校验 + `init()` 首帧自检返 `-3`、E-45 帧序号取代就绪电平标志、E-58 临界区原子快照;旧 `get_buf`/`data_ready`/`clear_ready` **已删**,删除前零调用者);`adc_task.c` **已挂进 `uvprojx`**(此前 Keil/模拟器两边都不注册 = 永不编译;simulator 无任务层,只挂 Keil);**仍欠**:栈预算核算(两任务未入 `freertos.c` 栈表,建任务前后各跑 `stack_report.py`;原 S-1 栈风险已于 2026-10-10 **削链销项**,defaultTask 现静态 2776/4096 余 32%、实测 2152 B)+ 消费者本体 + 建任务走 **L1(`.ioc` 的 `FREERTOS.Tasks01`)**;**取数必须按 `docs/硬件平台/ADC通道映射说明.md`**(TPAFE `buf[2]=IA`/`buf[5]=UN`/`buf[6]=UA`;STM32 侧 ADC1 **已于 2026-10-09 生成**:`hadc1` + `MX_ADC1_Init()`、9 通道 Rank1~9、144 cycles、ADCCLK=21 MHz、软件触发,网名 ADC17=PC4 用 `ADC_CHANNEL_14`;⚠ 全仓库至今**无 `HAL_ADC_Start`** → STM32 侧一路未跑) |
| **B2** | **RS-485 采集链路实现**(消化 E-50、E-49) | B0 ✅ + **E-59 门禁**(**尚未满足**:E-50 / E-49 未修) | 双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ 协议状态机(`App/protocol/` 正是为此预留);**B0 定用途 = 对下 ModBus RTU 采集** |
**建议**:驱动契约与编译接线已在 2026-10-10 铺完 → B1 的下一步是**栈预算 + 建任务(L1)**,
再谈消费者与节拍;B2 之前必须先修 E-50 / E-49。
@@ -99,8 +101,8 @@
### 2.4 建议执行顺序(一图)
```
【阶段 B 功能】 B0 产品定义确认 ─┬─ B3 E-59 门禁固化(并行)
(当前最高优先) └─ E-58 原子快照 → B1 ADC → B2 RS485
【阶段 B 功能】 B0 产品定义确认 ✅ ─┬─ B3 E-59 门禁固化(并行)
(当前最高优先) └─ E-58 原子快照 → B1 ADC → B2 RS485
↓
【阶段 C 结构】 C1 pending 二期 ─ C3 日志管线(N-2/S-3)
─ C5 收口 ─ C6 USART1 TX-only
+1 -1
View File
@@ -14,7 +14,7 @@
|---|---|
| **目录名一律不含空格** | 空格迫使脚本/链接/CI 处处加引号,且 URL 编码形态(`UI%20设计`)极易被漏改(D-6,2026-09-25 起强制;全库已无含空格目录) |
| **按领域归入子目录** | 顶层不放散落 `.md`;新领域先建无空格子目录,再在 [`README.md`](README.md) 登记 |
| 现有目录 | `架构设计/` `子系统设计/` `网络/` `测试说明/` `代码规范/` `内存管理/` `问题记录/` `环境与部署/` `UI设计/` `硬件平台/` `芯片手册/` `images/` |
| 现有目录 | `架构设计/` `子系统设计/` `算法/` `网络/` `测试说明/` `代码规范/` `内存管理/` `问题记录/` `环境与部署/` `UI设计/` `硬件平台/` `芯片手册/` `images/` |
### 1.1b 代码目录的 README.md
+1 -1
View File
@@ -2,7 +2,7 @@
> **范围**:本仓库文档(`docs/`)里的技术配图——协议帧 / 字节布局、分层架构、依赖 / 就绪屏障、流程 / 时序 / 状态机等。
> **目标**:统一绘图方法与工具链,保证图形**精确、可复现、可 diff、可过 pre-commit**,并与既有 `tools/arch_diagram/` 生成器一致。
> **沉淀**:本流程已沉淀为 `draw-diagram` skill(`.opencode/skills/draw-diagram/SKILL.md`)——画图时直接加载该 skill 即可。
> **沉淀**:本流程已沉淀为 `draw-diagram` skill(`.dsh/skills/draw-diagram/SKILL.md`)——画图时直接加载该 skill 即可。
> **产物目录**:生成的 `.svg` 统一放 **`docs/images/`**(专门配图目录,产物入库)。
---
@@ -223,7 +223,7 @@ ST-LINK_CLI -c SWD -P "MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex" -Rst -Run
| 复位后卡死(串口日志中断在半路) | ⓞ 2026-09-19 实测案例:`-c SWD HOTPLUG -SCore -CoreReg` 读 PC/寄存器定位卡点(案例:V2 引脚固件卡在 0x08000FA0 启动循环,见 §9)——**先定位再下结论**,勿直接怀疑探针 |
| 烧录报成功但芯片行为不变 | ⓞ **先怀疑静默写入失败**(2026-09-20 实测):命令缺 `-Rst -Run`(裸 `-P` 在目标核死循环/异常时不落地)或选项字节异常(RDP 字节非法,见 §10.4)。处置:`-CmpFile` 全片比对/回读向量表首字 → 用 `reset.bat flash` 重烧 → 再 `-CmpFile` 复核;勿直接怀疑探针/接线 |
| `daemon unresponsive after auto-start`(serial_tool) | ⓞ 复位后几秒内 daemon 忙于排空日志突发;稍等后直接读 `state/serial.log` 文件验证,勿反复重试 |
| `port not found: COMx (available: COMy)`(serial_tool) | ⓞ 端口重新枚举(板子重插常见):改 `.opencode/serial_config.json` → **kill 旧 daemon 进程** → 重新 `open`(daemon 启动时缓存配置,不重启不生效) |
| `port not found: COMx (available: COMy)`(serial_tool) | ⓞ 端口重新枚举(板子重插常见):改 `.serialtest/config.json` → **kill 旧 daemon 进程** → 重新 `open`(daemon 启动时缓存配置,不重启不生效) |
| `log --grep` 查不到明明存在的标记 | ⓞ 该子命令实测不可靠(0 命中);改用直接读/`Select-String` 查 `state/serial.log` |
| SWD 通信不稳 | 不传 `SWCLK` 用默认时钟(本机实测 4MHz);检查长线/夹子接触 |
| 误改 option bytes | `-rOB` 读回现状;`-OB RDP=0` 等回写后需再复位生效;**RDP=2 会锁死调试+全片擦除,操作前务必确认** |
@@ -30,7 +30,7 @@
# ① 看本机有哪些 COM 口(不依赖 daemon;configured = 配置目标口)
& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' ports
# ② 开串口(自动拉起 daemon;端口取 .opencode/serial_config.json,也可显式指定)
# ② 开串口(自动拉起 daemon;端口取 .serialtest/config.json,也可显式指定)
& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' open
# ③ 发一条数据(文本;--hex 发字节;--nl 末尾加 CRLF)
@@ -72,7 +72,7 @@
"configured": "COM6"}
```
- `configured` 来自 `.opencode/serial_config.json` 的 `portName`;找不到它 = 板子没接/驱动没装/口号变了。
- `configured` 来自 `.serialtest/config.json` 的 `portName`;找不到它 = 板子没接/驱动没装/口号变了。
- CH340 的 `description` 通常含"USB 串行设备"字样。
### 3.2 `open` — 开串口
@@ -304,7 +304,7 @@ Get-Content 'tools\serial_tool\state\daemon.log' -Tail 30 # ② daemon 自身
## 6. 配置
唯一配置源:`.opencode/serial_config.json`
唯一配置源:`.serialtest/config.json`
```json
{
@@ -328,7 +328,7 @@ Get-Content 'tools\serial_tool\state\daemon.log' -Tail 30 # ② daemon 自身
| 现象 | 原因 | 处理 |
|---|---|---|
| `port not found: COMx (available: …)` | 板子没接 / CH340 驱动没装 / 口号变了 | 对照 `available` 列表;装 CH340 驱动;改 `.opencode/serial_config.json` 的 `portName` |
| `port not found: COMx (available: …)` | 板子没接 / CH340 驱动没装 / 口号变了 | 对照 `available` 列表;装 CH340 驱动;改 `.serialtest/config.json` 的 `portName` |
| `port busy: COMx (held by another process)` | 别的程序占着口 | `Get-Process` 找占用者关掉;或 `… serial_tool.py close` 释放本工具占的口 |
| `daemon start timeout` / `daemon unreachable` | daemon 起不来(端口冲突/解释器问题) | 看 `state/daemon.log`;`… serial_tool.py restart`;确认 18765 未被占(改 `httpPort`) |
| `daemon did not answer within Ns (busy? raise --timeout)` | 命令耗时超过 `--timeout`——daemon 活着、只是还在等(典型:显式给 `wait-idle` 带了小 `--timeout`) | 调大 `--timeout`,或不显式给(`wait-idle` 按 `--max-ms` 自动推导)。2026-10-10 起这种情况**不再**顺手拉起第二个 daemon |
@@ -3,7 +3,7 @@
> **版本**:v1.1(需求 + 设计 + 实施记录)
> **日期**:2026-09-15
> **状态**:**已实施**(S1–S6 完成;本机验收 A1–A5/A8 通过,A6/A7 正路径待 CH340 硬件接入后补验)
> **关联文档**:`串口助手使用指南.md`(命令用法/工作流/排障) · `自动化测试流程.md` · `AGENTS.md`(串口调试/自动化测试节) · `.opencode/serial_config.json`(端口单一配置源,沿用)
> **关联文档**:`串口助手使用指南.md`(命令用法/工作流/排障) · `自动化测试流程.md` · `AGENTS.md`(串口调试/自动化测试节) · `.serialtest/config.json`(端口单一配置源,2026-10-10 由 `.opencode/serial_config.json` 迁入)
> **取代**:`serial-mcp-server_串口调试.md`(实施时删除,工具历史并入本文 §12)
## 1. 背景与目标
@@ -66,7 +66,7 @@ flowchart LR
- **单文件实现**:`tools/serial_tool/serial_tool.py`(stdlib + pyserial,约 1000 行);解释器统一 `.venv\Scripts\python.exe`
- **Agent 调用式**:`& '.venv\Scripts\python.exe' 'tools/serial_tool/serial_tool.py' <命令> [参数]`(任意 cwd;state 目录按脚本位置解析,与 cwd 无关)
- **历史 = 日志文件**:Agent 用 Read/Grep 直接看历史,无需专门 API(`log` 命令只是便捷封装)
- **配置沿用** `.opencode/serial_config.json`(`portName`/`baudRate` 为默认值;新增可选字段 `httpPort`,默认 18765)
- **配置沿用** `.serialtest/config.json`(`portName`/`baudRate` 为默认值;新增可选字段 `httpPort`,默认 18765)
### 3.2 "不卡死"的归属(对用户 #3 的重新表述)
@@ -48,7 +48,7 @@
| A4 | `.map` 非测试态 | 看 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map` 的 `ER_IROM1` | 产品态基线随已接受的修复增长:262,100(初版)→ 262,836 B(10-02 round 1~6)→ 264,284 B(round 7~9)→ **264,936 B(当前,含 A2/A3/A4 补码)**;明显阶跃 ≈3.7KB 及以上(10-02 实测产品 262,836 → 套件 266,540)= 停在套件态 → 重跑 A2 |
| A5 | 全量静态门禁 | `pre-commit run --all-files` | **17/17 Passed**(2026-10-03 实测;含新增 S5 `test-cppcheck`) |
| A6 | ST-LINK 探针可见 | `& "MDK-ARM\reset.bat" list`(CLI 经 `DTU_STLINK_CLI` / PATH 解析) | 列出探针 SN `0B250D12A218303030303032` |
| A7 | 串口端口正确 | 检查 `.opencode/serial_config.json` 的 `portName` | 端口单一配置源 = 此文件(当前 COM6,2026-09-21 台架重插后由 COM7 变更);变更后先杀旧 daemon 再 `open` |
| A7 | 串口端口正确 | 检查 `.serialtest/config.json` 的 `portName` | 端口单一配置源 = 此文件(当前 COM6,2026-09-21 台架重插后由 COM7 变更);变更后先杀旧 daemon 再 `open` |
| A8 | 串口助手 daemon 可用 | `& '.venv\Scripts\python.exe' tools/serial_tool/serial_tool.py status` | 返回 JSON,`open: true/false` 可读 |
> ⚠️ **A4 的陷阱**(2026-10-02 实测):`@build` 是**增量**构建,`run_all_suites.py` 跑完
@@ -275,7 +275,7 @@ static void phaseN_run(void) {
| **`test/host/sys_clock/run_unit_test.py`** | `test/host/sys_clock/` | **L0.5 主机侧单测**:穷举 `sys_clock` 时间换算 / 星期 / 惰性再基准化 / RTC 故障降级(100 断言,S1-a) |
| **`test/host/cfg_file/run_unit_test.py`** | `test/host/cfg_file/` | **L0.5 主机侧单测**:INI 解析 / 值编解码 / 段注册 / load-save-poll 契约,内存虚拟 FS 驱动(139 断言,S1-b) |
| **`scripts/ci_local.py`** | `scripts/` | **本地跑与 CI 等价的门禁**(L0 + L0.5):自动选用装了 pre-commit 的解释器;`.map` 自适应跳过 `mem-numbers`;退出码 0/1/2 与 CI 对齐。见 §9.3 |
| `.opencode/serial_config.json` | 仓库 | **串口端口单一配置源**(当前 COM6 / 115200);换端口只改这个文件 |
| `.serialtest/config.json` | 仓库 | **串口端口单一配置源**(当前 COM6 / 115200);换端口只改这个文件 |
| `test/host/ftp_*.py`(4 个)/ `ch395f_socket_test.py` / `time_sync_server.py` | `test/host/` | PC 端交互测试工具(FTP 客户端 / socket 回显 / 对时推送) |
| `simulator/tests/*.py`(4 个) | `simulator/tests/` | LVGL 模拟器回归脚本(见 §5) |
@@ -440,7 +440,7 @@ flowchart TD
### 6.3 三条铁律
1. **采集必须先于烧录武装** —— 开串口 + clear 在烧录前完成(daemon 常驻全量日志兜底,不会漏字节;`run_boot_test.py` 已保证顺序);
2. **端口以 `.opencode/serial_config.json` 为准** —— 每次连接前先读它;
2. **端口以 `.serialtest/config.json` 为准** —— 每次连接前先读它;
3. **静默判据覆盖时间窗** —— `-SettleMs=8000`(覆盖 boot ~3-4s 自然静默间隙)、`-MaxWaitMs=30000`(整体超时兜底);
---
+4 -4
View File
@@ -20,9 +20,9 @@
| 名称 | 位置 | 作用 |
|---|---|---|
| `@build` | `.opencode/command/build.md` | 仅编译验证(0 错误 0 警告) |
| `@download` | `.opencode/command/download.md` | 编译并烧录(ST-Link) |
| `@test` | `.opencode/command/test.md` | 完整闭环:build → capture+download → verify → iterate |
| `@build` | `keil-build` skill(`.dsh/skills/keil-build/`,自带 `keil_build.py`) | 仅编译验证(0 错误 0 警告) |
| `@download` | `stlink-flash` skill(`.dsh/skills/stlink-flash/`,自带 `stlink_flash.py`) | 编译并烧录(ST-Link) |
| `@test` | `serial-boot-test` skill(`.dsh/skills/serial-boot-test/`) | 完整闭环:build → capture+download → verify → iterate |
| `test/host/run_boot_test.py` | `test/host/run_boot_test.py` | **一键闭环**:open + clear → 烧录 → 固件身份戳(从 hex 抠 `fw build:`)→ wait-idle(静默 8s/超时 30s/首字节 12s)→ 提取 `[RX]`(每行加 `[+Nms]` 时基)→ 回读校验(`reset.bat cmp`)→ verify;`--keep-out` 清旧产物;退出码 0=PASS/1=FAIL/2=采集·烧录·回读错误/3=用法错误 |
| `MDK-ARM/reset.bat` | `MDK-ARM/reset.bat` | ST-LINK CLI 封装:`flash [hex]`(烧 + `-Rst -Run`)/ **`cmp [hex]`(回读比对,2026-10-10 加)**/ 无参复位 / `halt`/`run`/`list`/`hard` |
| `tools/serial_tool/serial_tool.py` | `tools/serial_tool/` | Python 串口助手(常驻 daemon + 薄 CLI):ports/open/send/status/log/clear/wait-idle/selftest;全量日志 `state/serial.log`(20MB 自动截头) |
@@ -86,7 +86,7 @@
| `marker order violated` | 标记全中但**先后顺序颠倒** = 某步在另一步之后补做(就绪屏障失序 / 失败重试补跑)。处置:看判定打印的各标记首次行号定位;`--require-order` 只在需要强约束时启用 |
| `boot time N ms > limit` | 能开机但慢(mount 重试 / PHY 重协商 / 复位重试)。实测基线:`net init: OK` 在 **+537ms**(2026-10-10 台架);默认只报告不判(`--max-boot-ms 0`),要设门禁再给预算 |
| 端口被占用(`port busy`) | 先 `serial_tool.py close` 或 `restart`;检查其他程序占用;Keil ST-Link 不占 COM |
| 配置里的 COM 号失效(换口/换机) | `serial_tool.py ports` 现回 `configured_present` + `hint`(系统里只有一个候选时直接给出口名),`open` 的报错里也带 `[hint: ...]`;确认后只改 `.opencode/serial_config.json` |
| 配置里的 COM 号失效(换口/换机) | `serial_tool.py ports` 现回 `configured_present` + `hint`(系统里只有一个候选时直接给出口名),`open` 的报错里也带 `[hint: ...]`;确认后只改 `.serialtest/config.json` |
| 日志中无 UI 相关输出 | 见下节「UI 自动化」 |
| 日志出现 `[ERR]` 行 | 固件错误级日志(`DBG_ERROR`),默认 Forbidden 会判 FAIL:按 TAG 查对应模块的 `docs/问题记录/*_Trap_Records.md`;若属测试套件的**预期**错误(守卫负路径、非法名校验等),用 `--forbidden` 放宽 |
@@ -184,7 +184,7 @@ python tools/font_gen/extract_cn.py # 任意 python3:
| 项 | 要求 | 说明 |
|---|---|---|
| Python 串口助手 | `tools/serial_tool/serial_tool.py`(仓库内置,.venv + pyserial) | 常驻 daemon + 薄 CLI + 全量日志文件;无需单独安装,`pip install -r requirements.txt` 即就绪 |
| 调试串口 | USART1(PA9 TX / PA10 RX),115200 8N1 | **端口单一配置源 `.opencode/serial_config.json`**(本机 COM6);换端口只改这个文件 |
| 调试串口 | USART1(PA9 TX / PA10 RX),115200 8N1 | **端口单一配置源 `.serialtest/config.json`**(本机 COM6);换端口只改这个文件 |
| 一键测试 | `test\run_boot_test.py`(即 `@test`,`& '.venv\Scripts\python.exe' test/host/run_boot_test.py`) | 开串口 + 清日志 → 烧录 → wait-idle(静默 8s/超时 30s)→ 提取 → 标记校验;默认端口取 `serial_config.json` / 115200,退出码 0=PASS / 1=FAIL / 2=采集或烧录错误 / 3=用法错误 |
> 采集 = 端口常开 + daemon 全量日志(`tools/serial_tool/state/serial.log`),无采集窗口/first-byte/EOF 重试仪式。
@@ -347,7 +347,7 @@ pre-commit run --all-files # 首次全库基线扫描
& '.venv\Scripts\python.exe' tools\serial_tool\serial_tool.py ports # 查 COM 号
```
把查到的端口写入 `.opencode\serial_config.json` 的 `portName`(唯一配置源,换口只改这里)。
把查到的端口写入 `.serialtest\config.json` 的 `portName`(唯一配置源,换口只改这里)。
**第 10 步:冒烟验证**(全过 = 环境就绪;前置:§2.1.1 的 `DTU_*` 变量已设置——未设时构建脚本会明确报出缺哪个变量及设置方法)
@@ -372,7 +372,7 @@ pre-commit run --all-files
- [ ] `git clone` 仓库 → `pre-commit install`;cppcheck 入 PATH
- [ ] 建 `.venv` 并 `pip install -r requirements.txt`
- [ ] `npm i -g lv_font_conv`
- [ ] 写好 `.opencode/serial_config.json`(本机 COM 口),`serial_tool selftest` PASS
- [ ] 写好 `.serialtest/config.json`(本机 COM 口),`serial_tool selftest` PASS
- [ ] 下载器(ST-Link 等)USB 驱动已装,Keil `Options for Target → Debug` 驱动一致
- [ ] 第 10 步冒烟验证全部通过(含 `test/host/watchdog/run_unit_test.py` → PASSED)
- [ ] (可选)Graphviz 已装(引用关系图渲染:`winget install Graphviz.Graphviz`,见 §2.8)
@@ -614,7 +614,7 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
| pip 装依赖报 UnicodeDecodeError | `requirements.txt` 含中文注释 | 保持该文件**纯 ASCII**(pip 按 GBK 代码页解码) |
| 字体生成 / 转 PNG 报缺模块 | 误用 PATH 里的 msys64 python | 一律用 `.venv\Scripts\python.exe` |
| 内容页回归 exit 2(参考缺失) | `tests/ref/` 是本地生成物、不入库 | 先 `check_content_pages.py --update` 生成参考,再跑回归 |
| 串口采集不到 / 端口占用 | COM 号变化 / 上一进程未释放 | 改 `.opencode/serial_config.json`;`serial_tool.py ports` 查实际端口,`open` 占用 ≤1s 报 `port busy` |
| 串口采集不到 / 端口占用 | COM 号变化 / 上一进程未释放 | 改 `.serialtest/config.json`;`serial_tool.py ports` 查实际端口,`open` 占用 ≤1s 报 `port busy` |
| 烧录失败 | 下载器未选 / USB 驱动缺失 | Keil `Options for Target → Debug` 选对驱动;安装下载器 USB 驱动 |
| 下载报 Flash 算法 / FLM 文件找不到 | 未安装 `Keil::STM32F4xx_DFP` pack(FLM 来自 pack 目录,不在仓库) | Pack Installer 安装该 pack 后重新下载 |
| UV4 启动弹 license 窗口 / 无法编译 | 90 天评估 license 过期或未激活 | `Options for Target → License` 查看/输入;长期使用购买正式 license |
+188
View File
@@ -0,0 +1,188 @@
> 从《项目详细分析-交流采样与有效值计算》中提取扩展,配图讲解傅氏算法(全周波傅里叶算法)的原理与工程实现。
> 工程背景:CLS100 DTU 保护测控装置,每周波 20 点采样(1000Hz @ 50Hz),保护有效值/相量由 `GlobalUnit/CalFFTVecFull.c` 全周傅氏计算。
> 公式为 LaTeX 排版,需 Markdown 预览(VS Code / Typora 等)渲染。
---
## 1. 一句话思想
**把一周波的采样序列分别和"标准正弦、标准余弦"做内积(投影)**:正弦分量投影到正弦上得实部,余弦分量投影到余弦上得虚部——用两根已知相位的"标杆"去量未知信号里基波的幅值和相位。数学上这就是**单频 DFT**(只计算 $k=1$ 那一根谱线)。
![投影原理](https://lsky.bitnasdaq.vip/gqvbns.png)
图中含 20% 五次谐波和 1V 直流的畸变波形,经两次投影后仍精确还原出基波:幅值 57.70V、相角 30.0°——谐波和直流在投影中"自己抵消了",这是傅氏算法的全部魔力,第 3 节用面积图解释为什么。
## 2. 数学推导
### 2.1 连续形式
设周期信号 $x(t)$,基波角频率 $\omega = 2\pi f$,其基波分量:
$$
x_1(t) = A_1\sin(\omega t + \varphi_1) = a_1\sin(\omega t) + b_1\cos(\omega t)
$$
在一个整周波 $T$ 上:
$$
a_1 = \frac{2}{T}\int_0^T x(t)\sin(\omega t)\,\mathrm{d}t
\qquad
b_1 = \frac{2}{T}\int_0^T x(t)\cos(\omega t)\,\mathrm{d}t
$$
### 2.2 离散形式(工程实现)
一个周波采 $N$ 个点 $x(0),\dots,x(N-1)$,积分 → 求和:
$$
a_1 \approx \frac{2}{N}\sum_{k=0}^{N-1} x(k)\,\sin\!\left(\frac{2\pi k}{N}\right)
\qquad
b_1 \approx \frac{2}{N}\sum_{k=0}^{N-1} x(k)\,\cos\!\left(\frac{2\pi k}{N}\right)
$$
幅值、相位、有效值:
$$
A_1 = \sqrt{a_1^2 + b_1^2}
\qquad
\varphi_1 = \arctan\!\frac{b_1}{a_1}
\qquad
U = \frac{A_1}{\sqrt{2}}
$$
### 2.3 本项目的写法:把 $\sqrt{2}$ 藏进系数表
`GIUnit/GLobalFunc.c` L337 的系数表预乘了 $\sqrt{2}/N$:
$$
g\_fFFTSin20[k] = \sin\!\left(\frac{2\pi k}{N}\right)\cdot\frac{\sqrt{2}}{N}
$$
于是累加结果直接是**有效值相量**分量:
$$
f_{Re} = \sum_{k=0}^{N-1} x(k)\,\sin\!\left(\frac{2\pi k}{N}\right)\frac{\sqrt{2}}{N} = \frac{a_1}{\sqrt{2}}
\qquad
f_{Im} = \frac{b_1}{\sqrt{2}}
$$
$$
f_{AmSQ} = \sqrt{f_{Re}^2 + f_{Im}^2} = \frac{A_1}{\sqrt{2}} = U
\quad (\text{直接就是有效值,无需再除}\ \sqrt{2})
$$
## 3. 为什么能滤除直流和谐波 —— 正交性
整周波上三角函数系正交:
$$
\int_0^T \sin(\omega t)\,\mathrm{d}t = 0,
\qquad
\int_0^T \sin(m\omega t)\sin(\omega t)\,\mathrm{d}t = 0 \quad (m \in \mathbb{Z},\ m \neq 1)
$$
![正交性](https://lsky.bitnasdaq.vip/BGNWjf.png)
看图最直观:**蓝=正面积,红=负面积**。
| 信号成分 × sinθ | 面积结果 | 结论 |
| --------------- | ------------ | ----------- |
| 直流 1V | 红蓝完全抵消 | **完全滤除** |
| 3、5、…次整数谐波 | 红蓝完全抵消 | **完全滤除** |
| 基波 | 正面积占优,净值 ≠ 0 | **被提取** |
| 衰减直流(非严格周期) | 近似抵消,有残余 | 大部分滤除 |
| 非整数次谐波(如 2.7 次) | 不严格抵消 | 按"泄漏"比例部分反映 |
**前提是数据窗恰好一个整周波**。窗长偏离整周波(系统频率漂移),正交性被破坏,直流和 2 次谐波就会漏进测量——这就是本工程用"软件测频 + 片内 EHRPWM 调频"严格锁定 20 点/周波的原因。
## 4. 频域视角:一个梳状带通滤波器
把整周数据窗对基波做相关,等效为滤波器,其频率响应:
$$
|H(f)| = \left|\frac{\sin\!\big(\pi (f/f_1 - 1)\big)}{N\,\sin\!\big(\pi (f/f_1 - 1)/N\big)}\right|
$$
![频率响应](https://lsky.bitnasdaq.vip/I67YT9.png)
- 中心 50Hz 通带,增益 1;
- **零点恰好落在 0Hz(直流)和 100、150、200…Hz(全部整数谐波)**;
- 窗越长(周波数越多)主瓣越窄、选择性越好,但时延越大。
"一窗 = 一个整周波"是保护领域在**速度**与**滤波**之间的经典折中,IEC 标准对保护动作时间的考核也按全周波算法进行。
## 5. 滑动窗:每 1ms 一个新有效值
数据窗定义为"以当前时刻为终止的前一周波"。每来一个新采样点(1ms),窗口滑动一格、丢弃最老点、20 点全部重算("暴力法"):
![滑动窗](https://lsky.bitnasdaq.vip/R6a1YN.png)
- **暴力法**:每点重算 20 次乘加 ×2(sin/cos),实现简单、无累积误差;
- **迭代法**(`CalIterFFTVecFull.c`,本工程未启用):增量更新
$$
S_{\text{new}} = S_{\text{old}} - x_{\text{old}}\cdot\sin\!\left(\frac{2\pi k}{N}\right) + x_{\text{new}}\cdot\sin\!\left(\frac{2\pi k}{N}\right)
$$
每次只 2 次乘加,但浮点舍入误差随时间累积,需定期用暴力法清洗。本工程 CPU 余量足够,选暴力法。
## 6. 数值算例:三种算法各测到什么
同一组 20 点采样(57.7V 基波 + 20% 五次谐波 + 1V 直流):
![数值算例](https://lsky.bitnasdaq.vip/A7dnSv.png)
| 算法 | 读数 | 说明 |
| -------------------------------- | ---------------- | ------------------------------------------------ |
| 直流平均 | 1.00 V | 只剩直流 |
| 真有效值 $\sqrt{\overline{x^2}}$ | ≈58.85 V | $\sqrt{57.7^2 + 11.5^2 + 1^2}$,谐波直流全算进去 |
| **全周傅氏** | **57.70 V ∠30°** | 精确回到基波,且给出相位 |
保护要的是"基波有效值 + 相位"(方向元件、同期、功率都要相角),且故障时短路电流含衰减直流——傅氏一个整周波积分把它抹掉,真 RMS 则会虚高导致误动。**这就是保护偏爱傅氏、计量偏爱真 RMS 的根本原因**(方法全景见主文档附录C)。
## 7. 工程实现:本工程数据流
![工程实现流程](https://lsky.bitnasdaq.vip/DFUBED.png)
核心循环只有 6 行(`GlobalUnit/CalFFTVecFull.c` L392-405):
```c
for( dwDot=0; dwDot<dwCalRate; dwDot++) {
fVal = pfCalUse[dwAdr]; // 第n个采样点(已乘通道系数)
fRe += fVal * pfFFTSin[dwFFTCnt]; // Σ x·sin·(√2/N)
fIm += fVal * pfFFTCos[dwFFTCnt]; // Σ x·cos·(√2/N)
dwAdr += dwLen; // 滑到下一个采样点
}
Fun_VectorAmp(ptVecSave); // fAmSQ = √(fRe²+fIm²) = 有效值
```
配套工程细节:
- **任意次谐波**:系数索引步进量从 1 改为 $k$ 即算 $k$ 次谐波相量 $f_{Re}(k)=\sum x(n)\sin\!\big(\tfrac{2\pi k n}{N}\big)\tfrac{\sqrt2}{N}$,同一循环复用于 2 次/5 次谐波(涌流判别、选线);遥测对 $k=1\sim11$ 全算再方和根 $U_{\text{rms}}=\sqrt{\sum_{k=1}^{11}U_k^2}$;
- **双区切换**:结果写入向量区 `tVectorRly[2][N]` 的计算区,算完原子交换"计算区/使用区"指针,保护元件读使用区,无锁并发;
- **4 个实例**:C01 基波 I/U、C02 零序基波、C03 二次谐波、C04 五次谐波(`APP/CLS100_Dsp/InstCalCell.c`)。
## 8. 全周波 vs 半周波
| | 全周傅氏(本工程用) | 半周傅氏(代码有但未启用) |
| -------- | -------------------- | ---------------------------------- |
| 数据窗 | 1 个周波(20 点) | 半个周波(10 点) |
| 滤波能力 | 直流 + 全部整数谐波 | 半周相减消直流和偶次谐波,奇次保留 |
| 速度 | 1 周波 | 快一倍 |
| 精度 | 高 | 低(受奇次谐波影响) |
本工程 `CN_ANA_DIF=FALSE`,半周波/差分组件全部注释掉——DTU 场景更看重精度和抗衰减直流能力。
## 9. 常见疑问
**Q1:傅氏算的是有效值还是幅值?**
取决于系数表。标准系数 $2/N$ 得幅值 $A_1$;本工程预乘 $\sqrt2/N$ 直接得有效值 $U=A_1/\sqrt2$。看 `GLobalFunc.c` 系数表注释"折算成有效值"即可确认。
**Q2:和 FFT 什么关系?**
傅氏算法 = 只算 $k=1$(或少数几次)谱线的 DFT。FFT 是同时算全部 $N$ 根谱线的快速算法。保护只需要基波(+少数谐波),逐次 DFT 比 FFT 更省算力。
**Q3:频率偏离 50Hz 还准吗?**
本工程靠闭环调频保证窗长恒等于实际周波(20 点/周波随频率微调),所以准。固定 1000Hz 采样不调整的方案,频偏 ±2Hz 时幅值误差约 1~2% 且出现相角偏差。
**Q4:衰减直流滤不干净怎么办?**
整周波对"严格周期"信号才完全正交,衰减直流有残余。对策:加长数据窗(1.5~2 周波)、微分/余弦滤波改进傅氏、或最小二乘把 $A\mathrm{e}^{-t/\tau}$ 作为未知量一并回归。
@@ -0,0 +1,436 @@
# 继电保护功能复现规划
> **定位**:把参考系统(CLS100 DTU 保护测控装置)的**继电保护链路**在本项目(STM32F4-Base DTU 平台)上分层复现的**总规划**——给出要实现的功能、性能指标、定值参数、平台适配口径与分阶段路线图。
> **参考来源**:`D:\Code\DTU\参考资料\huaiyuan\huaiyuan\Scatter_P_HV03.01_SV01.01\项目分析文档\04-算法与采样专题\ADC采集至数据使用全流程详解`(同专题另有《项目详细分析-交流采样与有效值计算》《傅氏算法详解》《项目详细分析-阶段6-继电器保护单元分析》)。
> **阅读前提**:先读 `docs/算法/傅氏算法详解.md`(算法原理)与 `docs/硬件平台/ADC通道映射说明.md`(采样通道权威口径)。
> **相关文档**:`docs/产品需求/产品需求设计文档.md`、`docs/待处理内容.md`、`docs/内存管理/RAM使用分析与优化方案.md`。
> **状态**:规划稿——保护链路本体尚未实现;其前置的 ADC 采集链路(`adc_task`)当前为空桩,见登记簿 **P1-1 / B1**。
---
## 1. 背景、目标与范围
### 1.1 参考系统(CLS100)保护实现概览
| 维度 | 参考实现 |
| ------ | ------------------------------------------------------------------------------------ |
| 硬件平台 | TI OMAP-L138(ARM926EJ-S + C674x DSP **双核**),无 FPGA |
| 操作系统 | VxWorks |
| 核心分工 | **DSP 核**跑保护算法(1 ms 中断节拍),**ARM 核**跑管理 / 通信 / 人机 |
| 采样率 | 50 Hz 系统,每周波 **20 点** → 保护采样率 **1000 Hz**(`CN_SAM_HERTZ=50`、`CN_SAM_RATE=20`) |
| 内部总线节拍 | **4000 Hz**(80 点/周波,为保护采样率的 4 倍,`CN_WAVE_RATIO=4`),供录波/高频量使用 |
| 保护相量 | **全周傅氏**(全周 DFT),每次刷新 15 个基波相量 + 3 个二次谐波相量 + 1 个五次谐波相量,**每 1 ms 重算** |
| 遥测有效值 | 每 **200 ms** 对 k=1~9 次谐波做 DFT 再**方和根**(`CN_NUM_YCHUMWAVE=9`),得"真有效值"轨 |
| 保护元件 | **89 个模块**(`RelayUnit/PRS_*.c`),统一 `tagPRS_XXX` 接口(Init / Main / 执行函数) |
| 并发机制 | 采样**双缓冲**(2 周波 = 40 点)+ 相量**双区指针原子交换** + 遥测 **0x55/0xaa 计算/拷贝标志协议** |
| 调度 | **时间片表**(单点 / 2 点 / 4 点 / 8 点)按 `g_dwSchedulerCnt` 位掩码分发 |
| 定值 | EEPROM 存定值 + 折算系数(`wCoeEEP` / `wCoeCal` / `wCoeRet`),TLV 通道;遥测微调 TLV10(±10%,0.1% 步长) |
| 有效值口径 | 保护用**基波有效值**(`CN_ANA_VEC_SQRT=FALSE`),计量/遥测用**谐波方和根** |
> 数据全链路(采样 → 内部总线 → 缓冲 → 预处理 → 算法 → 存储 → 使用)见参考文档《ADC采集至数据使用全流程详解》§5~§7;傅氏原理与系数折算见 `docs/算法/傅氏算法详解.md`。
### 1.2 本项目现状
| 维度 | 现状 |
| ------ | -------------------------------------------------------------------------------------------------------------------------- |
| 硬件平台 | STM32F407ZGTx(Cortex-M4F,168 MHz,**单核**,硬件 FPU) |
| 操作系统 | 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` **空桩**;无周期 CONVST 重触发;STM32 侧无 `HAL_ADC_Start` |
| 保护算法层 | **完全缺失**(无傅氏、无保护元件、无出口、无定值模型) |
| 已知硬件缺陷 | **N-18**:8 路电气量分属两片转换器 → V0.1 上禁止跨转换器做相位/功率/矢量运算 |
### 1.3 复现范围界定
**本期做(保护链路最小可用集)**
1. 采样与预处理:周期采样触发、通道语义映射、标定、有效性校验、等周波调频、自产零序。
2. 相量计算:全周傅氏基波/谐波相量、线/负序/零序合成、双区交换、每 1 ms 刷新。
3. 保护元件:三段式相间过流、三段式零序过流、过负荷、过压/欠压、过频/低频、零序过压、涌流制动、PT/CT 断线、母线接地告警、故障启动。
4. 出口与记录:跳闸/告警出口、SOE/动作记录、定值模型与 cfg_file 集成、自检闭锁。
**本期不做(延后或依赖条件)**
- 方向元件 / 功率 / 功率因数 / 对称分量类运算——受 **N-18** 制约,V0.1 上取子板计量结果,或待 V0.2 硬件改版后实现。
- 重合闸、馈线自动化(FA)等 FTU 专有功能——视产品定义(B0)。
- 双核 / DSP 拆分、VxWorks 特有机制、IEC 61850、完整故障录波——与单核 FreeRTOS 平台不匹配。
- 参考系统 89 个模块的**全量**移植——按需裁剪,只复现本产品定义的元件集。
### 1.4 前置依赖与阻塞项
| 依赖 | 说明 | 状态 |
| --------------- | ------------------------------------------------------------ | ------------------------ |
| **B0 产品定义** | 采集是否持续 / 采样率与通道 / 转发目标 / 保护元件清单——决定 B1 与保护层的**规模** | ✅ 已确认(2026-10-10,见 §1.5) |
| **B1 ADC 采集链路** | 周期 CONVST + `adc_task` 消费 `tpafe5160_snapshot()` + 建任务 + 栈预算 | ⬜ 未实现(驱动契约已就绪) |
| **N-18 硬件缺陷** | V0.1 跨转换器无同一时刻性 → 限定 V0.1 可实现的保护范围 | ⚠️ 硬件改版项(V0.2) |
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | ⬜ 待做 |
---
## 2. 总体架构设计
### 2.1 数据全链路(分层)
复现后的保护链路分为 6 层,自下而上:
| 层 | 职责 | 参考对应 | 本项目落点(拟) |
| ------------- | ----------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ |
| **L0 采样驱动** | 触发转换、读出原始码值 | AD 芯片 + 总线 | `Drivers/BSP/TPAFE5160/` + STM32 ADC1 HAL |
| **L1 采集与预处理** | 快照取数、语义映射、标定、有效性校验、等周波调频、自产零序 | `DataPreRecv` / `RealDataMerge` / `CalSoftFr` / `GetZoreSamData` | `adc_task` + `App/algo/`(拟) |
| **L2 相量计算** | 全周傅氏基波/谐波、线/负序/零序合成、双区交换 | `CalFFTVecFull` / `CalfLineVec` / `CalfNegVec` | `App/algo/`(拟) |
| **L3 保护元件** | 各保护判据(过流/零序/过压/频率/…) | `RelayUnit/PRS_*.c` | `App/protect/`(拟) |
| **L4 出口与信号** | 跳闸/告警出口、信号灯 | `TripKO` / KO | `App/protect/` + BSP 出口驱动 |
| **L5 记录与上送** | SOE/动作记录、UI 显示、遥测上送 | 记录模块 + 通信 | `App/log/` + `Drivers/BSP/UI/` + `App/protocol/` |
> **分层原则**:L1 只做"数"(码值→工程量),L2 只做"相量"(工程量→复相量),L3 只做"判据"(相量 + 定值→布尔),L4/L5 只做"动作与留痕"。**算法与 I/O 分离**,使 L2/L3 成为主机侧单元测试(L0.5)的天然适格对象(落实登记簿 **A-4**)。
### 2.2 任务与中断模型(映射到 STM32F4 + FreeRTOS)
参考系统用 DSP 的 1 ms 中断串起整条保护链。本项目为单核 FreeRTOS,采用"**中断触发 + 任务计算**"模型:
| 角色 | 载体 | 周期 | 优先级(拟) | 说明 |
| ------ | --------------------------- | -------- | ------- | -------------------------------------- |
| 采样节拍 | 定时器中断(TIMx) | **1 ms** | 最高(ISR) | 产生 CONVST 脉冲;ISR 内只置事件/计数,不做重运算 |
| 采集与预处理 | `adcTask` | 1 ms | 高 | `tpafe5160_snapshot()` 取数 → 标定 → 存入采样环 |
| 相量计算 | `adcTask` 内联 或 `algoTask` | 1 ms | 高 | 全周傅氏 → 相量双区交换 |
| 保护判据 | `protectTask` | 1 ms | 高 | 各保护元件 Init/Main → 出口 |
| 遥测与显示 | 复用 `uiTask` / 新增 `measTask` | 200 ms | 中 | 谐波方和根、死区/平滑、UI 与上送 |
| 记录 | `defaultTask`(已有) | 事件驱动 | 低 | SOE/动作记录落 `sys_log` |
> **铁律**:`adcTask` / `protectTask` 的 FS 路径若触碰存储,必须沿用卷锁 try 语义(`vol_lock_wait(0)`),且每任务纳入看门狗 `required_mask` 心跳(见 `docs/子系统设计/看门狗设计说明.md`)。**保护节拍任务不得阻塞在存储 I/O 上**——记录走队列异步落盘。
### 2.3 并发与数据一致性
参考系统用三重机制保证"采样—相量—保护"三段并发无锁:**采样双缓冲 + 相量双区指针交换 + 遥测标志协议**。本项目沿用同一思想,并复用已有的原子快照范式:
| 机制 | 参考做法 | 本项目做法 |
| ---- | -------------------------------------- | ------------------------------------------------------------------------------ |
| 采样缓冲 | 双缓冲(2 周波 = 40 点),写/读分属两区 | 环形缓冲 + **序号**(`tpafe5160_frame_seq()` 已有)+ 临界区快照,防撕裂 |
| 相量区 | `tVectorRly[2][N]`,算完**原子交换**计算区/使用区指针 | 双区结构体 + 指针/索引原子切换(单核下用临界区或 `__atomic`) |
| 遥测拷贝 | 0x55/0xaa 计算/拷贝握手标志 | 快照 + 序号,或 FreeRTOS 事件标志握手 |
| 取数契约 | —— | **只能用 `tpafe5160_snapshot()`**(`AGENTS.md` 铁律),不用已删除的 `get_buf` / `data_ready` |
### 2.4 与现有子系统的接口
| 保护层需求 | 复用现有能力 | 落点 |
| --------- | ------------------------------------ | ------------------------------------ |
| 定值存取 | **cfg_file 配置引擎**(替代参考的 EEPROM 定值文件) | `App/cfg/cfg_file.c` + 新增定值段 |
| 动作/SOE 记录 | `sys_log`(`/log/run.log`)与运行记录 | `App/log/` |
| 保护定值/测量显示 | 远端显示 UI(`ui_page_ac` 已有 24 行占位) | `Drivers/BSP/UI/ui_page_ac.h` |
| 遥测/事件上送 | 网络栈 + `App/protocol/`(协议预留) | `App/protocol/` + `Drivers/BSP/NET/` |
| 时间戳 | `sys_clock`(RTC 基准) | `App/util/sys_clock.c` |
| 自检留痕 | `selftest.log` / 自检框架 | `App/log/` |
---
## 3. 功能规划(分层清单)
> 每项给出:**功能点 / 关键参数 / 完成判据**。状态列 ⬜ 未实现。
### 3.1 L1 采集与预处理
| # | 功能点 | 关键参数 | 完成判据 | 状态 |
| ---- | ------------------ | ------------------------------------------- | --------------------------------------------------------------- | -- |
| L1-1 | 周期 CONVST 重触发 | 1000 Hz(与保护节拍同源) | 示波器见 U3 `BUSY` 连续脉冲;`tpafe5160_frame_seq()` 持续递增 | ⬜ |
| L1-2 | TPAFE 快照消费 | 8 通道 / 帧 | `adc_task` 每拍调 `tpafe5160_snapshot()`,返回 1/0/-1 有处理 | ⬜ |
| L1-3 | STM32 ADC1 启动与扫描 | 9 通道、144 cycles、软件触发 | 全库出现 `HAL_ADC_Start`;9 通道码值随注入变化 | ⬜ |
| L1-4 | 通道语义映射 | 见 `docs/硬件平台/ADC通道映射说明.md`(**按语义取数,不写死下标**) | `UA→buf[6]`、`UN→buf[5]`、`IA→buf[2]`;STM32 侧 `UB→ADC_CHANNEL_14` | ⬜ |
| L1-5 | 通道标定(一次系数 + 零漂) | 每通道 `k`、`b`;系数定点 `2^10` | 注入标准源,读数误差 ≤ 目标精度 | ⬜ |
| L1-6 | 采样有效性校验 | FRSTDATA 跳变、帧序号单调、丢帧计数 | 芯片静默/丢帧被检出并置告警 | ⬜ |
| L1-7 | 等周波采样(软件测频 + 调频闭环) | 20 点/周波;测频范围建议 **45~55 Hz**(参考 40.5~60.5) | 频率偏移 ±2 Hz 时幅值误差 ≤ 1% | ⬜ |
| L1-8 | 自产零序合成 | `3I0 = Ia+Ib+Ic`;外部/自产可选(参考 TLV13) | 零序通道可切换来源,值正确 | ⬜ |
| L1-9 | 二次谐波/五次谐波提取入口 | k=2(涌流)、k=5(选线) | 相量层可产出对应谐波相量 | ⬜ |
> ⚠️ **N-18 约束**:L1-4 中 `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 一致 | ⬜ |
| L2-2 | 基波相量实例 | 4 个实例:C01 基波 I/U、C02 零序基波、C03 二次谐波、C04 五次谐波 | 每实例输出 `{fRe, fIm, fAm, fAmSQ}` | ⬜ |
| L2-3 | 相量有效值输出 | `fAmSQ = √(fRe²+fIm²)` 直接为**有效值**(系数已折算) | 标准源读数 = 设定有效值 | ⬜ |
| L2-4 | 相位输出 | `φ = atan2(fIm, fRe)` | 相位误差 ≤ 目标值 | ⬜ |
| L2-5 | 线/负序/零序合成 | 线电压 `Uab=Ua−Ub` 等;负序 `3U2`/`3I2`;零序 `3U0`/`3I0` | 合成相量可复用于保护元件 | ⬜ |
| L2-6 | 每 1 ms 滑动窗刷新 | 每来新点,窗滑动一格、20 点重算(暴力法) | 相量每拍更新 | ⬜ |
| L2-7 | 双区指针原子交换 | 计算区/使用区切换 | 保护元件读使用区,无撕裂 | ⬜ |
| L2-8 | 遥测谐波轨(可选) | k=1~9,方和根 `√(ΣHk²)` | 与基波轨并行,供 UI/上送 | ⬜ |
> **双轨有效值**:保护要"基波有效值 + 相位"(抗衰减直流、抗谐波误动);计量/遥测要"真有效值"(谐波方和根)。两者**不可混用**——这是参考系统 `CN_ANA_VEC_SQRT=FALSE` 与遥测谐波轨并存的根本原因。
### 3.3 L3 保护元件
采用参考系统的**统一接口模式**:每元件一个 `tagPRS_XXX` 配置结构(定值号、模拟通道号、KI/KO、标志位、校验和)+ `Init` / `Main`(判据)/ 出口函数。
**核心集(P0/P1)**
| # | 元件 | 判据要点 | 关键定值 | 状态 |
| ---- | ------- | ----------------------- | ---------------- | -- |
| L3-1 | 三段式相间过流 | 相电流基波 > 定值,经延时出口;返回系数滞回 | Ⅰ/Ⅱ/Ⅲ 段电流 + 延时 | ⬜ |
| L3-2 | 三段式零序过流 | 零序电流 > 定值,经延时出口 | Ⅰ/Ⅱ/Ⅲ 段零序电流 + 延时 | ⬜ |
| L3-3 | 过负荷 | 相电流 > 定值,告警/跳闸可整定 | 过负荷电流 + 延时 | ⬜ |
| L3-4 | 过压 / 欠压 | 相/线电压越限,经延时出口 | 过压定值、失压定值 + 延时 | ⬜ |
| L3-5 | 过频 / 低频 | 频率越限,经延时出口 | 过频、低频定值 + 延时 | ⬜ |
| L3-6 | 零序过压 | 零序电压 > 定值 | 零序过压定值 + 延时 | ⬜ |
**扩展集(P2/P3)**
| # | 元件 | 判据要点 | 状态 |
| ----- | ---------- | --------------------- | -- |
| L3-7 | 涌流制动 | 二次谐波占比 > 制动系数,闭锁差动/过流 | ⬜ |
| L3-8 | PT 断线 | 电压突变/负序判据,闭锁电压类保护 | ⬜ |
| L3-9 | CT 断线 | 电流不平衡判据,闭锁 | ⬜ |
| L3-10 | 母线接地告警 | 零序电压 + 零序电流组合 | ⬜ |
| L3-11 | 故障启动(波形启动) | 突变量启动,触发录波/启动元件 | ⬜ |
| L3-12 | 无压/无流闭锁 | 低电压或低电流时闭锁过流 | ⬜ |
**延后集(受 N-18 / 产品定义制约)**
| # | 元件 | 制约 |
| ----- | ----------- | -------------------- |
| L3-13 | 方向元件 / 功率方向 | 需跨转换器相位一致 → V0.1 不可做 |
| L3-14 | 重合闸 | FTU 专有,视 B0 产品定义 |
| L3-15 | 手动跳闸 / 遥控 | 依赖出口硬件与协议定义 |
### 3.4 L4 出口与记录
| # | 功能点 | 说明 | 状态 |
| ---- | --------- | --------------------- | -- |
| L4-1 | 跳闸出口(KO) | 判据满足 → 驱动出口继电器,带保持/脉冲 | ⬜ |
| L4-2 | 告警出口 / 信号 | 告警类动作驱动信号灯/继电器 | ⬜ |
| L4-3 | 出口自检 | 出口回路检测(若有回读) | ⬜ |
| L4-4 | SOE 记录 | 带时标的事件顺序记录 | ⬜ |
| L4-5 | 动作记录 | 保护动作/返回记录,落 `run.log` | ⬜ |
| L4-6 | 故障录波(可选) | 4000 Hz 内部节拍预留 | ⬜ |
### 3.5 L5 自检与闭锁
| # | 功能点 | 说明 | 状态 |
| ---- | ------ | ----------------------------------- | -- |
| L5-1 | 定值校验和 | `tagPRS_XXX` 的 `dwTagSum` 自检,定值非法闭锁 | ⬜ |
| L5-2 | 采样通道自检 | 通道码值越界/静默检出 | ⬜ |
| L5-3 | 硬件自检 | 出口回路、电源、时钟 | ⬜ |
| L5-4 | 自检失败闭锁 | 任一项失败 → 闭锁相关保护并告警 | ⬜ |
---
## 4. 性能指标
### 4.1 实时性
| 指标 | 目标值 | 依据 |
| ------ | ---------------------------- | ------------------------------ |
| 保护节拍 | **1 ms** | 参考 `CN_PROTECT_PERIOD=1000 µs` |
| 保护采样率 | **1000 Hz**(20 点/周波 @ 50 Hz) | 全周傅氏窗长 |
| 相量刷新周期 | **1 ms** | 每来一点重算 |
| 遥测刷新周期 | **200 ms** | 参考遥测链周期 |
| 出口动作时间 | ≥ 1 周波(20 ms)算法窗 + 定值延时 | 全周波算法固有延时 |
| 内部总线节拍 | 4000 Hz(80 点/周波) | 参考 `CN_WAVE_RATIO=4`(本项目按需裁剪) |
### 4.2 精度
| 指标 | 目标值 | 说明 |
| ------ | --------------------------- | ------------------------- |
| 基波幅值误差 | ≤ 1%(频偏 ±2 Hz 内) | 依赖等周波采样 |
| 相位误差 | ≤ 目标角误差(依产品定义) | 依赖调频闭环 |
| 测频范围 | 建议 45~~55 Hz(参考 40.5~~60.5) | `CN_HERTZ_SOFTFR_MIN/MAX` |
| 定值折算 | 定点系数 `2^10` | 与参考一致 |
| 遥测微调 | ±10%,0.1% 步长(TLV10) | 参考口径 |
> **误差来源与预算**(参考《ADC采集至数据使用全流程详解》§12):采样量化(TPAFE LSB ≈ 152.6 µV)、通道标定残差、窗长偏离整周波(频偏)、系数定点舍入。前三项决定可达精度,最后一项可忽略。
### 4.3 算力与内存预算
| 项 | 估算 | 说明 |
| -------- | ------------------------------- | -------------------------------------- |
| 傅氏乘加 | 20 点 × 2(sin/cos)× 相量数 / 拍 | 参考用暴力法(CPU 余量足够);本项目 168 MHz + FPU 需实测 |
| 相量区 RAM | `tVectorRly[2][N] × sizeof(相量)` | 双区 + 4 实例 |
| 采样缓冲 RAM | 40 点/通道 × 通道数 × 字宽 | 双缓冲 2 周波 |
| 定值区 RAM | 元件数 × 定值项 × 字宽 | 可由 cfg_file 载入 |
| 任务栈 | `adcTask` / `protectTask` 待核算 | 建任务前后各跑 `scripts/stack_report.py` |
> ⚠️ **改内存相关代码后必须刷新快照**:`@build` 出 `.map` 后跑 `scripts/check_mem_numbers.py --write`,同步 `docs/内存管理/RAM使用分析与优化方案.md` §2.1(`mem-numbers` 钩子会因体积变化 FAIL)。
### 4.4 频率跟踪
- **原理**:软件测频(对电压/电流信号过零点或相角差测频)→ 调整采样定时器周期 → 使窗长恒等于实际周波(严格 20 点/周波)。
- **闭环**:测频 → 周期修正 → 采样 → 再测频;参考用片内 EHRPWM 调频,本项目用 TIM 重装载值调整。
- **必要性**:窗长偏离整周波会破坏正交性,直流与二次谐波漏入测量(见 `docs/算法/傅氏算法详解.md` §3)。
## 6. 平台适配与差异处理
### 6.1 采样源差异
| 维度 | 参考系统 | 本项目 | 适配要点 |
| ----- | ----------------- | -------------------------------------------------------- | ------------------------------ |
| AD 器件 | 专用同步采样 AD | TPAFE5160(16 位、8 通道同步、±5 V)+ STM32 ADC1(12 位、顺序、0~3.3 V) | 统一到"工程量"层,屏蔽码值差异 |
| 通道数 | 8 实通道(4U+4I,自产零序) | 8 路电气量(4U+4I)+ 温度 | 语义映射见 `docs/硬件平台/ADC通道映射说明.md` |
| 同一时刻性 | 单芯片同步 | **跨转换器无共同触发**(N-18) | V0.1 只做逐通道独立监视 |
| 量程/精度 | 一致 | TPAFE LSB ≈ 152.6 µV vs STM32 LSB ≈ 806 µV | 同族量不可统一算法处理 |
### 6.2 N-18 影响与降级口径
- **V0.1 现板**:主板侧只做**逐通道独立监视**(有效值/越限/温度);**禁止**跨转换器的同周期相位、功率、功率因数、矢量类运算。
- **受影响功能**:方向元件、功率方向、差动类——延后(L3-13)。
- **V0.2 改版后**:8 路电气量全部接 TPAFE(与 5 路备用路对调串联电阻目的地,BOM 不变),上层语义与代码**不动**,只改映射表内容 → 保护层无需重构。
- **接口设计启示**:**按语义取数、不写死下标**,是 V0.2 平滑升级的前提。
### 6.3 单核 vs 双核
| 维度 | 参考(ARM+DSP) | 本项目(单核) | 适配 |
| ----- | ----------- | ------------------- | ----------------------- |
| 保护计算 | DSP 核独占 | 与 FreeRTOS 任务共享 CPU | 保护任务优先级最高;避免长临界区 |
| 管理/通信 | ARM 核 | 同核分任务 | 依赖现有任务优先级体系 |
| 隔离 | 核间隔离 | 无 | 靠任务优先级 + 栈预算 + 看门狗保证实时性 |
### 6.4 零序自产 / 外部
- 参考:TLV13 选择映射表——外部零序(专用通道)或**自产零序**(`3I0 = Ia+Ib+Ic`)。
- 本项目:V0.1 无专用零序通道 → 一期**自产零序**(软件合成),外部零序待 V0.2 或子板提供。
- 落点:L1-8。
### 6.5 定值存储
| 维度 | 参考 | 本项目 |
| -- | ------------ | ------------------------------------ |
| 载体 | EEPROM 定值文件 | cfg_file(`/config.ini`,NAND + FatFs) |
| 折算 | `wCoeEEP` 定点 | 同模型(工程量 ↔ 码值) |
| 微调 | TLV10 ±10% | cfg_file 微调段(按需) |
---
## 7. 分阶段实施路线图
### 7.1 阶段划分与里程碑
| 阶段 | 名称 | 内容 | 前置 | 里程碑 |
| ------ | ---------- | ------------------------------------------------------------------------- | -------------- | ----------------------- |
| **P0** | 采样与相量底座 | B1(周期 CONVST + `adcTask` 消费 + 建任务 + 栈预算)+ L1 + L2 | B0 + B1 | 每 1 ms 产出正确的基波相量 |
| **P1** | 基础保护元件 | L3-1 三段式过流、L3-2 三段式零序过流、L3-3 过负荷 | P0 | 标准源注入可正确动作 |
| **P2** | 电压/频率类保护 | L3-4 过压/欠压、L3-5 过频/低频、L3-6 零序过压 | P0 | 电压/频率越限正确动作 |
| **P3** | 异常检测与闭锁 | L3-7 涌流制动、L3-8 PT 断线、L3-9 CT 断线、L3-10 母线接地、L3-11 故障启动、L3-12 无压/无流闭锁、L5 自检 | P1/P2 | 异常工况闭锁与告警正确 |
| **P4** | 出口、记录与定值集成 | L4 出口与记录、§5 定值模型落 cfg_file、UI 显示、上送 | P1 | 动作出口 + SOE 记录 + UI 显示闭环 |
| **P5** | 方向/功率类(延后) | L3-13 方向元件等 | V0.2 硬件 / 子板计量 | 跨转换器相位一致后实现 |
### 7.2 每阶段交付物与验收判据
| 阶段 | 交付物 | 验收判据 |
| -- | ------------------------------------ | ----------------------------------- |
| P0 | `adcTask`/`algo` 模块 + 设计文档 + L0.5 单测 | 标准源读数误差 ≤ 目标;相量每 1 ms 刷新;`@test` 通过 |
| P1 | 过流/零序/过负荷元件 + 定值模型 | 注入 1.2×/0.9× 定值,正确动作/返回;返回系数正确 |
| P2 | 电压/频率元件 | 越限动作时间符合定值延时 |
| P3 | 异常检测 + 自检闭锁 | 断线/涌流工况正确闭锁;自检失败闭锁 |
| P4 | 出口 + 记录 + 定值 UI | 动作驱动出口;SOE 带正确时标;UI 显示实时值 |
| P5 | 方向元件 | 需 V0.2 前置条件满足 |
### 7.3 依赖关系图
```text
B0 产品定义(阻塞)
└─ B1 ADC 采集链路(周期 CONVST + adcTask + 建任务 + 栈预算)
└─ P0 采样与相量底座
├─ P1 基础保护(过流/零序/过负荷)
│ └─ P4 出口/记录/定值
├─ P2 电压/频率保护
└─ P3 异常检测与闭锁
└─ P5 方向/功率类(依赖 V0.2 硬件 / 子板计量)
```
---
## 8. 测试与验证
### 8.1 测试分层
| 层 | 对象 | 方式 |
| --------- | ----------------------------------- | ------------------------------------------------------------------------------------------ |
| L0 静态 | 代码规范、文档链接、体积 | pre-commit 钩子(`cppcheck` / `doc-links` / `mem-numbers`) |
| L0.5 主机单测 | 傅氏相量、定值解析、保护判据(**算法与 I/O 分离**后天然适格) | `test/host/<模块>/run_unit_test.py`(MSVC 离线编译真实源文件,参考 `test/host/cfg_file/run_unit_test.py`) |
| L1 板端套件 | 采样/相量/保护元件 | `test/run_all_suites.py` 板端套件 |
| L2/L3 台架 | 标准源注入、动作出口、时序 | 台架闭环(COM6 @115200) |
### 8.2 A-4 约束落实
登记簿 **A-4** 对采集链路提出三条设计约束,保护层须一并满足:
1. **协议解析与硬件 I/O 分离**——保护判据函数只吃相量 + 定值,可单测;
2. **采集缓冲双缓冲 + 序号**——防撕裂(单测测不出时序撕裂,须设计上消除);
3. **DE 收尾超时路径**(RS-485,若保护涉及 485 通信)。
### 8.3 验收判据(保护层)
- 标准源注入:幅值/相位/频率读数误差在目标内;
- 定值动作:1.2× 定值可靠动作、0.9× 定值可靠返回,返回系数符合 `wCoeRet`;
- 时序:动作时间 = 算法窗(≥20 ms)+ 定值延时,误差在允许范围;
- 闭锁:PT/CT 断线、涌流、自检失败工况下相关保护可靠闭锁;
- 记录:SOE/动作记录时标正确(注意板载 RTC 比墙钟慢约 8 h)。
---
## 9. 风险与开放问题
| # | 风险 / 开放问题 | 影响 | 处置方向 |
| -- | ------------------ | --------------------- | -------------------------------------- |
| R1 | **B0 产品定义未定** | 保护元件清单与规模无法锁定 | 先按核心集(P1/P2)推进,扩展集待定义 |
| R2 | **N-18 硬件缺陷** | 方向/功率/矢量类无法在 V0.1 实现 | V0.2 硬件改版;V0.1 取子板计量 |
| R3 | **单核算力** | 1 ms 节拍内完成傅氏 + 全部保护元件 | 实测 CPU 余量;必要时裁剪遥测谐波轨或降低元件扫描频率 |
| R4 | **等周波调频实现** | 频偏时精度不达标 | TIM 重装载调频;先固定 1000 Hz 跑通再上闭环 |
| R5 | **STM32 侧无中点偏置** | 交流量负半周削顶,无法算 RMS | V0.1 只做监视;V0.2 补偏置 |
| R6 | **栈预算** | 新任务栈溢出 | 建任务前后跑 `scripts/stack_report.py`;纳入看门狗 |
| R7 | **出口硬件未确认** | 跳闸出口无法验证 | 确认出口继电器/回读电路;无硬件时先做逻辑级验证 |
| R8 | **TPAFE 自动扫描模式未知** | 影响采样实现方式 | 查手册确认(登记簿 §4 待确认项) |
---
## 10. 附录
### 10.1 参考系统关键常量
| <u>常量</u> | <u>值</u> | <u>含义</u> |
| -------------------------------- | --------------------- | ---------------------------- |
| <u>`CN_PROTECT_PERIOD`</u> | <u>1000 µs</u> | <u>保护中断周期</u> |
| <u>`CN_SAM_HERTZ`</u> | <u>50</u> | <u>系统频率(Hz)</u> |
| <u>`CN_SAM_RATE`</u> | <u>20</u> | <u>每周波采样点数</u> |
| <u>`CN_SAM_RATIO`</u> | <u>1</u> | <u>保护采样倍率</u> |
| <u>`CN_YCSAM_RATIO`</u> | <u>2</u> | <u>遥测采样倍率</u> |
| <u>`CN_WAVE_RATIO`</u> | <u>4</u> | <u>录波倍率(4000 Hz)</u> |
| <u>`CN_BUFSAM_CYCLE`</u> | <u>2</u> | <u>采样缓冲周波数</u> |
| <u>`CN_BUFSAM_LEN`</u> | <u>40</u> | <u>采样缓冲长度(点)</u> |
| <u>`CN_ANA_VEC_SQRT`</u> | <u>FALSE</u> | <u>保护用基波有效值(非方和根)</u> |
| <u>`CN_ANA_DIF`</u> | <u>FALSE</u> | <u>半周波/差分组件关闭</u> |
| <u>`CN_HERTZ_SOFTFR_MIN/MAX`</u> | <u>40.5 / 60.5 Hz</u> | <u>软测频范围</u> |
| <u>`CN_NUM_YCHUMWAVE`</u> | <u>9</u> | <u>遥测谐波次数上限(`(20>>1)−1`)</u> |
| <u>`CN_NUM_YCAVER`</u> | <u>4</u> | <u>遥测平均点数</u> |
| <u>系数定点</u> | <u>`2^10`</u> | <u>标定系数定标</u> |
### <u>10.2 术语表</u>
| <u>术语</u> | <u>含义</u> |
| ------------ | -------------------------------------------- |
| <u>全周傅氏</u> | <u>全周波傅里叶算法,单频 DFT,得基波相量</u> |
| <u>相量</u> | <u>`{fRe, fIm, fAm, fAmSQ}`,实部/虚部/幅值/有效值</u> |
| <u>等周波采样</u> | <u>软件测频 + 调频,保持严格 20 点/周波</u> |
| <u>自产零序</u> | <u>`3I0 = Ia+Ib+Ic` 软件合成</u> |
| <u>双区交换</u> | <u>相量计算区/使用区指针原子切换</u> |
| <u>时间片表</u> | <u>单点/2点/4点/8点调度表</u> |
| <u>TLV</u> | <u>参考系统的参数通道(定值/微调/映射)</u> |
| <u>返回系数</u> | <u>动作值/返回值之比(滞回)</u> |
### <u>10.3 待确认清单</u>
1. <u>保护元件清单(核心集/扩展集边界)——依 B0。</u>
2. 定值取值范围/步长/单位——依产品定义。
3. 出口硬件形态(继电器/回读)——依硬件。
4. 等周波调频范围与精度目标——依产品定义。
5. 是否保留遥测谐波轨(k=1~9)——依 UI/上送需求。
---
## 变更记录
| 日期 | 变更 | 说明 |
| ---------- | ----- | --------------------------------------------------------------------------------------------------------- |
| 2026-10-10 | 建立本文档 | 依据参考项目《ADC采集至数据使用全流程详解》等专题文档,规划 CLS100 保护链路在本项目(STM32F4-Base)的分层复现:功能/性能/参数/平台适配/路线图;登记至 `docs/README.md` |