技术标签: fpga开发 FOC算法 Verilog FOC控制算法与FPGA实现 SVPWM MATLAB
碎碎念:经过近一周的调试与查错(不好意思我实在太菜了),才终于从MATLAB代码的基础上,实现了Verilog对SVPWM算法的实现,同时给出仿真的结果。
2022年10月20日更新:实在抱歉,由于之前在算法中没有考虑到输入电压值量化以及死区时间的问题,我也是在电路测试过程中才发现这个错误,今天进行了更正与修改。电压值量化的具体原理可以参考我的上一篇文章~
目录
思路与上一篇文章基本一致,但是针对Verilog中的部分特点(包括精度以及时序),本文给出各个模块的代码,以及Vivado的仿真结果。
读者可以自行和上一篇文章进行对比:FOC:【1】浅析SVPWM算法(七段式)以及MATLAB仿真验证
用来实现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
用来实现输入是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
利用输入的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
利用时间长度信息,计算具体的开关切换时刻。
// 计算逆变器信号改变的时间
// 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
产生三角波,便于确定当前所处的时刻。其中的变量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
这个是对整体模块的测试代码,可以在里面设置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
已经通过Quartus进行了仿真验证,下面展示具体的仿真结果,并与MATLAB的结果进行对应,可以看到两者之间是完全吻合的,证明算法正确。
这里测试的例子是U_alpha_real = 3、U_beta_real = -8 时的调制结果~
具体的数据结果:
输出的波形结果:
来个整体的图:
再来个细节图:
可以看到是与MATLAB的输出结果是一致的。
值得一提的是,可能有读者会问,为什么XYZ的值,MATLAB和Verilog的计算结果刚好相差了一倍呢?这是因为问题出在了Ts上,在MATLAB中,使用的是具体的时间周期长度(计数值除以了50MHz的系统时钟),而Verilog中,由于SVPWM只是需要根据要求在固定周期内按次序输出调制波形,因此具体的周期长短不构成影响(占空比比例更为重要),因此就单纯使用Ts计数值的大小代替了具体的周期长度。
2022年10月20日更新:上面这段话是针对之前代码的Quartus仿真结果(针对的是上一篇博客中,MATLAB不考虑电压量化的情况,目前在今天更新之后由于我已经根据具体周期时常,使用了对应实际的Ts值1666,已经不存在这个问题了,大家可以忽略这段话~)
这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞收藏,分享给身边的朋友哇~
文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大
文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码
文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版
文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗
文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程
文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0
文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader
文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型
文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写
文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录
文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点
文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文