Sui Sui Nian: After nearly a week of debugging and error checking (sorry, I am too good at it), I finally realized Verilog's implementation of the SVPWM algorithm based on the MATLAB code, and at the same time gave the simulation results.
Update on October 20, 2022 : I am really sorry, because I did not consider the quantization of the input voltage value and the dead time in the algorithm before, I also discovered this error during the circuit test process, and corrected and modified it today. For the specific principle of voltage value quantification, please refer to my previous article~
Table of contents
3.1 MATLAB calculation results
3.2 Vivado 2018.3 Simulation Results
1 main idea
The idea is basically the same as the previous article, but for some features in Verilog (including accuracy and timing), this article gives the code of each module and the simulation results of Vivado.
Readers can compare with the previous article by themselves: FOC: [1] Analysis of SVPWM algorithm (seven-segment) and MATLAB simulation verification
2 module code
2.1 my_SVPWM module
Used to realize SVPWM, the input is Vα and Vβ after Park inverse transformation, and the output is the control signal of the three bridge arms.
// 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 module
It is used to realize that the input is Vα and Vβ after Park inverse transformation, and the value of the output sector.
The details that need to be noted here are that the calculation of n needs to refer to three expressions, but in fact only the specific symbols of the expressions need to be used, not the values. Therefore, the fractional part can be amplified by multiplication, so as to obtain a more accurate judgment of positive and negative signs.
Correspondingly, for the calculation of XYZ, specific values are required, and the precision is high. How to implement floating-point arithmetic? A better method is to implement all the multiplications first, and then perform all the divisions, so that better floating-point precision can be obtained.
// 用来实现扇区的判断
// 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 module
Using the input XYZ, calculate the length of time.
// 计算时间的长度
// 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 module
The time length information is used to calculate the specific switching moment of the switch.
// 计算逆变器信号改变的时间
// 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 module
Generate a triangle wave, which is convenient for determining the current moment. The variable CYCLE_NUM can be used to control the specific number of cycles output by SVPWM during simulation.
// 三角波生成模块
// 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 Test Module
This is the test code for the overall module, where you can set the values of Vα and Vβ, and perform simulation verification in 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 Simulation results
The simulation verification has been carried out by Quartus. The specific simulation results are shown below and correspond to the results of MATLAB. It can be seen that the two are completely consistent, which proves that the algorithm is correct.
The example tested here is the modulation result when U_alpha_real = 3, U_beta_real = -8~
3.1 MATLAB calculation results
Specific data results:
Output waveform result:
3.2 Vivado 2018.3 Simulation Results
Here's an overall picture:
Another detailed picture:
It can be seen that it is consistent with the output of MATLAB.
It is worth mentioning that some readers may ask, why the value of XYZ, the calculation results of MATLAB and Verilog just double? This is because the problem lies in Ts. In MATLAB, a specific time period length is used (the count value is divided by the 50MHz system clock), while in Verilog, since SVPWM only needs to be ordered in a fixed period according to requirements The modulation waveform is output, so the specific cycle length does not affect (the duty ratio is more important), so the value of the Ts count value is simply used instead of the specific cycle length.
Update on October 20, 2022: The above paragraph is for the Quartus simulation results of the previous code (for the previous blog, MATLAB does not consider the voltage quantization situation. After today’s update, because I have been based on the specific cycle from time to time , using the corresponding actual Ts value of 1666, this problem no longer exists, you can ignore this paragraph~)
This is the whole content of this issue. If you like my article, don't forget to like and collect it, and share it with your friends~