【从零开始实现stm32无刷电机FOC】【理论2/3】【 SVPWM数学模型】
上一节,我们找到了一种控制线圈合成磁矢量的方法—SVPWM,但是仅停留在逻辑层面上。本节对SVPWM进行数学推导,给出最终的线圈控制函数。本节的目标为——找到一个函数,输入目标线圈磁矢量,输出三相桥臂的pwm占空比。
目标磁矢量可以有两种表示方式,一种是极坐标,一种是笛卡尔坐标。
极坐标形式:
( D u , D v , D w ) ← s v p w m ( θ : 磁矢量方向 , s : 磁矢量强度 )
电机转子旋转靠的是切向受力,在极坐标形式下,磁矢量方向和磁矢量强度都会对切向分力有影响,存在耦合问题,以后难以进行电机控制,因此可以将磁矢量表达方式改为笛卡尔坐标,将磁矢量解耦为切向和直向。
笛卡尔坐标形式:
( D u , D v , D w ) ← s v p w m ( d : 磁矢量直向强度 , q : 磁矢量切向强度 )
由于极坐标形式下的推导非常简单清晰,因此本节先按照极坐标形式进行推导,形成大致的概念,再按照笛卡尔坐标形式进行推导。
本节推导过程不考虑物理单位,将各类数值归一化,比如扇区6个基础矢量长度视为1,pwm周期视为1,磁矢量强度最大为1,以后在推导结果上再乘物理量即可。
线性调制区
回顾上节的SVPWM扇区图,在此将坐标系建立在扇区图中心,扇区图中有6个基础矢量:

从图中可以看出,线圈磁矢量可以落在在扇形范围内任意位置,但是有一个问题,线圈磁矢量强度最大值不恒定,意味着电机转一圈的力矩有波动。所以我们将线圈磁矢量的范围限制为扇形内切圆,人为降低一些线圈磁矢量能达到的最大强度,让电机转动时力矩可以保持恒定,这称为线性调制(非线性过调制不在本文范围内)。

扇区pwm计算
从扇区图可知,如果目标线圈磁矢量落在扇区1,需要用pwm混合情况1和情况2;如果目标线圈磁矢量落在扇区2,需要用pwm混合情况2和情况3。同理,每个扇区都需要独立计算(你可能会想,为什么不把扇区1和扇区2合并起来用情况1和情况3进行混合?实际上这样混合出来的磁矢量强度较低)。
以扇区1的计算为例:
考虑到线性调制,线圈磁矢量最大强度为扇区内切圆半径,由于6个基础矢量长度为1,因此内切圆半径等于
以下计算过程先按照线圈磁矢量最大强度进行,最后将占空比乘上强度系数就可以实现强度控制。

注意,式(1-1)得到的占空比是基础矢量的在一个周期内的比例(权重),桥臂的占空比后续再计算。
其余扇区的几何形状与扇区1是相同的,比如扇区2的计算只需在式(1-1)的基础上将θ \thetaθ减去60°。把扇区顺时针方向的基础矢量记号为m mm,逆时针方向的基础矢量记号为n nn,结果为:


纯c语言代码验证
将式(1-2)用C语言描述出来,这一定是你见过最简洁优雅的SVPWM函数:
#include <stdio.h>
#include <math.h>
#define PI 3.14159265358979323846
#define deg_to_rad(a) (PI * (a) / 180)
typedef struct duty
{
float d_u;
float d_v;
float d_w;
} duty_t;
/**
* @brief 极坐标系下的svpwm
*
* @param theta 目标磁矢量角度
* @param s 目标磁矢量强度
* @return duty_t 三相桥臂占空比
*/
duty_t svpwm(float theta, float s)
{
const float rad60 = deg_to_rad(60);
const int v[6][3] = {{1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 1, 1}, {0, 0, 1}, {1, 0, 1}};
int sector = 1 + theta / rad60;
float t_m = s * sinf(sector * rad60 - theta);
float t_n = s * sinf(theta - (sector * rad60 - rad60));
float t_0 = 1 - t_m - t_n;
duty_t duty;
duty.d_u = t_m * v[sector - 1][0] + t_n * v[sector % 6][0] + t_0 / 2;
duty.d_v = t_m * v[sector - 1][1] + t_n * v[sector % 6][1] + t_0 / 2;
duty.d_w = t_m * v[sector - 1][2] + t_n * v[sector % 6][2] + t_0 / 2;
return duty;
}
int main()
{
for (float phi = 0; phi < 360; phi += 10)
{
// 这里我设置磁矢量与转子垂直,这样转子受力最大
duty_t duty = svpwm(deg_to_rad(fmodf(phi + 90, 360)), 1);
printf("%f,%f,%f,\r\n", duty.d_u, duty.d_v, duty.d_w);
}
return 0;
}
将运行结果用折线图绘制出来,可以看到三相桥臂占空比结果,将占空比设置给单片机的pwm产生器就可以控制电机旋转了:
参考:
1. 原文链接:
https://blog.csdn.net/qq570437459/article/details/138871835#pwm_15
2. gitee 项目
连接:https://gitee.com/best_pureer/stm32_foc

浙公网安备 33010602011771号