3. 数字控制器:PID控制器的基本原理,位置式与增量式PID的区别

说到数字电源的环路控制,PID 绝对是绕不开的核心。很多刚入行的工程师觉得 PID 就是调三个系数,没什么技术含量。说实话,我早年也这么想过,直到在一个 48V 转 1V 的 DC-DC 项目上栽了跟头——空载纹波 20mV,一带载直接振荡,调了三天三夜才发现是积分项饱和的问题。从那以后,我再也不敢小看 PID 了。

这一节,咱们就把 PID 的基本原理和两种数字实现方式——位置式与增量式——彻底讲透。你想想看,搞懂了这些,后面调环路参数才有底气。

3.1 PID 控制器的基本原理

PID 控制器,说白了就是根据「过去、现在、未来」三个维度的误差来调整输出。

  • 比例项(P):看现在的误差,误差大就猛调,误差小就微调。反应最快,但光靠它会有静差。
  • 积分项(I):看过去的误差累积,专门消灭静差。但调太强容易超调,调太弱响应慢。
  • 微分项(D):预测未来的误差变化趋势,提前刹车或加速。能抑制超调,但对噪声敏感。

连续域的 PID 公式长这样:

u(t) = Kp * e(t) + Ki * ∫e(τ)dτ + Kd * de(t)/dt

但在数字电源里,我们用的是离散域。把连续积分和微分换成累加和差分,就得到了数字 PID 的基础形式。

核心要点:数字 PID 的本质就是用采样周期 Ts 把连续时间切成离散点,在每个点上计算误差,然后加权求和。Ts 越小,越接近模拟 PID,但计算负担也越大。

3.2 位置式 PID

位置式 PID 是最直观的数字实现方式。它直接计算当前时刻应该输出的控制量绝对值。

离散公式如下:

u[k] = Kp * e[k] + Ki * Σe[i] + Kd * (e[k] - e[k-1])

其中:

  • u[k]:第 k 个采样周期的输出控制量(比如占空比)
  • e[k]:第 k 个采样周期的误差
  • Σe[i]:从启动到当前的所有误差累加和

优点:

  • 物理意义清晰,调试时容易理解每个项的作用
  • 输出直接对应执行机构的绝对位置(比如 PWM 占空比)

缺点:

  • 积分项 Σe[i] 会无限累积。一旦执行器饱和(比如占空比到 100%),误差还在累加,等误差反向时,积分项需要很长时间才能退回来——这就是我前面说的积分饱和问题。
  • 输出突变时,微分项容易产生尖峰,需要做限幅或滤波。

我曾经踩过的坑:在一个 500W 的 buck 变换器上用了位置式 PID,启动时积分项从零开始累加,输出占空比直接冲到 100%,电感电流飙升,差点烧 MOSFET。后来加了积分限幅和抗饱和处理才稳住。所以用位置式 PID,积分限幅和输出限幅是必须的。

3.3 增量式 PID

增量式 PID 不直接算输出绝对值,而是算当前输出相对于上一次输出的变化量 Δu[k]。

公式推导很简单,从位置式出发:

Δu[k] = u[k] - u[k-1]
       = 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]

优点:

  • 没有积分累积项,从根本上避免了积分饱和问题
  • 输出变化量 Δu 通常很小,执行机构动作平滑,适合伺服电机、步进电机等场景
  • 从手动模式切换到自动模式时,只需要把 u[k-1] 设为当前手动值,无冲击切换

缺点:

  • 输出是累加得到的,如果累加过程中出现数值误差或丢步,误差会一直带下去
  • 对执行机构的积分特性有依赖(比如电机位置环),如果执行机构本身没有积分作用,增量式可能不合适

我的个人习惯:在数字电源的电压环和电流环里,我更喜欢用增量式 PID。原因很简单——电源的 PWM 占空比本身就是累加量,增量式天然匹配。而且启动时不会出现积分饱和导致的过冲。但在需要精确位置控制的场合(比如数字电源的相位调节),位置式更直观。

3.4 位置式 vs 增量式:一张表说清楚

对比维度 位置式 PID 增量式 PID
输出含义 控制量的绝对值 控制量的变化量
积分饱和风险 高,需额外处理 低,天然避免
手动/自动切换 需做 bump-less 处理 天然无冲击
计算量 需存储所有误差累加 只需存储最近 3 个误差
适用场景 执行机构无积分特性(如比例阀) 执行机构有积分特性(如电机、PWM)
数值稳定性 累加误差会持续存在 累加误差只影响当前步

3.5 两种 PID 的代码实现对比

下面是我在实际项目中用过的两种实现,你可以对比一下差异。

位置式 PID 实现:

typedef struct {
    float Kp, Ki, Kd;
    float integral;      // 积分累加器
    float prev_error;    // 上一次误差
    float out_max;       // 输出上限
    float out_min;       // 输出下限
    float int_max;       // 积分限幅
} PositionalPID;

