资讯详情

FOC:【2】SVPWM(七段式)的Verilog实现与仿真

经过近一周的调试和检查(对不起,我真的很好吃),我终于从MATLAB在代码的基础上,实现了Verilog对SVPWM实现算法,同时给出模拟结果。

1 主要思路

2 模块代码

2.1 my_SVPWM 模块

2.2 Jud_sec 模块

2.3Cal_time 模块

2.4Switch_time 模块

2.5 Tri_gener 模块

2.6 测试模块

3 仿真结果

3.1 MATLAB计算结果

3.2 Quartus仿真结果


1 主要思路

思路与上一篇文章基本一致,但是针对Verilog本文给出了每个模块的代码和一些特征(包括精度和及时序列)Modelsim模拟结果。

读者可以自己比较上一篇文章: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的输出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

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 [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

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 [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

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 [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

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 = 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

2.6 测试模块

这个是对整体模块的测试代码,可以在里面设置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

3 仿真结果

已经通过Quartus进行了仿真验证,下面展示具体的仿真结果,并与MATLAB的结果进行对应,可以看到两者之间是完全吻合的,证明算法正确。

这里测试的例子是U_alpha = 10,U_beta  = 10时的调制结果~

3.1 MATLAB计算结果

具体的数据结果:

输出的波形结果:

3.2 Quartus仿真结果

来个放大的图:

再来个细节图:

可以看到是与MATLAB的输出结果相一致的。

值得一提的是,可能有读者会问,为什么XYZ的值,MATLAB和Verilog的计算结果刚好相差了一倍呢?这是因为问题出在了Ts上,在MATLAB中,使用的是具体的时间周期长度(计数值除以了50MHz的系统时钟),而Verilog中,由于SVPWM只是需要根据要求在固定周期内按次序输出调制波形,因此具体的周期长短不构成影响(占空比比例更为重要),因此就单纯使用Ts计数值的大小代替了具体的周期长度。


这就是本期的全部内容啦,如果你喜欢我的文章,不要忘了点赞收藏,分享给身边的朋友哇~

标签: 接近开关移位传感器vlg10

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台