593c5d0c84
用户裁定(2026-10-28):L1/L1.5/L2/L2.5/L3 这套层号「谁能看懂」,改用语义名。 映射(同一批定稿,含 L4/L5): L1 → 语义取数与有效性 L1.5 → 标定折算 L2 → 全周傅氏相量 L2.5 → 测频与遥测快照 L3 → 保护判据 L4 → 出口与记录 L5 → 动作留痕 实测规模:384 站点 / 62 文件(App/algo、App/task、test/host 六个套件、docs/算法、 产品需求、架构总览、启动顺序、ADC 采样节拍、IEC104 上行、采集短板评测、内存管理、 AGENTS.md、README.md、docs/README.md、.pre-commit-config.yaml 与 scripts 里的注释)。 改法(不是全局替换,逐模式有上下文规则): - 先吃同位语再落裸词:L1 有效性校验 → 语义取数与有效性校验、L2 相量层 → 全周傅氏 相量层、L3 保护 → 保护判据、L2.5 遥测快照 → 测频与遥测快照,避免「保护判据保护判据」 这类重复(第一版就是这么坏掉的,已整体回滚重做)。 - .c/.h 只改注释:先把字符串字面量切出去(引号数为奇数的跨行注释按整行处理), C 字符串里的 L2-in ring 之类原样保留——AGENTS 铁律「字符串字面量必须纯 ASCII」。 - 层内条目号(L1-3 / L2-3 这类)**本批不动**,属批次 2;另外三族(UI 菜单层级 L0~L3、链路延迟分段 L1~L8、CubeMX 防丢失三层)也不动,属批次 3。 - 顺手修的措辞:范围写法 L1~L3 → 「分层(语义取数与有效性 → 保护判据)」、 CI 段「不含 L1/L2/L3」→「不含采集链分层」、目录地图里同一处并列表述。 验证:@build 0 错 0 警(Code=236456,与改前逐字节同尺寸——纯注释改动); 内存布局配图已按新脚本重生成(自检通过);doc-links --all --sections-strict 通过 (195 文档);mojibake / bom-guard / coding-standard / 新编号门禁自查 全 rc=0; git diff --check 干净。
126 lines
4.1 KiB
C
126 lines
4.1 KiB
C
/*
|
||
* 模块名称:采样环缓冲(全周傅氏相量计算的输入)
|
||
* 模块功能:按语义通道保存最近 2 个周波(40 点)采样值,供 全周傅氏相量计算按窗取数。
|
||
* 适用平台:STM32F407ZGTx(纯算法,无寄存器/无 RTOS 依赖)
|
||
* 作者:王建锋
|
||
* 创建日期:2026-10-10
|
||
* 修改记录:
|
||
* v1.0 2026-10-10 王建锋 创建:全周傅氏相量输入环缓冲(20 点/周波 × 2 周波)
|
||
*/
|
||
|
||
#include "sample_ring.h"
|
||
|
||
#include <stddef.h>
|
||
|
||
/* 采样环:[语义通道][点]。按语义通道索引(0..ADC_SEM_COUNT-1),
|
||
* 故消费侧"按语义取数",不依赖任何物理通道号或转换器归属。 */
|
||
static float s_ring[ADC_SEM_COUNT][SAMPLE_RING_DEPTH];
|
||
/* 写指针:下一个待写入的点下标(0..SAMPLE_RING_DEPTH-1) */
|
||
static uint16_t s_head;
|
||
/* 已累积点数(饱和于 SAMPLE_RING_DEPTH) */
|
||
static uint16_t s_filled;
|
||
/* 累计入环帧数(不饱和,供心跳/丢帧观测) */
|
||
static uint32_t s_frames;
|
||
|
||
/*
|
||
* 函数功能:采样环缓冲初始化
|
||
* 入口参数:无
|
||
* 返 回 值:无
|
||
* 限定条件:无
|
||
* 函数说明:清空全部通道历史与计数;可重复调用(幂等)。
|
||
*/
|
||
void sample_ring_init(void) {
|
||
uint8_t c;
|
||
uint16_t i;
|
||
|
||
for (c = 0u; c < (uint8_t)ADC_SEM_COUNT; c++) {
|
||
for (i = 0u; i < SAMPLE_RING_DEPTH; i++) {
|
||
s_ring[c][i] = 0.0f;
|
||
}
|
||
}
|
||
s_head = 0u;
|
||
s_filled = 0u;
|
||
s_frames = 0u;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:压入一拍(一帧)全部语义通道的采样值
|
||
* 入口参数:values - 按语义通道顺序排列的一帧采样值(长度须 = ADC_SEM_COUNT)
|
||
* n - 实际长度(必须等于 ADC_SEM_COUNT)
|
||
* 返 回 值:0 - 成功;-1 - 参数错
|
||
* 限定条件:同一帧内各通道须同刻(同族量同刻性由上游 语义取数与有效性负责)
|
||
* 函数说明:整帧写入完毕后**统一**推进写指针——单帧内不存在"半新半旧",
|
||
* 消费侧取到的窗永远落在整帧边界上(无帧内撕裂)。
|
||
*/
|
||
int sample_ring_push_frame(const float *values, uint8_t n) {
|
||
uint8_t c;
|
||
|
||
if ((values == NULL) || (n != (uint8_t)ADC_SEM_COUNT)) {
|
||
return -1;
|
||
}
|
||
|
||
for (c = 0u; c < (uint8_t)ADC_SEM_COUNT; c++) {
|
||
s_ring[c][s_head] = values[c];
|
||
}
|
||
|
||
s_head = (uint16_t)((s_head + 1u) % SAMPLE_RING_DEPTH);
|
||
if (s_filled < SAMPLE_RING_DEPTH) {
|
||
s_filled++;
|
||
}
|
||
s_frames++;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:取指定语义通道最近 n 点的窗(按时间序,旧 → 新)
|
||
* 入口参数:ch - 语义通道
|
||
* n - 取点数(1..SAMPLE_RING_DEPTH)
|
||
* out - 输出缓冲(长度须 >= n)
|
||
* 返 回 值:0 - 成功;-1 - 参数错;-2 - 已累积点数不足 n
|
||
* 限定条件:无
|
||
* 函数说明:out[n-1] 为最新一点。最老点下标 = head - n(模 DEPTH)。
|
||
*/
|
||
int sample_ring_window(adc_semantic_t ch, uint8_t n, float *out) {
|
||
uint16_t start;
|
||
uint16_t i;
|
||
|
||
if ((out == NULL) || ((unsigned int)ch >= (unsigned int)ADC_SEM_COUNT)) {
|
||
return -1;
|
||
}
|
||
if ((n == 0u) || (n > SAMPLE_RING_DEPTH)) {
|
||
return -1;
|
||
}
|
||
if (s_filled < (uint16_t)n) {
|
||
return -2;
|
||
}
|
||
|
||
start = (uint16_t)((s_head + SAMPLE_RING_DEPTH - (uint16_t)n) % SAMPLE_RING_DEPTH);
|
||
for (i = 0u; i < (uint16_t)n; i++) {
|
||
out[i] = s_ring[ch][(uint16_t)((start + i) % SAMPLE_RING_DEPTH)];
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:读已累积点数(饱和于 SAMPLE_RING_DEPTH)
|
||
* 入口参数:无
|
||
* 返 回 值:已累积点数(0..SAMPLE_RING_DEPTH)
|
||
* 限定条件:无
|
||
* 函数说明:供上层判断"数据是否够一周波"。
|
||
*/
|
||
uint16_t sample_ring_filled(void) {
|
||
return s_filled;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:读累计入环帧数(不饱和)
|
||
* 入口参数:无
|
||
* 返 回 值:累计入环帧数
|
||
* 限定条件:无
|
||
* 函数说明:供心跳日志 / 丢帧观测(采样有效性校验 判据之一)。
|
||
*(保护功能清单见 docs/算法/继电保护功能复现规划.md)
|
||
*/
|
||
uint32_t sample_ring_frames(void) {
|
||
return s_frames;
|
||
}
|