3. SVPWM调制算法实现
任务目标
实现SVPWM调制算法,输入为静止α-β坐标系下的电压矢量分量(Uα、Uβ),输出为三相逆变器六个功率开关管的占空比信号(Ta、Tb、Tc),并通过仿真验证调制后逆变器输出的相电压波形接近正弦。
实现原理
SVPWM的核心思想是将期望电压矢量分解到由六个非零基本矢量(V1~V6)和两个零矢量(V0、V7)组成的八种开关状态中,通过在一个PWM周期内组合相邻基本矢量与零矢量,使平均输出电压等于期望矢量。实现步骤为:
- 判断期望矢量所在扇区;
- 计算相邻基本矢量的作用时间(X、Y、Z);
- 根据扇区分配各相占空比;
- 生成中心对齐的PWM波形。
关键完整代码
#include <stdio.h>
#include <math.h>
#define PI 3.14159265358979
#define T_SAMPLE 0.0001 // PWM周期 100us
#define V_DC 24.0 // 母线电压
typedef struct {
float u_alpha;
float u_beta;
} Vector2D;
typedef struct {
float ta; // A相上管占空比
float tb;
float tc;
} DutyCycles;
// 扇区判断
int calc_sector(Vector2D v) {
int sector = 0;
if (v.u_beta > 0) sector |= 1;
if ((sqrt(3)*v.u_alpha - v.u_beta) > 0) sector |= 2;
if ((-sqrt(3)*v.u_alpha - v.u_beta) > 0) sector |= 4;
return sector;
}
// SVPWM核心计算
DutyCycles svpwm_calc(Vector2D v) {
DutyCycles duty = {0, 0, 0};
int sector = calc_sector(v);
// 归一化时间
float t1, t2;
float x = sqrt(3) * v.u_beta * T_SAMPLE / V_DC;
float y = (1.5*v.u_alpha + sqrt(3)/2*v.u_beta) * T_SAMPLE / V_DC;
float z = (-1.5*v.u_alpha + sqrt(3)/2*v.u_beta) * T_SAMPLE / V_DC;
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: t1 = 0; t2 = 0; break;
}
// 过调制处理
float t_sum = t1 + t2;
if (t_sum > T_SAMPLE) {
float scale = T_SAMPLE / t_sum;
t1 *= scale;
t2 *= scale;
}
float t0 = (T_SAMPLE - t1 - t2) / 2;
float t1_shift = t1 + t0;
float t2_shift = t2 + t1_shift;
// 各扇区占空比分配
switch(sector) {
case 1: duty.ta = t1_shift; duty.tb = t2_shift; duty.tc = t0; break;
case 2: duty.ta = t1_shift; duty.tb = t0; duty.tc = t2_shift; break;
case 3: duty.ta = t0; duty.tb = t1_shift; duty.tc = t2_shift; break;
case 4: duty.ta = t2_shift; duty.tb = t1_shift; duty.tc = t0; break;
case 5: duty.ta = t2_shift; duty.tb = t0; duty.tc = t1_shift; break;
case 6: duty.ta = t0; duty.tb = t2_shift; duty.tc = t1_shift; break;
}
// 归一化到0~1
duty.ta /= T_SAMPLE;
duty.tb /= T_SAMPLE;
duty.tc /= T_SAMPLE;
return duty;
}
// 验证主函数:生成一个电周期的调制波形
int main() {
const int N = 200; // 每个电周期采样点数
float freq = 50.0; // 调制频率50Hz
float v_amp = V_DC * 0.5; // 相电压幅值
printf("时间(s), Ualpha(V), Ubeta(V), Ta, Tb, Tc\n");
for (int i = 0; i < N; i++) {
float theta = 2 * PI * freq * i * T_SAMPLE;
Vector2D v_ref;
// 圆形轨迹电压矢量
v_ref.u_alpha = v_amp * cos(theta);
v_ref.u_beta = v_amp * sin(theta);
DutyCycles d = svpwm_calc(v_ref);
printf("%.6f, %.3f, %.3f, %.4f, %.4f, %.4f\n",
i*T_SAMPLE, v_ref.u_alpha, v_ref.u_beta, d.ta, d.tb, d.tc);
}
return 0;
}
编译与运行
gcc -o svpwm svpwm.c -lm
./svpwm > svpwm_output.csv
验证方法
运行程序后,将生成的svpwm_output.csv导入Excel或Python中绘图:
- 占空比波形:绘制Ta、Tb、Tc随时间变化曲线,应观察到三个相位互差120°的马鞍形波形(中心对称,含三次谐波分量);
- 线电压合成:计算Vab = V_DC×(Ta-Tb),其波形应为六步阶梯波;
- 相电压基波:对Vab进行低通滤波或傅里叶分析,基波频率应为50Hz,幅值接近期望值(v_amp×√3/2 ≈ 10.4V);
- 判定通过条件:占空比始终在0~1范围内,且三相占空比之和的平均值约为1.5(中心对齐调制特性)。
预期输出示例
前几行输出数据(截取):
时间(s), Ualpha(V), Ubeta(V), Ta, Tb, Tc
0.000000, 12.000, 0.000, 0.5000, 0.5000, 0.5000
0.000100, 11.976, 0.754, 0.5337, 0.5000, 0.4663
0.000200, 11.905, 1.508, 0.5673, 0.5000, 0.4327
当θ=0时,三相占空比均为0.5(零矢量输出);随θ增大,A相占空比上升、C相下降,符合SVPWM调制规律。
上图展示了六个基本电压矢量将空间划分为六个扇区,任一期望电压矢量Vref可由所在扇区的两个相邻基本矢量合成。本实现中calc_sector()函数通过三个比较条件完成扇区判断,svpwm_calc()计算各矢量作用时间并输出三相占空比。