From b7c0889cc76340e88e715a8da6d72d698d2503c9 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Tue, 27 Oct 2026 08:59:26 +0800 Subject: [PATCH] =?UTF-8?q?refactor(=E7=BC=96=E5=8F=B7=C2=B7=E6=89=B9?= =?UTF-8?q?=E6=AC=A1=E4=BA=8C):=20=E4=BB=A3=E7=A0=81=E4=B8=8E=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E4=BE=A7=20215=20=E5=A4=84=E4=BF=9D=E6=8A=A4=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=8F=B7=E6=94=B9=E6=88=90=E5=8A=9F=E8=83=BD=E5=90=8D?= =?UTF-8?q?=EF=BC=8C=E9=9B=B6=E8=A1=8C=E4=B8=BA=E6=94=B9=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户裁定「不要用字母加数字的编号,语义标识是最好的」后的批次二代码半(道 ui-param 执行,逐文件站点数与 自证见其交付)。唯一口径 = 映射表 ci-artifacts/lprot_map.tsv 的功能名列原文,**零自造同义词**;L2.5 与 L-TEST 经实测各 0 处(不是本族),TC 族一字未动。 固件 22 文件 128 处(adc_task.c 21、phasor.c 22、phasor.h 13…),主机测试 13 文件 87 处(pha sor_test.c 57…);设计文档指针新增 19 行,另 16 只文件本来就写着规划文档 ⇒ 不重复加。 **两条只有真改过 215 处才会踩到的坑,都写进注释规范实践**: · 指针**不能接在原句尾部**——那会替原文一个未闭合的半括号封口,实测咬坏 App/algo/sample_ring.h 这类 跨行句 ⇒ 指针一律**单独成行**; · 号删掉会留下**叠词**(「自检失败闭锁 闭锁判定」「定值校验和 定值巡检」)⇒ 复扫并收口 4 处,措辞只用 映射名本身;具体对象需要留住时写成「自检失败闭锁(采样故障闭锁)」。 自证(不靠嘴说):改前把 35 只文件原文备份到仓外 temp,逐文件比 `/*`、`*/` 计数、三类括号计数、行数增量 恰等于指针行数、全角括号增删相等、残留号 0 ⇒ **35/35 通过**;Lead 复核后跑权威 @build **0 错 0 警**, Program Size `Code=233900 RO=26104 RW=1536 ZI=136808` —— **与三条道各自改前改后测的四数逐 字节同数**, 这就是「只动注释与文本」的机器证据;八套主机单测 exit 0,cppcheck 按钩子参数零发现,coding-standard 0。 文件头「修改记录」里的号**一并换名、不还原**(Lead 裁定):这些号是全仓退役的,留一个查无此号的引用比 留一条改过名的条目更坏——「冻结历史不回改」保护的是**别替历史改口**,不是保护一个再也查不到的字符串; id-check 对变更记录行本就豁免,两种选择都不影响门禁。 --- App/algo/README.md | 28 +++---- App/algo/adc_cal.c | 3 +- App/algo/adc_cal.h | 9 ++- App/algo/adc_health.c | 15 ++-- App/algo/adc_health.h | 15 ++-- App/algo/adc_input.c | 9 ++- App/algo/adc_input.h | 7 +- App/algo/freq.h | 5 +- App/algo/meas.c | 5 +- App/algo/meas.h | 5 +- App/algo/phasor.c | 28 +++---- App/algo/phasor.h | 17 +++-- App/algo/prot_elm.c | 5 +- App/algo/prot_elm.h | 17 +++-- App/algo/prot_set.c | 9 ++- App/algo/prot_set.h | 16 ++-- App/algo/sample_ring.c | 3 +- App/algo/sample_ring.h | 3 +- App/app/ui_data_feed.c | 4 +- App/cfg/prot_set_store.c | 2 +- App/log/soe_rec.h | 2 +- App/task/adc_task.c | 39 +++++----- App/task/iec104_serv.c | 2 +- App/task/net_task.c | 3 +- App/task/protect_task.c | 15 ++-- App/task/protect_task.h | 3 +- Src/freertos.c | 6 +- simulator/main.c | 3 +- simulator/sim/net_socket_sim.c | 2 +- test/board/ch395f_reuse_bench.c | 6 +- test/board/ch395f_test_task.c | 10 +-- test/board/net_latency_test.c | 4 +- test/host/adc_health/adc_health_test.c | 10 +-- test/host/adc_health/run_unit_test.py | 4 +- test/host/adc_input/adc_input_test.c | 2 +- test/host/adc_input/run_unit_test.py | 2 +- test/host/freq/run_unit_test.py | 2 +- test/host/net_socket/ns_s3_msg.c | 2 +- test/host/net_socket/ns_s4_state.c | 4 +- test/host/net_socket/ns_s5_io.c | 2 +- test/host/phasor/phasor_test.c | 100 ++++++++++++------------- test/host/phasor/run_unit_test.py | 4 +- test/host/prot_elm/prot_elm_test.c | 12 +-- test/host/prot_elm/run_unit_test.py | 2 +- test/host/prot_set/prot_set_test.c | 4 +- test/host/prot_set/run_unit_test.py | 4 +- test/host/soe/run_unit_test.py | 2 +- test/host/soe_store/run_unit_test.py | 2 +- 48 files changed, 239 insertions(+), 219 deletions(-) diff --git a/App/algo/README.md b/App/algo/README.md index f76b3e1d..39d316ee 100644 --- a/App/algo/README.md +++ b/App/algo/README.md @@ -9,21 +9,21 @@ | 文件 | 层 | 作用(一句话) | 主要对外入口 | 覆盖规划项 | |---|---|---|---|---| -| `adc_input.h` / `.c` | L1 | 统一语义取数:两片转换器的码值按语义(`UA…IN` / 温度)暴露,并消费 STM32 ADC1 的 DMA 乒乓缓冲 | `adc_input_init()` `adc_input_poll()` `adc_input_raw()` | L1-2 / L1-3 / L1-4 | -| `adc_health.h` / `.c` | L1 | 采样有效性判定:吃计数快照,产出静默 / 丢帧 / 单调性 / 错误增量故障位(判定与告警编排分离);L5-2 残余的码值贴轨观察器同层 | `adc_health_check()` `adc_health_flags()` `adc_health_rail_watch()` | L1-6 / L5-2(残余) | -| `adc_cal.h` / `.c` | L1.5 | 通道标定折算(「数据可信」卡 2/卡 4):工程量 =(code+b)×k,Q16 系数/零点两段落盘 + 三态 flags + 合法带哨兵 + 两点公式 | `adc_cal_apply()` `adc_cal_flags()` `adc_cal_set()` | L1-5(M4 半边) | +| `adc_input.h` / `.c` | L1 | 统一语义取数:两片转换器的码值按语义(`UA…IN` / 温度)暴露,并消费 STM32 ADC1 的 DMA 乒乓缓冲 | `adc_input_init()` `adc_input_poll()` `adc_input_raw()` | TPAFE 快照消费 / STM32 ADC1 启动与扫描 / 通道语义映射 | +| `adc_health.h` / `.c` | L1 | 采样有效性判定:吃计数快照,产出静默 / 丢帧 / 单调性 / 错误增量故障位(判定与告警编排分离);「采样通道自检」残余的码值贴轨观察器同层 | `adc_health_check()` `adc_health_flags()` `adc_health_rail_watch()` | 「采样有效性校验」/「采样通道自检」(残余) | +| `adc_cal.h` / `.c` | L1.5 | 通道标定折算(「数据可信」卡 2/卡 4):工程量 =(code+b)×k,Q16 系数/零点两段落盘 + 三态 flags + 合法带哨兵 + 两点公式 | `adc_cal_apply()` `adc_cal_flags()` `adc_cal_set()` | 「通道标定(一次系数 + 零漂)」(M4 半边) | | `meas.h` / `.c` | L2 发布 | 遥测快照(「数据可信」卡 8,M5 地基):200 ms 基波有效值 + 品质快照,双区无锁读,全仓唯一发布者 = adcTask | `meas_tick()` `meas_get()` `meas_seq()` | M5(卡 9/11 与 UI 是读者) | -| `sample_ring.h` / `.c` | L2 输入 | 按语义通道存最近 2 周波(40 点),供相量层"以当前时刻为终止"取窗 | `sample_ring_push_frame()` `sample_ring_window()` | L2 输入(为 L2-6 供数) | -| `phasor.h` / `.c` | L2 | 全周傅氏:一周波 20 点 DFT → 基波 / 谐波相量(有效值口径),双区原子切换供无锁读 | `phasor_run()` `phasor_get()` `phasor_calc()` | L2-1 / L2-2 / L2-3 / L2-6 / L2-7 | -| `freq.h` / `.c` | L2 派生量 | 频率测量:相邻两拍基波相量共轭乘积取角 + 自适应窗滑动平均 + 假值钳制 + 幅值门(UA→IA 源回退) | `freq_run()` `freq_get()` `freq_valid()` | L3-5 测量侧(测频范围 → `docs/算法/继电保护功能复现规划.md` §4.2) | -| `prot_set.h` / `.c` | L3 输入 | 保护定值模型:Q10 定点 RAM 表 + 范围校验 + 校验和封存 / 自检 / 闭锁 + 持久化 blob 纯逻辑 | `prot_set_load_raw()` `prot_set_get_f()` `prot_set_selfcheck()` | L5-1 载体 | -| `prot_elm.h` / `.c` | L3 | 保护元件框架:通用"越限 + 返回系数滞回 + 定时限"核 + 数据驱动实例表(过流三段 / 过负荷 / 过压 / 欠压 / 零序过压 / 过频 / 低频) | `prot_elm_run()` `prot_elm_eval()` `prot_elm_active_mask()` | L3-1 / L3-3 / L3-4 / L3-5 / L3-6(软件侧) | +| `sample_ring.h` / `.c` | L2 输入 | 按语义通道存最近 2 周波(40 点),供相量层"以当前时刻为终止"取窗 | `sample_ring_push_frame()` `sample_ring_window()` | L2 输入(为「每 1 ms 滑动窗刷新」供数) | +| `phasor.h` / `.c` | L2 | 全周傅氏:一周波 20 点 DFT → 基波 / 谐波相量(有效值口径),双区原子切换供无锁读 | `phasor_run()` `phasor_get()` `phasor_calc()` | 全周傅氏系数表 / 基波相量实例 / 相量有效值输出 / 每 1 ms 滑动窗刷新 / 双区指针原子交换 | +| `freq.h` / `.c` | L2 派生量 | 频率测量:相邻两拍基波相量共轭乘积取角 + 自适应窗滑动平均 + 假值钳制 + 幅值门(UA→IA 源回退) | `freq_run()` `freq_get()` `freq_valid()` | 「过频 / 低频」测量侧(测频范围 → `docs/算法/继电保护功能复现规划.md` §4.2) | +| `prot_set.h` / `.c` | L3 输入 | 保护定值模型:Q10 定点 RAM 表 + 范围校验 + 校验和封存 / 自检 / 闭锁 + 持久化 blob 纯逻辑 | `prot_set_load_raw()` `prot_set_get_f()` `prot_set_selfcheck()` | 「定值校验和」载体 | +| `prot_elm.h` / `.c` | L3 | 保护元件框架:通用"越限 + 返回系数滞回 + 定时限"核 + 数据驱动实例表(过流三段 / 过负荷 / 过压 / 欠压 / 零序过压 / 过频 / 低频) | `prot_elm_run()` `prot_elm_eval()` `prot_elm_active_mask()` | 「三段式相间过流」/「过负荷」/「过压 / 欠压」/「过频 / 低频」/「零序过压」(软件侧) | 依赖(自下而上、无环):`adc_input.h`(纯枚举 + 声明)← `adc_cal`(另依赖 `cfg_file.h` 接口, 纯头文件级)← `sample_ring` ← `phasor` ← `freq`;`meas` ← `sample_ring` + `phasor` (仅 `phasor_calc` 纯核;频率/品质由调用方注入,**不链** `freq`/`adc_cal`); `prot_set` **独立**;`prot_elm` ← `prot_set` + `phasor` + `freq`。 -`adc_health` 只吃调用方喂进来的计数 / 码值,不反向依赖 L1 实现(L5-2 贴轨门限由调用方 +`adc_health` 只吃调用方喂进来的计数 / 码值,不反向依赖 L1 实现(「采样通道自检」贴轨门限由调用方 从 `adc_cal_rail_ths()` 取,本层仍零算法依赖)。 **除 `adc_input.c` 外全部零平台依赖**(只用 `stdint.h` / `math.h` / `stddef.h` 与本目录头) @@ -33,7 +33,7 @@ ## 2. 一拍的数据流(一眼版) `adc_input_poll()` → `adc_input_raw()` ×9 → `adc_cal_apply()` ×9(L1.5 折算,现口径 = -ADC 引脚电压 V)+ `adc_health_rail_watch()` ×9(L5-2,码值域)→ `sample_ring_push_frame()` +ADC 引脚电压 V)+ `adc_health_rail_watch()` ×9(「采样通道自检」,码值域)→ `sample_ring_push_frame()` → `phasor_run()` → `freq_run()` → 消费者(`adcTask` 心跳与 L1 健康判定;`protectTask` 每 20 ms 取相量 / 频率跑 `prot_elm_run()`;**每 200 ms** `meas_tick()` 发布遥测快照供 iec104Task / uiTask 读,卡 8)。节拍 = TIM3 1 kHz 更新事件,两片转换器同源触发。 完整数据流图与初始化落点 → `docs/算法/采集与算法层设计说明.md` §2。 @@ -70,7 +70,7 @@ ADC 引脚电压 V)+ `adc_health_rail_watch()` ×9(L5-2,码值域)→ `s - **gap 不告警**(消费者超拍是已知现象);告警编排在 `adc_task.c`,不在本层。 - 首拍 `check()` 只建基线。→ `docs/算法/采集与算法层设计说明.md` §4。 -### 3.5 `prot_set.c` / `.h` — 保护定值模型(L5-1 载体) +### 3.5 `prot_set.c` / `.h` — 保护定值模型(「定值校验和」载体) - 装载 **all-or-nothing**:任一项越界整表不装载,越界项由 `prot_set_bad_mask()` 指认。 - 批量 `prot_set_set()` 后**必须** `prot_set_seal()`;单项原子写用 `prot_set_set_sealed()`。 - 定值项 / 实例**只许尾部追加**(枚举序 = 数组序 = 校验和覆盖序)。 @@ -82,7 +82,7 @@ ADC 引脚电压 V)+ `adc_health_rail_watch()` ×9(L5-2,码值域)→ `s - 零序过流(IN 走 STM32)**故意不在实例表**;OF / UF 无独立 104 遥信点,只经 YX15 总聚合可见。 - `prot_elm_init()` 须在 `phasor_init()` 之后。→ `docs/算法/采集与算法层设计说明.md` §9。 -### 3.7 `freq.c` / `.h` — 频率测量(L3-5 的测量输入) +### 3.7 `freq.c` / `.h` — 频率测量(「过频 / 低频」的测量输入) - `freq_run()` **仅 adcTask 上下文**,须在 `phasor_run()` 之后同拍调;保护口径 = `freq_get() == 0 && freq_valid() == 1`。 - 精度靠**自适应窗长**(窗长 = 泄漏纹波周期的整数倍);定长平均压不到 0.02 Hz, @@ -115,9 +115,9 @@ ADC 引脚电压 V)+ `adc_health_rail_watch()` ×9(L5-2,码值域)→ `s - 值口径(批 2 卡 8 A-lite 裁决):**基波有效值瞬时透传**,与 phasor 使用区 **同拍同核逐位相等**(单测钉死);**不做** 4 点平均 / 谐波方和根——按 docs/任务规划/数据可信.md §4.5"上送节拍非平均窗,再平均引入滞后";谐波 k-bin 轨 - (docs/算法/继电保护功能复现规划.md L2-8)扩展只许结构尾部追加, + (docs/算法/继电保护功能复现规划.md 「遥测谐波轨(可选)」)扩展只许结构尾部追加, docs/任务规划/数据可信.md §4.5 字段序 = 协议(布局由单测按偏移钉死,72 B × 双区)。 -- 并发 = phasor 双区 + 单字节索引翻转(L2-7 同型,无锁);seq 只增供消费者判换帧。 +- 并发 = phasor 双区 + 单字节索引翻转(「双区指针原子交换」同型,无锁);seq 只增供消费者判换帧。 - 品质注入:削顶位图唯一源 = `adc_cal_flags()`(口径 docs/任务规划/数据可信.md §4.2 三态表;由 adc_task 编排注入,本层不链 `adc_cal`);TEMP = 最新一拍原始值透传 + `NT`(「数据可信」决策 5);`MEAS_QDS_*` 低字节与 104 QDS 线上字节同值 diff --git a/App/algo/adc_cal.c b/App/algo/adc_cal.c index 7cf76a58..dc42dc67 100644 --- a/App/algo/adc_cal.c +++ b/App/algo/adc_cal.c @@ -403,7 +403,8 @@ int adc_cal_two_point(int32_t c_lo, int32_t c_hi, int32_t v_lo_uv, int32_t v_hi_ } /* - * 函数功能:通道码值域贴轨带门限(L5-2 判定的门限来源,按 FS 百分比) + * 函数功能:通道码值域贴轨带门限(采样通道自检 判定的门限来源,按 FS 百分比) + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 入口参数:sem - 语义通道;p_lo_th/p_hi_th - 输出下/上轨带界 int32_t * * 返 回 值:0 - 已给出门限;-1 - TEMP/越界/参数空(不做贴轨监视) int * 限定条件:无 diff --git a/App/algo/adc_cal.h b/App/algo/adc_cal.h index 8e43958f..6aaa4e8c 100644 --- a/App/algo/adc_cal.h +++ b/App/algo/adc_cal.h @@ -111,7 +111,8 @@ uint32_t adc_cal_flags(adc_semantic_t sem); * 的测量通道;UB/UC/IB/IC/IN 即使将来标定也另受 `CLIPPED` 品质约束 * (M5 快照层处理),不掺进本闭锁源。 * ② ⚠ **不得当「保护在跑」的总括用**:判据停走共四路来源,本函数只覆盖 - * 第二路——(a) L5-4 采样故障闭锁(`adc_health_flags()`);(b) 本函数 + * 第二路——(a) 自检失败闭锁 采样故障闭锁(`adc_health_flags()`);(b) 本函数 + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * (未标定);(c) 定值校验和失配闭锁(`prot_set_locked()`);(d) 全局软压板 * 退出(`PS_GLOBAL_EN` = 0)。要判「这拍到底评估了没有」必须四路一起看 * (编排顺序见 `App/task/protect_task.c`)。 @@ -134,7 +135,7 @@ uint8_t adc_cal_prot_blocked(void); * 入口参数:sem - 语义通道 adc_semantic_t * 返 回 值:k[µV/码](回退后口径);TEMP / 越界返 0 float * 限定条件:无 - * 函数说明:L5-2 门限换算、日志与整定界面回显用;勿据其反推二次值(看 flags) + * 函数说明:采样通道自检 门限换算、日志与整定界面回显用;勿据其反推二次值(看 flags) */ float adc_cal_k_uv(adc_semantic_t sem); @@ -177,14 +178,14 @@ int adc_cal_two_point(int32_t c_lo, int32_t c_hi, int32_t v_lo_uv, int32_t v_hi_ int32_t *p_k_q16, int32_t *p_b); /* - * 函数功能:通道码值域「贴轨带」门限(L5-2 越界检出的门限来源,按 FS 百分比) + * 函数功能:通道码值域「贴轨带」门限(采样通道自检 越界检出的门限来源,按 FS 百分比) * 入口参数:sem - 语义通道 adc_semantic_t * p_lo_th - 下轨带上界(code ≤ 此值判触底) int32_t * * p_hi_th - 上轨带下界(code ≥ 此值判触顶) int32_t * * 返 回 值:0 - 已给出门限;-1 - TEMP/越界(不做贴轨监视) int * 限定条件:无 * 函数说明:TPAFE 双极性 ±98% FS(±32112);STM32 上轨 98% FS(4013)、 - * 下轨 2% FS(81);判定状态机在 adc_health_rail_watch()(L5-2) + * 下轨 2% FS(81);判定状态机在 adc_health_rail_watch()(采样通道自检) */ int adc_cal_rail_ths(adc_semantic_t sem, int32_t *p_lo_th, int32_t *p_hi_th); diff --git a/App/algo/adc_health.c b/App/algo/adc_health.c index 4b888c02..295f1776 100644 --- a/App/algo/adc_health.c +++ b/App/algo/adc_health.c @@ -1,5 +1,6 @@ /* - * 模块名称:ADC 采样有效性校验(L1 采集与预处理,规划项 L1-6) + * 模块名称:ADC 采样有效性校验(L1 采集与预处理) + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 模块功能:见 adc_health.h 文件头。本文件为**纯逻辑实现**:输入计数快照、 * 输出故障位/事件位,零平台依赖(仅 stdint.h/string.h 标准 C)→ * 主机侧免桩单测。 @@ -7,18 +8,18 @@ * 作者:王建锋 * 创建日期:2026-10-11 * 修改记录: - * v1.0 2026-10-11 王建锋 创建:L1-6 采样有效性校验 + * v1.0 2026-10-11 王建锋 创建:采样有效性校验 * v1.1 2026-10-21 王建锋 新增 adc_health_age_stale():无模块状态的帧年龄 * 纯判据(参照系由调用方自存),供 protectTask 的 * 兜底新鲜度门使用,见 adc_health.h 同名声明 - * v1.2 2026-10-25 DTU 项目组 新增 L5-2 残余:码值越界(贴轨)观察器 + * v1.2 2026-10-25 DTU 项目组 新增 采样通道自检 残余:码值越界(贴轨)观察器 * (rail_watch/rail_sticky/rail_init),判据与释放 - * 沿理由见 adc_health.h L5-2 段注释 + * 沿理由见 adc_health.h 采样通道自检 段注释 */ #include "adc_health.h" -#include /* memset(L5-2 贴轨观察器数组复位) */ +#include /* memset(采样通道自检 贴轨观察器数组复位) */ /* ===================== 内部状态 ===================== */ @@ -42,7 +43,7 @@ static uint32_t s_flags; /* 电平位(stall 可自愈;backward 锁存在 static uint32_t s_sticky; /* 锁存位(含电平位历史并集) */ static uint32_t s_tpafe_gaps; -/* L5-2 贴轨观察器(每通道独立小状态机,单写者 = adcTask) */ +/* 采样通道自检 贴轨观察器(每通道独立小状态机,单写者 = adcTask) */ typedef struct { uint16_t run_hi; /* 连续贴上轨计数(饱和 0xFFFF) */ uint16_t run_lo; /* 连续贴下轨计数 */ @@ -257,7 +258,7 @@ uint32_t adc_health_tpafe_gaps(void) { return s_tpafe_gaps; } -/* ===================== L5-2 贴轨观察器实现 ===================== */ +/* ===================== 采样通道自检 贴轨观察器实现 ===================== */ /* * 函数功能:贴轨观察器复位(幂等;adc_health_init() 已内含) diff --git a/App/algo/adc_health.h b/App/algo/adc_health.h index 0273d21d..ce2fb550 100644 --- a/App/algo/adc_health.h +++ b/App/algo/adc_health.h @@ -1,5 +1,6 @@ /* - * 模块名称:ADC 采样有效性校验(L1 采集与预处理,规划项 L1-6) + * 模块名称:ADC 采样有效性校验(L1 采集与预处理) + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 模块功能:对两片转换器的"节拍是否还在喂数据"做**判定层**(观测计数由 * `adc_input` / `tpafe5160` 驱动提供,本模块只做判定与告警位): * ① 静默(stall):帧序号连续 >= ADC_HEALTH_STALL_MS 无前进; @@ -13,14 +14,14 @@ * 作者:王建锋 * 创建日期:2026-10-11 * 修改记录: - * v1.0 2026-10-11 王建锋 创建:L1-6 采样有效性校验(静默/丢帧/单调性/错误增量) + * v1.0 2026-10-11 王建锋 创建:采样有效性校验(静默/丢帧/单调性/错误增量) * v1.1 2026-10-21 王建锋 新增 adc_health_age_stale()(无模块状态的帧年龄 * 纯判据,参照系由调用方自存)与 ADC_HF_STALE 位: * 判定层的 stall/backward 位只在 adcTask 每拍跑 * check() 时才可能置起,节拍源停摆会把本任务卡在 * osThreadFlagsWait 上 → 那些位永远是 0,而相量冻在 * 最后一帧仍被 protectTask 用于判据。该纯判据让保护侧 - * 能用**自己的时基 + 中断侧计数器**独立判"数据还新不新" * v1.2 2026-10-25 DTU 项目组 新增 L5-2 残余「码值越界(贴轨)检出」: + * 能用**自己的时基 + 中断侧计数器**独立判"数据还新不新" * v1.2 2026-10-25 DTU 项目组 新增 采样通道自检 残余「码值越界(贴轨)检出」: * adc_health_rail_watch()/rail_sticky()/rail_init() * ——连续 N 拍贴满量程带且该通道见过释放沿才锁存 * (空载恒 0 / 开机恒 0 是合法工况,不误报); @@ -44,7 +45,7 @@ extern "C" { #define ADC_HEALTH_STALL_MS 100U /* 电平故障位(adc_health_flags(),当前活跃;stall 可自愈清除,backward 锁存) - * ——供后续 L5-4「自检失败闭锁」直接消费 */ + * ——供后续「自检失败闭锁」直接消费 */ #define ADC_HF_TPAFE_STALL (1uL << 0) /* TPAFE 帧序号静默 */ #define ADC_HF_STM32_STALL (1uL << 1) /* STM32 DMA 完成计数静默 */ #define ADC_HF_SEQ_BACKWARD (1uL << 2) /* 帧序号倒退(锁存,不自愈) */ @@ -142,7 +143,7 @@ uint8_t adc_health_age_stale(adc_health_age_t *a_p_age, uint32_t a_cur_seq, * 入口参数:无 * 返 回 值:ADC_HF_TPAFE_STALL / ADC_HF_STM32_STALL / ADC_HF_SEQ_BACKWARD 组合 * 限定条件:无 - * 函数说明:供 L5-4 闭锁判定与 UI;与 check() 出参 flags 同源。 + * 函数说明:供自检失败闭锁判定与 UI;与 check() 出参 flags 同源。 */ uint32_t adc_health_flags(void); @@ -165,7 +166,7 @@ uint32_t adc_health_sticky(void); */ uint32_t adc_health_tpafe_gaps(void); -/* ===================== L5-2 残余:码值越界(贴轨)检出,2026-10-25 ===================== */ +/* ===================== 采样通道自检 残余:码值越界(贴轨)检出,2026-10-25 ===================== */ /* 贴轨锁存的连续拍数:20 拍 = 1 kHz 节拍下一个 50 Hz 周波。削顶/触轨波形的 * 贴带段持续 ≥ 半周波;噪声毛刺不可能连续 20 拍钉在同侧轨带内(短板评测 §6.2 @@ -185,7 +186,7 @@ uint32_t adc_health_tpafe_gaps(void); void adc_health_rail_init(void); /* - * 函数功能:单通道单拍贴轨观察(L5-2 码值越界检出,纯算术) + * 函数功能:单通道单拍贴轨观察(采样通道自检 码值越界检出,纯算术) * 入口参数:ch - 通道号(0..ADC_RAIL_CH_NUM-1,越界忽略) uint8_t * code - 本拍原始码值(**码值域**,与标定无关) int32_t * lo_th - 下轨带上界(code ≤ 此值算贴底) int32_t diff --git a/App/algo/adc_input.c b/App/algo/adc_input.c index 76709547..2822b078 100644 --- a/App/algo/adc_input.c +++ b/App/algo/adc_input.c @@ -1,13 +1,14 @@ /* * 模块名称:ADC 输入层(L1 采集与预处理) - * 模块功能:语义通道映射(L1-4)+ STM32 ADC1 采样消费(L1-3,TIM3 TRGO 触发 + + * 模块功能:语义通道映射(通道语义映射)+ STM32 ADC1 采样消费(STM32 ADC1 启动与扫描,TIM3 TRGO 触发 + + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * DMA 双缓冲)+ TPAFE 快照消费。 * 消费侧经 adc_input_raw() 按语义取数,不写死下标。 * 适用平台:STM32F407ZGTx + TPAFE5160 * 作者:王建锋 * 创建日期:2026-10-10 * 修改记录: - * v1.0 2026-10-10 王建锋 创建:L1-3(STM32 ADC1 扫描)+ L1-4(语义映射) + * v1.0 2026-10-10 王建锋 创建:STM32 ADC1 启动与扫描(STM32 ADC1 扫描)+ 通道语义映射(语义映射) * v2.0 2026-10-10 王建锋 STM32 侧由"软件触发 + 逐通道轮询"改为 * "TIM3 TRGO 硬件触发 + DMA 双缓冲消费":本层不再触发 * 也不等待转换(消除最坏 2~3 ms 忙等);新增三个 HAL @@ -37,7 +38,7 @@ /* 连续"无新帧"达到该拍数才计一次停摆故障(单拍是相位伪影,见 stm32_take 注释) */ #define ADC_INPUT_STALL_RUN_MAX 2U -/* ===== 语义映射表(L1-4)===== +/* ===== 语义映射表(通道语义映射)===== * 权威口径:docs/硬件平台/ADC通道映射说明.md(2026-10-09 硬件确认的语义分配)。 * index 含义:TPAFE 源 = 驱动 buf 下标 0..7;STM32 源 = ADC1 通道号 0..15。 * ⚠ 消费侧一律经本表按语义取数,**不得写死下标**(V0.1 有 13/17 路被置换, @@ -83,7 +84,7 @@ static int s_stm32_rc; /* STM32 最近一次扫描状态码 */ static uint32_t s_stm32_errs; /* STM32 扫描累计失败次数 */ /* - * 函数功能:消费一帧 STM32 ADC1 采样(L1-3,DMA 双缓冲) + * 函数功能:消费一帧 STM32 ADC1 采样(STM32 ADC1 启动与扫描,DMA 双缓冲) * 入口参数:无 * 返 回 值:0 - 取到新一帧;-2 - 本拍无新帧(TIM3 未启动 / ADC 停摆 / DMA 出错) * 限定条件:仅任务上下文调用;adc_input_init() 已挂好 DMA diff --git a/App/algo/adc_input.h b/App/algo/adc_input.h index e471cd96..89eb8022 100644 --- a/App/algo/adc_input.h +++ b/App/algo/adc_input.h @@ -2,8 +2,9 @@ * 模块名称:ADC 输入层(L1 采集与预处理) * 模块功能:把两片转换器的原始码值按**语义**(UA/UB/UC/UN/IA/IB/IC/IN/温度)统一 * 暴露,使上层(UI / 自检 / 保护算法)**按语义取数,不写死下标**: - * ① 语义通道映射表(L1-4)——权威口径 docs/硬件平台/ADC通道映射说明.md; - * ② STM32 ADC1 9 通道采样(L1-3)——由 **TIM3 TRGO 硬件触发 + DMA 双缓冲 + * ① 语义通道映射表(通道语义映射)——权威口径 docs/硬件平台/ADC通道映射说明.md; + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) + * ② STM32 ADC1 9 通道采样(STM32 ADC1 启动与扫描)——由 **TIM3 TRGO 硬件触发 + DMA 双缓冲 * 搬运**,本层只消费、不触发、不等待。 * V0.1 上 8 路电气量分属两片转换器(硬件缺陷:双转换器无共同采样触发):UA/UN/IA 走 * TPAFE5160(16 位 / ±5 V 双极性),UB/UC/IB/IC/IN 走 STM32 ADC1 @@ -13,7 +14,7 @@ * 作者:王建锋 * 创建日期:2026-10-10 * 修改记录: - * v1.0 2026-10-10 王建锋 创建:L1-3(STM32 ADC1 扫描)+ L1-4(语义映射) + * v1.0 2026-10-10 王建锋 创建:STM32 ADC1 启动与扫描(STM32 ADC1 扫描)+ 通道语义映射(语义映射) * v2.0 2026-10-10 王建锋 STM32 侧改 TIM3 TRGO 硬件触发 + DMA 双缓冲消费: * 消除逐通道轮询的 2 ms 忙等;节拍源 TIM6 -> TIM3 * (换源判据:F4 上 ADC1 收不到 TIM6/TIM7 的 TRGO,见 diff --git a/App/algo/freq.h b/App/algo/freq.h index 18b5c190..2a39ee9e 100644 --- a/App/algo/freq.h +++ b/App/algo/freq.h @@ -1,5 +1,6 @@ /* - * 模块名称:频率测量层(L2 派生量,L3-5 过频/低频的测量输入) + * 模块名称:频率测量层(L2 派生量,过频 / 低频的测量输入) + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 模块功能:由 L2 相量使用区的基波相量导出系统频率——相邻两拍基波相量取 * **共轭乘积** P = Z(m)·conj(Z(m-1))(其角 = 每拍相位增量,纯音 = * +2πf/Fs,免显式解缠绕),再对**自适应窗长**的相位增量做滑动平均: @@ -7,7 +8,7 @@ * -> 非整周波 DFT 负序泄漏造成的 ~10 ms 周期相位纹波相消 * (定长窗平均实测扫频误差 0.2~0.32 Hz,自适应窗进入 0.01 Hz 量级, * 推导与实测见 freq.c 文件头与 test/host/freq 输出)。 - * 覆盖规划 §3.3 L3-5 的测量侧与 §4.2 测频范围(45~55 Hz 建议段)。 + * 覆盖规划 §3.3 过频 / 低频 的测量侧与 §4.2 测频范围(45~55 Hz 建议段)。 * * 原理与判据(详见 docs/算法/采集与算法层设计说明.md §7 与 test/host/freq/): * - 采样率 Fs = 1000 Hz(TIM3 节拍,与 phasor 同源);45~55 Hz 段每拍 diff --git a/App/algo/meas.c b/App/algo/meas.c index eaf8e35f..db409a98 100644 --- a/App/algo/meas.c +++ b/App/algo/meas.c @@ -3,7 +3,8 @@ * 模块功能:实现见 meas.h——200 ms 基波有效值 + 品质快照,双区无锁读。 * 本文件纯算法:输入 = sample_ring 取窗 + 调用方注入(频率/削顶位图), * 无 RTOS / 无寄存器 / 无日志(「数据可信」层内禁令:本目录不写日志)。 - * 双区不变量(docs/任务规划/数据可信.md §4.5,L2-7 同型,先例 = App/algo/ + * 双区不变量(docs/任务规划/数据可信.md §4.5,双区指针原子交换 同型,先例 = App/algo/ + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * phasor.c 的双区注释):写侧只碰**非使用区**,全部字段填完后一次 * volatile 单字节 store 翻转使用区;读者先取索引再整体拷贝 → 拷贝期 * 间写者不可能改读者所在区(两帧间隔 200 ms 远大于 72 B 拷贝)。 @@ -22,7 +23,7 @@ #include "phasor.h" /* phasor_calc():基波 DFT 纯函数核(与使用区同核) */ #include "sample_ring.h" /* sample_ring_window():以本拍为终止的一周波窗 */ -/* ===== 双区(计算区 / 使用区),口径同 App/algo/phasor.c 的 L2-7 ===== */ +/* ===== 双区(计算区 / 使用区),口径同 App/algo/phasor.c 的 双区指针原子交换===== */ static meas_snap_t s_ms_snap[2]; static volatile uint8_t s_ms_use; static uint8_t s_ms_ready; /* 使用区是否已产出过有效结果 */ diff --git a/App/algo/meas.h b/App/algo/meas.h index c3d0886d..6e148a7b 100644 --- a/App/algo/meas.h +++ b/App/algo/meas.h @@ -11,13 +11,14 @@ * docs/算法/采集与算法层设计说明.md §10 红线③);**不做** 4 点平均 / * 谐波方和根——docs/任务规划/数据可信.md §4.5 明示"200 ms 是上送节拍 * 不是平均窗,再平均引入滞后";谐波 k-bin 轨(docs/算法/继电保护功能 - * 复现规划.md L2-8)将来扩展时只许在本结构**尾部追加**或留在发布侧 + * 复现规划.md 遥测谐波轨(可选))将来扩展时只许在本结构**尾部追加**或留在发布侧 + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 内部状态,既有字段序不得变更。 * TEMP 通道(「数据可信」决策 5:不参与线性标定):yc = 最新一拍原始 * 帧值透传,qds 恒置 NT——值在场但非交流量语义,UI 按「数据可信」§4.2 * 三态表显示占位符,104 无对应点。 * 并发(docs/任务规划/数据可信.md §4.5 原文口径):沿用 phasor 的 - * **双区 + 单字节活跃索引翻转**(L2-7 同型,不是新机制)——写侧填满 + * **双区 + 单字节活跃索引翻转**(双区指针原子交换 同型,不是新机制)——写侧填满 * 计算区后一次 store 翻转,读者先取索引再整体拷贝,全程无锁; * seq 只增,消费者据此判"是否换帧"。 * 本层**纯算法**:不碰寄存器、不碰 RTOS、不自己取数(窗自 sample_ring、 diff --git a/App/algo/phasor.c b/App/algo/phasor.c index 66e83ad2..e87cef0e 100644 --- a/App/algo/phasor.c +++ b/App/algo/phasor.c @@ -1,12 +1,12 @@ /* * 模块名称:相量计算层(L2 相量计算) * 模块功能:全周傅氏算法(单频 DFT)——系数表预乘 √2/N,fAmSQ 直接即有效值。 - * 覆盖 L2-1 系数表 / L2-2 实例 / L2-3 有效值 / L2-6 滑动窗 / L2-7 双区交换。 + * 覆盖 全周傅氏系数表 / 基波相量实例 / 相量有效值输出 / 每 1 ms 滑动窗刷新 / 双区指针原子交换。 * 适用平台:STM32F407ZGTx(Cortex-M4F,硬件 FPU) * 作者:王建锋 * 创建日期:2026-10-10 * 修改记录: - * v1.0 2026-10-10 王建锋 创建:L2-1/2/3/6/7 + * v1.0 2026-10-10 王建锋 创建:全周傅氏系数表 等 */ #include "phasor.h" @@ -16,7 +16,7 @@ #include "sample_ring.h" -/* ===== L2-1 全周傅氏系数表 ===== +/* ===== 全周傅氏系数表 ===== * g_fFFTSin20[k] = sin(2πk/N)·(√2/N) * g_fFFTCos20[k] = cos(2πk/N)·(√2/N) N = PHASOR_N = 20 * 权威口径:docs/算法/傅氏算法详解.md §2.3("把 √2 藏进系数表")。 @@ -41,23 +41,23 @@ static const float k_fft_cos[PHASOR_N] = { /* √2:幅值 = √2 × 有效值(与系数表的 √2 折算互逆) */ #define PHASOR_SQRT2 1.4142135623730951f -/* ===== L2-2 相量实例表 ===== +/* ===== 基波相量实例表 ===== * 参考项目为 **4 个实例**(C01 基波 I/U、C02 零序基波、C03 二次谐波、C04 五次谐波, * `APP/CLS100_Dsp/InstCalCell.c`)。本项目按 V0.1 **有效通道**(`UA`/`UN`/`IA`, * 见 docs/算法/继电保护功能复现规划.md §1.6:`UB/UC/IB/IC/IN` 无中点偏置 → 削顶不可用)展开——C01 的"I/U" - * 拆为两行(IA 电流 / UA 电压),并补出 C04 的五次谐波轨(L1-9)。 + * 拆为两行(IA 电流 / UA 电压),并补出 C04 的五次谐波轨(二次谐波/五次谐波提取入口)。 * 新增实例只需在表尾加一行,其余代码自动适配。 */ static const phasor_inst_t k_inst[] = { - { "C01-IA-F1", ADC_SEM_IA, 1u }, /* A 相电流基波(L3-1 过流 / L3-3 过负荷) */ - { "C02-UA-F1", ADC_SEM_UA, 1u }, /* A 相电压基波(L3-4 过压/欠压、L3-5 频率) */ - { "C03-UN-F1", ADC_SEM_UN, 1u }, /* 零序电压基波(L3-6 零序过压) */ - { "C04-IA-F2", ADC_SEM_IA, 2u }, /* 二次谐波(L3-7 涌流制动) */ - { "C05-IA-F5", ADC_SEM_IA, 5u }, /* 五次谐波(L1-9 选线) */ + { "C01-IA-F1", ADC_SEM_IA, 1u }, /* A 相电流基波(三段式相间过流 / 过负荷) */ + { "C02-UA-F1", ADC_SEM_UA, 1u }, /* A 相电压基波(过压 / 欠压、过频 / 低频) */ + { "C03-UN-F1", ADC_SEM_UN, 1u }, /* 零序电压基波(零序过压) */ + { "C04-IA-F2", ADC_SEM_IA, 2u }, /* 二次谐波(涌流制动) */ + { "C05-IA-F5", ADC_SEM_IA, 5u }, /* 五次谐波(二次谐波/五次谐波提取入口(选线用)) */ }; #define PHASOR_INST_N (sizeof(k_inst) / sizeof(k_inst[0])) -/* ===== L2-7 双区(计算区 / 使用区)===== +/* ===== 双区指针原子交换(计算区 / 使用区)===== * 本拍结果先写入"计算区",全部实例写完后**一次性**切换 s_use_zone * (单字节 store,Cortex-M 上原子),消费侧读"使用区" → 无锁、无撕裂。 * s_use_zone 声明 volatile:阻止编译器把结果写入挪到切换之后 @@ -83,7 +83,7 @@ static void phasor_zero(phasor_t *p) { } /* - * 函数功能:对 n 点窗口算 harm 次相量(L2-1 系数表 + L2-3 有效值) + * 函数功能:对 n 点窗口算 harm 次相量(全周傅氏系数表 + 相量有效值输出) * 入口参数:x - 采样窗(按时间序,旧 → 新) * n - 窗长(必须等于 PHASOR_N) * harm - 谐波次数(>=1) @@ -134,7 +134,7 @@ int phasor_init(void) { } /* - * 函数功能:取相量实例数(L2-2) + * 函数功能:取相量实例数 * 入口参数:无 * 返 回 值:实例个数 * 限定条件:无 @@ -159,7 +159,7 @@ const phasor_inst_t *phasor_inst(uint8_t idx) { } /* - * 函数功能:重算全部实例 + 双区原子切换(L2-6 / L2-7) + * 函数功能:重算全部实例 + 双区原子切换(每 1 ms 滑动窗刷新 / 双区指针原子交换) * 入口参数:无 * 返 回 值:无 * 限定条件:仅任务上下文调用;须先 sample_ring_push_frame() 压入本拍数据 diff --git a/App/algo/phasor.h b/App/algo/phasor.h index 048b6254..bc12b2e9 100644 --- a/App/algo/phasor.h +++ b/App/algo/phasor.h @@ -4,15 +4,16 @@ * 产出基波/谐波相量。系数表**预乘 √2/N**(口径见 * `docs/算法/傅氏算法详解.md` §2.3),故 `fAmSQ = √(fRe²+fIm²)` * **直接就是有效值**,无需再除 √2。 - * 覆盖规划 §3.2:L2-1 系数表 / L2-2 实例 / L2-3 有效值输出 / - * L2-6 每 1 ms 滑动窗 / L2-7 双区指针原子交换。 + * 覆盖规划 §3.2:全周傅氏系数表 / 基波相量实例 / 相量有效值输出 / + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) + * 每 1 ms 滑动窗刷新 / 双区指针原子交换。 * ⚠ 本层**纯算法**:不碰寄存器、不碰任务调度、不自己取数(输入由 * `sample_ring` 提供)→ 主机侧可单测(L0.5)。 * 适用平台:STM32F407ZGTx(Cortex-M4F,硬件 FPU) * 作者:王建锋 * 创建日期:2026-10-10 * 修改记录: - * v1.0 2026-10-10 王建锋 创建:L2-1/2/3/6/7(基波 + 谐波相量) + * v1.0 2026-10-10 王建锋 创建:全周傅氏系数表 等(基波 + 谐波相量) */ #ifndef PHASOR_H @@ -35,7 +36,7 @@ extern "C" { * fIm - 虚部 = b1/√2(有效值相量虚部) * fAm - 幅值 = √2·√(fRe²+fIm²)(正弦峰值 A1) * fAmSQ - 有效值 = √(fRe²+fIm²)(系数已折算 √2/N,故直接即有效值) - * 相位(L2-4)按需由 `atan2(fIm, fRe)` 导出,不常驻本结构。 */ + * 相位输出按需由 `atan2(fIm, fRe)` 导出,不常驻本结构。 */ typedef struct { float fRe; float fIm; @@ -43,7 +44,7 @@ typedef struct { float fAmSQ; } phasor_t; -/* 相量实例(L2-2):**数据驱动**——新增实例只需在实例表尾加一行 */ +/* 基波相量实例:**数据驱动**——新增实例只需在实例表尾加一行 */ typedef struct { const char *name; /* 实例名(日志 / UI 用) */ adc_semantic_t sem; /* 语义通道 */ @@ -60,7 +61,7 @@ typedef struct { int phasor_init(void); /* - * 函数功能:取相量实例数(L2-2) + * 函数功能:取相量实例数 * 入口参数:无 * 返 回 值:实例个数 * 限定条件:无 @@ -78,7 +79,7 @@ uint8_t phasor_inst_count(void); const phasor_inst_t *phasor_inst(uint8_t idx); /* - * 函数功能:重算全部实例并从计算区原子切换到使用区(L2-6 滑动窗 + L2-7 双区交换) + * 函数功能:重算全部实例并从计算区原子切换到使用区(每 1 ms 滑动窗刷新 + 双区指针原子交换) * 入口参数:无 * 返 回 值:无 * 限定条件:仅任务上下文调用;须先经 `sample_ring_push_frame()` 压入本拍数据 @@ -99,7 +100,7 @@ void phasor_run(void); int phasor_get(uint8_t idx, phasor_t *out); /* - * 函数功能:对 n 点窗口算 harm 次相量(L2-1 系数表 + L2-3 有效值) + * 函数功能:对 n 点窗口算 harm 次相量(全周傅氏系数表 + 相量有效值输出) * 入口参数:x - 采样窗(按时间序,旧 → 新;长度须 = PHASOR_N) * n - 窗长(必须等于 PHASOR_N) * harm - 谐波次数(>=1) diff --git a/App/algo/prot_elm.c b/App/algo/prot_elm.c index ee0f2f9e..da1fc416 100644 --- a/App/algo/prot_elm.c +++ b/App/algo/prot_elm.c @@ -53,7 +53,7 @@ static const pe_cfg_t k_pe[PE_COUNT] = { /* ← 表头注释见上,行内列 { "OV-UA", 1u, PE_SRC_PHASOR, PS_OV_EN, PROT_ELM_NO_TRIP, PS_OV_VOL, PS_OV_DLY, PS_RET_OVER, "C02" }, { "UV-UA", 0u, PE_SRC_PHASOR, PS_UV_EN, PROT_ELM_NO_TRIP, PS_UV_VOL, PS_UV_DLY, PS_RET_UNDER, "C02" }, { "3U0-UN", 1u, PE_SRC_PHASOR, PS_3U0_EN, PROT_ELM_NO_TRIP, PS_3U0_VOL, PS_3U0_DLY, PS_RET_OVER, "C03" }, - /* 过频/低频(L3-5,B8):测量量 = freq 层测得频率(Hz),返回系数独立 + /* 过频/低频(过频 / 低频,B8):测量量 = freq 层测得频率(Hz),返回系数独立 * (RET_OF/RET_UF——频率滞回带与电气量不同量级,勿共用 0.95/1.05) */ { "OF-F", 1u, PE_SRC_FREQ, PS_OF_EN, PROT_ELM_NO_TRIP, PS_OF_HZ, PS_OF_DLY, PS_RET_OF, 0 }, { "UF-F", 0u, PE_SRC_FREQ, PS_UF_EN, PROT_ELM_NO_TRIP, PS_UF_HZ, PS_UF_DLY, PS_RET_UF, 0 }, @@ -136,7 +136,8 @@ void prot_elm_request_reset(void) { * 入口参数:now_ms - 单调时基(tick ms,差值法回绕安全) * meas - PE_COUNT 个测量值(工程量 A/V);NULL 视为全 0 * 返 回 值:无 - * 函数说明:投退=0 或定值闭锁(L5-1)→ 状态整体复位、不判据; + * 函数说明:投退=0 或定值闭锁(定值校验和)→ 状态整体复位、不判据; + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 滞回 = 已启动用返回门槛(定值×系数)、未启动用动作门槛; * 延时 dly=0 → 启动同拍即动作;返回即时(P4 接出口时再补返回延时)。 */ diff --git a/App/algo/prot_elm.h b/App/algo/prot_elm.h index fb4dc1fd..d7f7f9c4 100644 --- a/App/algo/prot_elm.h +++ b/App/algo/prot_elm.h @@ -5,11 +5,12 @@ * 主机侧可离线单测;出口/SOE(L4)与任务编排为后续。 * * V0.1 有效实例(双转换器无共同采样触发 → 仅 TPAFE 三路): - * OC1/OC2/OC3 三段式相间过流(A 相 IA,L3-1) - * OL 过负荷(A 相 IA,L3-3) - * OV/UV 过压/欠压(UA,L3-4) - * 3U0 零序过压(UN 外部零序电压通道,L3-6) - * OF/UF 过频/低频(测量量 = freq 层测得频率,L3-5,B8 落地) + * OC1/OC2/OC3 三段式相间过流(A 相 IA) + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) + * OL 过负荷(A 相 IA) + * OV/UV 过压/欠压(UA,过压 / 欠压) + * 3U0 零序过压(UN 外部零序电压通道) + * OF/UF 过频/低频(测量量 = freq 层测得频率,过频 / 低频,B8 落地) * * 测量数组口径:相量类实例 = 基波有效值(A/V);OF/UF = 测得频率(Hz)。 * run() 按实例表 src 字段取数(0=phasor rms,1=freq)。freq 无有效读数 @@ -48,8 +49,8 @@ typedef enum { PE_OV, /* 过压(UA) */ PE_UV, /* 欠压(UA,欠量方向) */ PE_3U0, /* 零序过压(UN) */ - PE_OF, /* 过频(测量量 = freq 层测得频率,B8,L3-5) */ - PE_UF, /* 低频(测量量 = freq 层测得频率,欠量方向,B8,L3-5) */ + PE_OF, /* 过频(测量量 = freq 层测得频率,B8,过频 / 低频) */ + PE_UF, /* 低频(测量量 = freq 层测得频率,欠量方向,B8,过频 / 低频) */ PE_COUNT } prot_elm_id_t; @@ -81,7 +82,7 @@ void prot_elm_request_reset(void); * meas - PE_COUNT 个测量值(工程量:A / V),NULL 视为全 0 * 返 回 值:无 * 限定条件:仅保护消费者任务上下文;调用方保证定值已装载 - * 函数说明:越限方向由实例表决定;投退=0 或定值闭锁(L5-1)→ 状态复位、 + * 函数说明:越限方向由实例表决定;投退=0 或定值闭锁(定值校验和)→ 状态复位、 * 不判据。延时判定用 (uint32_t)(int32_t)(now - t0) >= dly,回绕安全。 */ void prot_elm_eval(uint32_t now_ms, const float meas[PE_COUNT]); diff --git a/App/algo/prot_set.c b/App/algo/prot_set.c index 1392f47e..c79b0bb5 100644 --- a/App/algo/prot_set.c +++ b/App/algo/prot_set.c @@ -1,5 +1,6 @@ /* - * 模块名称:保护定值模型(P1,L5-1 载体)——实现 + * 模块名称:保护定值模型(P1,定值校验和 载体)——实现 + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 模块功能:见 prot_set.h。纯逻辑,零平台依赖(仅 stdint.h + 自身头)。 * * ⚠ 默认值/范围为拟定值(参考 EEPROM 出厂默认表不在本仓库,规划 §10.3 待补); @@ -55,7 +56,7 @@ const prot_set_meta_t g_prot_set_meta[PS_ID_COUNT] = { { 0x8825, 0u, PROT_SET_Q10(100.0), PROT_SET_Q10(1.0), PROT_SET_Q10(10000.0) }, { 0x8826, 0u, PROT_SET_Q10(5.0), PROT_SET_Q10(1.0), PROT_SET_Q10(10.0) }, { 0x0000, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, /* 全局软压板投退(YK12,B7) */ - /* --- 过频 / 低频(L3-5,B8):地址全 0 = 本地项(参考逐项地址不在 + /* --- 过频 / 低频(B8):地址全 0 = 本地项(参考逐项地址不在 * 本仓库,规划 §5.1 仅示"8820~8882 含低压/低频"类目); * 默认值/范围**拟定**(DTU 馈线典型量级),待对照参考出厂表修订 --- */ { 0x0000, 1u, PROT_SET_Q10(1), 0, PROT_SET_Q10(1) }, /* OF 投退(本地) */ @@ -75,7 +76,7 @@ static volatile uint8_t s_act; /* 活跃区下标(0/1);交换 = static uint32_t s_sum; /* 封存的正码 */ static uint32_t s_sumn; /* 封存的反码 */ static uint64_t s_bad_mask; /* load_raw/parse 越界位图(B8:40 项 → 64 位) */ -static uint8_t s_locked; /* 定值非法 → 闭锁(L5-1) */ +static uint8_t s_locked; /* 定值非法 → 闭锁(定值校验和) */ static uint8_t s_dirty; /* 未落盘定值改动(B7 持久化脏标志) */ /* @@ -293,7 +294,7 @@ void prot_set_seal(void) { } /* - * 函数功能:定值自检(L5-1)——重算 sum32 并与封存值比对 + * 函数功能:定值自检(定值校验和)——重算 sum32 并与封存值比对 * 入口参数:无 * 返 回 值:0 通过 / -1 失配(已置闭锁) * 函数说明:失配 → s_locked 置位并保持,直到下一次 seal; diff --git a/App/algo/prot_set.h b/App/algo/prot_set.h index 995b1f76..3893f358 100644 --- a/App/algo/prot_set.h +++ b/App/algo/prot_set.h @@ -1,5 +1,5 @@ /* - * 模块名称:保护定值模型(P1,L5-1 载体) + * 模块名称:保护定值模型(P1,定值校验和 载体) * 模块功能:保护定值的 RAM 模型——编号 / 通讯地址 / 范围 / 默认值 / 校验和自检, * 以及 B7 定值持久化的**纯逻辑层**(blob 序列化/解析 + 原子装载)。 * 文件读写胶水在 App/cfg/prot_set_store.c(MCU 端)。 @@ -8,7 +8,7 @@ * - 定点存储:Q10(×1024),与参考系统定点系数 2^10 一致(§5.3); * - 通讯地址:与参考 g_tCommSetParaTab(Comm/Pub/Const_CommSetPara.c)逐项对齐, * 基址 0x8820(=34848);告警类沿用运行参数段 0x8027/0x8029; - * - 校验和(L5-1):sum32 正码 + 反码成对封存(参考 tagPRS 的 + * - 校验和(定值校验和):sum32 正码 + 反码成对封存(参考 tagPRS 的 * dwTagSum/dwTagSumN 模式),selfcheck 失配 → 置闭锁; * - ⚠ 默认值/范围为**拟定值**:参考 EEPROM 出厂默认表未在本仓库, * 待对照后逐项修订(规划 §10.3 待补项);范围先按 DTU 馈线典型量级。 @@ -36,7 +36,7 @@ /* 定值项编号(枚举序 = RAM 数组序 = 校验和覆盖序,只增不删不改序) */ typedef enum { - /* --- 三段式相间过流(A 相,L3-1):投退/跳闸投退/电流/延时 --- */ + /* --- 三段式相间过流(A 相):投退/跳闸投退/电流/延时 --- */ PS_OC1_EN = 0, /* 0x8856 Ⅰ段投退 */ PS_OC1_TRIP, /* 0x8857 Ⅰ段跳闸投退(0 告警 / 1 跳闸) */ PS_OC1_CUR, /* 0x8858 Ⅰ段电流定值(A,二次值) */ @@ -49,19 +49,19 @@ typedef enum { PS_OC3_TRIP, /* 0x885F */ PS_OC3_CUR, /* 0x8860 */ PS_OC3_DLY, /* 0x8861 */ - /* --- 过负荷(A 相,L3-3) --- */ + /* --- 过负荷(A 相) --- */ PS_OL_EN, /* 0x8871 */ PS_OL_TRIP, /* 0x8872 */ PS_OL_CUR, /* 0x8873 */ PS_OL_DLY, /* 0x8874 */ - /* --- 过压 / 欠压(UA,L3-4;沿用参考告警段 0x8029/0x8027) --- */ + /* --- 过压 / 欠压(UA;沿用参考告警段 0x8029/0x8027) --- */ PS_OV_EN, /* 本地投退(参考告警类无独立投退,V0.1 补) */ PS_OV_VOL, /* 0x8029 过电压门限(V,二次值) */ PS_OV_DLY, /* 0x802A 过电压延时(ms) */ PS_UV_EN, /* 本地投退 */ PS_UV_VOL, /* 0x8027 低电压门限(V,二次值) */ PS_UV_DLY, /* 0x8028 低电压延时(ms) */ - /* --- 零序过压(UN,L3-6) --- */ + /* --- 零序过压(UN) --- */ PS_3U0_EN, /* 0x888E */ PS_3U0_VOL, /* 0x888F 3U0 定值(V,二次值) */ PS_3U0_DLY, /* 0x8890 延时(ms) */ @@ -74,7 +74,7 @@ typedef enum { PS_CT_SEC, /* 0x8826 CT 二次额定(A) */ /* --- 全局软压板(B7):104 YK12 两段式投退;0 = 保护退出服务 --- */ PS_GLOBAL_EN, /* 本地项(无通讯地址,经 YK12 写、C_RD 不可读) */ - /* --- 过频 / 低频(L3-5,B8):投退/动作频率/延时 + 各自返回系数 --- + /* --- 过频 / 低频(B8):投退/动作频率/延时 + 各自返回系数 --- * ⚠ 通讯地址:参考 g_tCommSetParaTab 的保护定值段(0x8820~0x8882) * 含"低压/低频"类目(规划 §5.1),但 OF/UF 的**逐项地址不在本仓库** * (参考 Comm 源文件未随仓库提供)→ 按"找不到对应即本地项"规则全部 @@ -130,7 +130,7 @@ int32_t prot_set_get(prot_set_id_t id); /* Q10 原值 */ float prot_set_get_f(prot_set_id_t id); /* 工程量浮点 */ uint8_t prot_set_get_ctl(prot_set_id_t id); /* 投退项:!=0 视为投入 */ -/* 校验和(L5-1):sum32 覆盖 RAM 值区;seal 封存正/反码对 */ +/* 校验和(定值校验和):sum32 覆盖 RAM 值区;seal 封存正/反码对 */ uint32_t prot_set_checksum(void); void prot_set_seal(void); /* 自检:重算并与封存值比对,失配 → 置闭锁并返回 -1(已闭锁也返回 -1) */ diff --git a/App/algo/sample_ring.c b/App/algo/sample_ring.c index ce56fd7c..f3047e11 100644 --- a/App/algo/sample_ring.c +++ b/App/algo/sample_ring.c @@ -117,7 +117,8 @@ uint16_t sample_ring_filled(void) { * 入口参数:无 * 返 回 值:累计入环帧数 * 限定条件:无 - * 函数说明:供心跳日志 / 丢帧观测(L1-6 判据之一)。 + * 函数说明:供心跳日志 / 丢帧观测(采样有效性校验 判据之一)。 + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) */ uint32_t sample_ring_frames(void) { return s_frames; diff --git a/App/algo/sample_ring.h b/App/algo/sample_ring.h index c01b7da1..b2526d97 100644 --- a/App/algo/sample_ring.h +++ b/App/algo/sample_ring.h @@ -76,7 +76,8 @@ uint16_t sample_ring_filled(void); * 入口参数:无 * 返 回 值:累计入环帧数(32 位,1 kHz 下约 49.7 天回绕) * 限定条件:无 - * 函数说明:与 L1 的 `tpafe5160_frame_seq()` 对照可判丢帧(L1-6 采样有效性校验 + * 函数说明:与 L1 的 `tpafe5160_frame_seq()` 对照可判丢帧(采样有效性校验 + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 的判据之一,本层只提供计数,不做判定)。 */ uint32_t sample_ring_frames(void); diff --git a/App/app/ui_data_feed.c b/App/app/ui_data_feed.c index 997795b4..cbd5f9b7 100644 --- a/App/app/ui_data_feed.c +++ b/App/app/ui_data_feed.c @@ -140,7 +140,7 @@ static uint8_t s_map_done; /* 发布节拍与参数变化检测状态 * par 帧有**三个各自独立**的变化源,任一变了就要重发一帧(详见 tick 里的门控注释): * s_par_sum 定值改动(校验和) - * s_par_locked 定值闭锁(L5-1 自检失配,校验和不动) + * s_par_locked 定值闭锁(定值校验和自检失配,校验和不动) * s_par_cal_block 未标定闭锁(卡 12 标定完成,校验和也不动) * 后两个各占一字节——省下来就是"屏上状态与真值脱拍"这笔债 */ static uint32_t s_last_rt_ms; @@ -464,7 +464,7 @@ static int feed_param_check(uint8_t a_id, int32_t a_q10) { * 函数说明:用 prot_set_set_sealed()(影子拷贝→改→重封→单字交换,**每项自带置脏**, * 落盘由 defaultTask 50 ms 圈扫脏写 /prot_set.bin,本模块不碰 FatFs)。 * ⚠ 不得改成 prot_set_set() + 批末 prot_set_seal():两条路径之间有 - * "已改未封存"窗口,prot_set.c 明令不得交错,撞上就被 L5-1 自检判成 + * "已改未封存"窗口,prot_set.c 明令不得交错,撞上就被定值校验和自检判成 * "定值被非法改写"→ 整台保护闭锁 */ static int feed_param_apply(uint8_t a_id, int32_t a_q10) { diff --git a/App/cfg/prot_set_store.c b/App/cfg/prot_set_store.c index df3691fe..4a5bab7b 100644 --- a/App/cfg/prot_set_store.c +++ b/App/cfg/prot_set_store.c @@ -52,7 +52,7 @@ static uint32_t s_ld32(const uint8_t *p) { * -1 损坏被拒 * 函数说明:读失败与"文件不存在"同归 1——启动期卷锁无竞争(本任务独占 * bring-up),try-lock 失败即真 I/O 故障,此时保持出厂默认并让 - * 调用方按"无档"处理是安全侧(定值仍封存自洽,L5-1 不误锁)。 + * 调用方按"无档"处理是安全侧(定值仍封存自洽,定值校验和不误锁)。 * **换代与损坏分开**(B8):magic 完好但 ver/cnt 与当前固件不符 = * 定值表升级(如 B8 32→40 项),是**预期升级路径**不是损坏 → * 归 2 并打 INFO("version change"措辞),调用方不得按 CORRUPT diff --git a/App/log/soe_rec.h b/App/log/soe_rec.h index 153e74cb..af91f096 100644 --- a/App/log/soe_rec.h +++ b/App/log/soe_rec.h @@ -4,7 +4,7 @@ * CP56Time2a 时标 + 记录类型 + 元件号 + 单调序号 + 值 + 校验和。 * **零 I/O、零 OS 依赖**(仅 stdint/string)→ 主机侧 L0.5 离线单测 * (分层约束:协议/记录与硬件 I/O 分离)。 - * 记录口径(docs/算法/继电保护功能复现规划.md §3.4 L4-4/L4-5,B9): + * 记录口径(docs/算法/继电保护功能复现规划.md §3.4「SOE 记录」「动作记录」,B9): * 落盘文件 = /log/soe.log(8.3 合规;FF_USE_LFN=0 约束),定长 64B 一条 * (照 run.log 先例:count = filesize/64 O(1)、容量满删除重建)。 * 独立于 run.log 的理由:run.log 是文本记录(时间戳+epoch+UTF-8 描述, diff --git a/App/task/adc_task.c b/App/task/adc_task.c index 4218ddf8..8af190f6 100644 --- a/App/task/adc_task.c +++ b/App/task/adc_task.c @@ -17,7 +17,8 @@ * docs/子系统设计/ADC采样节拍设计说明.md §6。 * **L1 采集层**:取数改走 App/algo/adc_input.c—— * 本任务每拍调 adc_input_poll()(TPAFE 快照 + STM32 ADC1 9 通道扫描), - * 经 adc_input_raw() **按语义**读通道(L1-3/L1-4),不再直接触碰驱动缓冲。 + * 经 adc_input_raw() **按语义**读通道(STM32 ADC1 启动与扫描 / 通道语义映射),不再直接触碰驱动缓冲。 + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * V0.1 上只有 TPAFE 三路(UA/UN/IA)测量有效;本任务只取数,不做保护运算。 * 接入前必读:取数只用 adc_input_raw() / tpafe5160_snapshot()(临界区原子快照, * 仅任务上下文;旧的 get_buf/data_ready/clear_ready 已删除);接消费者前的 @@ -37,7 +38,7 @@ * 就绪前挂起上报,就绪后补报最近一帧。 * v2.2 2026-10-10 王建锋 采样节拍改由 TIM3 更新中断(1 kHz)硬件触发;本任务 * 删除自行触发,退化为纯消费者(见文件头"采样节拍")。 - * v2.3 2026-10-10 王建锋 L1-3/L1-4:取数改走 App/algo/adc_input.c(语义映射 + + * v2.3 2026-10-10 王建锋 STM32 ADC1 启动与扫描 / 通道语义映射:取数改走 App/algo/adc_input.c(语义映射 + * STM32 ADC1 9 通道扫描);首帧日志补全 8 路电气量 + 温度, * 心跳日志增 adc1_rc / adc1_err 观测 STM32 侧健康度。 * v2.4 2026-10-10 王建锋 L2:接入相量层——每拍把 9 路语义值压入采样环 @@ -46,9 +47,9 @@ * 10 s 心跳),心跳日志增 ring / skip 计数与各实例相量 * (Re/Im/有效值,×0.1 定点打印,因 MicroLIB 的 snprintf * 无 %f)。 - * ⚠ L1-5 通道标定未实现(缺标准源)→ 暂以**原始码值** + * ⚠ 通道标定(一次系数 + 零漂)未实现(缺标准源)→ 暂以**原始码值** * 充作工程量(系数 = 1),故相量读数只证明**链路通**, - * 不可作幅值精度判据(同 L1-3 的替代口径)。 + * 不可作幅值精度判据(同 STM32 ADC1 启动与扫描 的替代口径)。 * v2.5 2026-10-10 王建锋 常开耗时测量埋点:单拍加探针 * (task_prof ADC_BEAT),用于判定本任务是否超拍 * (名义节拍 1 ms = 168000 周期)而挤占低优先级任务 @@ -70,7 +71,7 @@ * §3.2);STM32 侧改 DMA 双缓冲 * 消费,adc_input_poll() 不再忙等;心跳日志增 * adc1_seq / adc1_hw(adc1_err 语义改为"本拍无新帧") - * v2.9 2026-10-11 王建锋 L1-6 采样有效性校验:每拍调 adc_health_check() + * v2.9 2026-10-11 王建锋 采样有效性校验:每拍调 adc_health_check() * (App/algo/adc_health.c,纯逻辑判定:静默/丢帧/ * 单调性/错误计数增量)——严重事件与故障电平上升沿 * 打 DBG_ERROR + 每类每次开机一次 SYSLOG_SELFTEST; @@ -84,11 +85,11 @@ * 者;该入口同时不再打日志——它落在本任务静态最坏链上, * 每条 DBG_* 约 216 B 栈,而这一行毫无诊断价值(本任务 * 存活由首帧日志与 TASK_WD_ADC 心跳证明) - * v3.1 2026-10-25 DTU 项目组 L1.5 折算 + L5-2 贴轨观测(「数据可信」卡 2,道A): + * v3.1 2026-10-25 DTU 项目组 L1.5 折算 + 采样通道自检 贴轨观测(「数据可信」卡 2,道A): * frame[s] 由 (float)code 改 adc_cal_apply()——工程量 = * (code+b)×k,现口径 = ADC 引脚电压 V(eng=0,卡 1 冻结的 * ROM 系数,docs/硬件平台/ADC通道映射说明.md §7.1);同拍 - * 经 adc_health_rail_watch() 逐通道贴轨观察(L5-2 残余, + * 经 adc_health_rail_watch() 逐通道贴轨观察(采样通道自检 残余, * 门限 adc_cal_rail_ths,码值域与标定正交),锁存边沿 → * DBG_ERROR + 每开机一次 SYSLOG;心跳增 cal: 行(mV 定点 * + valid/clipped 位图 + rail 锁存),台架注入口径见该行判读 @@ -107,7 +108,7 @@ #include "sample_ring.h" /* L2 输入:sample_ring_push_frame()(采样环缓冲) */ #include "phasor.h" /* L2 相量层:phasor_run()/phasor_get()(全周傅氏) */ #include "freq.h" /* L2 派生量:freq_run()/freq_get()(测频,B8) */ -#include "adc_health.h" /* L1-6:采样有效性校验(静默/丢帧/单调性/错误增量/贴轨) */ +#include "adc_health.h" /* 采样有效性校验(静默/丢帧/单调性/错误增量/贴轨) */ #include "adc_cal.h" /* L1.5:通道标定折算(「数据可信」卡 2;flags 供 cal 心跳行) */ #include "meas.h" /* L2 发布侧:遥测快照 meas_tick()(「数据可信」卡 8,道D) */ #include "tpafe5160.h" @@ -131,14 +132,14 @@ static uint32_t s_frames_idle; /* 因通道尚未首次成功而**整拍跳过入环**的次数(不向相量窗注入 0 点) */ static uint32_t s_frames_skip; -/* L1-6 告警编排状态: +/* 采样有效性校验 告警编排状态: * s_health_prev - 上次电平故障位(判上升/下降沿,避免每拍重复告警) * s_health_logged- 已写 SYSLOG_SELFTEST 的位(每类每次开机只留痕一次, * 防持续故障刷屏把 32KB selftest.log 写满) */ static uint32_t s_health_prev; static uint32_t s_health_logged; -/* L5-2 贴轨编排状态(锁存本体在 adc_health 内,这里只留编排层视角): +/* 采样通道自检 贴轨编排状态(锁存本体在 adc_health 内,这里只留编排层视角): * s_rail_edge_latched - 本开机以来出现过锁存边沿的通道位图(心跳 cal: 行展示) * s_rail_syslogged - SYSLOG 留痕只写一次的闸门(init 重置) */ static uint32_t s_rail_edge_latched; @@ -206,7 +207,7 @@ static void log_phasors(const char *tag) { } } - /* 测频行(B8,L3-5 测量侧台架可见性):同样 x0.01 定点(分辨率 0.01 Hz)。 + /* 测频行(B8,过频 / 低频 测量侧台架可见性):同样 x0.01 定点(分辨率 0.01 Hz)。 * valid=0 = 未启动收敛或幅值门失效(浮空输入 rms≈0),此时 f 为保持值 * (从未收敛则 0)——判读:正常带波形应 valid=1 且 f≈5000。 */ { @@ -219,7 +220,7 @@ static void log_phasors(const char *tag) { } /* - * 函数功能:L1-6 判定结果的告警编排(边沿 → 日志 + 自检留痕) + * 函数功能:采样有效性校验 判定结果的告警编排(边沿 → 日志 + 自检留痕) * 入口参数:hs - adc_health_check() 判定结果快照 * 返 回 值:无 * 限定条件:仅任务上下文;日志仍受写者就绪门控(SYSLOG 不受——内核前有 @@ -278,7 +279,7 @@ int adc_task_init(void) { s_rail_edge_latched = 0u; s_rail_syslogged = 0u; s_meas_ms = 0u; - adc_health_init(); /* 内含 L5-2 贴轨观察器复位(rail_init) */ + adc_health_init(); /* 内含 采样通道自检 贴轨观察器复位(rail_init) */ (void)meas_init(); /* 遥测快照双区/序号复位(幂等;发布状态属本任务,init 无日志) */ return 0; } @@ -340,7 +341,7 @@ void adc_task_func(void *arg) { } /* 2) L2 输入 + 相量重算:把本拍 9 路语义值转浮点帧压入采样环,再重算全部 - * 相量实例(L2-6 滑动窗:每拍以"当前时刻为终止的前一周波"整窗重算)。 + * 相量实例(每 1 ms 滑动窗刷新:每拍以"当前时刻为终止的前一周波"整窗重算)。 * * ⚠ **仅在本拍确有新帧(r == 1)时**才压环。 * 原实现在 r == 0(TPAFE 无新帧)时**仍然**压环 + phasor_run(),只有 r == -1 @@ -373,7 +374,7 @@ void adc_task_func(void *arg) { * 不折算(决策 5)。*/ frame[s] = adc_cal_apply((adc_semantic_t)s, code); - /* L5-2 码值越界(贴轨)观察:在**码值域**判定,与标定正交—— + /* 采样通道自检 码值越界(贴轨)观察:在**码值域**判定,与标定正交—— * 连续一周波贴轨带且此前见过释放沿才锁存(空载恒 0 不误报)。 * TEMP 无「轨」语义,adc_cal_rail_ths() 返 -1 自然跳过。*/ if (adc_cal_rail_ths((adc_semantic_t)s, &lo_th, &hi_th) == 0) { @@ -428,7 +429,7 @@ void adc_task_func(void *arg) { } } - /* 2b) L1-6 采样有效性校验(每拍,常数次整数运算):把驱动侧观测计数交给 + /* 2b) 采样有效性校验(每拍,常数次整数运算):把驱动侧观测计数交给 * 纯逻辑判定层,本任务只做告警编排。⚠ 计数一律取**本拍 poll 之后** * 的值——与刚消费的帧同一时点,避免"下一拍的增量被提前看到"。 */ { @@ -449,7 +450,7 @@ void adc_task_func(void *arg) { /* 3) 首帧码值上报:**写者就绪后**才落日志。写者未注册时 con_append 走 * 无锁直发路径,与 defaultTask 的存储初始化日志会字节级交错 * (2026-10-10 台架实测);此时挂起上报,就绪后补报最近一帧。 - * 8 路电气量 + 温度全部经 adc_input_raw() **按语义**取数(L1-4), + * 8 路电气量 + 温度全部经 adc_input_raw() **按语义**取数(通道语义映射), * 用于验证"语义 → 物理通道"映射与两片转换器取数契约 */ if ((first_logged == 0u) && (s_frames_consumed != 0u) && (dbg_console_writer_ready() != 0u)) { @@ -500,7 +501,7 @@ void adc_task_func(void *arg) { * adc1_hw = HAL ADC/DMA 错误回调 * 判读:adc1_seq 停增而 seq 仍涨 → STM32 侧停摆; * adc1_gap 增长 → 本任务耗时超拍(看 adcm/adcn); - * tgap = TPAFE 侧同类丢帧计数(L1-6,与 adc1_gap 对称) */ + * tgap = TPAFE 侧同类丢帧计数(采样有效性校验,与 adc1_gap 对称) */ DBG_INFO("frames=%lu idle=%lu skip=%lu seq=%lu frst_err=%u ring=%lu" " adc1_rc=%d adc1_err=%lu adc1_seq=%lu adc1_gap=%lu adc1_hw=%lu" " tgap=%lu", @@ -519,7 +520,7 @@ void adc_task_func(void *arg) { log_phasors("hb"); - /* L1.5/L5-2 台架观测面(×1000 mV 定点,MicroLIB 无 %f): + /* L1.5/采样通道自检 台架观测面(×1000 mV 定点,MicroLIB 无 %f): * ua/un/ia_mv = 三路 TPAFE 引脚电压毫伏(未标定域,**不是** * 二次值;卡 12 注入验证的读数落点,偏差判据 ≤2 %) * vl = VALID 位图(默认构建应恒 0x00——未标定即未标定, diff --git a/App/task/iec104_serv.c b/App/task/iec104_serv.c index c7a567f7..2e9aba98 100644 --- a/App/task/iec104_serv.c +++ b/App/task/iec104_serv.c @@ -261,7 +261,7 @@ static void s_serv_poll(void) { if (s_client < 0) { int c; - /* F-NET-4:门控从 net_can_accept(只认 ESTABLISHED,已退役) + /* accept 门控迁移(docs/网络/网络自愈架构设计.md §4.2):门控从 net_can_accept(只认 ESTABLISHED,已退役) * 迁 net_listener_armed——旧门控把 LISTENING 窗口全挡掉,:2404 的丢 * CONNECT 探针(net_accept_locked 内)因此从不运行(与已修的 :7003 * 同型);armed=ESTABLISHED 待 accept / LISTENING / diff --git a/App/task/net_task.c b/App/task/net_task.c index 461cd5e8..406d5728 100644 --- a/App/task/net_task.c +++ b/App/task/net_task.c @@ -115,7 +115,8 @@ int net_stack_bring_up(void) { /* 强制 PHY 模式后链路会短暂掉线再重建,CH395F 会锁存 GINT_STAT_PHY_CHANGE(0x04) 全局中断标志。 * 这里只轮询 ch395f_get_phy_status() 确认链路是否已真正建立——**不读全局中断寄存器**: - * 它读即清,唯一读者 = net_poll(F-NET-7,用户裁定 2026-10-13 测试代码同样禁自行读取)。 + * 它读即清,唯一读者 = net_poll(唯一读者红线,docs/网络/网络自愈架构设计.md §4.10; + * 用户裁定 2026-10-13 测试代码同样禁自行读取)。 * 锁存的 PHY_CHANGE 会在 net_poll 首轮被正常消费(喂驱动链路态缓存,无害)。 * 链路一就绪(phy != DISCONN)即跳出;最多等约 3s(60 × 50ms),超时仍按实际状态继续(由下方日志暴露问题)。 */ uint8_t phy = CH395F_PHY_DISCONN; diff --git a/App/task/protect_task.c b/App/task/protect_task.c index 162f1f5d..f5d39fd1 100644 --- a/App/task/protect_task.c +++ b/App/task/protect_task.c @@ -1,9 +1,10 @@ /* * 模块名称:保护任务(L3 板端接线,B5)——实现 * 模块功能:见 protect_task.h。每拍三件事: - * ① L5-4 采样故障闭锁:adc_health_flags() 电平位命中 → 元件状态 + * ① 自检失败闭锁 采样故障闭锁:adc_health_flags() 电平位命中 → 元件状态 + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 复位(防陈旧判据)+ 本拍不 eval; - * ② prot_set_selfcheck()(L5-1 定值完整性巡检,40 项 sum32—— + * ② prot_set_selfcheck()(定值校验和 完整性巡检,40 项 sum32—— * B8 后 PS_ID_COUNT=40,开销 * 可忽略;失配 → prot_set 内部闭锁,eval 自动复位全元件); * ③ prot_elm_run()(phasor rms → 判据步进)+ 动作位图边沿日志; @@ -26,7 +27,7 @@ * 跨上下文复归(104 YK11)经 prot_elm_request_reset 落请求。 * 创建日期:2026-10-12(B5) * 修改记录: - * v1.0 2026-10-12 王建锋 创建:L5-4 采样故障闭锁 + L5-1 定值巡检 + 判据节拍 + * v1.0 2026-10-12 王建锋 创建:自检失败闭锁(采样故障闭锁)+ 定值校验和 巡检 + 判据节拍 * v1.1 2026-10-21 王建锋 ①之外增加**兜底新鲜度门**:本任务用自己的时基直接 * 看两个中断侧计数器是否还在前进(ADC_HF_STALE)。 * adc_health 的 stall 位依赖 adcTask 每拍跑 check(), @@ -64,7 +65,7 @@ #include "task_watchdog.h" #include "tpafe5160.h" /* tpafe5160_frame_seq():帧序号(BUSY EXTI 写) */ -/* L5-4 采样故障电平闭锁位:stall(可自愈)+ backward(锁存)都须停判据。 +/* 自检失败闭锁 采样故障电平闭锁位:stall(可自愈)+ backward(锁存)都须停判据。 * 锁存类(FRSTDATA/HW_ERR 等)不在此列——它们是一次性事件痕迹,不构成 * "当前测量不可信";持续 stall/backward 才是。 */ #define PROT_HF_LOCK_MASK (ADC_HF_TPAFE_STALL | ADC_HF_STM32_STALL | \ @@ -195,7 +196,7 @@ void protect_task(void *argument) { uint32_t now = osKernelGetTickCount(); uint32_t hf = adc_health_flags(); - /* 兜底新鲜度门(L5-4 的独立通道):节拍源停摆时 adcTask 会永久阻塞在 + /* 兜底新鲜度门(自检失败闭锁 的独立通道):节拍源停摆时 adcTask 会永久阻塞在 * osThreadFlagsWait(那是刻意的 fail-safe),check() 不再执行 → stall 位 * 永远是 0。这里用本任务自己的时基直接读两个**中断侧递增**的计数器, * 与 adcTask 的存亡无关;两者都只要 TIM3 还在触发就会前进。 @@ -218,7 +219,7 @@ void protect_task(void *argument) { } if ((hf & PROT_HF_LOCK_MASK) != 0u) { - /* L5-4:测量链不可信 → 复位元件(本任务上下文,直接 init 合法) + /* 自检失败闭锁:测量链不可信 → 复位元件(本任务上下文,直接 init 合法) * 并跳过判据;stall 自愈后下一拍自动恢复 */ if (s_prev_hf_lock == 0u) { DBG_ERROR("sampling FAULT -> protection blocked (hf=0x%08lX)", @@ -256,7 +257,7 @@ void protect_task(void *argument) { SOE_ELM_NONE, 1u); s_prev_cal_lock = 0u; } - /* L5-1 巡检:定值区与封存校验和不符 → prot_set 闭锁(下一拍起 + /* 定值校验和 巡检:定值区与封存校验和不符 → prot_set 闭锁(下一拍起 * eval 自动复位全元件)。B7 收口:104 定值写改走 * prot_set_set_sealed(影子区写+封存后单字交换),selfcheck 另有 * seqlock 式复核(提交撞见 = 本轮跳过),误锁窗口已消除。 */ diff --git a/App/task/protect_task.h b/App/task/protect_task.h index 8d2aeed6..1bda48a0 100644 --- a/App/task/protect_task.h +++ b/App/task/protect_task.h @@ -1,7 +1,8 @@ /* * 模块名称:保护任务(L3 板端接线,B5) * 模块功能:protectTask 线程入口——以固定节拍驱动保护判据 - * (`prot_elm_run()`:phasor rms → 元件步进),并落实 L5-4 采样 + * (`prot_elm_run()`:phasor rms → 元件步进),并落实 自检失败闭锁 采样 + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 故障闭锁(`adc_health_flags()` 电平位 → 元件状态复位 + 本拍不判据)。 * 判据本体在 `App/algo/prot_elm.c`(纯逻辑,L0.5 已覆盖),本文件 * 只做消费/编排(AGENTS 目录地图:task 不装算法)。 diff --git a/Src/freertos.c b/Src/freertos.c index cefd1985..d14afe71 100644 --- a/Src/freertos.c +++ b/Src/freertos.c @@ -125,7 +125,7 @@ static int hook_ptr_ok(const void *p) * 784 B < 1024 B ISR 底线 → 抬至 **640 words**(2.5 KB),余 1296 B / 50%; * 堆开销 +512 B。 * adcTask 640 words:本区下方手工定义(同上,不在 `.ioc` 里)。B1(2026-10-10) - * ADC 采集消费者;L2 相量(2026-10-11)+ L1-6 有效性校验(同日)后链上为 + * ADC 采集消费者;L2 相量(2026-10-11)+ 采样有效性校验(同日)后链上为 * adc_input_poll + sample_ring/phasor + adc_health_report(DBG_ERROR + * syslog_post 回显尾)。静态最坏链 1080 B,512 words 时余 968 B < 1024 B * ISR 底线 → 抬至 640 words(2.5 KB,堆余量 min_ever 7152→≈6640 B,可承受)。 @@ -136,7 +136,7 @@ static int hook_ptr_ok(const void *p) * 重建监听 → net_bind → SPI 故障 → 日志尾,日志主导)。512 words 时余 * 592 B < 1024 B ISR 底线 → 抬至 640(2.5 KB)。 * protectTask 512 words:B5(2026-10-12)保护判据节拍(prot_elm_run 消费者 - * + L5-4 采样闭锁)。stack_report 实测静态最坏链 872 B(float 判据 + + * + 自检失败闭锁 采样闭锁)。stack_report 实测静态最坏链 872 B(float 判据 + * phasor 快照 + 日志尾),余 1176 B / 57% ≥ ISR 底线 → 512 保持。 */ /* 存储测试变量(g_storage_stats / s_perf_buf)已迁至 test/board/storage_test_task.c */ @@ -170,7 +170,7 @@ const osThreadAttr_t iec104Task_attributes = { .stack_size = 640 * 4, .priority = (osPriority_t) osPriorityNormal, }; -/* B5(2026-10-12):保护判据节拍(prot_elm_run 消费者 + L5-4 采样闭锁)。 +/* B5(2026-10-12):保护判据节拍(prot_elm_run 消费者 + 自检失败闭锁 采样闭锁)。 * 手写于此而非 .ioc(同上)。512 words:stack_report 实测静态最坏链 872 B * (float 判据 + phasor 快照 + 日志尾),余 1176 B / 57% ≥ ISR 底线 → 保持。 * 优先级 Normal:V0.1 无出口硬件(风险项见 docs/算法/继电保护功能复现规划.md §9), diff --git a/simulator/main.c b/simulator/main.c index 365bce96..7b365780 100644 --- a/simulator/main.c +++ b/simulator/main.c @@ -600,7 +600,8 @@ static void sim_publish_data_frames(void) { /* * 函数功能:写路径判定"定值闭锁中吗"(模拟器版,镜像 App/app/ui_data_feed.c) * 入口参数:无 - * 返回值:prot_set 的闭锁态(模拟器里恒 0:不跑 L5-1 自检) uint8_t + * 返回值:prot_set 的闭锁态(模拟器里恒 0:不跑 定值校验和 自检) uint8_t + *(保护功能清单见 docs/算法/继电保护功能复现规划.md) * 限定条件:主循环 / 无头注键链(单线程) */ static uint8_t sim_param_locked(void) { diff --git a/simulator/sim/net_socket_sim.c b/simulator/sim/net_socket_sim.c index 906a8e6b..81403958 100644 --- a/simulator/sim/net_socket_sim.c +++ b/simulator/sim/net_socket_sim.c @@ -342,7 +342,7 @@ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen) { return nidx; } -/* F-NET-4:net_can_accept 双端退役——监听 accept 门控统一用 +/* accept 门控迁移(docs/网络/网络自愈架构设计.md §4.2):net_can_accept 双端退役——监听 accept 门控统一用 * net_listener_armed()(本文件同名实现保留恒 1 语义),recv 门控 net_can_read() 保留。 */ /* diff --git a/test/board/ch395f_reuse_bench.c b/test/board/ch395f_reuse_bench.c index 972e226b..7b177556 100644 --- a/test/board/ch395f_reuse_bench.c +++ b/test/board/ch395f_reuse_bench.c @@ -73,7 +73,7 @@ static int bench_wait_sock_int(uint8_t sock, uint32_t timeout, uint8_t *out_bits while ((uint32_t)(HAL_GetTick() - t0) < timeout) { /* 直读本 Socket SINT(读即清)。不用全局寄存器门控:它读即清,未配对 * 读取会吞事件;且门控观察分不清"芯片未锁存"与"全局位被读清" - * (TRAP-NET-20 观察混淆源)。唯一读者 = net_poll(F-NET-7)。 */ + * (TRAP-NET-20 观察混淆源)。唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7))。 */ uint8_t si = ch395f_get_sock_int_status(sock); if (si != 0U) { if (out_bits != 0) { @@ -173,7 +173,7 @@ static void bench_round(unsigned idx) { /* 排事件在 LISTEN **之前**(对齐生产 listen 路径 E14 改法:post-listen 排事件 * 会吞掉快速到达的 CONNECT——上一版矩阵 3/48 被本探针现场抓获,现已根除该 * 自伤形态;本探针保留,drain 若仍见 CONNECT 即回归信号)。 - * 逐 Socket SINT 读(读即清,不读全局——唯一读者 = net_poll,F-NET-7) */ + * 逐 Socket SINT 读(读即清,不读全局——唯一读者 = net_poll,唯一读者红线) */ for (int j = 0; j < 8; j++) { uint8_t dj = ch395f_get_sock_int_status((uint8_t)j); if (dj != 0U) { @@ -456,7 +456,7 @@ static int bench_wait_closed(uint8_t sock, uint32_t timeout_ms) { /* 排空本 Socket 事件:直读 SINT(读即清),连续 2 轮(20ms 节奏)无新位即停; * 返回排空期间见过的 SINT 位 OR(E8 M5 drain-until-quiescent 的 bench 版)。 - * 不读全局寄存器——读即清,唯一读者 = net_poll(F-NET-7) */ + * 不读全局寄存器——读即清,唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7)) */ static uint8_t bench_drain_events(uint8_t sock, uint32_t max_ms) { uint32_t t0 = HAL_GetTick(); uint8_t seen = 0U; diff --git a/test/board/ch395f_test_task.c b/test/board/ch395f_test_task.c index 385f397e..706f3ecd 100644 --- a/test/board/ch395f_test_task.c +++ b/test/board/ch395f_test_task.c @@ -77,7 +77,7 @@ static void test_parse_ip(const char *str, uint8_t *ip_arr) static void phase1_run(void) { uint8_t ip_info[20]; - /* 全局中断寄存器读即清,唯一读者 = net_poll(F-NET-7;用户裁定 2026-10-13: + /* 全局中断寄存器读即清,唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7);用户裁定 2026-10-13: * 测试代码同样禁自行读取)。net_stack_bring_up() 的 set_phy 强制重协商会 * 锁存 GINT_STAT_PHY_CHANGE(0x0004)——由全局中断状态项内部双读自清,不在此预清。 */ @@ -339,7 +339,7 @@ static void phase2_tc201(void) * 直接读本 Socket 中断状态 CMD_GET_INT_STATUS_SN(8 位,读即清)——事件位: * SENBUF_FREE / SEND_OK / RECV_OK / CONNECT / DISCONNECT / DISCARD / SOCK_TIMEOUT。 * 不用全局寄存器 GET_GLOB_INT_STATUS_ALL 做门控:它读即清,任何未配对 SINT - * 消费的读取都会吞掉事件通知;唯一读者 = net_poll(F-NET-7),测试代码同样 + * 消费的读取都会吞掉事件通知;唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7)),测试代码同样 * 禁自行读取(用户裁定 2026-10-13)。测试知道自己操作哪个 Socket,直读 * SINT 即可——每轮一次 SPI 事务,成本与旧两级方案相同,且观察无门控混淆。 */ @@ -897,7 +897,7 @@ static void phase2_tc203(void) /* 预清陈旧事件(TRAP-NET-12):上一会话 close 的 DISCONNECT 可能滞后锁存 * 在 SINT_SN 中(wait-CLOSED 轮询的 STATUS 是纯查询、不清中断), * 若不清除,本用例首次读中断会误吃旧事件导致负向误判。 - * 只清本 Socket SINT——全局寄存器读即清,唯一读者 = net_poll(F-NET-7)。 */ + * 只清本 Socket SINT——全局寄存器读即清,唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7))。 */ (void)ch395f_get_sock_int_status(sock); /* 步2:OPEN + CONNECT。命令为异步下发,此时均应立即返回成功, @@ -1188,7 +1188,7 @@ static void phase4_run(void) { uint8_t dhcp_ok = 0; while (HAL_GetTick() - tick < 30000) { /* DHCP 状态寄存器是真相(纯查询);不读全局寄存器——读即清, - * 唯一读者 = net_poll(F-NET-7),测试代码同样禁自行读取 */ + * 唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7)),测试代码同样禁自行读取 */ if (ch395f_get_dhcp_status() == 0x00) { dhcp_ok = 1; break; } HAL_Delay(500); } @@ -1459,7 +1459,7 @@ static void phase5_run(void) { } else { /* ---- 等待上一次写入被芯片搬走(SENBUF_FREE) ---- * 直读本 Socket SINT(读即清);不读全局寄存器——读即清且 - * 唯一读者 = net_poll(F-NET-7)。 + * 唯一读者 = net_poll(唯一读者红线(docs/网络/网络自愈架构设计.md §7 I7))。 */ if (ch395f_get_sock_int_status(sock) & CH395F_SINT_STAT_SENBUF_FREE) { can_write = 1; /* 缓冲已腾空,下一轮写入下一块 */ diff --git a/test/board/net_latency_test.c b/test/board/net_latency_test.c index eea7fb57..75e16dae 100644 --- a/test/board/net_latency_test.c +++ b/test/board/net_latency_test.c @@ -449,7 +449,7 @@ void net_latency_phase12_run(void) default: /* 例外(同 Phase 1 全局中断状态用例):被测对象就是本 API 的 SPI 时延——硬件层 * 独占上下文、无并发消费者;除此之外测试代码禁读全局寄存器 - * (读即清,唯一读者 = net_poll,F-NET-7) */ + * (读即清,唯一读者 = net_poll,唯一读者红线) */ (void)ch395f_get_glob_int_status_all(); break; } @@ -760,7 +760,7 @@ void net_latency_phase13_run(int32_t sockfd) if (s_p13_state != P13_ST_ABORT) { return; /* 正常完成/DONE:会话终态,不再处理 */ } - /* F-NET-3:原"进 abort 分状态手动重同步 + 10s 周期 relisten" + /* 冗余 API 面清理(docs/网络/网络自愈架构设计.md §7):原"进 abort 分状态手动重同步 + 10s 周期 relisten" * 已删——三种去向全部由 net 层自动机制认领(静默回收滞留 ESTABLISHED * → 对账⑤ RESYNC;CLOSED 失位 → 对账③④ 认领重建;LISTENING 静默丢 * 监听 → 形态③"芯片不在听"判据),手动 API net_resync_listen/net_relisten diff --git a/test/host/adc_health/adc_health_test.c b/test/host/adc_health/adc_health_test.c index 23da2fe1..db3947d5 100644 --- a/test/host/adc_health/adc_health_test.c +++ b/test/host/adc_health/adc_health_test.c @@ -1,5 +1,5 @@ /* - * 模块名称:ADC 采样有效性校验(L1-6)主机侧单元测试 + * 模块名称:ADC 采样有效性校验主机侧单元测试 * 模块功能:在 PC 上对 App/algo/adc_health.c 做离线验证。 * * 被测对象:真实源文件(以 #include 原样纳入,保证测的是生产代码而非副本): @@ -13,7 +13,7 @@ * 只有合成计数序列能精确构造; * 3. 不占 MCU 的 RAM,毫秒级完成。 * - * 覆盖点(对应 docs/算法/继电保护功能复现规划.md §3.1 L1-6): + * 覆盖点(对应 docs/算法/继电保护功能复现规划.md §3.1 采样有效性校验): * TC-ADCHEALTH-001 init + 首拍只建基线(不误报) * TC-ADCHEALTH-002 正常 1 kHz 推进 2000 拍:零故障零事件(健康不误报) * TC-ADCHEALTH-003 TPAFE 静默:99ms 不报 / 100ms 报 / 恢复清除电平位、锁存位留痕 @@ -31,7 +31,7 @@ * TC-ADCHEALTH-015 帧年龄纯判据:tick 与序号跨 0xFFFFFFFF 不误判、停滞仍判老 * TC-ADCHEALTH-016 帧年龄纯判据:序号倒退按「有变化」处理,不判老(判据分工) * TC-ADCHEALTH-017 帧年龄纯判据:两个 age 对象互不干扰;空指针不判老 - * —— L5-2 残余「码值越界(贴轨)检出」(2026-10-25 道A,卡 2 分支加入)—— + * —— 采样通道自检 残余「码值越界(贴轨)检出」(2026-10-25 道A,卡 2 分支加入)—— * TC-ADCHEALTH-018 释放沿后连续 20 拍贴上轨 -> 锁存 + 边沿只报一次 * TC-ADCHEALTH-019 无释放沿(开机/空载恒 0)永不锁存(合法工况不误报) * TC-ADCHEALTH-020 中带样本清零连续计数(19+19 不锁);触轨含等号边界 @@ -482,7 +482,7 @@ static void tc_age_two_observers(void) { "TC-ADCHEALTH-017 NULL age never reports stale (no false lock)"); } -/* ===================== L5-2 贴轨观察器(2026-10-25 道A) ===================== */ +/* ===================== 采样通道自检 贴轨观察器(2026-10-25 道A) ===================== */ /* 便捷喂数:连发 n 拍同值,返回最后一次 watch 的边沿结果 */ static uint32_t feed(uint8_t ch, int32_t code, int n) { @@ -605,7 +605,7 @@ int main(void) { tc_tick_wrap(); tc_null_guard(); tc_reinit(); - printf("-- L5-2 rail watch --\n"); + printf("-- 采样通道自检 rail watch --\n"); tc_rail_latch_after_release(); tc_rail_static_zero_ok(); tc_rail_reset_by_mid(); diff --git a/test/host/adc_health/run_unit_test.py b/test/host/adc_health/run_unit_test.py index d418e88c..cdeaef23 100644 --- a/test/host/adc_health/run_unit_test.py +++ b/test/host/adc_health/run_unit_test.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""ADC 采样有效性校验(L1-6)的主机侧单元测试运行器(L0.5,纯标准库)。 +"""ADC 采样有效性校验的主机侧单元测试运行器(L0.5,纯标准库)。 做什么: 用本机 MSVC 编译 test/host/adc_health/adc_health_test.c(它以 #include 纳入 @@ -25,7 +25,7 @@ 退出码:0=PASS / 1=测试失败 / 2=环境错误(找不到编译器 / 编译失败 / 无汇总行)。 -设计依据:docs/算法/继电保护功能复现规划.md §3.1(L1-6); +设计依据:docs/算法/继电保护功能复现规划.md §3.1(采样有效性校验); docs/测试说明/测试开发标准流程.md §4.2(L0.5 主机侧单测)。 创建日期:2026-10-11 """ diff --git a/test/host/adc_input/adc_input_test.c b/test/host/adc_input/adc_input_test.c index d4d890c6..778424e3 100644 --- a/test/host/adc_input/adc_input_test.c +++ b/test/host/adc_input/adc_input_test.c @@ -17,7 +17,7 @@ * 2. HAL 启动失败 / 转换超时 / 参数错等分支在真机上极难稳定复现,主机侧一次钉死。 * 3. 不占 MCU 的 RAM,毫秒级完成。 * - * 覆盖点(对应 docs/算法/继电保护功能复现规划.md §2.1 的 L1-3 / L1-4): + * 覆盖点(对应 docs/算法/继电保护功能复现规划.md §2.1 的 STM32 ADC1 启动与扫描 / 通道语义映射): * —— adc_input_init(TC-ADCIN-001..006)—— * TC-ADCIN-001 poll 失败后失败计数可见(前置状态构造) * TC-ADCIN-002 poll 成功后 TPAFE 侧可取数(前置状态构造) diff --git a/test/host/adc_input/run_unit_test.py b/test/host/adc_input/run_unit_test.py index b55e4aa7..237f8ad4 100644 --- a/test/host/adc_input/run_unit_test.py +++ b/test/host/adc_input/run_unit_test.py @@ -24,7 +24,7 @@ 退出码:0=PASS / 1=测试失败 / 2=环境错误(找不到编译器 / 编译失败 / 无汇总行)。 -设计依据:docs/算法/继电保护功能复现规划.md §2.1(L1-3 / L1-4); +设计依据:docs/算法/继电保护功能复现规划.md §2.1(STM32 ADC1 启动与扫描 / 通道语义映射); 创建日期:2026-10-10 """ import os diff --git a/test/host/freq/run_unit_test.py b/test/host/freq/run_unit_test.py index ad81f08d..d7b5c077 100644 --- a/test/host/freq/run_unit_test.py +++ b/test/host/freq/run_unit_test.py @@ -12,7 +12,7 @@ 退出码:0=PASS / 1=测试失败 / 2=环境错误。 -设计依据:docs/算法/继电保护功能复现规划.md §3.3(L3-5)、§4.2(测频范围)。 +设计依据:docs/算法/继电保护功能复现规划.md §3.3(过频 / 低频)、§4.2(测频范围)。 创建日期:2026-10-12(B8) """ import os diff --git a/test/host/net_socket/ns_s3_msg.c b/test/host/net_socket/ns_s3_msg.c index 8362c1f1..7f0fb7bd 100644 --- a/test/host/net_socket/ns_s3_msg.c +++ b/test/host/net_socket/ns_s3_msg.c @@ -562,7 +562,7 @@ static void tc_240_drop_conn_branches(void) s_net_socks[fd].auto_relisten == 1U, "TC-NETSOCK-240h only session bookkeeping is closed out: fd, listener attribute and port all survive"); CHECK(g_fxchip.glob_calls == 0, - "TC-NETSOCK-240i teardown only touches its own socket (F-NET-7: never reads the global register)"); + "TC-NETSOCK-240i teardown only touches its own socket (sole reader of the global register: never reads it elsewhere)"); reset_all(); } diff --git a/test/host/net_socket/ns_s4_state.c b/test/host/net_socket/ns_s4_state.c index 8654a3f8..a2c64e88 100644 --- a/test/host/net_socket/ns_s4_state.c +++ b/test/host/net_socket/ns_s4_state.c @@ -163,7 +163,7 @@ static void tc_302_poll_event_dispatch(void) reset_all(); } -/* TC-NETSOCK-303 PHY 变更位经驱动 feed 落到链路缓存(F-DRV-13 接线) */ +/* TC-NETSOCK-303 PHY 变更位经驱动 feed 落到链路缓存(链路事件投喂接线(网络自愈 §7)) */ static void tc_303_phy_feed(void) { bring_up(); @@ -249,7 +249,7 @@ static void tc_320_close_two_paths(void) "TC-NETSOCK-320b already CLOSED -> reset skipped (saves a pointless 100-600ms occupation)"); CHECK(g_fxchip.sock_events_calls >= 1, "TC-NETSOCK-320c the fast path still clears this socket leftover events (else the next connection sees a false immediate drop)"); - CHECK(g_fxchip.glob_calls == 0, "TC-NETSOCK-320d zero global reads throughout (F-NET-7)"); + CHECK(g_fxchip.glob_calls == 0, "TC-NETSOCK-320d zero global reads throughout (sole reader of global reg)"); reset_all(); /* 慢路径:芯片还 OPEN → 走 sock_reset,且必须是 GRACEFUL */ diff --git a/test/host/net_socket/ns_s5_io.c b/test/host/net_socket/ns_s5_io.c index 3390e8a7..b98c81ed 100644 --- a/test/host/net_socket/ns_s5_io.c +++ b/test/host/net_socket/ns_s5_io.c @@ -372,7 +372,7 @@ static void tc_430_connect(void) CHECK(g_chip.set_port_calls == 1 && g_fx.des_port[fd] == 8888U, "TC-NETSOCK-430i source port issued once (SET_SOUR_PORT), the peer port goes via SET_DES_PORT=8888"); CHECK(g_fxchip.sock_events_calls == 1 && g_fxchip.glob_calls == 0, - "TC-NETSOCK-430j clearing stale interrupts only clears this socket (F-NET-7: the old extra global read welded others shut)"); + "TC-NETSOCK-430j clearing stale interrupts only clears this socket (sole-reader rule, 网络自愈 §7 I7: the old extra global read welded others shut)"); CHECK(ch395f_fake_log_find('v') < ch395f_fake_log_find('T') || ch395f_fake_log_find('v') < 0, "TC-NETSOCK-430k clearing events precedes TCP_CONNECT (the two-stage pre-clear of TRAP-NET-12/-18)"); diff --git a/test/host/phasor/phasor_test.c b/test/host/phasor/phasor_test.c index cfdc51a2..0009e964 100644 --- a/test/host/phasor/phasor_test.c +++ b/test/host/phasor/phasor_test.c @@ -9,23 +9,23 @@ * * 为什么要主机侧单测(而不是只用板端套件): * 1. 相量算法是纯数学变换,与硬件无关;板端**无信号源**,无法注入已知幅值/相位/ - * 频率的标准波形,因而无法验证"读数 = 设定值"这一核心判据(同 L1-3 的替代口径)。 + * 频率的标准波形,因而无法验证"读数 = 设定值"这一核心判据(同 STM32 ADC1 启动与扫描 的替代口径)。 * 主机侧可合成任意波形,把幅值精度/谐波抑制/频率敏感性一次性钉死。 * 2. 可精确构造边界:恰好一周波 / 不足一周波 / 环形回绕 / 任意次谐波 / 频偏。 * 3. 不占 MCU 的 RAM,毫秒级完成。 * * 覆盖点(对应 docs/算法/继电保护功能复现规划.md §3.2): - * TC-PHASOR-001 L2-1 系数表逐项等于 sin(2πk/N)·(√2/N) / cos(2πk/N)·(√2/N)(防转录错) - * TC-PHASOR-002 L2-1 系数表精确零点(sin@0,10 / cos@5,15)与归一化 Σcoe² = 1/N - * TC-PHASOR-003 L2-3 纯基波:fAmSQ = A/√2(有效值),fAm = √2·fAmSQ(幅值) - * TC-PHASOR-004 L2-3/L2-4 实部虚部与相位:atan2(fIm,fRe) = 注入相角 + * TC-PHASOR-001 全周傅氏系数表逐项等于 sin(2πk/N)·(√2/N) / cos(2πk/N)·(√2/N)(防转录错) + * TC-PHASOR-002 全周傅氏系数表精确零点(sin@0,10 / cos@5,15)与归一化 Σcoe² = 1/N + * TC-PHASOR-003 相量有效值输出 纯基波:fAmSQ = A/√2(有效值),fAm = √2·fAmSQ(幅值) + * TC-PHASOR-004 相量有效值输出 / 相位输出 实部虚部与相位:atan2(fIm,fRe) = 注入相角 * TC-PHASOR-005 直流 + 2/3/5 次谐波被完全滤除(基波读数不变) * TC-PHASOR-006 任意次谐波提取(索引步进 = 谐波次数):k=2 / k=5 * TC-PHASOR-007 频率偏离 50 Hz 的幅值误差(±1 Hz ≤ 1.5%,±2 Hz ≤ 3%,见 §9 Q3) * TC-PHASOR-010 采样环:入环/取窗时序、回绕、饱和、帧计数、参数守卫 - * TC-PHASOR-020 L2-2 实例层:实例数/实例表/未攒满一周波不产出 - * TC-PHASOR-021 L2-6 滑动窗:连续滑动 20 拍基波读数恒定 - * TC-PHASOR-022 L2-7 双区交换:使用区交替 + get 返回**最后一次** run 的结果(非陈旧) + * TC-PHASOR-020 基波相量实例层:实例数/实例表/未攒满一周波不产出 + * TC-PHASOR-021 每 1 ms 滑动窗刷新:连续滑动 20 拍基波读数恒定 + * TC-PHASOR-022 双区指针原子交换:使用区交替 + get 返回**最后一次** run 的结果(非陈旧) * TC-PHASOR-030..034 phasor_zero 四字段清零 / phasor_init 双区清零 + 使用区与就绪标志复位 + 幂等 * * 通过:全部 TC PASS(main 返回 0)。 @@ -98,7 +98,7 @@ static void frame_at(float *f, uint32_t t, double amp, double phase) { } } -/* ===================== TC-PHASOR-001/002:L2-1 系数表 ===================== */ +/* ===================== TC-PHASOR-001/002:全周傅氏系数表 ===================== */ static void tc_table(void) { const double scale = sqrt(2.0) / (double)PHASOR_N; @@ -123,17 +123,17 @@ static void tc_table(void) { sum_cos += (double)k_fft_cos[k] * (double)k_fft_cos[k]; } - CHECK(ok_sin, "L2-1 coeff sin[k] == sin(2*pi*k/N)*(sqrt2/N) for all k"); - CHECK(ok_cos, "L2-1 coeff cos[k] == cos(2*pi*k/N)*(sqrt2/N) for all k"); - CHECK(ok_norm, "L2-1 per-k sin^2+cos^2 == 2/N^2 (normalization)"); + CHECK(ok_sin, "全周傅氏系数表 coeff sin[k] == sin(2*pi*k/N)*(sqrt2/N) for all k"); + CHECK(ok_cos, "全周傅氏系数表 coeff cos[k] == cos(2*pi*k/N)*(sqrt2/N) for all k"); + CHECK(ok_norm, "全周傅氏系数表 per-k sin^2+cos^2 == 2/N^2 (normalization)"); /* Σsin² = Σcos² = (√2/N)²·(N/2) = 1/N:这就是"fAmSQ 直接是有效值"的根 */ - CHECK(fabs(sum_sin - 1.0 / PHASOR_N) < 1e-7, "L2-1 sum(sin^2) == 1/N (=> RMS, not amplitude)"); - CHECK(fabs(sum_cos - 1.0 / PHASOR_N) < 1e-7, "L2-1 sum(cos^2) == 1/N (=> RMS, not amplitude)"); + CHECK(fabs(sum_sin - 1.0 / PHASOR_N) < 1e-7, "全周傅氏系数表 sum(sin^2) == 1/N (=> RMS, not amplitude)"); + CHECK(fabs(sum_cos - 1.0 / PHASOR_N) < 1e-7, "全周傅氏系数表 sum(cos^2) == 1/N (=> RMS, not amplitude)"); - CHECK((k_fft_sin[0] == 0.0f) && (k_fft_sin[10] == 0.0f), "L2-1 sin exact zeros at k=0,10"); - CHECK((k_fft_cos[5] == 0.0f) && (k_fft_cos[15] == 0.0f), "L2-1 cos exact zeros at k=5,15"); + CHECK((k_fft_sin[0] == 0.0f) && (k_fft_sin[10] == 0.0f), "全周傅氏系数表 sin exact zeros at k=0,10"); + CHECK((k_fft_cos[5] == 0.0f) && (k_fft_cos[15] == 0.0f), "全周傅氏系数表 cos exact zeros at k=5,15"); CHECK(fabs((double)k_fft_sin[5] - sqrt(2.0) / PHASOR_N) < 1e-7, - "L2-1 sin[5] == sqrt(2)/N (peak coefficient)"); + "全周傅氏系数表 sin[5] == sqrt(2)/N (peak coefficient)"); } /* ===================== TC-PHASOR-003/004:基波幅值 / 有效值 / 相位 ===================== */ @@ -171,9 +171,9 @@ static void tc_fundamental(void) { } } - CHECK(ok_rms, "L2-3 pure fundamental: fAmSQ == A/sqrt(2) (RMS) within 1%"); - CHECK(ok_amp, "L2-3 fAm == sqrt(2)*fAmSQ (amplitude) within 1%"); - CHECK(ok_ph, "L2-4/L2-3 atan2(fIm,fRe) == injected phase (6 amp/phase cases)"); + CHECK(ok_rms, "相量有效值输出 pure fundamental: fAmSQ == A/sqrt(2) (RMS) within 1%"); + CHECK(ok_amp, "相量有效值输出 fAm == sqrt(2)*fAmSQ (amplitude) within 1%"); + CHECK(ok_ph, "相位输出 / 相量有效值输出 atan2(fIm,fRe) == injected phase (6 amp/phase cases)"); } /* ===================== TC-PHASOR-005:直流与谐波被滤除 ===================== */ @@ -215,7 +215,7 @@ static void tc_filtering(void) { } } - CHECK(ok, "L2-3 DC + 2nd/3rd/5th harmonics fully rejected (5 cases, err <= 1%)"); + CHECK(ok, "相量有效值输出 DC + 2nd/3rd/5th harmonics fully rejected (5 cases, err <= 1%)"); } /* ===================== TC-PHASOR-006:任意次谐波提取 ===================== */ @@ -250,7 +250,7 @@ static void tc_harmonic(void) { } } - CHECK(ok, "L2-1 harmonic extraction k=1/2/5 from a mixed signal (index step = order)"); + CHECK(ok, "全周傅氏系数表 harmonic extraction k=1/2/5 from a mixed signal (index step = order)"); /* 纯基波时谐波轨应≈0(选择性) */ gen_sine(x, (uint8_t)PHASOR_N, 100.0, PH_F0, 0.0); @@ -259,7 +259,7 @@ static void tc_harmonic(void) { phasor_calc(x, (uint8_t)PHASOR_N, 2u, &p2); phasor_calc(x, (uint8_t)PHASOR_N, 5u, &p5); CHECK(((double)p2.fAmSQ < 1e-3) && ((double)p5.fAmSQ < 1e-3), - "L2-1 pure fundamental leaves 2nd/5th harmonic bins ~0"); + "全周傅氏系数表 pure fundamental leaves 2nd/5th harmonic bins ~0"); } } @@ -299,7 +299,7 @@ static void tc_freqdev(void) { if (worst > k_case[i].limit_pct) { ok = 0; } } - CHECK(ok, "L2-3 frequency sensitivity: 50Hz<=0.1%, +-1Hz<=1.5%, +-2Hz<=3% (worst phase)"); + CHECK(ok, "相量有效值输出 frequency sensitivity: 50Hz<=0.1%, +-1Hz<=1.5%, +-2Hz<=3% (worst phase)"); } /* ===================== TC-PHASOR-010:采样环 ===================== */ @@ -370,15 +370,15 @@ static void tc_instances(void) { int ok; uint8_t i; - CHECK(phasor_inst_count() == 5u, "L2-2 instance count == 5"); - CHECK((phasor_inst(0u) != NULL) && (phasor_inst(0u)->name != NULL), "L2-2 instance name available"); - CHECK(phasor_inst((uint8_t)phasor_inst_count()) == NULL, "L2-2 out-of-range instance -> NULL"); + CHECK(phasor_inst_count() == 5u, "基波相量实例 instance count == 5"); + CHECK((phasor_inst(0u) != NULL) && (phasor_inst(0u)->name != NULL), "基波相量实例 instance name available"); + CHECK(phasor_inst((uint8_t)phasor_inst_count()) == NULL, "基波相量实例 out-of-range instance -> NULL"); phasor_init(); - CHECK(s_use_zone == 0u, "L2-7 use zone starts at 0"); - CHECK(phasor_get(0u, &p) == -2, "L2-2 no result before a full cycle"); - CHECK(phasor_get((uint8_t)phasor_inst_count(), &p) == -1, "L2-2 out-of-range index -> -1"); - CHECK(phasor_get(0u, NULL) == -1, "L2-2 NULL out -> -1"); + CHECK(s_use_zone == 0u, "双区指针原子交换 use zone starts at 0"); + CHECK(phasor_get(0u, &p) == -2, "基波相量实例 no result before a full cycle"); + CHECK(phasor_get((uint8_t)phasor_inst_count(), &p) == -1, "基波相量实例 out-of-range index -> -1"); + CHECK(phasor_get(0u, NULL) == -1, "基波相量实例 NULL out -> -1"); /* 喂 19 帧(不足一周波)→ 仍不产出 */ for (t = 0u; t < 19u; t++) { @@ -386,27 +386,27 @@ static void tc_instances(void) { (void)sample_ring_push_frame(f, (uint8_t)ADC_SEM_COUNT); phasor_run(); } - CHECK(phasor_get(0u, &p) == -2, "L2-2 still no result after 19 frames"); - CHECK(s_use_zone == 0u, "L2-7 use zone unchanged while not producing"); + CHECK(phasor_get(0u, &p) == -2, "基波相量实例 still no result after 19 frames"); + CHECK(s_use_zone == 0u, "双区指针原子交换 use zone unchanged while not producing"); /* 第 20 帧 → 攒满一周波,产出 */ frame_at(f, 19u, amp, 0.0); (void)sample_ring_push_frame(f, (uint8_t)ADC_SEM_COUNT); phasor_run(); - CHECK(phasor_get(0u, &p) == 0, "L2-2 result available after 20 frames"); - CHECK(s_use_zone == 1u, "L2-7 use zone toggles to 1 after first production"); + CHECK(phasor_get(0u, &p) == 0, "基波相量实例 result available after 20 frames"); + CHECK(s_use_zone == 1u, "双区指针原子交换 use zone toggles to 1 after first production"); CHECK(fabs((double)p.fAmSQ - exp_rms) / exp_rms < 0.01, - "L2-2/L2-3 instance 0 (C01-IA-F1) RMS == A/sqrt(2)"); + "基波相量实例 / 相量有效值输出 instance 0 (C01-IA-F1) RMS == A/sqrt(2)"); { phasor_t p2, p5; int ok_sel = 1; if (phasor_get(3u, &p2) != 0) { ok_sel = 0; } if (phasor_get(4u, &p5) != 0) { ok_sel = 0; } CHECK(ok_sel && ((double)p2.fAmSQ < 1e-3) && ((double)p5.fAmSQ < 1e-3), - "L2-2 harmonic instances (C04-IA-F2 / C05-IA-F5) ~0 on pure fundamental"); + "基波相量实例 harmonic instances (C04-IA-F2 / C05-IA-F5) ~0 on pure fundamental"); } - /* L2-6 滑动窗:继续推 20 帧,每拍重算,基波读数应恒定 */ + /* 每 1 ms 滑动窗刷新:继续推 20 帧,每拍重算,基波读数应恒定 */ ok = 1; for (t = 20u; t < 40u; t++) { frame_at(f, t, amp, 0.0); @@ -415,7 +415,7 @@ static void tc_instances(void) { if (phasor_get(0u, &p) != 0) { ok = 0; } else if (fabs((double)p.fAmSQ - exp_rms) / exp_rms > 0.01) { ok = 0; } } - CHECK(ok, "L2-6 sliding window: RMS constant across 20 consecutive slides"); + CHECK(ok, "每 1 ms 滑动窗刷新 sliding window: RMS constant across 20 consecutive slides"); /* 实例表一致性:逐实例复核"实例窗 == 独立 phasor_calc 结果" */ ok = 1; @@ -430,7 +430,7 @@ static void tc_instances(void) { if (phasor_get(i, &got) != 0) { ok = 0; break; } if ((ref.fRe != got.fRe) || (ref.fIm != got.fIm) || (ref.fAmSQ != got.fAmSQ)) { ok = 0; break; } } - CHECK(ok, "L2-2/L2-6 instance results == phasor_calc() on the same ring window"); + CHECK(ok, "基波相量实例 / 每 1 ms 滑动窗刷新 instance results == phasor_calc() on the same ring window"); } /* ===================== TC-PHASOR-030..034:phasor_zero / init 清零 ===================== */ @@ -472,7 +472,7 @@ static void tc_zero(void) { CHECK((s_use_zone == 0u) && (phasor_get(0u, &p) == -2), "TC-PHASOR-034 phasor_init is idempotent"); } -/* ===================== TC-PHASOR-022:L2-7 双区指针原子交换 ===================== */ +/* ===================== TC-PHASOR-022:双区指针原子交换 ===================== */ static void tc_dualzone(void) { const double amp = 100.0; @@ -488,17 +488,17 @@ static void tc_dualzone(void) { (void)sample_ring_push_frame(f, (uint8_t)ADC_SEM_COUNT); phasor_run(); } - CHECK(s_use_zone == 1u, "L2-7 use zone == 1 after 1st production"); + CHECK(s_use_zone == 1u, "双区指针原子交换 use zone == 1 after 1st production"); frame_at(f, 20u, amp, 0.0); (void)sample_ring_push_frame(f, (uint8_t)ADC_SEM_COUNT); phasor_run(); - CHECK(s_use_zone == 0u, "L2-7 use zone == 0 after 2nd production"); + CHECK(s_use_zone == 0u, "双区指针原子交换 use zone == 0 after 2nd production"); frame_at(f, 21u, amp, 0.0); (void)sample_ring_push_frame(f, (uint8_t)ADC_SEM_COUNT); phasor_run(); - CHECK(s_use_zone == 1u, "L2-7 use zone == 1 after 3rd production"); + CHECK(s_use_zone == 1u, "双区指针原子交换 use zone == 1 after 3rd production"); /* 2) 每拍产出后 get() 必须等于"当前环窗的独立重算"。 * 幅值每 20 拍切换(100 <-> 10),故"读到陈旧区"会立刻不相等—— @@ -521,16 +521,16 @@ static void tc_dualzone(void) { if (phasor_get(0u, &got) != 0) { ok = 0; break; } if ((ref.fRe != got.fRe) || (ref.fIm != got.fIm) || (ref.fAmSQ != got.fAmSQ)) { ok = 0; break; } } - CHECK(ok, "L2-7 dual-zone: get() == fresh recompute of the live window, all 60 beats"); - CHECK(phasor_get(0u, &p) == 0, "L2-7 result still readable after the sweep"); + CHECK(ok, "双区指针原子交换 dual-zone: get() == fresh recompute of the live window, all 60 beats"); + CHECK(phasor_get(0u, &p) == 0, "双区指针原子交换 result still readable after the sweep"); } int main(void) { printf("=== Phasor Tests ===\n"); - printf("-- L2-1 coefficient table --\n"); + printf("-- 全周傅氏系数表 coefficient table --\n"); tc_table(); - printf("-- L2-3/L2-4 fundamental amplitude/RMS/phase --\n"); + printf("-- 相量有效值输出 / 相位输出 fundamental amplitude/RMS/phase --\n"); tc_fundamental(); printf("-- DC/harmonic rejection --\n"); tc_filtering(); @@ -540,9 +540,9 @@ int main(void) { tc_freqdev(); printf("-- L2 input sample ring --\n"); tc_ring(); - printf("-- L2-2/L2-6/L2-7 instance layer --\n"); + printf("-- 基波相量实例 / 每 1 ms 滑动窗刷新 / 双区指针原子交换 instance layer --\n"); tc_instances(); - printf("-- L2-7 dual-zone swap --\n"); + printf("-- 双区指针原子交换 dual-zone swap --\n"); tc_dualzone(); printf("-- L2 zero / init --\n"); tc_zero(); diff --git a/test/host/phasor/run_unit_test.py b/test/host/phasor/run_unit_test.py index a916aca0..1d5b5ea7 100644 --- a/test/host/phasor/run_unit_test.py +++ b/test/host/phasor/run_unit_test.py @@ -14,7 +14,7 @@ 为什么要主机侧单测(而不是只用板端套件): 相量算法是纯数学变换,与硬件无关。**板端无信号源**,无法注入已知幅值/相位/频率 - 的标准波形,因而无法验证"读数 = 设定有效值"这一 L2-3 核心判据(与 L1-3 的替代口径 + 的标准波形,因而无法验证"读数 = 设定有效值"这一 相量有效值输出 核心判据(与 STM32 ADC1 启动与扫描 的替代口径 同源)。主机侧可合成任意波形并精确构造边界(恰好一周波 / 不足一周波 / 环形回绕 / 任意次谐波 / 频偏),且不占 MCU 的 RAM。 @@ -26,7 +26,7 @@ 退出码:0=PASS / 1=测试失败 / 2=环境错误(找不到编译器 / 编译失败 / 无汇总行)。 -设计依据:docs/算法/继电保护功能复现规划.md §3.2(L2-1/2/3/4/6/7); +设计依据:docs/算法/继电保护功能复现规划.md §3.2(全周傅氏系数表 等); docs/算法/傅氏算法详解.md §2.3(系数口径); docs/测试说明/测试开发标准流程.md §4.2(L0.5 主机侧单测)。 创建日期:2026-10-10 diff --git a/test/host/prot_elm/prot_elm_test.c b/test/host/prot_elm/prot_elm_test.c index 84132c4f..9f30a482 100644 --- a/test/host/prot_elm/prot_elm_test.c +++ b/test/host/prot_elm/prot_elm_test.c @@ -8,20 +8,20 @@ * TC-PROTELEM-001~010 走 prot_elm_eval 纯判据路径,TC-PROTELEM-013 走 * run() 适配层 = 合成波形跑真实 L2+测频链) * - * 覆盖点(docs/算法/继电保护功能复现规划.md §3.3 L3-1/3/4/6、§8 验收): + * 覆盖点(docs/算法/继电保护功能复现规划.md §3.3 三段式相间过流 等、§8 验收): * TC-PROTELEM-001 init:全状态清零、动作位图 0 * TC-PROTELEM-002 过量滞回 + 定时限:1.01× 定值启动、延时到点动作、 * 返回系数内保持、跌破返回门槛释放(1.2×/0.9× 验收口径的核) * TC-PROTELEM-003 延时 0:启动同拍即动作 * TC-PROTELEM-004 欠量方向(UV):低于定值启动、高于返回门槛释放 * TC-PROTELEM-005 投退=0:不判据、状态复位 - * TC-PROTELEM-006 定值闭锁(L5-1 联动):locked → 全元件复位;解锁后恢复 + * TC-PROTELEM-006 定值闭锁(定值校验和 联动):locked → 全元件复位;解锁后恢复 * TC-PROTELEM-007 时基回绕:跨 0xFFFFFFFF 的延时判定仍正确 * TC-PROTELEM-008 动作位图聚合 * TC-PROTELEM-009 守卫:state(NULL)/越界编号、name 越界 * TC-PROTELEM-010 跨上下文复归请求(B5):request 不当拍生效、下一拍 eval 头部消费 - * TC-PROTELEM-011 过频 OF(B8/L3-5):越限 + RET_OF 滞回 + 定时限 - * TC-PROTELEM-012 低频 UF(B8/L3-5):欠量方向 + RET_UF 滞回 + 方向隔离 + * TC-PROTELEM-011 过频 OF(B8/过频 / 低频):越限 + RET_OF 滞回 + 定时限 + * TC-PROTELEM-012 低频 UF(B8/过频 / 低频):欠量方向 + RET_UF 滞回 + 方向隔离 * TC-PROTELEM-013 run() 接线(B8):测频驱动 OF 动作;幅值门失效 OF 复位且 * 相量类元件仍被评估(不整拍跳过) * TC-PROTELEM-014 启动位图与动作位图分离(道F task-10「保护启动」记录的前置): @@ -213,7 +213,7 @@ static void tc_set_lock(void) { prot_elm_eval(4100u, m); prot_elm_state(PE_OC1, &st); CHECK((st.enabled == 0u) && (st.asserted == 0u), - "TC-PROTELEM-006 settings lock resets all elements (L5-1 gating)"); + "TC-PROTELEM-006 settings lock resets all elements (定值校验和 gating)"); prot_set_seal(); prot_elm_eval(4200u, m); @@ -299,7 +299,7 @@ static void tc_request_reset(void) { "TC-PROTELEM-010 next eval consumes request -> cleared in hysteresis band"); } -/* ===================== OF/UF(L3-5,B8)===================== */ +/* ===================== OF/UF(过频 / 低频,B8)===================== */ /* TC-PROTELEM-011:过频——越限 + RET_OF 滞回 + 定时限(判据核级) */ static void tc_of_hysteresis(void) { diff --git a/test/host/prot_elm/run_unit_test.py b/test/host/prot_elm/run_unit_test.py index df79edff..9344ffdd 100644 --- a/test/host/prot_elm/run_unit_test.py +++ b/test/host/prot_elm/run_unit_test.py @@ -11,7 +11,7 @@ 退出码:0=PASS / 1=测试失败 / 2=环境错误。 -设计依据:docs/算法/继电保护功能复现规划.md §3.3(L3-1/3/4/6)、§8(验收判据)。 +设计依据:docs/算法/继电保护功能复现规划.md §3.3(三段式相间过流 等)、§8(验收判据)。 创建日期:2026-10-11 """ import os diff --git a/test/host/prot_set/prot_set_test.c b/test/host/prot_set/prot_set_test.c index 9c64dc2e..df809982 100644 --- a/test/host/prot_set/prot_set_test.c +++ b/test/host/prot_set/prot_set_test.c @@ -4,11 +4,11 @@ * * 被测对象:真实源文件(#include 原样纳入)。纯逻辑,无需桩。 * - * 覆盖点(docs/算法/继电保护功能复现规划.md §5.2 / §3.4 L5-1): + * 覆盖点(docs/算法/继电保护功能复现规划.md §5.2 / §3.4 定值校验和): * TC-PROTSET-001 init:默认值装载、越界位图 0、selfcheck 通过、未闭锁 * TC-PROTSET-002 set:范围内写入生效;越界拒写且原值不动 * TC-PROTSET-003 校验和封存语义:set 后未 seal → selfcheck 失败并闭锁; - * seal → 通过并解锁(L5-1 核心闭环) + * seal → 通过并解锁(定值校验和 核心闭环) * TC-PROTSET-004 load_raw:合法整表装载并封存;含越界项 → 整表不装载 + * bad_mask 指认越界项(定值一致性:宁可全旧不可半新) * TC-PROTSET-005 Q10 往返精度(±1 LSB) diff --git a/test/host/prot_set/run_unit_test.py b/test/host/prot_set/run_unit_test.py index 3778894c..4d6e5eba 100644 --- a/test/host/prot_set/run_unit_test.py +++ b/test/host/prot_set/run_unit_test.py @@ -4,14 +4,14 @@ 做什么:用本机 MSVC 离线编译 test/host/prot_set/prot_set_test.c(#include 纳入 生产源文件 App/algo/prot_set.c),验证 Q10 定点模型 / 范围校验 / - 整表装载 all-or-nothing / 校验和封存-自检-闭锁(L5-1)闭环。 + 整表装载 all-or-nothing / 校验和封存-自检-闭锁(定值校验和)闭环。 用法(仓库根目录): & '.venv\\Scripts\\python.exe' test/host/prot_set/run_unit_test.py 退出码:0=PASS / 1=测试失败 / 2=环境错误。 -设计依据:docs/算法/继电保护功能复现规划.md §5(定值参数模型)、§3.4(L5-1)。 +设计依据:docs/算法/继电保护功能复现规划.md §5(定值参数模型)、§3.4(定值校验和)。 创建日期:2026-10-11 """ import os diff --git a/test/host/soe/run_unit_test.py b/test/host/soe/run_unit_test.py index 9988bb94..bdd62624 100644 --- a/test/host/soe/run_unit_test.py +++ b/test/host/soe/run_unit_test.py @@ -12,7 +12,7 @@ 退出码:0=PASS / 1=测试失败 / 2=环境错误。 -设计依据:docs/算法/继电保护功能复现规划.md §3.4(L4-4/L4-5,B9)。 +设计依据:docs/算法/继电保护功能复现规划.md §3.4(SOE 记录 / 动作记录,B9)。 创建日期:2026-10-12 """ import os diff --git a/test/host/soe_store/run_unit_test.py b/test/host/soe_store/run_unit_test.py index 7248411e..356f88e8 100644 --- a/test/host/soe_store/run_unit_test.py +++ b/test/host/soe_store/run_unit_test.py @@ -38,7 +38,7 @@ r"""SOE 落盘胶水层(soe_store)的主机侧单元测试运行器(L0.5 退出码:0=PASS / 1=测试失败 / 2=环境错误(找不到编译器 / 编译失败 / 无汇总行)。 设计依据:docs/架构设计/STM32F4-Base存储架构说明.md §10.1 第 10/11 条、 -docs/算法/继电保护功能复现规划.md §3.4(L4-4/L4-5,B9)、 +docs/算法/继电保护功能复现规划.md §3.4(SOE 记录 / 动作记录,B9)、 docs/测试说明/主机单测覆盖率口径.md §9 P2 第 2 项 创建日期:2026-10-24 """