FOC 参考手册 05 控制与估算

电流环

到目前为止的一切都是铺垫。Clarke 与 Park 变换将三个随时间变化的正弦量转化为两个稳态直流量,以便 PI 控制器能够对其进行调节。本页要讲的就是这个控制器。

这也是驱动器中理论最为简洁清晰的最后一处。下方的整定过程精确无误,无需反复试凑,直接源自电机数据表上的两个参数。然而现实情况随即出现——桥臂无法瞬间切换、角度存在微小偏差、直流母线电压不足等——而工作的难点在于判断究竟是哪一项因素在影响系统性能。

电流环的一个轴:带比例和积分通道的 PI 控制器、解耦前馈、矢量电压限幅,以及返回积分器的抗积分饱和路径。 误差 前馈 v q 实测 iq 抗积分饱和:被限幅裁剪的量 交叉解耦 ω e (L d i d + λ m ) i q * 给定 + − k p = L · ω c + 电压限幅 作用于合成矢量 电机 R + sL k i / s = R · ω c / s
PI 控制器和被控对象是显而易见的部分。解耦前馈和抗积分饱和路径才是最容易被漏掉的两项——即便缺少这两项,只要电机转速不高或电流给定不大,环路看起来依然能正常工作。

被控对象是一个电感

在转子坐标系中,电机的一个轴看起来是这样的:

暂且忽略最后一项。剩下的部分就是一个电阻与一个电感的串联:

这是一个极点位于 的一阶惯性环节。对于本站使用的基准电机——,——该极点位于 265 Hz,仅靠自身响应需要 600 µs。

整定不是反复试凑

取一个 PI 控制器 ,将其改写为一个零点除以一个积分环节:

现在将控制器零点精确置于被控对象极点之上。令 ,零极点即可相互对消:

此时开环传递函数变成纯积分环节,因此闭环传递函数为

一个时间常数由你选定的一阶惯性环节。令 即可使闭环带宽精确等于 :

没有超调,没有振荡,也无需反复试凑调参。两个增益参数直接由电机自身的电阻、电感以及你设定的目标带宽唯一确定。

在实验台上 凸极电机满足 ,因此两个轴需要不同的增益——对于基准电机而言,q 轴所需的 比 d 轴高出 57%。两轴共用同一套增益是非常常见的偷懒做法,代价则是两轴动态响应不一致。本站的整定函数之所以返回一对增益,正是出于这一原因。

是什么限制了可设定的带宽

上述推导假定控制器是连续时间的。但实际上并非如此——它每个 PWM 周期才执行一次,所计算出的电压要到下一个周期才会真正施加到电机上。这一延迟在连续域代数推导中完全不可见,但在示波器上却一清二楚。

工程上的经验法则是取 PWM 频率的十分之一。在 20 kHz 开关频率下,这意味着带宽上限约为 2 kHz;若强行要求更高带宽,换来的只会是振荡而非响应速度。在下方的实验台中将带宽滑块拖过 2 kHz,观察超调量指标的攀升:整定公式本身没有任何改变,失效的只是“更新速率远高于环路带宽”这一假设。

实验台

下方的所有内容均使用本站其余部分所用的同一仿真器:一台永磁同步电机、一个三相桥式逆变器,以及上述推导出的控制器。每次修改都会使驱动器从静止状态重新启动,因此您可以单独调整某一项参数,精确观察其带来的影响。

淡淡的虚线是同一驱动器在关闭所有非理想因素时的理想响应。实线与虚线之间的差距,就是这些非理想因素带来的性能代价。

给定
整定
引入非理想因素
闭环电流阶跃响应,48 V 直流母线,20 kHz PWM。基准电机参数:0.35 Ω,210/330 µH,4 极对。先调节 带宽,再通过 死区时间 和 角度误差 观察非理想因素的影响。

值得尝试的实验

下面的每一个数值都是该模型的实际输出,而非经验估算。

扫描带宽。 250 Hz 带宽下上升时间为 1350 µs;500 Hz 下为 650 µs;1 kHz 下为 300 µs。 每翻一倍,上升时间便减半,与理论公式完全吻合。继续推高到 4 kHz(即开关频率的五分之一),4.6% 的超调便凭空出现。整定公式没有任何变化,只是环路相对于其自身的更新速率已不再足够慢。

在实验台上 当带宽超过约 1.5 kHz 时,测量本身的分辨率便捉襟见肘:实验台每个 PWM 周期采样一次,因此 175 µs 的上升时间仅跨越三个半采样点。这并非仿真模型的缺陷——真实驱动器若每周期记录一个采样点,会面临完全相同的问题,这也是为什么电流环阶跃响应应当用示波器探头测量,而非仅靠固件内部录波。

