经过近一周的调试与查错(不好意思我实在太菜了),才终于从MATLAB代码的基础上,实现了Verilog对SVPWM算法的实现,同时给出仿真的结果。
目录
思路与上一篇文章基本一致,但是针对Verilog中的部分特点(包括精度以及时序),本文给出各个模块的代码,以及Modelsim的仿真结果。
读者可以自行和上一篇文章进行对比: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的输出1 PWM_a
- // output wire pwm_b, //SVPWM的输出2 PWM_b
- // output wire pwm_c //SVPWM的输出3 PWM_c
- // );
-
- //下面的是调试版本,用来观察中间变量
- 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 [16:0] x;
- // wire signed [16:0] y;
- // wire signed [16:0] z;
- // wire Jug_sec_out_en;
- // wire signed [16:0] Tfirst;
- // wire signed [16:0] Tsecond;
- // wire signed [16:0] Tzero;
- // wire Cal_time_out_en;
- // wire signed [16:0] Tcm1;
- // wire signed [16:0] Tcm2;
- // wire signed [16:0] Tcm3;
- // wire Switch_time_out_en;
- // wire signed [11:0] Ts_cnt;
- // wire Tri_gener_out_en;
-
-
-
- // 01 扇区判断--------------------------------------------------------------------------------------------------------------------------------------------------
- // 功能:利用当前的Valpha与Vbeta判断所在的扇区
- // 输入:Valpha Vbeta
- // 输出:扇区数字sector,以及相关参数N
-
- assign Jug_sec_in_en = Tri_gener_out_en || in_en;
-
- 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,以及当前的
- // 输出:
-
- reg signed [11:0] Tcm1_reg;
- reg signed [11:0] Tcm2_reg;
- reg signed [11:0] Tcm3_reg;
-
- always @(posedge clk)
- begin
- if(~rstn)
- begin
- Tcm1_reg <= 12'd3000;
- Tcm2_reg <= 12'd3000;
- Tcm3_reg <= 12'd3000;
- end
- else
- begin
- if(Switch_time_out_en)
- begin
- Tcm1_reg <= Tcm1;
- Tcm2_reg <= Tcm2;
- Tcm3_reg <= Tcm3;
- end
- end
- end
-
- assign pwm_a = (Ts_cnt >= Tcm1_reg) ? 1:0;
- assign pwm_b = (Ts_cnt >= Tcm2_reg) ? 1:0;
- assign pwm_c = (Ts_cnt >= Tcm3_reg) ? 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 [16:0] x, //就是X
- output reg signed [16:0] y, //就是Y
- output reg signed [16:0] z, //就是Z
- output reg out_en
-
- );
-
-
- //reg [16:0] Vref1; // 不需要定义,就是 Vbeta本身
- reg signed [16:0] Vref1;
- reg signed [16:0] Vref2;
- reg signed [16:0] Vref3;
- reg en_flag;
- reg flag2;
- //reg [16:0] y;
- //reg [16:0] z;
-
- wire signed [31:0] alphasqrt3;
- parameter Ts = 2048;
- parameter sqrt3Ts = 3547;
- parameter Vdc = 10;
- //parameter temp = sqrt3Ts/Vdc;
-
-
-
- always@(posedge clk)
- begin
- if(en_flag)
- begin
- out_en <= 1'd1;
- end
-
- else
- begin
- out_en <= 1'd0;
- end
-
-
- end
-
-
-
-
- always @(posedge clk)
- begin
- if(~rstn)
- begin
-
- end
- else
- begin
-
- end
- end
-
- always @(*)
- begin
- if(~rstn)
- begin
- n <= 4'b0000;
- end
- else
- begin
- n[2:0]<= {~Vref3[16], ~Vref2[16], ~Vbeta[15]};
- end
- end
-
-
- always@(*)
- if(~rstn)
- begin
- Vref1 <= 17'd0;
- Vref2 <= 17'd0;
- Vref3 <= 17'd0;
- x <= 17'd0;
- y <= 17'd0;
- z <= 17'd0;
- sector <= 4'b0000;
- en_flag<= 1'd0;
- flag2 <= 1'd0;
- end
-
- else
- begin
- if(flag2)
- begin
- flag2 <= 1'd0;
- case(n) //通过符号来判断
-
- 4'd3: //3
- begin
- sector <= 4'd1;
- en_flag<= 1'd1;
- end
-
- 4'd1:
- begin
- sector <= 4'd2;
- en_flag<= 1'd1;
- end
-
- 4'd5:
- begin
- sector <= 4'd3;
- en_flag<= 1'd1;
- end
-
- 4'd4:
- begin
- sector <= 4'd4;
- en_flag<= 1'd1;
- end
-
- 4'd6:
- begin
- sector <= 4'd5;
- en_flag<= 1'd1;
- end
-
- 4'd2:
- begin
- sector <= 4'd6;
- en_flag<= 1'd1;
- end
-
- default:
- begin
- sector <= 4'd0;
- en_flag<= 1'd0;
- end
-
- endcase
- end
-
- if(out_en)
- begin
- en_flag<= 1'd0;
- end
-
- if(in_en)
- begin
- //实现高精度的方法,先计算所有的乘法,最后计算除法!
- //对于只需要计算符号的,不需要除以分母啦
- 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
-
-
-
- //将输入的值乘以443,代表根号3,乘以256的就代表乘以1
- // mul1 mul1(
- // .dataa ( Valpha ), //输入的Vα
- // .result ( alphasqrt3 ) //输出的值,根号3alpha
- // );
-
-
- 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 [16:0] x,
- input wire signed [16:0] y,
- input wire signed [16:0] z,
-
- input wire [3:0] n,
-
- output reg signed [16:0] Tfirst,
- output reg signed [16:0] Tsecond,
- output reg signed [16:0] Tzero,
- output reg out_en, //输出使能信号
- output reg out_en2,
- output reg out_en3,
- output reg signed [30:0] temp2,
- output reg signed [30:0] temp3,
- output reg signed [30:0] temp
-
-
- //output reg flag2
- );
-
-
- parameter Tp = 1024; //开关周期的一半,对应等腰三角形底边的一半
- parameter Ts = 2048;
-
-
- //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
- flag2 <= 1'd1;
- end
-
- if(~rstn)
- begin
- Tfirst <= 17'd0;
- Tsecond <= 17'd0;
- temp2 <= 31'd0;
- temp3 <= 31'd0;
- flag2 <= 1'd0;
- out_en <= 1'd0;
- out_en2 <= 1'd0;
- out_en3 <= 1'd0;
- Tzero <= 17'd0;
- temp <= 31'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;
- 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 [16:0] Tfirst,
- input wire signed [16:0] Tsecond,
- input wire signed [16:0] Tzero,
-
- output reg signed [16:0] Tcm1, //三个逆变器的切换时间
- output reg signed [16:0] Tcm2,
- output reg signed [16:0] Tcm3,
- output reg out_en, //输出使能信号
- output reg out_en2 //延迟一拍
- );
-
- wire signed [16:0] Ta_wire;
- wire signed [16:0] Tb_wire;
- wire signed [16:0] Tc_wire;
-
- assign Ta_wire = Tzero/2;
- assign Tb_wire = Ta_wire + Tfirst/2;
- assign Tc_wire = Tb_wire + Tsecond/2;
-
- reg signed [16:0] Ta;
- reg signed [16:0] Tb;
- reg signed [16:0] Tc;
- reg flag2;
-
-
-
-
- always @(*)
- begin
- if(!rstn)
- begin
- Ta <= 17'd0;
- Tb <= 17'd0;
- Tc <= 17'd0;
- end
- else
- begin
- Ta <= Ta_wire;
- Tb <= Tb_wire;
- Tc <= Tc_wire;
- end
-
- if(out_en2)
- begin
- Ta <= 17'd0;
- Tb <= 17'd0;
- Tc <= 17'd0;
- end
-
- end
-
-
-
-
-
-
-
-
-
- always @(posedge clk) //
- begin
- if(in_en)
- begin
- flag2 <= 1'd1;
- end
-
- if(!rstn)
- begin
- Tcm1 <= 17'd0;
- Tcm2 <= 17'd0;
- Tcm3 <= 17'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;
- 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 = 1024, //开关周期的一半
- pfs= 10000; //频率控制输入,5000:7K,10000:15K,20000:30K
-
- parameter CYCLE_NUM = 3;
-
-
- ///三角波产生//
-
- // always @(posedge clk) //相位累加器,溢出信号提供给周期循环计数器
- // begin
- // if(!rst)
- // begin
- // adder <= 17'b0;
- // Ts_cp <= 1'b0;
- // end
- // else
- // begin
- // adder <= adder + pfs;
-
- // if(adder[16])
- // begin
- // Ts_cp <= 1'b1;
- // adder[16] <= 1'b0;
- // end
- // else
- // Ts_cp <= 1'b0;
- // end
- // end
-
- 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中进行仿真验证。
- // Copyright (C) 2018 Intel Corporation. All rights reserved.
- // Your use of Intel Corporation's design tools, logic functions
- // and other software and tools, and its AMPP partner logic
- // functions, and any output files from any of the foregoing
- // (including device programming or simulation files), and any
- // associated documentation or information are expressly subject
- // to the terms and conditions of the Intel Program License
- // Subscription Agreement, the Intel Quartus Prime License Agreement,
- // the Intel FPGA IP License Agreement, or other applicable license
- // agreement, including, without limitation, that your use is for
- // the sole purpose of programming logic devices manufactured by
- // Intel and sold by Intel or its authorized distributors. Please
- // refer to the applicable agreement for further details.
-
- // *****************************************************************************
- // This file contains a Verilog test bench template that is freely editable to
- // suit user's needs .Comments are provided in each section to help the user
- // fill out necessary details.
- // *****************************************************************************
- // Generated on "06/27/2022 19:37:37"
-
- // Verilog Test Bench template for design : my_SVPWM
- //
- // Simulation tool : ModelSim (Verilog)
- //
-
- `timescale 1 ps/ 1 ps
- module my_SVPWM_vlg_tst();
- // constants
- // general purpose registers
- reg eachvec;
- reg clk;
- reg rstn;
- reg in_en;
- // test vector input registers
- reg [15:0] Valpha;
- reg [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 pwm_a;
- wire pwm_b;
- wire pwm_c;
- 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(in_en), //系统的输入使能信号
- // .Valpha(Valpha), //Park逆变换的结果Vα
- // .Vbeta(Vbeta), //Park逆变换的结果Vβ
- // .pwm_a(pwm_a), //SVPWM的输出1 PWM_a
- // .pwm_b(pwm_b), //SVPWM的输出2 PWM_b
- // .pwm_c(pwm_c) //SVPWM的输出3 PWM_c
- // );
-
- 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'd10;
- Vbeta = 16'd10;
- end
-
-
- initial
- begin
- in_en = 0;
- #90 in_en = 1;
- #20 in_en = 0;
- end
-
-
-
-
- always
- // optional sensitivity list
- // @(event1 or event2 or .... eventn)
- begin
- // code executes for every event on sensitivity list
- // insert code here --> begin
-
- @eachvec;
- // --> end
- end
- endmodule
-
已经通过Quartus进行了仿真验证,下面展示具体的仿真结果,并与MATLAB的结果进行对应,可以看到两者之间是完全吻合的,证明算法正确。
这里测试的例子是U_alpha = 10,U_beta = 10时的调制结果~
具体的数据结果:

输出的波形结果:


来个放大的图:

再来个细节图:
可以看到是与MATLAB的输出结果相一致的。
值得一提的是,可能有读者会问,为什么XYZ的值,MATLAB和Verilog的计算结果刚好相差了一倍呢?这是因为问题出在了Ts上,在MATLAB中,使用的是具体的时间周期长度(计数值除以了50MHz的系统时钟),而Verilog中,由于SVPWM只是需要根据要求在固定周期内按次序输出调制波形,因此具体的周期长短不构成影响(占空比比例更为重要),因此就单纯使用Ts计数值的大小代替了具体的周期长度。
这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞收藏,分享给身边的朋友哇~