2. PID控制基础理论:比例(P)、积分(I)、微分(D)的物理意义与数学模型
各位好,欢迎来到第二章。说实话,PID 这三个字母,搞嵌入式的没人不认识。但你真的理解它背后的物理意义吗?
我见过不少同事,调参全靠“试”,拧一下比例,转一下积分,波形抖了就降,响应慢了就加。运气好能调出来,运气不好就原地打转。其实,理解 P、I、D 各自在干什么,调试效率能翻一倍。
这一章,咱们就把 PID 的底裤扒干净。从物理意义到数学模型,再到离散化实现,一步到位。
2.1 比例控制(P)—— 当下的误差,当下的响应
比例控制是最直观的。说白了,就是“误差有多大,我就推多大力”。
数学上很简单:
u(t) = Kp * e(t)
其中 e(t) 是当前误差,Kp 是比例增益。
物理意义呢?你想想看,一个弹簧。你拉得越长,它往回弹的力就越大。比例控制就是这个弹簧。
核心特点:
- 响应快:误差一出现,立即输出控制量
- 有静差:纯比例控制无法消除稳态误差
- Kp 越大:响应越快,但容易超调、振荡
我在项目中遇到过一个问题:一个直流电机速度环,只用 P 控制,空载时转速很稳,但一加载,转速就掉下来,永远回不到设定值。这就是静差。比例控制需要误差存在才能输出,所以它永远“差一口气”。
调试小技巧:
我个人习惯先调 P,让系统稳定下来,不振荡。然后看稳态误差有多大,再决定要不要加 I。
2.2 积分控制(I)—— 过去的积累,消除静差
积分控制解决的就是 P 留下的“那口气”。它把过去的误差全部累加起来,只要还有误差,积分项就会一直增长,直到误差归零。
数学形式:
u(t) = Ki * ∫ e(t) dt
物理意义?像一个不断注水的水桶。误差是水流,积分项是水位。只要还在漏水(有误差),水位就会一直上升,直到把漏洞堵住。
核心特点:
- 消除静差:这是 I 的唯一使命
- 引入滞后:积分需要时间积累,响应变慢
- 积分饱和:这是个大坑,后面会讲
我曾经吃过积分饱和的亏。一个温控系统,启动时误差很大,积分项疯狂累加,等温度到了设定值,积分项已经积累了一大堆,导致温度冲过头,来回振荡了好几次才稳定下来。后来加了抗积分饱和,问题才解决。
避坑指南:
积分项不是越大越好。Ki 太大,系统会振荡;Ki 太小,消除静差的速度太慢。我一般从 Ki = Kp / 100 开始试,再根据响应曲线微调。
2.3 微分控制(D)—— 未来的预测,抑制超调
微分控制看的是误差的变化趋势。误差在变大,它就反向输出,阻止它继续变大;误差在变小,它就“收油”,防止冲过头。
数学形式:
u(t) = Kd * de(t)/dt
物理意义?像一个“阻尼器”。你推门的时候,门后面有个阻尼器,你推得越快,它阻力越大。微分项就是干这个的。
核心特点:
- 抑制超调:提前“刹车”,让系统更平稳
- 对噪声敏感:微分放大高频噪声,这是它的致命伤
- 不能单独使用:D 必须配合 P 或 PI 使用
嗯,这里要注意。微分项在实际工程中很容易引入噪声。我做过一个伺服电机位置环,加了 D 之后,波形反而更抖了。后来一查,是编码器信号有毛刺,微分项把这些毛刺放大了。解决办法是加一个低通滤波器,或者用不完全微分。
实用建议:
如果系统本身惯性很大(比如大负载的电机),D 的效果很明显。如果系统噪声大,建议先做信号滤波,再考虑加 D。
2.4 PID 控制器传递函数
把 P、I、D 合在一起,就是完整的 PID 控制器。在连续域(s 域)中,它的传递函数长这样:
G(s) = Kp + Ki/s + Kd * s
或者写成更标准的形式:
G(s) = Kp * (1 + 1/(Ti * s) + Td * s)
其中:
- Ti = Kp / Ki:积分时间常数
- Td = Kd / Kp:微分时间常数
这两种形式在工程中都会用到。我个人更喜欢用 Kp、Ki、Kd 的形式,因为调试时直接调这三个值,更直观。
传递函数有什么用?它让我们可以用频域分析工具(比如波特图)来研究系统的稳定性。不过在实际嵌入式调试中,我们更多是看时域响应曲线。
2.5 数字 PID 离散化方法
好了,理论讲完了。但我们的单片机是数字系统,它不认识连续的积分和微分。所以,必须把 PID 算法离散化,变成单片机能跑的代码。
离散化的核心思想:
- 积分 → 累加:把连续的积分变成离散的求和
- 微分 → 差分:把连续的微分变成相邻采样点的差值
常用的离散化方法有三种:
| 方法 | 积分近似 | 微分近似 | 特点 |
|---|---|---|---|
| 前向欧拉 | e[k] * T | (e[k+1] - e[k]) / T | 实现简单,但稳定性稍差 |
| 后向欧拉 | e[k] * T | (e[k] - e[k-1]) / T | 最常用,稳定,推荐 |
| 双线性变换 | (e[k] + e[k-1]) * T / 2 | 2 * (e[k] - e[k-1]) / T - 前值 | 精度最高,计算量大 |
其中 T 是采样周期。采样周期怎么选?我一般遵循“采样频率是系统带宽的 10 倍以上”这个原则。比如电机电流环带宽 1kHz,采样频率至少 10kHz。
下面给出最常用的位置式 PID 离散化公式(后向欧拉法):
u[k] = Kp * e[k] + Ki * Σ(e[i] * T) + Kd * (e[k] - e[k-1]) / T
对应的 C 代码实现:
float pid_update(float setpoint, float measurement) {
float error = setpoint - measurement;
// 比例项
float p_out = Kp * error;
// 积分项(累加)
integral += error * dt;
float i_out = Ki * integral;
// 微分项(差分)
float derivative = (error - prev_error) / dt;
float d_out = Kd * derivative;
// 保存当前误差供下次使用
prev_error = error;
// 总输出
return p_out + i_out + d_out;
}
重要提醒:
上面的代码只是教学示例。实际工程中,你还需要考虑:
- 输出限幅(防止积分饱和)
- 积分分离(误差大时停止积分)
- 微分滤波(对微分项做一阶低通滤波)
这些内容我们会在后面的章节详细展开。
2.6 知识体系总览
最后,我用一张图把本章的核心内容串起来。这张图展示了 PID 从物理意义到数学建模,再到离散化实现的完整链路。
这张图把本章的知识链路完整呈现出来了。从顶层的 P、I、D 物理意义,到底层的 C 代码实现,每一步都有明确的对应关系。你调试的时候,遇到问题可以反向追溯:是 P 太强了?还是 I 饱和了?还是 D 引入了噪声?