最近的科研项目需要使用到SVPWM算法,网上相关的原理介绍很多。对于纯应用的需求来说,或许有些内容上的冗余。
本文的目的就是简要并且明确的给出具体的计算步骤,可以帮助快速上手。同时利用MATLAB进行了简单算法验证。
2022年10月20日更新:由于之前的代码没有考虑电压的量化问题,今天重新修改进行了补充~
目录
1 算法流程
算法部分,结合网上博主的文章主要分为四个部分:扇区判断、基本矢量作用时间长度计算、逆变器开关接环时间计算、三角波改变开关状态。部分截图直接摘自了博主的@玻璃伞的图片,在此表示感谢。
这一部分的内容有非常多的细节,因此我将分步骤进行介绍,这里默认我们已经获得了定子坐标系(α-β坐标系)上的电压值,这将作为SVPWM的已知条件。
SVPWM的主要思想是在高频率的情况下,利用三相逆变器对三相电机电压控制,用数字量调制方法实现任意矢量电压的输出,从而更好地控制电机的运转过程,提高能量的转化效率,具体的算法原理可以看本文的参考文献。
1.1 扇区判断
SVPWM利用逆变器三相桥臂将坐标系分为了六个扇区,利用上下桥臂的不同开关组合有了8种组合形式,对应了图中的8个电压矢量。
在SVPWM运算过程中,因此首先是需要进行扇区的判断,首先利用α-β坐标系下,定义三个变量。
可以将Vref1,Vref2,Vref3分别看作A,B,C三个变量,这三个变量与0的关系就可以得到当前所在的扇区。
这里的N可以利用一个二进制数字进行表示,这样就可以将N的值与所在扇区进行唯一的对应。
1.2 基本矢量作用时间计算
充分利用Uα与Uβ就可以大大简化基本电压矢量作用的时间,参考文献中给出了具体的结论,计算原理是伏秒平衡,可以按照下面的表格直接找到对应扇区需要满足的作用时间。为了让表格更加简洁,首先定义三个变量:
利用上面的变量,可以确定每个扇区逆时针两个矢量,以及两个零矢量的作用时间:
当出现Tfirst+Tsecond>Ts时,需要进行如下的变换:
1.3 逆变器开关切换时间计算
有了持续时间,我们需要进一步确定逆变器开关的切换时间,用下面的图为例子,进行说明:
其中各个变量时间满足下面的表达式:
这里的T4,T6可以与上面的Tfirst,Tsecond进行对应,在不同的扇区有下面的关系:
这样就有了在不同扇区逆变器的切换时间。
1.4 利用三角波改变开关状态
有了逆变器切换时间和矢量的作用时间长度后,算法还不能自己判断时间,因为他是没有时间的概念的,这里可以使用三角波或者计数器来精确指定当前的时刻。
我们需要定义一个高是底边的一半,底边长是一个开关周期Ts的三角波信号,如下图所示,就可以利用三角波的值,确定是否需要改变逆变器的控制信号。
到此为止,我们利用输入的两个电压值Vα和Vβ计算出了三相逆变器的三个输出信号,与图片中是对应的。
2 MATLAB仿真验证(不考虑电压量化)
注意:“不考虑电压量化”里面是单纯进行算法验证,因此输入的电压值U_alpha = 1;就表示实际电压1伏,这是不完善的,因为在实际电路过程中,需要对浮点数进行量化处理。
例如:利用AD7604进行采样处理,±10V以内的电压会量化为16位的有符号数,因此需要进一步修改MATLAB,这个代码写在了本文后面。
%用来验证文档中SVPWM的正确性。
clc
clear all
close all
%01 扇区判断---------------------------------------------------------------
U_alpha = 1;
U_beta = 3;
Vref1 = U_beta;
Vref2 = (sqrt(3)/2)*U_alpha - (1/2)*U_beta;
Vref3 = -1*(sqrt(3)/2)*U_alpha - (1/2)*U_beta;
A = sign(Vref1);
B = sign(Vref2);
C = sign(Vref3);
if(A==-1)
A = 0;
end
if(B==-1)
B = 0;
end
if(C==-1)
C = 0;
end
N = 4*C + 2*B + A;
switch N
case{3}
sector = 1;
case{1}
sector = 2;
case{5}
sector = 3;
case{4}
sector = 4;
case{6}
sector = 5;
case{2}
sector = 6;
end
%02 计算时间长度------------------------------------------------------------
Ts = 2048/50000000;
Vdc = 10;
X = (sqrt(3)*Ts*U_beta)/(Vdc);
Y = (sqrt(3)*Ts*((sqrt(3)/2)*U_alpha+0.5*U_beta))/(Vdc);
Z = (sqrt(3)*Ts*((-1*sqrt(3)/2)*U_alpha+0.5*U_beta))/(Vdc);
switch N
case{1}
Tfirst = Z;
Tsecond = Y;
case{2}
Tfirst = Y;
Tsecond = -1*X;
case{3}
Tfirst = -1*Z;
Tsecond = X;
case{4}
Tfirst = -1*X;
Tsecond = Z;
case{5}
Tfirst = X;
Tsecond = -1*Y;
case{6}
Tfirst = -1*Y;
Tsecond = -1*Z;
end
if(Tfirst + Tsecond > Ts)
temp = Tfirst/(Tfirst+Tsecond);
Tfirst = (temp)*Ts;
Tsecond = (1-temp)*Ts;
end
Tzero = (Ts - Tfirst - Tsecond)/2;
%03 计算计逆变器开关的切换时间-----------------------------------------------
Ta = Tzero/2;
Tb = Ta + Tfirst/2;
Tc = Tb + Tsecond/2;
switch N
case{1}
Tcm1 = Tb;
Tcm2 = Ta;
Tcm3 = Tc;
case{2}
Tcm1 = Ta;
Tcm2 = Tc;
Tcm3 = Tb;
case{3}
Tcm1 = Ta;
Tcm2 = Tb;
Tcm3 = Tc;
case{4}
Tcm1 = Tc;
Tcm2 = Tb;
Tcm3 = Ta;
case{5}
Tcm1 = Tc;
Tcm2 = Ta;
Tcm3 = Tb;
case{6}
Tcm1 = Tb;
Tcm2 = Tc;
Tcm3 = Ta;
end
num = 2048 / 50000000;
Tcm1_q = round(2048*Tcm1/num);
Tcm2_q = round(2048*Tcm2/num);
Tcm3_q = round(2048*Tcm3/num);
%04 产生三角波-------------------------------------------------------------
t = [0:1:2048];
Tri = [[0:1:1023] [1024:-1:0]];
a = zeros(1,2049);
b = zeros(1,2049);
c = zeros(1,2049);
for i=1:2049
if(Tri(i) >= Tcm1_q)
a(i)=1;
end
if(Tri(i) >= Tcm2_q)
b(i)=1;
end
if(Tri(i) >= Tcm3_q)
c(i)=1;
end
end
%05 绘图展示
figure;
subplot(4,1,1);
plot(t,Tri);
title('Triangle Wave');
subplot(4,1,2);
plot(t,a);
title('a');
subplot(4,1,3);
plot(t,b);
title('b');
subplot(4,1,4);
plot(t,c);
title('c');
运行结果如下图所示:
4 MATLAB仿真验证(考虑电压量化)
由于我这里使用的AD7606,其电压转换表达式见下图:
其中REF=2.5V,使用的电压输入范围是±10V RANGE,因此在代码中需要对输入的电压U_alpha、U_beta、V_dc都量化到十六位有符号数,具体代码见下文。
代码中的控制周期是根据我实际电路进行设置的,这个部分大家可以自己修改。
%用来验证文档中SVPWM的正确性。
%这个是第二版的程序,
%由于上一版本没有考虑输入电压的16位有符号数量化情况,只能作为算法验证,对于硬件移植需要进一步修改
clc
clear all
close all
%实际的输入电压与DC电压
U_alpha_real = 3;
U_beta_real = -8;
V_dc_real = 24;
%00 数据有效性判断----------------------------------------------------------
if(U_alpha_real^2 + U_beta_real^2 > V_dc_real^2)
disp("Invalid Input!")
clear all
return;
end
%01 扇区判断---------------------------------------------------------------
%数据是16位的,因此是65536为最大值(有符号数 -32768 到 32767 )
%实际电压和这个的对应关系就是U_alpha_real/Vdc_real*32768(手册写的)
V_RANGE = 10; %AD模块的采样精度
V_alpha = U_alpha_real/V_RANGE*32768;
V_beta = U_beta_real /V_RANGE*32768;
Vref1 = V_beta;
Vref2 = (sqrt(3)/2)*V_alpha - (1/2)*V_beta;
Vref3 = -1*(sqrt(3)/2)*V_alpha - (1/2)*V_beta;
A = sign(Vref1);
B = sign(Vref2);
C = sign(Vref3);
if(A==-1)
A = 0;
end
if(B==-1)
B = 0;
end
if(C==-1)
C = 0;
end
N = 4*C + 2*B + A;
switch N
case{3}
sector = 1;
case{1}
sector = 2;
case{5}
sector = 3;
case{4}
sector = 4;
case{6}
sector = 5;
case{2}
sector = 6;
end
%02 计算时间长度------------------------------------------------------------
Ts = 1665; % 控制周期是1665个计数值
V_dc = V_dc_real/V_RANGE*32768; % V_RANGE变成32768
X = (sqrt(3)*Ts*V_beta)/(V_dc);
Y = (sqrt(3)*Ts*((sqrt(3)/2)*V_alpha+0.5*V_beta))/(V_dc);
Z = (sqrt(3)*Ts*((-1*sqrt(3)/2)*V_alpha+0.5*V_beta))/(V_dc);
switch N
case{1}
Tfirst = Z;
Tsecond = Y;
case{2}
Tfirst = Y;
Tsecond = -1*X;
case{3}
Tfirst = -1*Z;
Tsecond = X;
case{4}
Tfirst = -1*X;
Tsecond = Z;
case{5}
Tfirst = X;
Tsecond = -1*Y;
case{6}
Tfirst = -1*Y;
Tsecond = -1*Z;
end
if(Tfirst + Tsecond > Ts)
temp = Tfirst/(Tfirst+Tsecond);
Tfirst = (temp)*Ts;
Tsecond = (1-temp)*Ts;
end
Tzero = (Ts - Tfirst - Tsecond)/2;
%03 计算计逆变器开关的切换时间-----------------------------------------------
Ta = Tzero/2;
Tb = Ta + Tfirst/2;
Tc = Tb + Tsecond/2;
switch N
case{1}
Tcm1 = Tb;
Tcm2 = Ta;
Tcm3 = Tc;
case{2}
Tcm1 = Ta;
Tcm2 = Tc;
Tcm3 = Tb;
case{3}
Tcm1 = Ta;
Tcm2 = Tb;
Tcm3 = Tc;
case{4}
Tcm1 = Tc;
Tcm2 = Tb;
Tcm3 = Ta;
case{5}
Tcm1 = Tc;
Tcm2 = Ta;
Tcm3 = Tb;
case{6}
Tcm1 = Tb;
Tcm2 = Tc;
Tcm3 = Ta;
end
Tcm1_q = round(Tcm1);
Tcm2_q = round(Tcm2);
Tcm3_q = round(Tcm3);
%04 产生三角波(单周期)------------------------------------------------------
%注意,因为是单周期的,因此t这里是1667,实际上应该是1666(实际多周期)
%单周期的话,需要保证对称性绘图
t = [1:1:1667];
Tri = [[0:1:832] [833:-1:0]];
a = zeros(1,1667);
b = zeros(1,1667);
c = zeros(1,1667);
for i=1:1667
if(Tri(i) >= Tcm1_q)
a(i)=1;
end
if(Tri(i) >= Tcm2_q)
b(i)=1;
end
if(Tri(i) >= Tcm3_q)
c(i)=1;
end
end
%05 绘图展示
figure;
subplot(4,1,1);
plot(t,Tri);
axis([1 1667 0 833 ])
title('Triangle Wave');
subplot(4,1,2);
plot(t,a);
axis([1 1667 -1 2 ])
title('a');
subplot(4,1,3);
plot(t,b);
axis([1 1667 -1 2 ])
title('b');
subplot(4,1,4);
plot(t,c);
axis([1 1667 -1 2 ])
title('c');
运行结果如下图所示:
经过测试,这个输出的占空比也不受Vdc的变化影响,是符合实际的。
这部分代码的Verilog实现就在我的下一篇博客哦,欢迎交流讨论!
5 参考文献
【1】SVPWM分析、各个扇区详细计算以及Matlab仿真_michaelf的博客-CSDN博客_svpwm扇区
【3】3第二章-SVPWM原理分析_哔哩哔哩_bilibili
这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞收藏,分享给身边的朋友哇~