关闭解耦,并将转速设为 4000 rpm。 在静止状态下,这不会产生任何变化。但在 4000 rpm 下,上升时间会从 300 µs 恶化到 1050 µs,且稳态电流停留在 9.10 A 而非 10.04 A——产生了 9% 的稳态误差且控制器始终无法消除,因为它正在对抗随转速增长的反电动势。这就是经典的“在台架上静止调得极好,一上工况跑起来就掉链子”的故障。

加入死区时间,然后减小电流给定。 在 2000 rpm、2% 死区时间下, 的纹波约为 0.6 A。现在将电流给定从 12 A 降至 3 A:纹波依然约为 0.6 A。死区时间造成的电压误差是固定的 0.96 V(48 V 母线的 2%),因此在 12 A 时占所需电压的 3.5%,而在 3 A 时占比升至 7.2%。它不会随工作点降低而按比例缩小,这正是为什么死区补偿在低速轻载时至关重要,而在高速重载时几乎可以忽略。

加入角度误差。 控制器依然会报告 达到了目标值,因为在它自己的坐标系下确实达到了。请转而观察 Peak |id|:在 20° 角度误差下,有一个高达 3.6 A 的电流分量出现在了根本没人请求的 d 轴上。不过,转矩随之发生的变化比乍看之下更加微妙——详见下文。

关闭抗积分饱和,设转速为 4000 rpm、给定 40 A、惯量 ×100。 此时反电动势加上 压降已超过直流母线电压,因此控制器在整个阶跃保持阶段始终处于饱和状态,驱动器只能输出约 22 A 电流,达不到所请求的 40 A。

观察 Release fall 指标。启用反算抗饱和时,撤销电流给定后仅 300 µs 电流便迅速回落;而关闭抗饱和时,积分器在长达 11 ms 的时间里一直对着无法逾越的电压限幅疯狂累积,结果是永不回落——直到记录结束电流仍在流动,相电流仍以全幅值摆动,逆变桥也仍处于饱和状态。对比实线与理想虚线,这一故障一目了然。

这是最容易被误诊的情况。它看起来像是增益过大,因此常见的应对措施是降低环路的调节强度,但这只会使驱动变慢,而不会消除真正的故障根源。

在实验台上 设为大惯量并非为了让演示效果更夸张的噱头——而是为了让演示符合真实工况。基准电机裸转子惯量仅为 12 g·cm²,轻到在积分器还来不及深度饱和之前就已经加速脱离了饱和区。任何真实负载的惯量都要大得多,而积分饱和正是在真实带载工况下必然发作的问题。

顺便一提:角度误差的转矩代价没你想的那么大

直观的角度误差模型认为转矩会按 规律下降,理由是只有 q 轴电流分量才产生转矩。但在实验台上跑一下就会发现数据对不上:

产生的 转矩(凸极电机)转矩()
10°−1.82 A100.8%98.4%98.5%
20°−3.60 A98.0%93.6%94.0%
45°−7.35 A75.8%69.5%70.7%

非凸极电机(表贴式)那一列几乎完全符合 ,理应如此。但基准凸极电机却不然——在 10° 角度误差下,它产生的转矩甚至高于完全对齐时的驱动器。

原因在于磁阻项。正的角度误差会使电流矢量超前于控制器所认为的位置,从而产生——即一个负的 d 轴电流。对于一台的电机而言,负的会产生正的磁阻转矩:

在小角度下,磁阻转矩的增加几乎刚好抵消了 带来的转矩损失。

由此可以得出两个方向相反的推论。好消息是,凸极电机对小角度误差的容忍度比教科书公式所暗示的更高;坏消息则是,仅凭转矩读数根本无法发现角度偏了。在 20° 角度误差下,该驱动器的输出转矩仅下降 2%——与测量噪声无异——但同时却流过 3.6 A 无人请求的 d 轴电流,白白使电机发热并削弱磁场。

如果要从本页带走一个诊断习惯,那就是:排查角度误差时,请看 ,绝不要看转矩。

这也是最大转矩电流比(MTPA)的出发点。如果负的 可以额外产生转矩,那么正确的问题就不再是“如何将 保持为零”,而是“在给定 时,最优的 是多少”——这将在另一页中讨论。

解耦

之前略去的项此时又重新出现。两轴之间存在耦合,而永磁体产生的反电动势会随转速无限制地增大:

如果不加补偿,这三项都会在控制器看来成为随转速增大的扰动。因此,只在静止状态下整定的环路,会随着电机升速而逐渐变差。加入前馈补偿只需两次乘法运算:

在任何实际转速下,反电动势项都比其他两项大一个数量级。如果只能实现三项中的一项,就实现这一项。

