技术标签: matlab 算法 Verilog FOC控制算法与FPGA实现 SVPWM 开发语言
最近的科研项目需要使用到SVPWM算法,网上相关的原理介绍很多。对于纯应用的需求来说,或许有些内容上的冗余。
本文的目的就是简要并且明确的给出具体的计算步骤,可以帮助快速上手。同时利用MATLAB进行了简单算法验证。
2022年10月20日更新:由于之前的代码没有考虑电压的量化问题,今天重新修改进行了补充~
目录
算法部分,结合网上博主的文章主要分为四个部分:扇区判断、基本矢量作用时间长度计算、逆变器开关接环时间计算、三角波改变开关状态。部分截图直接摘自了博主的@玻璃伞的图片,在此表示感谢。
这一部分的内容有非常多的细节,因此我将分步骤进行介绍,这里默认我们已经获得了定子坐标系(α-β坐标系)上的电压值,这将作为SVPWM的已知条件。
SVPWM的主要思想是在高频率的情况下,利用三相逆变器对三相电机电压控制,用数字量调制方法实现任意矢量电压的输出,从而更好地控制电机的运转过程,提高能量的转化效率,具体的算法原理可以看本文的参考文献。
SVPWM利用逆变器三相桥臂将坐标系分为了六个扇区,利用上下桥臂的不同开关组合有了8种组合形式,对应了图中的8个电压矢量。
在SVPWM运算过程中,因此首先是需要进行扇区的判断,首先利用α-β坐标系下,定义三个变量。
可以将Vref1,Vref2,Vref3分别看作A,B,C三个变量,这三个变量与0的关系就可以得到当前所在的扇区。
这里的N可以利用一个二进制数字进行表示,这样就可以将N的值与所在扇区进行唯一的对应。
充分利用Uα与Uβ就可以大大简化基本电压矢量作用的时间,参考文献中给出了具体的结论,计算原理是伏秒平衡,可以按照下面的表格直接找到对应扇区需要满足的作用时间。为了让表格更加简洁,首先定义三个变量:
利用上面的变量,可以确定每个扇区逆时针两个矢量,以及两个零矢量的作用时间:
当出现Tfirst+Tsecond>Ts时,需要进行如下的变换:
有了持续时间,我们需要进一步确定逆变器开关的切换时间,用下面的图为例子,进行说明:
其中各个变量时间满足下面的表达式:
这里的T4,T6可以与上面的Tfirst,Tsecond进行对应,在不同的扇区有下面的关系:
这样就有了在不同扇区逆变器的切换时间。
有了逆变器切换时间和矢量的作用时间长度后,算法还不能自己判断时间,因为他是没有时间的概念的,这里可以使用三角波或者计数器来精确指定当前的时刻。
我们需要定义一个高是底边的一半,底边长是一个开关周期Ts的三角波信号,如下图所示,就可以利用三角波的值,确定是否需要改变逆变器的控制信号。
到此为止,我们利用输入的两个电压值Vα和Vβ计算出了三相逆变器的三个输出信号,与图片中是对应的。
注意:“不考虑电压量化”里面是单纯进行算法验证,因此输入的电压值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');
运行结果如下图所示:
由于我这里使用的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实现就在我的下一篇博客哦,欢迎交流讨论!
【1】SVPWM分析、各个扇区详细计算以及Matlab仿真_michaelf的博客-程序员宅基地_svpwm扇区
【3】3第二章-SVPWM原理分析_哔哩哔哩_bilibili
这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞收藏,分享给身边的朋友哇~
文章浏览阅读122次。还是A+BTime Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24568Accepted Submission(s): 11729Problem Description读入两个小于10000的正整数A和B,计算A+B。...
文章浏览阅读419次。HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息。FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。BASIC:仅记录请求的方法,URL以及响应状态码和执行时间。NONE:不记录任何日志信息,这是默认值。配置Feign日志有两种方式;方式二:java代码实现。注解中声明则代表某服务。方式一:配置文件方式。_feign 日志设置
文章浏览阅读155次。将容器管理的持久性 Bean 用于面向服务的体系结构本文将介绍如何使用 IBM WebSphere Process Server 对容器管理的持久性 (CMP) Bean的连接和持久性逻辑加以控制,使其可以存储在非关系数据库..._javax.ejb.objectnotfoundexception: no such entity!
文章浏览阅读1.5k次。基础java练习题一、递归实现跳台阶从第一级跳到第n级,有多少种跳法一次可跳一级,也可跳两级。还能跳三级import java.math.BigDecimal;import java.util.Scanner;public class Main{ public static void main(String[]args){ Scanner reader=new Scanner(System.in); while(reader.hasNext()){ _java 递归例题
文章浏览阅读1.5k次,点赞6次,收藏6次。目录1.串应用- 计算一个串的最长的真前后缀题目描述输入输出样例输入样例输出题解2.字符串替换(string)题目描述输入输出样例输入样例输出题解3.可重叠子串 (Ver. I)题目描述输入输出样例输入样例输出题解4.字符串操作(string)题目描述输入输出样例输入样例输出题解1.串应用- 计算一个串的最长的真前后缀题目描述给定一个串,如ABCDAB,则ABCDAB的真前缀有:{ A, AB,ABC, ABCD, ABCDA }ABCDAB的真后缀有:{ B, AB,DAB, CDAB, BCDAB_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。
文章浏览阅读68次。西安交通大学/算法设计与问题求解/树与二叉树/MOOC_算法设计与问题求解西安交通大学
文章浏览阅读1.6k次。问题:在Vue项目中出现如下错误提示:[Vue warn]: Computed property "totalPrice" was assigned to but it has no setter. (found in <Anonymous>)代码:<input v-model="totalPrice"/>原因:v-model命令,因Vue 的双向数据绑定原理 , 会自动操作 totalPrice, 对其进行set 操作而 totalPrice 作为计..._computed property "totalprice" was assigned to but it has no setter.
文章浏览阅读60次。十分暴力而简洁的解决方式:读取P和T的位置并自动生成唯一正确答案,将题给测点与之对比,不一样就给我爬!_basic 1003 case 1
文章浏览阅读422次。原标题:详解将Web项目War包部署到Tomcat服务器基本步骤详解将Web项目War包部署到Tomcat服务器基本步骤1 War包War包一般是在进行Web开发时,通常是一个网站Project下的所有源码的集合,里面包含前台HTML/CSS/JS的代码,也包含Java的代码。当开发人员在自己的开发机器上调试所有代码并通过后,为了交给测试人员测试和未来进行产品发布,都需要将开发人员的源码打包成Wa..._/opt/bosssoft/war/medical-web.war/web-inf/web.xml of module medical-web.war.
文章浏览阅读3k次,点赞3次,收藏13次。# -*- coding: utf-8 -*-# 简述:这里有四个数字,分别是:1、2、3、4#提问:能组成多少个互不相同且无重复数字的三位数?各是多少?def f(n):list=[]count=0for i in range(1,n+1):for j in range(1, n+1):for k in range(1, n+1):if i!=j and j!=k and i!=k:list.a..._python求从0到9任意组合成三位数数字不能重复并输出
文章浏览阅读1k次,点赞3次,收藏2次。<el-table-column prop="studentSex" label="性别" :formatter="sex"></el-table-column>然后就在vue的methods中写方法就OK了methods: { sex(row,index){ if(row.studentSex == 1){ return '男'; }else{ return '女'; }..._elementui table 性别
文章浏览阅读1.1k次。java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下