FOC:【1】浅析SVPWM算法(七段式)以及MATLAB仿真验证

最近的科研项目需要使用到SVPWM算法,网上相关的原理介绍很多。对于纯应用的需求来说,或许有些内容上的冗余。

本文的目的就是简要并且明确的给出具体的计算步骤,可以帮助快速上手。同时利用MATLAB进行了简单算法验证。

2022年10月20日更新:由于之前的代码没有考虑电压的量化问题,今天重新修改进行了补充~

目录

1 算法流程

1.1 扇区判断

1.2 基本矢量作用时间计算

1.3 逆变器开关切换时间计算

1.4 利用三角波改变开关状态

2 MATLAB仿真验证(不考虑电压量化)

4 MATLAB仿真验证(考虑电压量化)

5 参考文献


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扇区

【2】彻底吃透SVPWM如此简单 - 知乎

【3】3第二章-SVPWM原理分析_哔哩哔哩_bilibili


这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞收藏,分享给身边的朋友哇~

猜你喜欢

转载自blog.csdn.net/Alex497259/article/details/125441988