在实验台上 前馈项必须在输出限幅之前加入,而不是在限幅之后。如果在限幅之后才叠加前馈,控制器输出实际上已经饱和,但抗积分饱和模块却毫不知情、永远不会触发——这一隐蔽缺陷只会在前馈量很大的高速工况下暴露出来。

抗积分饱和

电流环会在每次大阶跃以及电机接近基速时持续达到电压限幅。积分器在这些时段的行为决定了系统的恢复是否平稳。

反算法(Back-calculation)是标准方案:先计算未限幅的输出,对其进行限幅,再将限幅前后的差值反馈回积分器:

float unsat = kp * error + integral + feedforward;
float out   = clampf(unsat, -v_limit, +v_limit);

/* Unwind by exactly as much as the clamp threw away. */
integral += (ki * error + k_aw * (out - unsat)) * dt;

跟踪增益并非自由参数

k_aw 是抗饱和跟踪增益 ,标准做法是将跟踪时间常数设为积分时间常数 。因此:

在零极点对消整定下,它恰好又等于被控对象的极点频率。

不妨看看为什么应当取这个值而不是别的值。在饱和期间,当积分更新式中的两项相互抵消时,积分器停止继续累积:

当 时,系统会稳定在 :积分器恰好停在饱和边界,一旦限幅解除就能立即恢复。若将 设得太小,积分器仍会继续累积,只是速度较慢;抗积分饱和项便形同虚设。这类错误很隐蔽:代码看似正确,相关项也存在,但问题只在持续饱和时出现。

对矢量限幅,而非对单轴独立限幅

还有一个陷阱,而且是本页中最隐蔽的一个。

d、q 两轴的电压并不是各自独立受限的。逆变器限制的是两轴合成矢量的幅值(不超过 ),因此正确的顺序必须是:先分别算出两轴的未限幅电压,对合成矢量做一次统一限幅,最后再根据实际通过限幅的电压对两个积分器分别执行反算退饱和。

如果只是把每个轴各自独立钳位在 并自以为完成了抗积分饱和,那实际上毫无作用。因为单轴限幅几乎永远不会触发,而合成矢量限幅却在频繁触发——导致反算项看到的始终是 out == unsat,反馈回积分器的修正量为零,积分器依然会像代码里根本没写抗饱和一样疯狂累积。

/* Both axes first... */
float vd_unsat = kp_d * e_d + integral_d + ff_d;
float vq_unsat = kp_q * e_q + integral_q + ff_q;

/* ...then ONE limit on the vector they form... */
float vd = vd_unsat, vq = vq_unsat;
limit_voltage(&vd, &vq, VDC * ONE_OVER_SQRT3);

/* ...then unwind both against what actually got through. */
integral_d += (ki_d * e_d + k_aw_d * (vd - vd_unsat)) * dt;
integral_q += (ki_q * e_q + k_aw_q * (vq - vq_unsat)) * dt;

这个缺陷在代码走查时极难察觉,在常规阶跃响应测试中也看不出来,只有当驱动器被迫长时间顶着电压极限运行时才会暴露——而此时的症状看起来更像是抗积分饱和增益设错了,而不是抗积分饱和逻辑根本没被触发。

代码实现

整个电流环,每个 PWM 周期执行一次:

void current_loop(float id, float iq, float id_ref, float iq_ref,
                  float we, float dt, float *vd, float *vq)
{
    /* Feedforward: cancel the speed-dependent terms. */
    const float ff_d = -we * Lq * iq;
    const float ff_q =  we * (Ld * id + flux_m);

    *vd = pi_update(&pi_d, id_ref - id, dt, ff_d);
    *vq = pi_update(&pi_q, iq_ref - iq, dt, ff_q);

    /* Never ask the bridge for more than it has. */
    limit_voltage(vd, vq, VDC * ONE_OVER_SQRT3);
}

四次乘法、两次 PI 更新和一次矢量限幅。难点从来不在算术代码本身——而在于知道该往 pi_d 和 pi_q 里填什么系数,而这些系数直接来自数据手册上的两个电机参数。

要点回顾

  • 与 就是电流环整定的全部。如果你还在靠手动试凑来调电流环,那说明你还没拿到准确的 或 。
  • 带宽受限于更新频率,大约为 。超过这个值后,再增加增益只会导致振荡。
  • 解耦使环路在高速与低速下的行为一致。反电动势项才是关键。
  • 抗积分饱和绝非可选项——电流环的饱和是家常便饭而非偶发异常——而且它必须作用于合成矢量限幅之上,并采用 作为跟踪增益。这两个细节只要错了一个,代码看起来依然工整,实际上却毫无作用。
  • 死区时间和角度误差都会在不让控制器报告任何异常的情况下劣化驱动性能。排查角度误差请看 ;转矩读数不会告诉你真相,在凸极电机上转矩甚至几乎不变。

接下来:在没有编码器的情况下,角度从何而来。