目前世界上使用最广的控制算法-PID的大白话理解及数学原理C代码
你有没有想过,为什么一些设备能够自动保持在我们想要的状态,比如房间的温度、风扇的转速等?其中一个重要的原因就是PID控制算法,PID算法是目前世界上可以说使用最广的最经典的控制算法,在自动控制领域至今地位无法被撼动。在这篇文章中,我们将以大白话的方式,深入探讨PID算法的奥秘,一篇文章就够,一定要认真读完!
1. 什么是PID?
PID(
Proportional-Integral-Derivative)控制算法是一种经典的反馈控制方法,广泛应用于自动控制系统,例如温度控制、速度控制、位置控制等。
PID控制算法的核心包含三个部分:比例项(P),积分项(I),和微分项(D)。它们分别对系统的当前误差、过去误差的积累和误差的变化率进行响应。PID控制器的输出由这三部分的加权和组成。

PID数学公式
其中,e 就是当前误差,Kp、Ki 和 Kd 分别是比例、积分和微分的调节系数。
大白话理解就是如下:
- 比例项(P):根据当前误差的大小进行调节,使系统更快地接近目标值。比如你开车时,如果离目标位置很远,就会踩得比较重。
- 积分项(I):根据过去误差的积累进行调节,消除系统持续积累的偏差。比如你在开车时,可能因为之前踩油门不足,导致距离目标位置偏差,积分项就会帮你逐渐补偿。
- 微分项(D):根据误差的变化率进行调节,提高系统的稳定性,防止系统震荡,考虑未来的趋势,比如你开车时,如果感觉速度变化很快,可能会轻踩刹车,避免过度加速。
2. 如何在现实中应用PID?
让我们结合一个简单的温度控制的案例来理解一下现实工程应用中如何实现PID控制。假设你有一个电热器,你想让它保持在40摄氏度。你可以用PID算法来调整它的加热功率。
- 比例 Kp:你观察当前温度,如果比40度低,就调高加热功率。
- 积分 Ki:如果电热器的温度长时间低于40度,积分项就慢慢增加功率,确保逐渐达到目标。
- 微分Kd:如果电热器的温度变化很快,微分项就减小功率,避免过度升温。
3. C语言实现PID控制代码
让我们看一下如何用C语言实现PID控制。我们用C语言代码实现上面的让水温保持在40摄氏度的控制算法代码如下:
#include
double compute_pid(double setpoint, double current_value, double *prev_error, double *integral, double Kp, double Ki, double Kd, double dt) {
double error = setpoint - current_value;
double derivative = (error - *prev_error) / dt;
*integral += error * dt;
double output = Kp * error + Ki * (*integral) + Kd * derivative;
*prev_error = error;
return output;
}
int main() {
double setpoint = 40.0; // 目标温度
double current_value = 25.0; // 当前温度
double prev_error = 0.0;
double integral = 0.0;
double Kp = 0.05;
double Ki = 0.01;
double Kd = 0.5;
double dt = 1.0; // 控制周期
int i;
for (i = 0; i < 10; i++) {
double output = compute_pid(setpoint, current_value, &prev_error, &integral, Kp, Ki, Kd, dt);
// 模拟应用PID控制器输出
current_value += output;
printf("%f\n", current_value);
}
return 0;
}

