位置式PID与增量式PID:两种算法的数学推导、优缺点对比、适用场景分析
做电机控制这些年,我见过不少新手在PID实现上栽跟头。明明算法原理都懂,一写代码就出问题。说白了,就是没搞清楚位置式和增量式的本质区别。
这一章,咱们就把这两种PID算法掰开揉碎了讲。我会从数学推导开始,再到实际项目中的坑,最后告诉你什么场景该用哪个。
1. 位置式PID:最直观的算法
位置式PID,顾名思义,直接计算当前时刻的控制量。它的数学形式是这样的:
u(k) = Kp * e(k) + Ki * Σe(i) + Kd * [e(k) - e(k-1)]
其中:
- u(k):第k时刻的控制输出
- e(k):第k时刻的偏差(目标值 - 实际值)
- Σe(i):从开始到现在的偏差累加
- Kp, Ki, Kd:比例、积分、微分系数
这个公式看着简单,但有个关键问题——积分项会一直累加。我在做直流电机调速时遇到过这种情况:电机启动瞬间偏差很大,积分项疯狂累加,等电机转起来后,这个积分值已经大到离谱,导致系统严重超调。
⚠ 避坑指南:位置式PID的积分饱和是新手最容易踩的坑。我曾经在一个温控项目中,积分项累加到了满量程的3倍,系统直接失控。解决办法是加积分限幅,或者用抗积分饱和算法。
2. 增量式PID:只算变化量
增量式PID的思路完全不同——它只计算当前控制量相对于上一次的变化量。数学推导如下:
先写出k-1时刻的位置式:
u(k-1) = Kp * e(k-1) + Ki * Σe(i-1) + Kd * [e(k-1) - e(k-2)]
然后用u(k)减去u(k-1),得到增量:
Δu(k) = Kp * [e(k) - e(k-1)] + Ki * e(k) + Kd * [e(k) - 2*e(k-1) + e(k-2)]
最终的控制输出:
u(k) = u(k-1) + Δu(k)
你想想看,这个公式有什么好处?没有积分累加项。每次只算变化量,就算偏差很大,也不会出现积分饱和的问题。
💡 个人经验:我在做四轴飞行器姿态控制时,用的就是增量式PID。飞行器姿态变化快,如果位置式PID的积分项处理不好,飞机会抖得像筛子一样。增量式天然避免了这个问题。
3. 两种算法的核心差异
为了让你看得更清楚,我整理了一个对比表:
| 对比维度 | 位置式PID | 增量式PID |
|---|---|---|
| 计算方式 | 直接计算全量控制输出 | 只计算控制量的变化值 |
| 积分项 | 偏差累加,可能饱和 | 无累加项,天然抗饱和 |
| 输出突变 | 切换时可能产生大跳变 | 输出平滑,无跳变 |
| 故障影响 | 输出异常可能导致执行器全开 | 输出异常影响较小 |
| 内存需求 | 需存储所有历史偏差 | 只需存储最近3个偏差 |
| 手动/自动切换 | 需做无扰切换处理 | 天然支持无扰切换 |
4. 适用场景分析
搞清楚了差异,咱们来看看实际项目中该怎么选。
4.1 位置式PID适合的场景
- 执行器有记忆功能:比如步进电机的位置控制,每次给一个绝对位置值
- 系统对积分精度要求高:比如高精度温控,需要精确消除静差
- 控制周期固定且较长:有足够时间处理积分饱和问题
- 输出直接对应物理量:比如阀门开度、加热功率等
4.2 增量式PID适合的场景
- 执行器是积分元件:比如伺服电机的速度环,增量输出直接对应加速度
- 系统需要频繁切换:比如手动/自动模式切换,增量式天然无扰
- 对输出突变敏感:比如精密运动控制,不允许控制量跳变
- 嵌入式资源受限:只需存储3个偏差值,内存占用极小
🔧 实战建议:我个人习惯在电机速度环和位置环中使用增量式PID,在温度控制这类大惯性系统中使用位置式PID。当然,这不是绝对的,具体还要看你的执行器特性和控制要求。
5. 两种算法的代码实现对比
光说不练假把式。我写两个简单的C语言实现,你看看区别:
// 位置式PID
float PositionalPID(float setpoint, float feedback) {
float error = setpoint - feedback;
integral += error; // 积分累加
float derivative = error - prev_error;
float output = Kp * error + Ki * integral + Kd * derivative;
// 输出限幅
if (output > max_output) output = max_output;
if (output < min_output) output = min_output;
prev_error = error;
return output;
}
// 增量式PID
float IncrementalPID(float setpoint, float feedback) {
float error = setpoint - feedback;
float delta = Kp * (error - prev_error)
+ Ki * error
+ Kd * (error - 2*prev_error + prev_prev_error);
output += delta; // 累加增量
// 输出限幅
if (output > max_output) output = max_output;
if (output < min_output) output = min_output;
prev_prev_error = prev_error;
prev_error = error;
return output;
}
看到区别了吗?位置式PID的integral变量会一直增长,而增量式PID只用了3个偏差值做计算。这就是为什么增量式PID在嵌入式系统里更受欢迎。
6. 知识结构图
下面这张图帮你理清两种算法的核心逻辑和选择路径:
7. 我的选择建议
说了这么多,到底该怎么选?我总结几条实战经验:
- 电机速度环和位置环:优先用增量式PID。电机响应快,增量式能避免积分饱和导致的超调。
- 温度、压力等大惯性系统:位置式PID更合适。这类系统需要精确的积分作用来消除静差。
- 系统需要频繁切换模式:增量式PID是首选。无扰切换特性让你少掉很多头发。
- 单片机资源紧张:增量式PID只需要3个变量,位置式需要存储所有历史偏差,高下立判。
⚠ 重要提醒:不管你选哪种算法,输出限幅和积分限幅都是必须加的。我曾经在一个项目中忘了加积分限幅,结果积分项跑到天上去,系统直接崩溃。这个教训,希望你不要重蹈覆辙。