碎碎念:经过近一周的调试与查错(不好意思我实在太菜了),才终于从MATLAB代码的基础上,实现了Verilog对SVPWM算法的实现,同时给出仿真的结果。
2022年10月20日更新:实在抱歉,由于之前在算法中没有考虑到输入电压值量化以及死区时间的问题,我也是在电路测试过程中才发现这个错误,今天进行了更正与修改。电压值量化的具体原理可以参考我的上一篇文章~
目录
1 主要思路
2 模块代码
2.1 my_SVPWM 模块
2.2 Jud_sec 模块
2.3 Cal_time 模块
2.4 Switch_time 模块
2.5 Tri_gener 模块
2.6 测试模块
3 仿真结果
3.1 MATLAB计算结果
3.2 Vivado 2018.3 仿真结果
1 主要思路
思路与上一篇文章基本一致,但是针对Verilog中的部分特点(包括精度以及时序),本文给出各个模块的代码,以及Vivado的仿真结果。
读者可以自行和上一篇文章进行对比:FOC:【1】浅析SVPWM算法(七段式)以及MATLAB仿真验证
2 模块代码
2.1 my_SVPWM 模块
用来实现SVPWM,输入是Park 逆变换后的Vα与Vβ,输出是三个桥臂的控制信号。
// SVPWM模块
// Type : synthesizable
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// 功能?? 用来实现SVPWM,输入是Park 逆变换后的Vα与Vβ,输出是三个桥臂的控制信号
// 包含四个部分:
// 01 扇区判断
// 02 矢量作用时间计算
// 03 逆变器开关切换时间计算
// 04 利用三角波改变开关状态
module my_SVPWM(
input wire clk, //时钟信号
input wire rstn, //复位信号
input wire in_en, //系统的输入使能信号
input wire signed [15:0] Valpha, //Park逆变换的结果Vα
input wire signed [15:0] Vbeta, //Park逆变换的结果Vβ
output wire pwm_a, //SVPWM的输出信号 PWM_a
output wire pwm_an, //SVPWM的输出信号 PWM_an
output wire pwm_b, //SVPWM的输出信号 PWM_b
output wire pwm_bn, //SVPWM的输出信号 PWM_bn
output wire pwm_c, //SVPWM的输出信号 PWM_c
output wire pwm_cn //SVPWM的输出信号 PWM_cn
);
parameter Dead_Zone = 39; //死区的宽度
//下面的是调试版本,用来观察中间变??
// module my_SVPWM(
// input wire clk, //时钟信号
// input wire rstn, //复位信号
// input wire in_en, //系统的输入使能信号
// input wire signed [15:0] Valpha, //Park逆变换的结果Vα
// input wire signed [15:0] Vbeta, //Park逆变换的结果Vβ
// output wire pwm_a, //SVPWM的输入1 PWM_a
// output wire pwm_b, //SVPWM的输入2 PWM_b
// output wire pwm_c, //SVPWM的输入3 PWM_c
// output wire [3:0] n,
// output wire [3:0] sector,
// output wire Jug_sec_in_en,
// output wire signed [16:0] x,
// output wire signed [16:0] y,
// output wire signed [16:0] z,
// output wire Jug_sec_out_en,
// output wire signed [16:0] Tfirst,
// output wire signed [16:0] Tsecond,
// output wire signed [16:0] Tzero,
// output wire Cal_time_out_en,
// output wire signed [16:0] Tcm1,
// output wire signed [16:0] Tcm2,
// output wire signed [16:0] Tcm3,
// output wire Switch_time_out_en,
// output wire signed [11:0] Ts_cnt,
// output wire Tri_gener_out_en
// );
// SVPWM的实例化过程------------------------------------------------------------------------------------------------------------
// 00 实例化需要使用到的导线
wire [3:0] n;
wire [3:0] sector;
wire Jug_sec_in_en;
wire signed [63:0] x;
wire signed [63:0] y;
wire signed [63:0] z;
wire Jug_sec_out_en;
wire signed [63:0] Tfirst;
wire signed [63:0] Tsecond;
wire signed [63:0] Tzero;
wire Cal_time_out_en;
wire signed [63:0] Tcm1;
wire signed [63:0] Tcm2;
wire signed [63:0] Tcm3;
wire Switch_time_out_en;
wire signed [11:0] Ts_cnt;
wire Tri_gener_out_en;
reg first_start;
reg [4:0] first_start_cnt;
//00 首次启动---------------------------------------------------------------------------------------------------------------------
always_ff @(posedge clk or negedge rstn) begin
if(~rstn) begin
first_start <= 0;
first_start_cnt <= 5'd0;
end else begin
if(first_start_cnt <= 20)
first_start_cnt <= first_start_cnt + 5'd1;
if(first_start_cnt == 18)
first_start <= 1;
else
first_start <= 0;
end
end
// 01 扇区判断--------------------------------------------------------------------------------------------------------------------------------------------------
// 功能:利用当前的Valpha与Vbeta判断所在的扇区
// 输入:Valpha Vbeta
// 输出:扇区数字sector,以及相关参数N
//assign Jug_sec_in_en = Tri_gener_out_en || in_en;
assign Jug_sec_in_en = Tri_gener_out_en || first_start;
Jug_sec Jug_sec(
.clk ( clk ), //时钟信号
.rstn ( rstn ), //复位信号
.in_en ( Jug_sec_in_en ), //输入有效信号
.Valpha ( Valpha ), //Park逆变换的结果Vα (是有符号数,-32768~32767)
.Vbeta ( Vbeta ), //Park逆变换的结果Vβ (是有符号数,-32768~32767)
.n ( n ), //扇区计算中常用的N
.sector ( sector ), //扇区的结果
.x ( x ), //就是 X
.y ( y ), //就是 Y
.z ( z ), //就是 Z
.out_en ( Jug_sec_out_en ) //输出使能信号
);
// 02 矢量作用时间计算--------------------------------------------------------------------------------------------------------------------------------------------------
// 功能:矢量作用时间计算
// 输入: X,Y,Z三个变量以及N
// 输出: 根据N判断出的时间长度
Cal_time Cal_time(
.clk ( clk ), //时钟信号
.rstn ( rstn ), //复位信号
.in_en ( Jug_sec_out_en ), //输入使能信号
.x ( x ),
.y ( y ),
.z ( z ),
.n ( n ),
.Tfirst ( Tfirst ),
.Tsecond ( Tsecond ),
.Tzero ( Tzero ),
.out_en ( ), //输出使能信号
.out_en2 ( ),
.out_en3 ( Cal_time_out_en )
);
// 03 计算逆变器开关切换的时间--------------------------------------------------------------------------------------------------------------------------------------------------
// 功能:利用查表的方式,计算三个相开关切换的时间
// 输入:
// 输出:
Switch_time Switch_time(
.clk ( clk ), //时钟信号
.rstn ( rstn ), //复位信号
.in_en ( Cal_time_out_en ), //输入使能信号
.n ( n ),
.Tfirst ( Tfirst ),
.Tsecond ( Tsecond ),
.Tzero ( Tzero ),
.Tcm1 ( Tcm1 ), //三个逆变器的切换时间
.Tcm2 ( Tcm2 ),
.Tcm3 ( Tcm3 ),
.out_en ( ), //输出使能信号
.out_en2 ( Switch_time_out_en )
);
// 04 产生三角??--------------------------------------------------------------------------------------------------------------------------------------------------
// 功能:绘制三角波
// 输入:
// 输出:
Tri_gener Tri_gener(
.clk ( clk ), //输入时钟
.rst ( rstn ), //复位信号
.in_en ( Switch_time_out_en ), //输入使能信号
.Ts_cnt ( Ts_cnt ), //Ts的计数器,用来产生一个周期为Ts=2*Tp的三角波
.deta_clk ( Tri_gener_out_en ) //每次输出一个时钟,就给一个高电平
);
// 05 结合三角波,产生SVPWM结果(包含死区的计算)
// 功能:结合三角波,产生SVPWM的结果
// 输入: 计算出来的输出波形切换时间Tcm1,Tcm2,Tcm3,以及当前的
// 输出:
assign pwm_a = (Ts_cnt >= Tcm1) ? 1:0;
assign pwm_b = (Ts_cnt >= Tcm2) ? 1:0;
assign pwm_c = (Ts_cnt >= Tcm3) ? 1:0;
// 06 死区时间的考虑,这里由于我电路中需要给同相信号,所以是下面的表达式
// 要根据实际电路确定正负,但是这个延时的思路是相同的
assign pwm_an = (Ts_cnt >= Tcm1-Dead_Zone) ? 1:0;
assign pwm_bn = (Ts_cnt >= Tcm2-Dead_Zone) ? 1:0;
assign pwm_cn = (Ts_cnt >= Tcm3-Dead_Zone) ? 1:0;
endmodule
2.2 Jud_sec 模块
用来实现输入是Park 逆变换后的Vα与Vβ,输出扇区的值。
这里需要注意的细节是,n的计算需要参考三个表达式,但是实际上只需要利用到表达式的具体符号,而不是数值。因此可以通过成乘法,来放大其中的小数部分,从而获得更加准确的正负符号判断。
相应的,对于XYZ的计算,由于是需要具体数值的,并且对精度要求较高。怎么实现浮点数的运算呢?比较好的方法是先实现所有的乘法,在进行所有的除法,这样可以获得比较好的浮点数精度。
// 用来实现扇区的判断
// Type : synthesizable
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// 功能: 用来实现输入是Park 逆变换后的Vα与Vβ,输出扇区的值
module Jug_sec(
input wire clk, //时钟信号
input wire rstn, //复位信号
input wire in_en, //输入有效信号
input wire signed [15:0] Valpha, //Park逆变换的结果Vα (是有符号数,-32768~32767)
input wire signed [15:0] Vbeta, //Park逆变换的结果Vβ (是有符号数,-32768~32767)
output reg [3:0] n, //扇区计算中常用的N
output reg [3:0] sector, //扇区的结果
output reg signed [63:0] x, //就是X
output reg signed [63:0] y, //就是Y
output reg signed [63:0] z, //就是Z
output reg out_en
);
//reg [16:0] Vref1; // 不需要定义,就是 Vbeta本身
reg signed [31:0] Vref1;
reg signed [31:0] Vref2;
reg signed [31:0] Vref3;
//reg en_flag;
reg flag2;
//reg [16:0] y;
//reg [16:0] z;
wire signed [31:0] alphasqrt3;
parameter Ts = 1666;
parameter sqrt3Ts = 2884;
parameter Vdc = 78643; //V_dc_real/V_RANGE*32768;
//parameter temp = sqrt3Ts/Vdc;
always @(*)
begin
if(~rstn)
begin
n <= 4'b0000;
end
else
begin
n[2:0]<= {~Vref3[31], ~Vref2[31], ~Vbeta[15]};
end
end
always@(posedge clk)
if(~rstn)
begin
Vref1 <= 32'd0;
Vref2 <= 32'd0;
Vref3 <= 32'd0;
x <= 64'd0;
y <= 64'd0;
z <= 64'd0;
sector <= 4'b0000;
flag2 <= 1'd0;
out_en <= 1'd0;
end
else
begin
if(flag2 == 1'd1)
begin
flag2 <= 1'd0;
case(n) //通过符号来判断
4'd3: //3
begin
sector <= 4'd1;
out_en <= 1'd1;
end
4'd1:
begin
sector <= 4'd2;
out_en <= 1'd1;
end
4'd5:
begin
sector <= 4'd3;
out_en <= 1'd1;
end
4'd4:
begin
sector <= 4'd4;
out_en <= 1'd1;
end
4'd6:
begin
sector <= 4'd5;
out_en <= 1'd1;
end
4'd2:
begin
sector <= 4'd6;
out_en <= 1'd1;
end
default:
begin
sector <= 4'd0;
out_en <= 1'd0;
end
endcase
end
if(out_en)
begin
$display("OUTPUT:");
$display(" sector : %d",sector);
$display(" n : %d",n);
$display(" x : %d",x);
$display(" y : %d",y);
$display(" z : %d",z);
out_en<= 1'd0;
end
if(in_en)
begin
//实现高精度的方法,先计算所有的乘法,最后计算除法!
//对于只需要计算符号的,不需要除以分母啦
$display("--------------------05 SVPWM--------------------");
$display(" ----------05-01 Judge Section---------- ");
$display("INPUT:");
$display(" Valpha : %d",Valpha);
$display(" Vbeta : %d",Vbeta);
Vref1 <= Vbeta;
Vref2 <= (-1*Vbeta*512 + Valpha*887);///1024; //这一步,相当于alphasqrt3*根号三去掉后面的几位就是实现了除以255(新策略,都乘以256,再除以512)
Vref3 <= (-1*Vbeta*512 - Valpha*887);///1024;
x <= sqrt3Ts*(Vbeta)/Vdc;
y <= (sqrt3Ts*Vbeta*512 + sqrt3Ts*Valpha*887)/(1024*Vdc); //这里与Vref是差倍数的
z <= (sqrt3Ts*Vbeta*512 - sqrt3Ts*Valpha*887)/(1024*Vdc);
flag2 <= 1'd1;
end
end
endmodule
2.3 Cal_time 模块
利用输入的XYZ,计算时间的长度。
// 计算时间的长度
// Type : synthesizable
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// 功能: 利用输入的XYZ,计算时间的长度
module Cal_time(
input wire clk, //时钟信号
input wire rstn, //复位信号
input wire in_en, //输入使能信号
input wire signed [63:0] x,
input wire signed [63:0] y,
input wire signed [63:0] z,
input wire [3:0] n,
output reg signed [63:0] Tfirst,
output reg signed [63:0] Tsecond,
output reg signed [63:0] Tzero,
output reg out_en, //输出使能信号
output reg out_en2,
output reg out_en3,
output reg signed [63:0] temp2,
output reg signed [63:0] temp3,
output reg signed [63:0] temp
//output reg flag2
);
parameter Ts = 1666;
//reg signed [30:0] temp2;
//reg signed [30:0] temp3;
reg flag2;
//wire signed [30:0] temp;
//assign =
always @(posedge clk)
begin
if(in_en)
begin
$display("--------------------05 SVPWM--------------------");
$display(" ----------05-02 Calculate Time---------- ");
$display("INPUT:");
$display(" x : %d",x);
$display(" y : %d",y);
$display(" z : %d",z);
flag2 <= 1'd1;
end
if(~rstn)
begin
Tfirst <= 64'd0;
Tsecond <= 64'd0;
temp2 <= 64'd0;
temp3 <= 64'd0;
flag2 <= 1'd0;
out_en <= 1'd0;
out_en2 <= 1'd0;
out_en3 <= 1'd0;
Tzero <= 64'd0;
temp <= 64'd0;
end
else
Tzero <= (Ts - Tfirst - Tsecond)/2;
begin
if(flag2)
begin
flag2 <= 1'd0;
case(n)
4'd1:begin
Tfirst <= z;
Tsecond <= y;
out_en <= 1'd1;
end
4'd2:begin
Tfirst <= y;
Tsecond <= -1*x;
out_en <= 1'd1;
end
4'd3:begin
Tfirst <= -1*z;
Tsecond <= x;
out_en <= 1'd1;
end
4'd4:begin
Tfirst <= -1*x;
Tsecond <= z;
out_en <= 1'd1;
end
4'd5:begin
Tfirst <= x;
Tsecond <= -1*y;
out_en <= 1'd1;
end
4'd6:begin
Tfirst <= -1*y;
Tsecond <= -1*z;
out_en <= 1'd1;
end
default:
begin
Tfirst <= 17'd0;
Tsecond <= 17'd0;
out_en <= 1'd0;
end
endcase
end
if(out_en)
begin
out_en <= 1'd0;
out_en2<= 1'd1;
end
if(out_en2)
begin
out_en2 <= 1'd0;
out_en3 <= 1'd1;
end
if(out_en3)
begin
out_en3 <= 1'd0;
$display("OUTPUT:");
$display(" Tfirst : %d",Tfirst);
$display(" Tsecond : %d",Tsecond);
$display(" Tzero : %d",Tzero);
end
end
if(Tfirst + Tsecond > Ts)
begin
//temp2 <= Ts*Tfirst;
//temp3 <= Ts*Tsecond;
Tfirst <= Ts*Tfirst/(Tfirst + Tsecond);
Tsecond <= Ts*Tsecond/(Tfirst + Tsecond);
end
end
endmodule
2.4 Switch_time 模块
利用时间长度信息,计算具体的开关切换时刻。
// 计算逆变器信号改变的时间
// Type : synthesizable
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// 功能: 利用时间长度信息,计算具体的开关切换时刻。
module Switch_time(
input wire clk, //时钟信号
input wire rstn, //复位信号
input wire in_en, //输入使能信号
input wire [3:0] n,
input wire signed [63:0] Tfirst,
input wire signed [63:0] Tsecond,
input wire signed [63:0] Tzero,
output reg signed [63:0] Tcm1, //三个逆变器的切换时间
output reg signed [63:0] Tcm2,
output reg signed [63:0] Tcm3,
output reg out_en, //输出使能信号
output reg out_en2 //延迟一拍
);
wire signed [63:0] Ta_wire;
wire signed [63:0] Tb_wire;
wire signed [63:0] Tc_wire;
assign Ta_wire = Tzero/2;
assign Tb_wire = Ta_wire + Tfirst/2;
assign Tc_wire = Tb_wire + Tsecond/2;
reg signed [63:0] Ta;
reg signed [63:0] Tb;
reg signed [63:0] Tc;
reg flag2;
always @(*)
begin
if(!rstn)
begin
Ta <= 64'd0;
Tb <= 64'd0;
Tc <= 64'd0;
end
else
begin
Ta <= Ta_wire;
Tb <= Tb_wire;
Tc <= Tc_wire;
end
if(out_en2)
begin
Ta <= 64'd0;
Tb <= 64'd0;
Tc <= 64'd0;
end
end
always @(posedge clk) //
begin
if(in_en)
begin
flag2 <= 1'd1;
$display("--------------------05 SVPWM--------------------");
$display(" ----------05-03 Switch Time---------- ");
$display("INPUT:");
$display(" Tfirst : %d",Tfirst);
$display(" Tsecond : %d",Tsecond);
$display(" Tzero : %d",Tzero);
end
if(!rstn)
begin
Tcm1 <= 64'd0;
Tcm2 <= 64'd0;
Tcm3 <= 64'd0;
flag2 <= 1'd0;
out_en <= 1'd0;
out_en2 <= 1'd0;
end
else
begin
if(flag2)
begin
// Ta <= Tzero/2;
// Tb <= Ta + Tfirst/2;
// Tc <= Tb + Tsecond/2;
case(n)
4'd1:begin
Tcm1 <= Tb;
Tcm2 <= Ta;
Tcm3 <= Tc;
out_en <= 1'd1;
end
4'd2:begin
Tcm1 <= Ta;
Tcm2 <= Tc;
Tcm3 <= Tb;
out_en <= 1'd1;
end
4'd3:begin
Tcm1 <= Ta;
Tcm2 <= Tb;
Tcm3 <= Tc;
out_en <= 1'd1;
end
4'd4:begin
Tcm1 <= Tc;
Tcm2 <= Tb;
Tcm3 <= Ta;
out_en <= 1'd1;
end
4'd5:begin
Tcm1 <= Tc;
Tcm2 <= Ta;
Tcm3 <= Tb;
out_en <= 1'd1;
end
4'd6:begin
Tcm1 <= Tb;
Tcm2 <= Tc;
Tcm3 <= Ta;
out_en <= 1'd1;
end
default:
begin
Tcm1 <= Tb;
Tcm2 <= Ta;
Tcm3 <= Tc;
out_en <= 1'd0;
end
endcase
end
if(out_en)
begin
out_en <= 1'd0;
flag2 <= 1'd0;
end
if(out_en)
begin
out_en2 <= 1'd1;
$display("OUTPUT:");
$display(" Tcm1 : %d",Tcm1);
$display(" Tcm2 : %d",Tcm2);
$display(" Tcm3 : %d",Tcm3);
end
if(out_en2)
begin
out_en2 <= 1'd0;
// Ta <= 17'd0;
// Tb <= 17'd0;
// Tc <= 17'd0;
flag2 <= 1'd0;
out_en <= 1'd0;
end
end
end
endmodule
2.5 Tri_gener 模块
产生三角波,便于确定当前所处的时刻。其中的变量CYCLE_NUM可以用来控制仿真的时候,SVPWM输出的具体循环数量。
// 三角波生成模块
// Type : synthesizable
// Standard: SystemVerilog 2005 (IEEE1800-2005)
// 功能: 产生三角波,便于确定当前所处的时刻。
module Tri_gener(
input wire clk, //输入时钟
input wire rst, //复位信号
input wire in_en, //输入使能信号
// output reg Ts_cp, //对PGFS输入时钟进行同步化后的时钟,提供给Ts累加的脉冲
output reg signed [11:0] Ts_cnt, //Ts的计数器,用来产生一个周期为Ts=2*Tp的三角波
output reg deta_clk //每次输出一个时钟,就给一个高电平
);
///三角波产生//
reg [16:0] adder; //Ts有关的相位累加器
reg Ts_dir; //Ts的计数器的计数方向
reg flag2;
reg signed [5:0] cycle_num; //计数完成了多少个周期
parameter Tp = 833; //开关周期的一半;实际是833个周期,是0-832,
// pfs= 10000; //频率控制输入,5000:7K,10000:15K,20000:30K
// 1 2 3 4 5 1 2 3 4 5
// 0 1 2 1 0 1 2 1 0
// 1 2 3 4 5 6 1 2 3 4 5
// 0 1 2 3 2 1 0 1 2 1 0
parameter CYCLE_NUM = 3;
always @(posedge clk)
begin
if(in_en)
begin
flag2 <= 1'd1;
end
if(!rst)
begin
Ts_cnt <= 12'd0;
Ts_dir <= 1'b1;
deta_clk <= 1'b0;
flag2 <= 1'd0;
cycle_num<= 1'd0;
end
else
begin
// if(cycle_num == CYCLE_NUM)
// flag2 <= 1'd0;
if(flag2)
begin
if(Ts_dir)
Ts_cnt <= Ts_cnt + 12'b1;
else
Ts_cnt <= Ts_cnt - 12'b1;
if( Ts_cnt == Tp-1 ) //注意是非阻塞赋值
begin
Ts_dir <= 1'b0;
end
if( Ts_cnt == 1 ) //注意是非阻塞赋值
begin
Ts_dir <= 1'b1;
end
if( Ts_cnt == 1 && ~Ts_dir)
begin
deta_clk <= 1'b1;
cycle_num <= cycle_num + 1'b1;
end
else
begin
deta_clk <= 1'b0;
end
end
end
end
endmodule
2.6 测试模块
这个是对整体模块的测试代码,可以在里面设置Vα与Vβ的值,在Quartus中进行仿真验证。
// Verilog Test Bench template for design : my_SVPWM
`timescale 1 ps/ 1 ps
module my_SVPWM_vlg_tst();
// constants
// general purpose registers
reg clk;
reg rstn;
// reg in_en;
// test vector input registers
reg signed [15:0] Valpha;
reg signed [15:0] Vbeta;
// wires
// wire Cal_time_out_en;
// wire Jug_sec_in_en;
// wire Jug_sec_out_en;
// wire Switch_time_out_en;
// wire [16:0] Tcm1;
// wire [16:0] Tcm2;
// wire [16:0] Tcm3;
// wire [16:0] Tfirst;
// wire Tri_gener_out_en;
// wire signed [11:0] Ts_cnt;
// wire [16:0] Tsecond;
// wire [16:0] Tzero;
// wire [3:0] n;
wire Tim1_Ch1; // SVPWM处理后的结果Ch1
wire Tim1_Ch1N; // SVPWM处理后的结果Ch1N,(电路层已经和CH1连接)
wire Tim1_Ch2; // SVPWM处理后的结果Ch2
wire Tim1_Ch2N; // SVPWM处理后的结果Ch2N,(电路层已经和CH2连接)
wire Tim1_Ch3; // SVPWM处理后的结果Ch3
wire Tim1_Ch3N; // SVPWM处理后的结果Ch3N,(电路层已经和CH3连接)
// wire [3:0] sector;
// wire [16:0] x;
// wire [16:0] y;
// wire [16:0] z;
parameter half_cycle = 10;
// assign statements (if any)
// my_SVPWM i1 (
// // port map - connection between master ports and signals/registers
// .Cal_time_out_en(Cal_time_out_en),
// .Jug_sec_in_en(Jug_sec_in_en),
// .Jug_sec_out_en(Jug_sec_out_en),
// .Switch_time_out_en(Switch_time_out_en),
// .Tcm1(Tcm1),
// .Tcm2(Tcm2),
// .Tcm3(Tcm3),
// .Tfirst(Tfirst),
// .Tri_gener_out_en(Tri_gener_out_en),
// .Ts_cnt(Ts_cnt),
// .Tsecond(Tsecond),
// .Tzero(Tzero),
// .Valpha(Valpha),
// .Vbeta(Vbeta),
// .n(n),
// .pwm_a(pwm_a),
// .pwm_b(pwm_b),
// .pwm_c(pwm_c),
// .sector(sector),
// .x(x),
// .y(y),
// .z(z),
// .clk(clk),
// .rstn(rstn),
// .in_en(in_en)
// );
my_SVPWM i1 (
.clk ( clk ), //时钟信号
.rstn ( rstn ), //复位信号
.in_en ( ~rstn ), //系统的输入使能信号
.Valpha ( Valpha ), //Park逆变换的结果Vα
.Vbeta ( Vbeta ), //Park逆变换的结果Vβ
.pwm_a ( Tim1_Ch1 ), //SVPWM的输出1 PWM_a
.pwm_an ( Tim1_Ch1N ), //SVPWM的输出1 PWM_an
.pwm_b ( Tim1_Ch2 ), //SVPWM的输出2 PWM_b
.pwm_bn ( Tim1_Ch2N ), //SVPWM的输出2 PWM_bn
.pwm_c ( Tim1_Ch3 ), //SVPWM的输出3 PWM_c
.pwm_cn ( Tim1_Ch3N ) //SVPWM的输出3 PWM_cn
);
initial
begin
// code that executes only once
// insert code here --> begin
clk = 0;
forever begin
#half_cycle clk = 1;
#half_cycle clk = 0;
end
// --> end
$display("Running testbench");
end
initial
begin
rstn = 1;
#5 rstn = 0;
#10 rstn = 1;
end
initial
begin
Valpha = 16'd9830;
Vbeta = -1*16'd26214;
end
// initial
// begin
// in_en = 0;
// #90 in_en = 1;
// #20 in_en = 0;
// end
endmodule
3 仿真结果
已经通过Quartus进行了仿真验证,下面展示具体的仿真结果,并与MATLAB的结果进行对应,可以看到两者之间是完全吻合的,证明算法正确。
这里测试的例子是U_alpha_real = 3、U_beta_real = -8 时的调制结果~
3.1 MATLAB计算结果
具体的数据结果:
输出的波形结果:
3.2 Vivado 2018.3 仿真结果
来个整体的图:
再来个细节图:
可以看到是与MATLAB的输出结果是一致的。
值得一提的是,可能有读者会问,为什么XYZ的值,MATLAB和Verilog的计算结果刚好相差了一倍呢?这是因为问题出在了Ts上,在MATLAB中,使用的是具体的时间周期长度(计数值除以了50MHz的系统时钟),而Verilog中,由于SVPWM只是需要根据要求在固定周期内按次序输出调制波形,因此具体的周期长短不构成影响(占空比比例更为重要),因此就单纯使用Ts计数值的大小代替了具体的周期长度。
2022年10月20日更新:上面这段话是针对之前代码的Quartus仿真结果(针对的是上一篇博客中,MATLAB不考虑电压量化的情况,目前在今天更新之后由于我已经根据具体周期时常,使用了对应实际的Ts值1666,已经不存在这个问题了,大家可以忽略这段话~)文章来源:https://www.toymoban.com/news/detail-403719.html
这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞收藏,分享给身边的朋友哇~文章来源地址https://www.toymoban.com/news/detail-403719.html
到了这里,关于FOC:【2】SVPWM(七段式)的Verilog实现与仿真的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!