float PositionalPID_Calc(PositionalPID *pid, float setpoint, float feedback) {
    float error = setpoint - feedback;
    
    // 比例项
    float P = pid->Kp * error;
    
    // 积分项(带限幅)
    pid->integral += error;
    if (pid->integral > pid->int_max) pid->integral = pid->int_max;
    if (pid->integral < -pid->int_max) pid->integral = -pid->int_max;
    float I = pid->Ki * pid->integral;
    
    // 微分项
    float D = pid->Kd * (error - pid->prev_error);
    pid->prev_error = error;
    
    // 输出(带限幅)
    float output = P + I + D;
    if (output > pid->out_max) output = pid->out_max;
    if (output < pid->out_min) output = pid->out_min;
    
    return output;
}

增量式 PID 实现:

typedef struct {
    float Kp, Ki, Kd;
    float error[3];      // 环形缓冲区:e[k], e[k-1], e[k-2]
    float last_output;   // 上一次输出 u[k-1]
    float delta_max;     // 单步变化量限幅
    float out_max;       // 输出上限
    float out_min;       // 输出下限
} IncrementalPID;

float IncrementalPID_Calc(IncrementalPID *pid, float setpoint, float feedback) {
    // 更新误差缓冲区
    pid->error[2] = pid->error[1];
    pid->error[1] = pid->error[0];
    pid->error[0] = setpoint - feedback;
    
    // 计算增量
    float delta = pid->Kp * (pid->error[0] - pid->error[1])
                + pid->Ki * pid->error[0]
                + pid->Kd * (pid->error[0] - 2*pid->error[1] + pid->error[2]);
    
    // 增量限幅
    if (delta > pid->delta_max) delta = pid->delta_max;
    if (delta < -pid->delta_max) delta = -pid->delta_max;
    
    // 累加输出
    pid->last_output += delta;
    if (pid->last_output > pid->out_max) pid->last_output = pid->out_max;
    if (pid->last_output < pid->out_min) pid->last_output = pid->out_min;
    
    return pid->last_output;
}

注意:增量式 PID 的积分项 Ki * e[k] 其实是在 Δu 里体现的,不是直接累加误差。所以它没有传统意义上的积分饱和问题。但输出限幅还是要做,否则累加值可能溢出。

3.6 知识体系:PID 控制器核心逻辑

下面这张图帮你把位置式和增量式的区别、各自优缺点、适用场景串起来。建议保存下来,调试时对照着看。

PID 控制器核心逻辑框架图 PID 控制器核心逻辑框架 设定值 + 反馈值 → 误差 e[k] 位置式 PID 增量式 PID 位置式公式 u[k] = Kp·e[k] + Ki·Σe[i] + Kd·Δe[k] 输出 = 绝对值(如占空比 0~100%) 需积分限幅 + 输出限幅 增量式公式 Δu[k] = Kp·Δe[k] + Ki·e[k] + Kd·Δ²e[k] 输出 = 变化量(累加得到绝对值) 天然抗积分饱和 位置式特点 ✅ 物理意义清晰,调试直观 ⚠️ 积分饱和风险高,需额外处理 ✅ 适合无积分特性的执行机构 增量式特点 ✅ 无积分饱和,切换无冲击 ✅ 计算量小,只需 3 个误差值 ⚠️ 依赖执行机构的积分特性 选择建议 数字电源电压/电流环 → 增量式 位置/速度伺服 → 位置式 提示:实际项目中两种方式可互相转换,核心是理解各自适用边界

3.7 实际项目中的选择建议

说了这么多理论,到底怎么选?我根据这些年做项目的经验,给你几个实用建议:

  1. 数字电源的电压环和电流环:优先用增量式。PWM 占空比本身就是累加量,增量式天然匹配,而且启动时不会因为积分饱和导致过冲。我在一个 12V 输入、1.2V 输出的 POL 电源上做过对比,增量式的启动过冲比位置式小了 60%。
  2. 电机的位置环或速度环:位置式更合适。因为电机的位置输出是绝对角度,增量式的累加误差会随时间漂移。我做过一个云台电机项目,用增量式 PID 位置环,半小时后位置漂了 5 度,换成位置式就稳了。
  3. 如果必须用位置式:一定要加积分限幅和抗饱和处理。我常用的方法是:当输出饱和时,停止积分累加,或者把积分项强制拉回到饱和边界。
  4. 采样周期 Ts 的选择:不管用哪种 PID,Ts 都不能太大。一般建议 Ts 小于系统时间常数的 1/10。对于开关电源,Ts 通常取开关周期的 1~2 倍。

一个小技巧:调试初期,我习惯先用增量式 PID 把环路调稳,然后再根据需求决定是否切换到位置式。增量式的参数调试更安全,不容易炸管子。等参数基本确定后,再换成位置式做精细优化。