手把手教你电机FOC控制
手把手教你电机FOC控制
更新日志
2024.07.17 作者已很久没做过电机了,此文停更
2022.09.16 完善图片内容与代码,更新到速度闭环
FOC框架引入
三向电机,分别为UVW三向,角度互差120度。若使用BLDC控制方法,如下图每次换向增加60度,转子只能到达六个位置,所以六步换向时会有振动。使用FOC控制方法可以使转子到达任意角度,所以运行起来会更加平滑。
如果想到达40度的位置,只需要在0度方向通电一段时间,在60度方向通电一段时间,再在空矢量的状态下通电一段时间(全桥000或111的位置为空矢量,空矢量的时长用来调节扭矩。后面会讲到),三段时间组成一个周期,以这个周期循环产生PWM,即可锁定至40度。若想到达其他角度,只需改变0度和60度的通电时长比例。
要想使磁场旋转起来,就需要输入正弦电压,但我们输入的是直流电,我们马上想到可以使用PWM波。通过不断改变PWM脉宽就可以模拟正弦电压,体现在电流上则为正弦电流。
下图为一个完整的FOC流程图:
我们先来看正向通路:输入 $I_{d_ref}$ 和 $I_{q_ref}$ 与下文反馈通路采样得到的电流 $I_d$ 和 $I_q$ 进行PID控制输出 $U_d$ 和 $U_q$ (输入的 $I_{d_ref}$ 通常为0, $I_{q_ref}$ 前通常还需要接入一个速度PID构成速度环),再通过反Park变换转换成 $U_\alpha$ 和 $U_\beta$ ,通过SVPWM模块控制定时器产生六路互补的PWM信号,最后使用PWM信号控制全桥MOS管的通断,产生三向电压使电机转动。
再来看反馈通路:通过采样电阻采集任意两相电流,根据基尔霍夫电流定律可以算出第三相电流,将三向电流通过Clark变换转化成 $I_\alpha$ 和 $I_\beta$ ,再通过Park变换转换成 $I_d$ 和 $I_q$ ,作为反馈传入PID控制器构成电流环。
上图中的Park变换和反Park变换需要当前的角度作为输入;速度PID需要速度作为反馈。所以需要获得电机的速度与角度。角度和速度的获取方法分为有感和无感。有感方式使用霍尔元件(Hall Sensor),安装在电机上就可以检测电机磁铁的位置。无感使用观测器(observer)获得角度速度信息,本文将使用扩展卡尔曼滤波观测器(EKF),输入为 $U_\alpha$ 、 $U_\beta$ 、 $I_\alpha$ 、 $I_\beta$ 。使用无感方式不需要霍尔传感器,可以减少连接线的数量,也可以减小成本。
坐标变换
为什么要使用坐标变换?电机控制大多是在控制速度/转矩,需要用PID闭环控制正弦交流电压的幅值和角度,不是很容易实现,所以通过坐标变化把正弦交流信息分解成角度信息(Q轴控制转矩)和幅值信息(D轴控制磁场)单独控制。
FOC的变换中要满足等幅值变换,即变换前后幅值不变。
坐标变换都分为正向变换和反向变换,正向变换都是对电流进行操作的,反向变换都是对电压进行操作的。
下面的变换均采用联立和矩阵两种形式表示,以方便使用。
Clark变换
Clark变换实现了三向坐标系 $(a,b,c)$ 与直角坐标系 $(\alpha,\beta)$ 间的转换。
正向Clark变换
Clark变换将三相信号转换为两相信号。已知三相坐标系 $(I_a,I_b,I_c)$ ,这三个基向量不是正交的,所以可以将其正交化为一个直角坐标系,命名为 $\alpha-\beta$ 坐标系,变换公式为:
表示为矩阵形式:
我们一般在电路中只采集两相电流,第三相电流可以使用基尔霍夫电流定律得出( $I_a+I_b+I_c=0$ ),故上式也可整理为以下形式:
矩阵形式:
由于变换前后 $I_a$ 和 $I_\alpha$ 幅值要相同,所以要进行等幅值变换,变换系数为 $\frac{2}{3}$ ,即变为
矩阵形式:
(这里的系数在后文SVPWM里相电压的幅值与电压空间矢量之间有一个 $\frac{3}{2}$ 的系数相抵消)
MATLAB实现为:
反向Clark变换
Clark反变换则将两相信号转换为三相信号。根据图可以写出:
矩阵形式:
MATLAB实现为:
Park变换
Park变换实现了两相坐标系 $(\alpha,\beta)$ 与转子坐标系 $(d,q)$ 间的转换,此变换可以将正弦变量线性化。其中 $d$ 指向转子中心, $q$ 指向切线方向, $\theta$ 是转子当前的角度,也就是说 $d-q$ 坐标系始终跟着转子同步旋转。
正向Park变换
则根据上图可以写出
很明显上述变换可以用旋转矩阵来表示,使用矩阵形式可以很方便地写出:
(如果 $d$ 轴为0,则功率全部输出在 $q$ 轴上。)
MATLAB实现为
反Park变换
根据上面的推导可以求得反Park变换
同理,使用旋转矩阵可以求出反变换的系数矩阵:
MATLAB实现为
MATLAB仿真
为了更清楚地仿真,这里不用矩阵形式表示,如需矩阵形式可以看我写的另一篇文章。
请注意,正向变换都是对电流进行操作的,反向变换都是对电压进行操作的。但是在这节的仿真中,把正变换和反变换连在一起,这样做没有实际意义,只是为了验证变化算法。
输入Vd为0,Vq为1,角度为由0到2pi的连续值。
再来看子模块内部,输入经过两个逆变换,再经过两个正变换。
运行查看波形(新版本MATLAB常值输入为一个圆圈)
SVPWM
根据BLDC的六步换向,可以将一圈分为六个扇区,前文FOC引入章节已经讲过,只需要控制每个状态通电的时间就可以控制转子到达任意角度。这就是SVPWM。
SVPWM的输入为 $U_{\alpha}$ 和 $U_{\beta}$ ,输出为三向计数器的比较值。所以应该首先判断用哪两个相邻矢量,然后计算两个相邻矢量的作用时长,然后将作用时长转化成计数器的比较数值送入定时器。下面对这三个步骤进行讲解。
扇区判断
三相电压可以表示为( $U_{m}$ 为电压幅值):
将其转换为 $\alpha-\beta$ 坐标系,可以算出
从这个式子发现,可以从中算出角度信息从而可以判断在哪个扇区
由于除法和反三角函数对于MCU来说计算量比较大。我们来找一个简便算法。
$U_{\alpha}$ 是关于cos的三角函数, $U_{\beta}$ 是关于sin的三角函数,可以得到:
可以看到,通过 $U_{\beta}$ 的正负可以判断出是1/2/3扇区还是4/5/6扇区。
这个条件只将扇区分为两个部分,我们还需要几个条件来更细致地分。将每个扇区的反三角函数范围计算出来:
观察这个结论, $U_{\beta}$ 和 $\sqrt{3}U_{\alpha}$ 似乎有关系,回顾反Clark变换, $U_{b}$ 和 $U_{c}$ 的式子就是这种关系。所以可以把上面的结论往反Clark变换上凑。看一下反Clark变换的图像,注意我们需要的关系里的 $\sqrt{3}$ 是乘在 $U_{\alpha}$ 上的,所以我们把 $U_{\beta}$ 和 $U_{\alpha}$ 反一下,对应的公式为:
生成上述公式的图像,其中黄色的线为 $U_{a}$ 为 $U_{\beta}$ ,蓝色的线 $U_{b}$ 为 $\frac{\sqrt3}{2}U_{\alpha} - \frac{1}{2}U_{\beta}$ ,红色的线 $U_{c}$ 为 $-\frac{\sqrt3}{2}U_{\alpha} - \frac{1}{2}U_{\beta}$ ,
可以看到在每个扇区内总有一向大于0,两向小于0,所以 $U_{b}$ 和 $U_{c}$ 的正负可以当做判断条件之一。我们顺便还又一次得到了 $U_{\beta}$ 这个判断条件。整理一下上面的式子
所以通过计算 $\frac{\sqrt3}{2}U_{\alpha} - \frac{1}{2}U_{\beta}$ 和 $-\frac{\sqrt3}{2}U_{\alpha} - \frac{1}{2}U_{\beta}$ 的正负可以判断出是1/6扇区,3/4扇区,2扇区,5扇区的哪一组。
综上,我们的判断条件有: $U_{\beta}$ 、 $\frac{\sqrt3}{2}U_{\alpha} - \frac{1}{2}U_{\beta}$ 和 $-\frac{\sqrt3}{2}U_{\alpha} - \frac{1}{2}U_{\beta}$ 。我们分别定义:
综合这三个条件就可以判断是在哪个扇区 。那么有没有一种算法可以将这一堆判断数值化并转换成1~6的数字呢?可以用下面的公式:
式中A代表 $U_a$ 的正负,B代表 $U_b$ 的正负,C代表 $U_c$ 的正负,大于0为1,小于0为0。最后转换出来的的N即为1~6的数字:
至此,我们成功完成了扇区判断。
计算相邻矢量作用时长
控制相邻矢量作用时长就可以控制转子到达任意方向,下面进行分析。
六个矢量的大小
六个MOS管可以产生8种状态
设上开下合为0(电流从O往对应的向流),上合下开为1(电流从对应的向往O流),表示其中的六个矢量。
放在一张图中即为:
还有两个零矢量(000和111),无电流,不产生磁场。
对于100的状态,可以等效为下面的电路图:
可以计算出电机中三个相电压(每相相对于电机中间连接点的电压)
同理可以计算其他所有方向矢量的相电压,可以看出,六个矢量的大小均为 $\frac{2}{3} U_{d c}$ ,即SVPWM相电压幅值为 $\frac{2}{3} U_{d c}$
电压利用率
电压利用率等于合成矢量的电压除以母线电压。下面在复平面计算合成矢量的电压 $U_{out}$ :
根据欧拉公式可以推导出:
又因为三相电压与相电压幅值之间的关系:
带入可以计算出 $U_{out}$ :
合成矢量的电压是相电压幅值的 $\frac{3}{2}$ 倍,而SVPWM相电压幅值 $U_m$ 为 $\frac{2}{3} U_{d c}$ ,所以
即合成矢量的电压等于母线电压。所以SVPWM的电压利用率是100%。
SVPWM输出电压是马鞍波
由于中间连接点N的点位 是浮动的,为三角波,而相电压是每相相对于电机中间连接点N的电压,所以相电压不是一个正弦波,而是一个正弦波与一个三角波叠加而成的,即为马鞍波。网图:
矢量作用时长
合成矢量的电压是所在扇区两个矢量与空矢量不同时长的组合,其中 $T_N$ 为空矢量作用时长:
由于SVPWM的输入是 $U_{\alpha}$ 和 $U_{\beta}$ ,但是要控制 $T_x$ 和 $T_y$ ,所以要找到他们的对应关系。
对于第一个扇区,将 $U_{out}$ 在 $\alpha-\beta$ 坐标系中表示:
其中 $|U_x|$ 和 $|U_y|$ 根据前面的计算均为 $\frac{2}{3} U_{d c}$ ,可以解出:
同理,可以计算出所有六个扇区:
第二扇区
第三扇区
第四扇区
第五扇区
第六扇区
六个扇区中都有相同的项,其中包含前文判断扇区所用的 $U_1$ 、 $U_2$ 、 $U_3$ 。直接把前面已经计算过的变量拿过来使用,大大减少了计算量。式中的 $\frac{\sqrt{3}T_S}{U_{dc}}$ 为调制比,定义:
可以将六个扇区表示为:
注意:当非零矢量作用时间 $Tx+Ty>Ts$ ,需要进行过饱和处理:
定时器比较值计算
我们前文算出来的 $T_x$ 和 $T_y$ 以秒为单位,在单片机中使用定时器控制MOS管的通断需要配置比较值,所以需要把 $T_x$ 和 $T_y$ 转换为三个互补的定时器比较值 $T_1$ 、 $T_2$ 和 $T_3$ 。
定时器应设置为中心对齐模式,若为向上计数,计数器会从0开始计数到最大值,再反向从最大值计数到0;向下计数反之。故只需要控制前半个周期的比较值就可以产生相对中心对称的PWM波。
为了减少MOS管的开关损耗,提高其使用寿命,应尽量减少MOS管的开关次数。在一个扇区内切换状态的时候,合理使用零矢量可以保证每次切换只改变一个MOS管。
先来看第一扇区,以每次只改变一个MOS管为原则,则切换顺序为:
可以看到,切换顺序构成了一个环路。在一个周期内我们需要控制三段作用时长:
六个MOS需要产生六路PWM来控制他们的状态。由于上下半桥是互补的,所以只需要生成三个PWM:
由于是中心对齐模式,所以只需要控制半个周期的时长 $\frac{T_x}{2}$ 和 $\frac{T_y}{2}$ 。在半个周期内 $T_N$ 出现了两次,分别为000和111,在半个周期内将这两段时间平均分配。即为 $\frac{T_S-T_x-T_y}{4}$ 。
这样就可以计算三个定时器的比较值 $T_1$ 、 $T_2$ 和 $T_3$ :
同理,可以计算出全部六个扇区的切换顺序,这里计算过程不再赘述。由图像和计算结果可以分析出,无论在哪个扇区中,三个定时器切换的图像都是由上图中三个方波构成,三个图像排列组合也正好就是六个扇区的组合方式。故为了方便程序运行,将六个扇区的定时器比较值归纳如下:
设
此时六个扇区可以表示为:
也就是说编程时只需要计算 $T_a$ 、 $T_b$ 和 $T_c$ ,通过判断就可以得到对应扇区的比较值。
至此,SVPWM输出比较值 $T_1$ 、 $T_2$ 、 $T_3$ ,互补得到六个比较值,输入到定时器,输出三路PWM。
MATLAB仿真
假设需要产生10Khz的PWM波,则一个周期为0.0001秒。若单片机主频为180Mhz,预分频系数为100-1,由下面计算公式:(其中 $ARR$ 是计数值, $PSC$ 是预分频值)
180,000,000/(18,000*100)=10,000Hz,则定时器的计数值应设置为18000-1。
在模型中设定 $Udc$ 为24, $Tpwm$ 为18000。
在foc子模块中,将park反变换的输出输入到SVPWM模块:
SVPWM模块代码为:
1 | function [T1,T2,T3,sector] = fcn(Ualpha,Ubeta,Udc,Tpwm) |
可以看到,定时器比较值为马鞍波
扇区为从1到6的循环
电流闭环
经过前文的反Park变换、SVPWM、定时器与全桥,输入的 $U_{d}$ 和 $U_{q}$ 最终转换为三相电压输出到电机。如果需要让电机以设定的电流值运行,就需要使用PI控制器闭环控制电流。但三相交流电流是不太容易实现闭环控制的,所以我们选择对直流电流 $I_{d}$ 和 $I_{q}$ 进行闭环控制。
PI控制器输入目标参考电流 $I_{d_{ref}}$ 和 $I_{q_{ref}}$ ,输出 $U_{d}$ 和 $U_{q}$ ,现在还缺少反馈量 $I_{d}$ 和 $I_{q}$ ,这就需要用到前文讲到的Park与Clark正变换。安装采样电阻,用单片机的ADC采集全桥上任意两相的电流,通过基尔霍夫电流定律可计算第三相的电流,通过Clark变换计算出 $I_{\alpha}$ 和 $I_{\beta}$ ,再通过Park变换计算出反馈量 $I_{d}$ 和 $I_{q}$ 。
对于PI控制器参数的设定,以下为一个参考值(但还是需要自行调整):
其中 $\alpha$ 的取值为:(其中 $\tau$ 为电机的时间常数)
电机分为表贴电机和内嵌式电机,表贴式电机的永磁体贴在转子表面,内嵌式电机的永磁体安装在转子内。我们常用的电机都是表贴电机,对于表贴电机, $L_d=L_q=L$ ,则可以得到PI控制器的参考参数:
角度和速度的获取
有感(HALL)
霍尔传感器分为60度和120度
画一下转一圈三个霍尔传感器的波形
可以看到,这两种排列方式除了组合方式不同,其他都一样。
单片机通过输入捕获采集三路高低电平的跳变,通过对三路信号进行异或,则转一圈可以进6次中断,进入中断后检测IO电平就可以知道电机对应角度。但现在一圈只能获取到6个固定的角度值,无法获取到如80度这个角度。这时可以对速度进行积分得到角度,速度的获取可以通过查询60-120之间定时器的计数值来获得。但是转到80度的时候没办法获取到120度时候的定时器计数值就无法获取当前段的速度,这时可以用前一段的速度近似为当前段的速度。
无感(EKF)
引入
前面的有感部分,是在电机上安装霍尔传感器,引出三根线到单片机通过输入捕获算出当前角度,再与预设角度完成角度闭环。
而无感控制则不需要霍尔传感器,只需要三根UVW线输出到电机即可,去掉了霍尔传感器和三根线,节省了成本;有些使用场合无法使用霍尔传感器,则需要使用无感,比如空调压缩机,内部充满了润滑油,无法安装霍尔传感器;有些时候有感算法或硬件出现问题也可以切换至无感,防止系统闸机,比如汽车运行中霍尔传感器突然坏了,为了使整个系统正常运行,就可以临时切换到无感。上述这些都是无感控制的优点。无感控制现在已经越来越普及,空调、洗衣机、高端风扇、汽车都在用无感控制。
状态观测器
观测器有很多种,扩展卡尔曼滤波观测器、滑膜观测器、龙伯格观测器、自适应观测器、磁链观测器等。其中扩展卡尔曼滤波观测器的低速性能比较好,所以本文重点讨论EKF。
状态观测器实质上就是用数学方法建立一个可以模拟真实被控对象的模型,用这个模型来得知一些无法通过测量得到的状态量。对于电机系统来说,如果没有传感器去测量电机的转速和转子位置,那么就可以通过搭建状态观测器来估算电机的转子和转子位置,这就是基于状态观测器的电机的无传感器控制。
但是使用这种方法建立的观测器有着诸多问题:
- 抗干扰能力差:加入扰动或负载,此时的状态观测器很难保持正确的响应而导致输出错误或者系统崩溃;
- 存在误差:误差主要存在与系统误差和测量误差
- 系统误差:在建模的时候电机的参数不可能完全精确,在建模的时候造成误差。
- 测量误差:观测器需要电流作为输入,而电流的采集就会存在误差。
所以为了解决以上问题,需要给状态观测器增加反馈,通过反馈来修正状态观测器的输出,让观测器尽可能的去贴近真实的电机。
状态空间表示
线性系统的状态空间方程为:
永磁同步电机的方程:
上述方程的含义为:将每一相抽象为一个电阻,一个电感和一个反电动势的串联,则每一相的电压为前面三项压降之和(反电动势为速度乘磁链)。方程中的电阻R、电感L、和磁链flux为电机的固有参数,电流可以通过采样电阻得到,只剩下了角度和转速,将电机方程转化为状态空间表达:
矩阵化表示
接下来我们将上面的式子整理成矩阵形式,首先确认状态变量分别为 $ \dot{i_\alpha},\dot{i_\beta},\dot{\omega_e},\dot{\theta}$ ,则有:
输入 $u$ ,对于电机来说就是电压,我们选择 $\alpha-\beta$ 坐标系:
输出矩阵 $y$ 为通过采样电阻测得的电流:
则 $H$ 和 $B$ 矩阵就可以表示为:
此时矩阵形式的表示为:
对比状态空间表示,无法显式地表示出线性的 $Ax$ ,因为电机系统不是线性的,所以用 $f(x)$ 这一非线性项替代这一项。 $f(x)$ 定义为:
则此时的状态空间方程变为:
扩展卡尔曼滤波器
关于卡尔曼滤波器的知识请看这篇文章:手撕卡尔曼滤波器
扩展卡尔曼滤波器(Extend Kalman Filter),简称EKF。带“扩展”二字,是因为卡尔曼滤波器只能处理线性系统,而电机是一个非线性,强耦合的系统,使用扩展卡尔曼滤波器可以处理这种非线性系统。
前文的状态空间方程中 $f(x)$ 是非线性的,如果想对非线性系统进行卡尔曼滤波,需要对其线性化(Linearization),泰勒级数展开是将非线性系统线性化的一种方法。将 $f(x)$ 泰勒级数展开并取前两项:
对 $f(x)$ 求偏导:
此时状态空间方程变为:
状态方程是建立在连续系统的基础上,需要将其转化成离散化系统后,才能在微控制器中实现卡尔曼滤波状态观测器。在离散化系统中, $\dot{x}=\frac{x_{k}-x_{k-1}}{\Delta t}$ ,则状态空间方程表示为:
令 $A=(I+F\Delta t)$ ,扩展卡尔曼滤波器的流程为以下五步:
预测
计算预估值
$\hat{x}_k^-=\hat{x}_{k-1}+(f(x_{k-1})+B u_{k-1}) \Delta t$
计算误差协方差
$P_k^-=(I+F\Delta t)P_{k-1}(I+F\Delta t)^T+Q$
校正
计算卡尔曼增益
$K_k=P_k^-H^T(HP_k^-H^T+R)^{-1}$
修正预估值
$\hat{x}_k=\hat{x}_k^- + K_k(z_k-H\hat{x}_k^-)$
更新误差协方差,用于下一次计算
$P_k=(I-K_kH)P_k^-$
上面的五个方程中, $\Delta t$ 为采样时间, $Q$ 为模型误差, $R$ 为测量误差
在MATLAB中建立EKF观测器,需要建立全局变量x和P用于保存每一次迭代的值给下一次迭代使用:
1 | function x_posteriori = fcn(Ialpha,Ibeta,Ualpha,Ubeta,Ls,Rs,Flux) |
调整R矩阵和Q矩阵至最优,查看观测器效果:
蓝色为观测角度,黄色为真实角度。可以看到经过很短时间的迭代,观测器就已经可以很好地预测电机角度,至此完成了EKF无感算法。
速度闭环
前文电流闭环精准地控制了电机电流从而控制转矩,但要想精确地控制电机的速度就需要进行速度闭环。速度闭环是在电流闭环的外环,控制Id=0,通过前面有感或无感获取到的速度与速度参考作比较,通过PID控制Iq的值。
对于速度闭环PID,一班只是用PD控制。 $K_p$ 和 $K_d$ 的理论计算值为:
其中 $\beta$ 是速度环的带宽,一般为50rad/s; $J$ 为电机转动惯量,是电机的固有参数; $P$ 是电机的极对数; $\psi_f$ 是电机的磁链。
由于有观测器的存在,观测器的参数对速度环参数也会有影响,所以以上计算只是理论值,实际参数需要在理论值的基础上通过观察点击运行效果进行调整。