refactor(编号·批次二): 代码与测试侧 215 处保护功能号改成功能名,零行为改动
用户裁定「不要用字母加数字的编号,语义标识是最好的」后的批次二代码半(道 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 对变更记录行本就豁免,两种选择都不影响门禁。
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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; /* 缓冲已腾空,下一轮写入下一块 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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 侧可取数(前置状态构造)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user