4、电流环PI控制器设计:连续域到离散域的映射,抗积分饱和实现
电流环是FOC控制中最内层的环,也是决定动态响应速度的关键。说白了,电流环PI控制器设计得好不好,直接决定了电机能不能跑得稳、跑得快。我刚开始做FOC时,在连续域里调得挺顺的参数,一搬到MCU上就各种不对劲。后来才明白——连续域到离散域的映射,不是简单抄个公式就完事的。
4.1 连续域PI控制器的基本形式
先回顾一下连续域里PI控制器的标准形式:
u(t) = Kp * e(t) + Ki * ∫e(t)dt
其中:
- Kp:比例增益,决定响应速度
- Ki:积分增益,消除稳态误差
- e(t):电流误差(给定值 - 反馈值)
在FOC电流环里,我们通常对d轴和q轴分别做PI控制。d轴控制励磁分量,q轴控制转矩分量。两轴的PI参数可以独立整定,但结构是一样的。
关键点:电流环的带宽通常设置为速度环的5~10倍。我一般先把电流环带宽定在1~2kHz,再根据实际响应微调。
4.2 离散化方法的选择
MCU只能处理离散信号,所以必须把连续域的PI控制器映射到离散域。常用的方法有三种:
| 方法 | 公式(积分项) | 特点 | 适用场景 |
|---|---|---|---|
| 前向欧拉 | u[k] = u[k-1] + Ts * e[k] | 实现简单,精度一般 | 采样率远高于带宽时可用 |
| 后向欧拉 | u[k] = u[k-1] + Ts * e[k] | 数值稳定性好 | 大多数工程场景的首选 |
| 双线性变换(Tustin) | u[k] = u[k-1] + (Ts/2)*(e[k] + e[k-1]) | 精度最高,无频率失真 | 对相位精度要求高的场合 |
我个人习惯用后向欧拉法。为什么?因为它在MCU上实现简单,数值稳定性好,而且对于电流环这种高采样率的场景(通常10~20kHz),三种方法的差异其实不大。我在一个项目里试过双线性变换,效果确实好一点,但代码量多了不少,调试也麻烦。后来我就一直用后向欧拉了。
4.3 离散域PI控制器的实现
用后向欧拉法离散化后,PI控制器的递推公式长这样:
// 位置式PI(直接计算输出)
u[k] = Kp * e[k] + Ki * Ts * Σe[k]
// 增量式PI(计算输出变化量)
Δu[k] = Kp * (e[k] - e[k-1]) + Ki * Ts * e[k]
u[k] = u[k-1] + Δu[k]
在FOC电流环里,我推荐用增量式PI。原因有两个:
- 增量式只计算变化量,不容易出现大幅跳变
- 抗积分饱和实现起来更自然
小技巧:实际代码里,我会把Ki * Ts预先算好,存成一个系数。这样每次中断里只需要做乘法和加法,省掉一次除法。GD32的FPU虽然快,但能省则省嘛。
4.4 抗积分饱和的实现
积分饱和是个老生常谈的问题,但在FOC电流环里特别要命。你想想看,电机启动时电流误差很大,积分项一路狂飙。等电流追上给定值时,积分项已经积了一大堆,导致输出超调,甚至震荡。
我遇到过最夸张的一次,积分饱和让电机在启动时直接过流保护跳了。查了半天才发现是积分项没处理好。
常用的抗积分饱和方法有几种:
| 方法 | 原理 | 实现复杂度 | 效果 |
|---|---|---|---|
| 积分限幅 | 直接限制积分项的上下限 | 低 | 一般,可能仍会饱和 |
| 积分冻结 | 输出饱和时停止积分 | 低 | 较好,常用 |
| 反向计算 | 饱和时重新计算积分项 | 中 | 好,但需注意稳定性 |
| 条件积分 | 误差大时减小积分增益 | 高 | 最好,但调参复杂 |
我在工程里最常用的是积分冻结加积分限幅的组合。代码实现如下:
// 增量式PI + 抗积分饱和
float pi_current_loop(float error, float *integral, float Kp, float Ki, float Ts, float limit) {
float output;
float delta_u;
// 计算增量
delta_u = Kp * (error - prev_error) + Ki * Ts * error;
prev_error = error;
// 计算输出
output = prev_output + delta_u;
// 输出限幅
if (output > limit) {
output = limit;
// 积分冻结:不更新积分项
} else if (output < -limit) {
output = -limit;
// 积分冻结
} else {
// 正常更新积分项
*integral += Ki * Ts * error;
// 积分限幅
if (*integral > INTEGRAL_LIMIT) *integral = INTEGRAL_LIMIT;
if (*integral < -INTEGRAL_LIMIT) *integral = -INTEGRAL_LIMIT;
}
prev_output = output;
return output;
}
注意:积分限幅的阈值INTEGRAL_LIMIT不能随便设。我一般取输出限幅的50%~80%。设太小了积分没效果,设太大了等于没限幅。具体值得根据实际调试来定。
4.5 连续域到离散域的映射流程
把整个设计流程串起来,大概是这样的:
- 确定电流环带宽:根据电机参数和系统要求,定出目标带宽(比如1kHz)
- 计算连续域PI参数:用极点配置或经验公式算出Kp和Ki
- 选择离散化方法:推荐后向欧拉法
- 离散化PI参数:把Kp和Ki映射到离散域
- 实现抗积分饱和:选择合适的方法并编码
- 调试验证:用示波器或DA输出看电流响应
下面这张图把整个映射关系画清楚了:
4.6 工程部署中的注意事项
把PI控制器部署到GD32上时,有几个坑我得提醒你:
- 变量类型:电流环的误差和输出都用float,别用int。GD32有FPU,浮点运算不慢。
- 中断优先级:电流环中断优先级要设得最高。我一般设成0(最高),速度环设成1。
- 执行时间:电流环中断服务函数要在采样周期内跑完。20kHz采样就是50μs,代码要精简。
- 参数整定:先在连续域调好参数,再离散化。别直接在MCU上盲调。
经验之谈:我曾经在一个项目里把电流环中断优先级设错了,导致电流环被其他中断打断,电流波形全是毛刺。查了两天才发现是优先级的问题。嗯,从那以后我每次建工程第一件事就是检查中断优先级配置。
好了,这一章的内容就这些。连续域到离散域的映射是FOC工程化的基础,抗积分饱和则是保证系统稳定性的关键。把这两块吃透了,电流环的调试就会顺手很多。