C代码实现
我们来解释一下代码,main函数中setpoint就是温度目标值,我们目标水温是40摄氏度,所以我们这里是40。current_value就是温度实际当前值。prev_error是记录上一次的温度误差。integral记录所有累积误差值。kp,ki和kd分别是三个控制项的权重比例系数,我们就是通过调节这三个参数来到较好的控制效果。dt是控制周期为1s。for循环次数变量i就是是控制周期次数,在这里我们只是简单给个10次。每一次循环我们都调用compute_pid函数来计算误差输出。compute_pid函数就是核心代码,实现了PID算法,下面我们来看看如何计算的,需要结合上面的数学公式理解:
第4行,double error = setpoint - current_value;这是将目标值减去当前温度值得到的error是当前时刻的温度误差。
第5行,double derivative = (error - *prev_error) / dt;就是误差微分控制项计算,当前误差error减去上一次误差prev_error,再除以时间周期dt,典型微分计算。
第7行,*integral += error * dt;这个就是积分项计算,误差error乘以时间周期dt,再将其加入到之前的累计误差和integral中,integral就保存了累计误差和。
第9行,就是总输出计算,三个误差控制项分别乘以自己的权重比例系数,最终将三个误差控制项叠加输出。
第30行就是将本次周期的误差控制输出叠加到实际当前温度值,起到调节当前温度的目的。
到此我们就完全学会了通过C代码简单实现PID控制。
4. 如何“调参”?
通过上面你可以知道,PID算法公式固定,其实代码实现工程中应用中也基本上是通用固定的,所以实现不难,难就难在如何调参?如何通过调整kp,ki,kd三个误差控制项的权重系统值,让你的控制效果达到最佳状态。
调整PID的三个参数就像是调整你做菜的火候一样,需要一些经验。这里有一些宝贵的通用调参思路:
- 比例系数Kp:如果你觉得系统反应慢,可以增大Kp。但如果太大,系统可能会过冲。
- 积分系数Ki:增大Ki可以减小系统持续存在累计偏差,但太大可能导致系统过度调整,反而不稳定。
- 微系数Kd:增大Kd 可以减小系统震荡,但太大可能使系统对噪声过于敏感。
下面我们结合曲线图来展示一下调参的大概过程。
1.这是上面C代码的默认参数,Kp = 0.05,Ki = 0.01,Kd = 0.5,当前实际温度输出曲线如下:

响应过慢
图中红色水平线是目标值40,蓝色线是温度实际输出值,下面所有曲线图都一样。
我们可以看到Kp比例系数过小导致温度10个控制周期结束也未达到40摄氏度。
下面要加大kp。
2.将Kp = 0.5,其他不变,Ki = 0.01,Kd = 0.5,曲线如下:

过冲
可以看到结果过冲了,第一个温度值直接大于40度了,后面一直震荡,这样肯定不行。
3.将Kp = 0.3,其他不变,Ki = 0.01,Kd = 0.5,曲线如下:

比例调节比较合适
可以看到这个比例调节响应就比较合适,而且快速稳步最终温度接近40。
4.Kp = 0.3差不多,我们调整一下ki,Ki =调整为0.1,Kd = 0.5,曲线如下:

积分过调整
可以看到明显积分项过于调整,其实上一次默认ki=0.01的时候,我们看到累积误差最后非常小,0.01这个值本身已经比较合适了,现在放大10倍积分项,一下子就过调了,让大家了解一下过调是什么样子的,这里我们将ki改回到0.01,ki就不做调整了。
5.Kp = 0.3,Ki = 0.01,下面我们看一下温度值在靠近40度的过程中,温度值的震荡非常大,这个应该是微分项权重过大,导致变化率影响过于敏感,我们减小点kd系数,调整为Kd = 0.2;曲线如下:

kd调小
可以看到Kd调小之后,效果好很多,整个响应曲线光滑很多,震荡非常小了。
当然到此,调参工作其实还是没结束,因为通过调节还能达到更好的效果,这里我就不继续下去了,以此几步调参基本给大家展示一下调参大概过程,相信通过以上过程大家对调参有个更加直观深刻的体会了。
控制领域有句话,控制算法工程就是调参大师,这句话虽然有点嘲讽但是是大实话,不过记住一点,调参能调到一个比较好的效果前提是你要深刻理解算法思想。
后续持续更新系列高质量文章,码字不易,觉得写的不错欢迎关注、点赞、收藏以及提问。
菜鸟问:市场上面看到很多说是pid算法调温的设备,例如电烙铁,工具非常小,应该是用芯片完成这样的控制,是专门有这样的芯片吗?
一般是pid算法控制代码以固件形式跑在芯片(比如MCU)上,芯片平台可以换
九零年上学的时候导师让我做一个恒温箱控制器,他教我的就是这个PID。后来导师让我试试模糊控制,也做成了,效果也很好。两个控制法都需要调参,调参人工调,后来听说有人工智能,意思是机器可以学习被控制系统的特征,自己学会调参。
您这是前辈了,专家了。调参师训练AI替自己调参
PID控制惯性较大,变化缓慢的效果较好,比如说控制温度。 调节阀门大小,控制风机压力,使用PID算法效果不理想,阀门一多开一点,压力立即太大,阀门少开一点压力又太小,波动太大