3. 抗积分饱和PID
任务目标
在标准PID控制器中,当系统存在持续误差(如启动阶段或执行器饱和)时,积分项会不断累积,导致积分饱和(windup)。这会造成严重的超调、振荡甚至系统失稳。本案例实现一个带积分限幅和抗积分饱和机制的PID控制器,核心策略为:当控制器输出达到执行器限幅时,停止积分累加(条件积分法),从而防止积分过度累积。
核心实现
#include <stdio.h>
#include <stdint.h>
typedef struct {
float kp, ki, kd; // PID增益
float dt; // 采样周期(s)
float integral; // 积分累积值
float prev_error; // 上一次误差
float out_min, out_max; // 执行器输出限幅
float int_min, int_max; // 积分限幅(抗饱和上限)
} AntiWindupPID;
void pid_init(AntiWindupPID *pid, float kp, float ki, float kd, float dt,
float out_min, float out_max) {
pid->kp = kp; pid->ki = ki; pid->kd = kd; pid->dt = dt;
pid->integral = 0.0f;
pid->prev_error = 0.0f;
pid->out_min = out_min; pid->out_max = out_max;
// 积分限幅设为输出限幅的1.5倍(工程经验值,可按需调整)
pid->int_min = out_min * 1.5f;
pid->int_max = out_max * 1.5f;
}
float pid_update(AntiWindupPID *pid, float setpoint, float measurement) {
float error = setpoint - measurement;
float p_term = pid->kp * error;
// 积分项(带限幅)
pid->integral += pid->ki * error * pid->dt;
if (pid->integral > pid->int_max) pid->integral = pid->int_max;
if (pid->integral < pid->int_min) pid->integral = pid->int_min;
// 微分项(实际微分,带低通滤波可在此扩展)
float d_term = pid->kd * (error - pid->prev_error) / pid->dt;
pid->prev_error = error;
// 计算未限幅输出
float output = p_term + pid->integral + d_term;
// 抗积分饱和:输出饱和时,撤销本次积分累加
if (output > pid->out_max) {
output = pid->out_max;
pid->integral -= pid->ki * error * pid->dt; // 回退积分
} else if (output < pid->out_min) {
output = pid->out_min;
pid->integral -= pid->ki * error * pid->dt;
}
return output;
}
// 简单测试:模拟电机启动(设定值阶跃,执行器饱和)
int main() {
AntiWindupPID pid;
pid_init(&pid, 2.0f, 0.5f, 0.1f, 0.01f, -100.0f, 100.0f);
float measurement = 0.0f;
float setpoint = 50.0f; // 目标位置
float output;
printf("step, measurement, output, integral\n");
for (int i = 0; i < 200; i++) {
output = pid_update(&pid, setpoint, measurement);
// 模拟一阶被控对象(电机响应)
measurement += (output * 0.1f - measurement) * 0.05f;
if (i % 20 == 0)
printf("%d, %.2f, %.2f, %.2f\n", i, measurement, output, pid.integral);
}
return 0;
}
运行与验证
编译运行:
gcc -o antiwindup antiwindup.c -lm
./antiwindup
验证方法:观察输出数据,系统应满足:
- 启动阶段输出被限制在±100以内,不会超出执行器限幅;
- 测量值最终收敛到设定值50附近,无明显超调(超调量<5%);
- 积分项数值始终在积分限幅范围内(±150),不会无限增长。
对比测试:将pid_update中抗饱和回退逻辑注释掉(删除integral -= ...两行),重新编译运行,可观察到测量值出现明显超调(通常>15%)和振荡,以此验证抗饱和机制的有效性。
关键说明
- 积分限幅(
int_min/int_max)与输出限幅解耦,允许积分项在输出饱和时仍保留一定余量,避免积分完全失效; - 条件积分法(输出饱和时回退积分)是工程中最常用的抗饱和策略,实现简单且无需额外状态判断;
- 实际工程中若被控对象存在纯滞后,建议在微分项后级联一阶低通滤波器(截止频率≈1/(2π·dt)),本案例为聚焦抗饱和逻辑未包含该部分。