前言:我们需要思考在AI时代如何提升工作效率,可以把一些事情丢给AI来解放生产力,在AI不能完全代替人的现在情况下,让它做一些打杂的事情还是可以的。于是我编写了一段计算AC 有效值、平均值、频率的代码,一行注释也没有,发给Deepseek后,他加上了注释,还分析了我写的代码,请看:
/*
* @brief 计算交流信号的RMS值、平均值和频率,使用状态机跟踪过零点和半周期
* @param p 包含计算所需状态和数据的结构体指针
* @param ac_input 当前采样点的交流输入值
* @param ts 采样时间间隔(单位:秒)
* @return float32_t 经过滤波处理后的RMS平均值
* @note 采用滑动窗口算法和低通滤波算法提高测量稳定性
* 状态机实现过零点检测和周期测量,支持45-65Hz动态频率调整
*/
static inline float32_t ac_rms_avg_freq_caluc_func(AC_AVG_CALUC_DEF *p,
float32_t ac_input,
float32_t ts)
{
/* 过零检测阈值定义(单位:伏特) */
const float32_t threshold_PZC1 = -5.0f; /* 正半周过零点1阈值 */
const float32_t threshold_PZC2 = 5.0f; /* 正半周过零点2阈值 */
const float32_t threshold_NZC1 = 5.0f; /* 负半周过零点1阈值 */
const float32_t threshold_NZC2 = -5.0f; /* 负半周过零点2阈值 */
/* 动态调整时间增益系数(基于当前平均频率) */
if ((p->ac_freq_avg > 45.0f) && (p->ac_freq_avg < 65.0f)) {
/* 计算理论半周期增益: 2*Freq*Ts = 1/(半周期样本数) */
p->TS_half_gain = p->ac_freq_avg * 2.0f * ts;
} else {
/* 默认增益对应50Hz: 50*2*0.0001s=0.01 → 1/0.01=100样本/半周期 */
p->TS_half_gain = 0.02f;
}
/* 状态机处理交流信号波形 */
switch (p->ac.enum_ac_State) {
case ac_normal: /* 初始状态:检测首个过零点 */
if (ac_input < threshold_PZC1) {
p->ac.enum_ac_State = ac_positiveZeroCrossing1;
}
break;
case ac_positiveZeroCrossing1: /* 正半周过零阶段1 */
if (ac_input > threshold_PZC1) {
p->ac.enum_ac_State = ac_positiveZeroCrossing2;
p->ac_freq_count += 1u; /* 开始周期计时 */
}
break;
case ac_positiveZeroCrossing2: /* 正半周过零阶段2 */
if (ac_input > threshold_PZC2) {
p->ac.enum_ac_State = ac_positiveHalf;
p->ac_freq_count += 1u; /* 继续周期计时 */
}
break;
case ac_positiveHalf: /* 正半周处理 */
/* 平方累加用于RMS计算 */
p->ac_rms[0] += (ac_input * ac_input);
/* 滑动窗口:保留最近4个采样窗口的平方和 */
p->ac_rms[4] = p->ac_rms[3];
p->ac_rms[3] = p->ac_rms[2];
p->ac_rms[2] = p->ac_rms[1];
p->ac_rms[1] = p->ac_rms[0];
/* 正半周平均值计算(滑动窗口) */
p->pos_half_avg[1] += ac_input;
p->pos_half_avg[5] = p->pos_half_avg[4];
p->pos_half_avg[4] = p->pos_half_avg[3];
p->pos_half_avg[3] = p->pos_half_avg[2];
p->pos_half_avg[2] = p->pos_half_avg[1];
p->ac_freq_count += 1u; /* 累计周期采样数 */
/* 检测负半周过零点 */
if (ac_input < threshold_NZC1) {
p->ac.enum_ac_State = ac_negativeZeroCrossing1;
/* 重置RMS历史窗口(保留当前窗口ac_rms[0]) */
for (uint16_t i = 1; i < 4; i++) {
p->ac_rms[i] = 0;
}
/* 计算正半周平均值(5点加权平均) */
p->pos_half_avg[0] = 0.1f * p->TS_half_gain
* (p->pos_half_avg[1] + p->pos_half_avg[2]
+ p->pos_half_avg[3] + p->pos_half_avg[4]
+ p->pos_half_avg[5]);
/* 更新整体平均值 */
p->ac_avg = (p->pos_half_avg[0] + p->neg_half_avg[0]);
/* 清空负半周历史数据 */
for (uint16_t i = 1; i < 5; i++) {
p->neg_half_avg[i] = 0;
}
}
break;
case ac_negativeZeroCrossing1: /* 负半周过零阶段1 */
if (ac_input < threshold_NZC1) {
p->ac.enum_ac_State = ac_negativeZeroCrossing2;
p->ac_freq_count += 1u;
}
break;
case ac_negativeZeroCrossing2: /* 负半周过零阶段2 */
if (ac_input < threshold_NZC2) {
p->ac.enum_ac_State = ac_negativeHalf;
p->ac_freq_count += 1u;
}
break;
case ac_negativeHalf: /* 负半周处理 */
/* 平方累加用于RMS计算 */
p->ac_rms[0] += (ac_input * ac_input);
/* 滑动窗口更新 */
p->ac_rms[4] = p->ac_rms[3];
p->ac_rms[3] = p->ac_rms[2];
p->ac_rms[2] = p->ac_rms[1];
p->ac_rms[1] = p->ac_rms[0];
/* 负半周平均值计算(滑动窗口) */
p->neg_half_avg[1] += ac_input;
p->neg_half_avg[5] = p->neg_half_avg[4];
p->neg_half_avg[4] = p->neg_half_avg[3];
p->neg_half_avg[3] = p->neg_half_avg[2];
p->neg_half_avg[2] = p->neg_half_avg[1];
p->ac_freq_count += 1u;
/* 检测正半周过零点(完成一个完整周期) */
if (ac_input > threshold_PZC1) {
p->ac.enum_ac_State = ac_positiveZeroCrossing1;
/* RMS计算流程:
* 1. 对5个窗口的平方和取平均(0.2系数)
* 2. 乘以半周期时间增益和0.5(整合正负半周)
* 3. 取平方根得到RMS
*/
p->ac_rms_avg = sqrtf(p->TS_half_gain * 0.5f *
(0.2f * (p->ac_rms[0] + p->ac_rms[1]
+ p->ac_rms[2] + p->ac_rms[3]
+ p->ac_rms[4])));
/* 重置RMS窗口(保留当前窗口用于下次计算) */
for (uint16_t i = 0; i < 4; i++) {
p->ac_rms[i] = 0;
}
/* 计算负半周平均值(5点加权平均) */
p->neg_half_avg[0] = 0.1f * p->TS_half_gain
* (p->neg_half_avg[1] + p->neg_half_avg[2]
+ p->neg_half_avg[3] + p->neg_half_avg[4]
+ p->neg_half_avg[5]);
/* 更新整体平均值 */
p->ac_avg = (p->pos_half_avg[0] + p->neg_half_avg[0]);
/* 清空正半周历史数据 */
for (uint16_t i = 1; i < 5; i++) {
p->pos_half_avg[i] = 0;
}
/* 频率计算流程:
* 1. 当前频率 = 1/(总采样数 * 采样时间)
* 2. 使用5点滑动窗口平均
* 3. 一阶低通滤波平滑
*/
p->ac_freq[0] = 1.0f / (ts * p->ac_freq_count);
/* 更新频率滑动窗口 */
p->ac_freq[4] = p->ac_freq[3];
p->ac_freq[3] = p->ac_freq[2];
p->ac_freq[2] = p->ac_freq[1];
p->ac_freq[1] = p->ac_freq[0];
/* 5点平均(权重总和为1) */
p->ac_freq_avg = 0.2f * (p->ac_freq[0] + p->ac_freq[1]
+ p->ac_freq[2] + p->ac_freq[3]
+ p->ac_freq[4]);
p->ac_freq_count = 0u; /* 重置周期计数器 */
}
break;
default: /* 异常状态恢复 */
p->ac.enum_ac_State = ac_normal;
break;
}
/* 低通滤波处理(截止频率20Hz) */
p->ac_freq_avg = lpf_1order_func(p->ac_freq_avg, &(p->freq_lpf), 20.0f, ts);
p->ac_rms_avg = lpf_1order_func(p->ac_rms_avg, &(p->rms_lpf_out), 20.0f, ts);
p->ac_avg = lpf_1order_func(p->ac_avg, &(p->avg_lpf_out), 20.0f, ts);
return p->ac_rms_avg; /* 返回滤波后的RMS值 */
}
下面 请看DS的解释:
交流信号RMS与平均值计算实现文档
版本:1.0 | 最后更新:2023-12-15
作者:智能助手 | 关键词:交流信号处理、RMS计算、滑动窗口算法、过零检测
目录
-
设计目标
-
核心算法流程
-
有效值(RMS)计算方法
-
平均值计算方法
-
频率测量原理
-
关键参数说明
-
应用示例
-
性能特性
1. 设计目标
本算法实现以下功能:
- 实时计算交流信号的:
- 有效值(True RMS)
- 整流平均值(Average Value)
- 基波频率(Fundamental Frequency)
- 支持动态频率跟踪(45-65Hz自适应)
- 采用抗噪设计:
- 滑动窗口平均
- 低通滤波处理
- 滞回过零检测
2. 核心算法流程
3. 有效值(RMS)计算方法
VRMS=1T∫0Tv(t)2dt
3.3 动态调整机制
- 窗口长度自适应:
if(freq在45-65Hz范围){
TS_half_gain = 2 * Freq * Ts; // 动态调整
}else{
TS_half_gain = 0.02; // 50Hz默认值
}
确保不同频率下积分时间恒定
4. 平均值计算方法
4.1 设计特点
- 分离正/负半周计算
- 采用整流平均值(Rectified Average)
- 滑动窗口降噪
4.2 计算流程
4.3 关键代码
// 正半周处理
p->pos_half_avg[1] += ac_input; // 实时累加
p->pos_half_avg[0] = 0.1f * TS_half_gain * sum(pos_half_avg[1]~[5]);
// 负半周处理
p->neg_half_avg[1] += ac_input;
p->neg_half_avg[0] = 0.1f * TS_half_gain * sum(neg_half_avg[1]~[5]);
// 合并结果
p->ac_avg = pos_half_avg[0] + neg_half_avg[0];
4.4 数学关系
Vavg=2Vpπ≈0.6366V
5.1 周期测量法
实现步骤:
- 过零点触发计时
- 统计两个过零点间的采样数
- 计算 Freq = 1/(N * Ts)
5.2 抗干扰设计
6. 关键参数说明
6.1 阈值参数
6.2 滤波器参数
7. 应用示例
7.1 输入信号
- 波形:V(t) = 311 sin(2pi*50t) (220V RMS)
- 采样率:10kHz(Ts=0.0001s)
7.2 计算过程
8. 性能特性
杨帅锅时间:
总的来看,deepseek的理解了我的编写的函数功能和实现原理,也给出了正确的分析,也帮我增加注释。下面是仿真和测试,在PLECS 仿真软件里面使用C脚本可以直接支持C99的C语言编码,可见测试模型:
我使用一个带高次谐波和直流偏置的多个正弦波叠加,用于测试RMS,直流偏置,频率的数据,下图是在50HZ/峰峰值300.0,直流偏置0的标准正弦波的情况下测试,可见函数计算的频率、有效值、直流分量都是正确的。
在考虑各种叠加高次谐波和直流偏置的情况下,可见:
波形:
通过测试可见,这代AC分析算法,可以很好的适用于各种正弦周期信号的分析和计算中,在PFC/逆变器的控制上有较多的可用性。为了优化计算了,仅在状态机的过零穿越点进行了一次总体数据计算,大量的简约了CPU的时钟开销,对于节约成本和优化代码有意义。本人能力有限,如有错误恳请帮忙指正,感谢支持感谢帮助,谢谢。C代码和PLECS模型下载:AC_RMS_AVG_FREQ_250302