3. SVPWM调制算法实现
任务目标
实现SVPWM(空间矢量脉宽调制)算法,输入为静止αβ坐标系下的电压矢量分量Uα、Uβ及直流母线电压Udc,输出为逆变器三相桥臂的占空比(Ta、Tb、Tc),用于生成开关信号。本案例聚焦SVPWM的核心算法实现,不涉及具体硬件驱动。
实现原理
SVPWM的基本思想是:将期望电压矢量用相邻的两个基本电压矢量(共8个,含2个零矢量)在时间上合成。算法流程为:
- 根据Uα、Uβ判断参考电压矢量所在扇区;
- 计算相邻基本矢量的作用时间X、Y、Z;
- 根据扇区分配各相占空比Ta、Tb、Tc;
- 输出占空比信号(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的精度。