【从零开始实现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,结果为:

表(1-1) 

纯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

 

posted @ 2025-07-25 23:38  FBshark  阅读(288)  评论(0)    收藏  举报