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:
2026-10-27 08:59:26 +08:00
parent 26a97e99f9
commit b7c0889cc7
48 changed files with 239 additions and 219 deletions
+5 -5
View File
@@ -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();
+2 -2
View File
@@ -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
"""
+1 -1
View File
@@ -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 侧可取数(前置状态构造)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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();
}
+2 -2
View File
@@ -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 */
+1 -1
View File
@@ -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)");
+50 -50
View File
@@ -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();
+2 -2
View File
@@ -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
+6 -6
View File
@@ -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) {
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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)
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
"""