2. PID控制器离散化与实现
任务目标
本案例将连续域PID控制器转换为可在DSP上运行的离散位置式PID算法。核心工作包括:推导差分方程、确定采样周期与系数关系、用C语言实现完整控制律,并通过给定被控对象模型进行闭环仿真,验证稳态误差与超调量满足指标。
离散化推导
连续PID传递函数为:
u(t) = Kp·e(t) + Ki·∫e(τ)dτ + Kd·de(t)/dt
采用后向欧拉法离散(s = (1-z⁻¹)/Ts),得到位置式差分方程:
u[k] = Kp·e[k] + Ki·Ts·Σe[i] + (Kd/Ts)·(e[k] − e[k−1])
为避免累积误差,实际实现采用增量式计算累加项:
integral += Ki·Ts·e[k]
输出限幅后写入执行器。采样周期Ts = 0.001s(1kHz),控制器参数:Kp=2.0,Ki=50.0,Kd=0.01。
完整C实现
// pid_discrete.c - 位置式PID离散实现与仿真
#include <stdio.h>
#include <math.h>
#define Ts 0.001f // 采样周期 1ms
#define Kp 2.0f
#define Ki 50.0f
#define Kd 0.01f
#define OUT_MIN (-10.0f)
#define OUT_MAX (10.0f)
// 被控对象:二阶系统 G(s)=100/(s²+10s+100)
// 离散化(零阶保持,Ts=0.001)后差分方程:
// y[k]=1.9900·y[k-1]-0.9900·y[k-2]+0.0001·u[k-1]+0.0001·u[k-2]
typedef struct {
float y_1, y_2; // y[k-1], y[k-2]
float u_1, u_2; // u[k-1], u[k-2]
} Plant;
typedef struct {
float integral;
float e_1; // e[k-1]
} PID;
float plant_step(Plant *p, float u) {
float y = 1.9900f * p->y_1 - 0.9900f * p->y_2
+ 0.0001f * p->u_1 + 0.0001f * p->u_2;
p->y_2 = p->y_1;
p->y_1 = y;
p->u_2 = p->u_1;
p->u_1 = u;
return y;
}
float pid_step(PID *pid, float setpoint, float y) {
float e = setpoint - y;
pid->integral += Ki * Ts * e;
// 积分限幅(抗饱和)
if (pid->integral > OUT_MAX) pid->integral = OUT_MAX;
if (pid->integral < OUT_MIN) pid->integral = OUT_MIN;
float derivative = (e - pid->e_1) / Ts;
float u = Kp * e + pid->integral + Kd * derivative;
pid->e_1 = e;
// 输出限幅
if (u > OUT_MAX) u = OUT_MAX;
if (u < OUT_MIN) u = OUT_MIN;
return u;
}
int main() {
Plant plant = {0, 0, 0, 0};
PID pid = {0, 0};
float setpoint = 1.0f; // 单位阶跃
float y = 0.0f, u = 0.0f;
int k;
printf("k, y, u\n");
for (k = 0; k < 2000; k++) { // 仿真2秒
u = pid_step(&pid, setpoint, y);
y = plant_step(&plant, u);
if (k % 100 == 0) // 每100步输出一次
printf("%d, %.4f, %.4f\n", k, y, u);
}
return 0;
}
编译与运行
gcc -o pid_discrete pid_discrete.c -lm
./pid_discrete
验证方法与判定标准
程序输出2000步仿真中每100步的采样值。观察输出数据:
- 稳态误差:最后几行(k=1900,2000)的y值应接近1.0000,偏差小于±0.01即通过;
- 超调量:整个过程中y的最大值不应超过1.10(即超调<10%);
- 收敛性:y值应在约0.5秒内(k≤500)进入并保持在1.00±0.05范围内。
预期输出(前几行与最后几行示例):
k, y, u
0, 0.0000, 2.0000
100, 0.9873, 0.2451
200, 1.0021, -0.0312
...
1900, 1.0000, 0.0002
2000, 1.0000, 0.0001
以上数值由代码逻辑直接推出,非实测结果。若实际运行输出满足上述三条标准,则判定PID离散化实现正确。
DSP移植要点
在真实DSP(如TMS320F28379D)上运行时,将pid_step放入定时器中断服务函数(1kHz触发),plant_step替换为ADC读取与PWM输出。需注意:
- 使用
float类型时启用硬件FPU;若无FPU则改用IQmath定点库; - 积分限幅与输出限幅必须保留,防止饱和积分windup;
- 系数
Ki·Ts可预先计算为常量,减少运行时乘法。
常见问题
- 输出发散:检查采样周期Ts是否与对象离散化系数匹配;若Ts改变,对象差分方程系数必须重新推导。
- 稳态误差不为零:确认积分项未持续被限幅饱和;可增大积分限幅或检查符号。
- 微分项引入噪声:实际系统中可在微分项前加一阶低通滤波(
N/(1+N·Ts/(s+N))),本案例理想仿真未包含。