/* * 模块名称:采样环缓冲(L2 相量计算的输入) * 模块功能:按语义通道保存最近 2 个周波(40 点)采样值,供 L2 相量计算按窗取数。 * 适用平台:STM32F407ZGTx(纯算法,无寄存器/无 RTOS 依赖) * 作者:王建锋 * 创建日期:2026-10-10 * 修改记录: * v1.0 2026-10-10 王建锋 创建:L2 输入环缓冲(20 点/周波 × 2 周波) */ #include "sample_ring.h" #include /* 采样环:[语义通道][点]。按语义通道索引(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 - 参数错 * 限定条件:同一帧内各通道须同刻(同族量同刻性由上游 L1 负责) * 函数说明:整帧写入完毕后**统一**推进写指针——单帧内不存在"半新半旧", * 消费侧取到的窗永远落在整帧边界上(无帧内撕裂)。 */ 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; }