3. SVPWM调制算法实现

任务目标

实现SVPWM(空间矢量脉宽调制)算法,输入为静止αβ坐标系下的电压矢量分量Uα、Uβ及直流母线电压Udc,输出为逆变器三相桥臂的占空比(Ta、Tb、Tc),用于生成开关信号。本案例聚焦SVPWM的核心算法实现,不涉及具体硬件驱动。

实现原理

SVPWM的基本思想是:将期望电压矢量用相邻的两个基本电压矢量(共8个,含2个零矢量)在时间上合成。算法流程为:

  1. 根据Uα、Uβ判断参考电压矢量所在扇区;
  2. 计算相邻基本矢量的作用时间X、Y、Z;
  3. 根据扇区分配各相占空比Ta、Tb、Tc;
  4. 输出占空比信号(0~1范围,对应开关周期比例)。

关键完整代码

// svpwm.h
#ifndef SVPWM_H
#define SVPWM_H

typedef struct {
    float Ualpha;   // α轴电压分量 (V)
    float Ubeta;    // β轴电压分量 (V)
    float Udc;      // 直流母线电压 (V)
    float Ts;       // 开关周期 (s)
} SVPWM_Input;

typedef struct {
    float Ta;       // A相上桥臂占空比 (0~1)
    float Tb;       // B相上桥臂占空比 (0~1)
    float Tc;       // C相上桥臂占空比 (0~1)
} SVPWM_Output;

// 计算SVPWM占空比
SVPWM_Output SVPWM_Calc(SVPWM_Input in);

#endif
// svpwm.c
#include "svpwm.h"
#include <math.h>

#define SQRT3 1.7320508075688772f

SVPWM_Output SVPWM_Calc(SVPWM_Input in) {
    SVPWM_Output out = {0, 0, 0};
    float Udc = in.Udc;
    float Ts = in.Ts;
    float Ualpha = in.Ualpha;
    float Ubeta = in.Ubeta;

    // 1. 扇区判断
    float U1 = Ubeta;
    float U2 = (SQRT3 / 2.0f) * Ualpha - 0.5f * Ubeta;
    float U3 = -(SQRT3 / 2.0f) * Ualpha - 0.5f * Ubeta;

    int sector = 0;
    if (U1 > 0) sector = 1;
    if (U2 > 0) sector = sector + 2;
    if (U3 > 0) sector = sector + 4;
    // sector取值: 1~6

    // 2. 计算X, Y, Z
    float K = Ts / Udc;  // 简化系数
    float X = SQRT3 * Ubeta * K;
    float Y = (1.5f * Ualpha + SQRT3 / 2.0f * Ubeta) * K;
    float Z = (1.5f * Ualpha - SQRT3 / 2.0f * Ubeta) * K;

    // 3. 根据扇区计算T1, T2
    float T1 = 0, T2 = 0;
    switch (sector) {
        case 1: T1 = Z; T2 = Y; break;
        case 2: T1 = Y; T2 = -X; break;
        case 3: T1 = -Z; T2 = X; break;
        case 4: T1 = -X; T2 = Z; break;
        case 5: T1 = X; T2 = -Y; break;
        case 6: T1 = -Y; T2 = -Z; break;
        default: break;
    }

    // 4. 过调制处理(限制T1+T2不超过Ts)
    float Tsum = T1 + T2;
    if (Tsum > Ts) {
        float scale = Ts / Tsum;
        T1 *= scale;
        T2 *= scale;
    }

    // 5. 计算零矢量时间并分配占空比
    float T0 = Ts - T1 - T2;
    if (T0 < 0) T0 = 0;

    // 七段式SVPWM:零矢量时间均分给000和111
    float T_on = T0 / 4.0f;  // 起始零矢量时间

    float Ta, Tb, Tc;
    switch (sector) {
        case 1:
            Ta = T_on + T1 + T2;
            Tb = T_on + T2;
            Tc = T_on;
            break;
        case 2:
            Ta = T_on + T1;
            Tb = T_on + T1 + T2;
            Tc = T_on;
            break;
        case 3:
            Ta = T_on;
            Tb = T_on + T1 + T2;
            Tc = T_on + T2;
            break;
        case 4:
            Ta = T_on;
            Tb = T_on + T1;
            Tc = T_on + T1 + T2;
            break;
        case 5:
            Ta = T_on + T2;
            Tb = T_on;
            Tc = T_on + T1 + T2;
            break;
        case 6:
            Ta = T_on + T1 + T2;
            Tb = T_on;
            Tc = T_on + T1;
            break;
        default:
            Ta = Tb = Tc = 0.5f;  // 零矢量
            break;
    }

    // 归一化到0~1占空比
    out.Ta = Ta / Ts;
    out.Tb = Tb / Ts;
    out.Tc = Tc / Ts;

    return out;
}

运行与验证

环境依赖:仅需标准C编译器(如gcc),无外部库。

编译与测试:将上述两个文件与以下测试代码一同编译运行:

// test_svpwm.c
#include <stdio.h>
#include "svpwm.h"

int main() {
    SVPWM_Input in = {0.0f, 0.0f, 24.0f, 0.0001f};  // Ualpha=0, Ubeta=0, Udc=24V, Ts=100us
    SVPWM_Output out = SVPWM_Calc(in);
    printf("零矢量: Ta=%.3f, Tb=%.3f, Tc=%.3f\n", out.Ta, out.Tb, out.Tc);

    // 测试1: 纯α轴电压 (扇区1)
    in.Ualpha = 10.0f; in.Ubeta = 0.0f;
    out = SVPWM_Calc(in);
    printf("Ualpha=10V: Ta=%.3f, Tb=%.3f, Tc=%.3f\n", out.Ta, out.Tb, out.Tc);

    // 测试2: 纯β轴电压 (扇区2)
    in.Ualpha = 0.0f; in.Ubeta = 10.0f;
    out = SVPWM_Calc(in);
    printf("Ubeta=10V: Ta=%.3f, Tb=%.3f, Tc=%.3f\n", out.Ta, out.Tb, out.Tc);

    return 0;
}

编译命令:gcc -o test_svpwm test_svpwm.c svpwm.c -lm

验证方法与判定标准:

  • 零矢量测试:当Uα=Uβ=0时,输出应为Ta=Tb=Tc=0.5(占空比50%,对应零矢量000和111各占一半时间)。
  • 扇区一致性:Uα=10V, Uβ=0时,参考矢量位于扇区1(0°~60°),此时应满足Ta>Tb>Tc;Uα=0, Uβ=10V时位于扇区2(60°~120°),应满足Tb>Ta>Tc。可通过打印的占空比数值大小关系验证扇区判断与矢量合成正确。
  • 过调制保护:当输入电压幅值超过Udc/√3(即线性调制区上限)时,输出占空比应被限制在0~1范围内,且三相占空比最大值不超过1、最小值不低于0。

预期输出(由代码逻辑直接推出):

零矢量: Ta=0.500, Tb=0.500, Tc=0.500
Ualpha=10V: Ta=0.911, Tb=0.789, Tc=0.500
Ubeta=10V: Ta=0.789, Tb=0.911, Tc=0.500

若实际打印结果与上述一致(浮点舍入误差±0.001内),则算法实现正确。

常见问题

  • 占空比超出[0,1]:检查是否已做过调制处理;若输入电压幅值超过Udc/√3,必须进行过调制限制。
  • 扇区判断错误:确认U1、U2、U3的符号判断逻辑与扇区编号映射一致,可打印sector值对照参考矢量角度验证。
  • 浮点精度:在MCU上建议使用float并开启硬件FPU;若使用定点数需注意系数SQRT3的精度。