PID比例-积分-微分控制算法
详情概述
将比例、积分、微分三种调节规律结合在一起, 只要三项作用的强度配合适当,既能快速调节,又能消除余差,可得到满意的控制效果。
- 比例(P)控制:根据偏差的大小来产生控制作用,偏差越大,控制作用越强。但单独的比例控制可能存在稳态误差。
- 积分(I)控制:主要用于消除稳态误差,它对偏差进行积分,随着时间的积累,积分作用逐渐增强,直到消除稳态误差
- 微分(D)控制:根据偏差的变化率来产生控制作用,能提前预测偏差的变化趋势,从而起到超前控制的作用,改善系统的动态性能。
PID 算法通过合理调整比例系数、积分系数和微分系数,可以实现对系统的精确控制,使系统具有良好的稳定性、准确性和快速性。
比例控制(P)(●’◡’●)
比例控制项是根据当前偏差的大小直接计算出控制量,控制量与偏差成正比。
作用:比例控制可以快速响应偏差并施加相应的控制力。当偏差较大时,比例控制的输出会较大,能够迅速纠正系统的状态。
缺点:比例控制本身无法完全消除偏差。通常会出现稳态误差,即在系统达到稳定状态后,仍然存在一个小的残留偏差。
积分控制(I)
积分控制项对偏差随时间的积累进行计算。通过累积偏差的面积来消除稳态误差。
作用:积分控制可以消除比例控制留下的稳态误差。即使偏差很小,随着时间的推移,积分项的作用会不断增加,直到偏差消除为止。
缺点:过高的积分增益可能导致系统过冲(超调)和振荡,特别是在响应速度较快的系统中。
微分控制(D)
微分控制项根据偏差的变化率进行计算。微分项预测偏差的未来变化趋势,并提前采取控制措施。
作用:微分控制可以减缓系统的超调和振荡。通过对偏差变化率的响应,微分控制能够提前减小控制量,从而使系统更平稳地接近目标值。
缺陷:微分控制对噪声敏感,容易因系统中的小幅波动产生过度反应。
PID数学模型公式🥰
PID参数调试步骤
- 先仅设置比例控制,增大 KP 值直到系统开始出现稳定的振荡。此时,系统的响应速度较快,但可能会有显著的稳态误差和超调。
- 逐步增加积分系数 Ki ,以消除稳态误差。需要注意的是,过高的积分系数会导致系统的响应变慢,并可能引发振荡。
- 最后,增加微分系数 KD 以减小超调并提高系统的稳定性。微分控制对于噪声较多的系统要谨慎使用,避免放大噪声引发不必要的波动。
可以使用Ziegler-Nichols法,将系统调到临界振荡状态,通过观测振荡周期和增益来确定PID参数。此方法适合线性系统,但可能在非线性系统中表现不佳
代码大致实现
#include <stdio.h>
// PID结构体
typedef struct {
double kp; // 比例系数
double ki; // 积分系数
double kd; // 微分系数
double prev_error; // 前一次误差
double integral; // 积分值
} PID;
// 初始化PID
void PID_Init(PID *pid, double kp, double ki, double kd) {
pid->kp = kp;
pid->ki = ki;
pid->kd = kd;
pid->prev_error = 0.0;
pid->integral = 0.0;
}
// 计算PID输出
// setpoint:目标值、measured_value:测量值、dt:时间间隔
double PID_Compute(PID *pid, double setpoint, double measured_value, double dt) {
// 计算误差
double error = setpoint - measured_value;
// 计算积分
pid->integral += error * dt;
// 计算微分
double derivative = (error - pid->prev_error) / dt;
// 计算PID输出
double output = (pid->kp * error) + (pid->ki * pid->integral) + (pid->kd * derivative);
// 保存当前误差以备下次使用
pid->prev_error = error;
return output;
}
int main() {
// 创建并初始化PID控制器
PID pid;
PID_Init(&pid, 1.0, 0.1, 0.01);
// 假设目标值和初始测量值
double setpoint = 100.0;
double measured_value = 50.0;
double dt = 0.1; // 时间间隔(秒)
// 进行一次PID计算
double output = PID_Compute(&pid, setpoint, measured_value, dt);
printf("PID 输出: %f\n", output);
return 0;
}
根据不同场景进行不同优化,如有错误,请指正