Sui Sui Nian:ほぼ 1 週間のデバッグとエラー チェックの後 (申し訳ありませんが、私はそれが得意すぎます)、MATLAB コードに基づく SVPWM アルゴリズムの Verilog の実装にようやく気付き、同時にシミュレーション結果を提供しました。
2022 年 10 月 20 日更新: 申し訳ありませんが、これまでアルゴリズムで入力電圧値の量子化とデッドタイムを考慮していなかったため、回路テストプロセス中にこのエラーも発見し、修正して修正しました今日修正しました。電圧値定量化の具体的な原理については、以前の記事を参照してください〜
目次
1 主なアイデア
考え方は基本的に前回の記事と同じですが、Verilog の一部の機能 (精度やタイミングなど) については、この記事で各モジュールのコードと Vivado のシミュレーション結果を示します。
読者は自分で以前の記事と比較できます: FOC: [1] SVPWM アルゴリズム (7 セグメント) の解析と MATLAB シミュレーション検証
2 モジュールコード
2.1 my_SVPWM モジュール
SVPWM を実現するために使用され、入力は Park 逆変換後の Vα と Vβ であり、出力は 3 つのブリッジ アームの制御信号です。
// 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 モジュール
入力がパーク逆変換後の Vα と Vβ であり、出力セクターの値であることを認識するために使用されます。
ここで注意する必要がある詳細は、n の計算では 3 つの式を参照する必要があることですが、実際には、値ではなく、式の特定の記号のみを使用する必要があります。したがって、小数部分を乗算によって増幅することで、より正確な正負の判断を得ることができます。
それに応じて、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 の結果に対応しています.2 つが完全に一致していることがわかり、アルゴリズムが正しいことが証明されます.
ここでテストした例は、U_alpha_real = 3、U_beta_real = -8~ の場合の変調結果です。
3.1 MATLAB 計算結果
特定のデータ結果:
出力波形結果:
3.2 Vivado 2018.3 のシミュレーション結果
全体像は次のとおりです。
別の詳細な画像:
MATLAB の出力と一致していることがわかります。
MATLAB と Verilog の計算結果である XYZ の値が 2 倍になるのはなぜですか? これは、問題が Ts にあるためです。MATLAB では、特定の期間の長さが使用されます (カウント値は 50MHz のシステム クロックで除算されます)。一方、Verilog では、SVPWM は要件に応じて一定の期間で注文するだけでよいためです。変調波形が出力されるため、特定の周期長は影響しない(デューティ比の方が重要)ため、特定の周期長の代わりに Ts カウント値の値が単純に使用されます。
2022 年 10 月 20 日の更新: 上記の段落は、以前のコードの Quartus シミュレーション結果に関するものです (以前のブログの場合、MATLAB は電圧の量子化状況を考慮していません。対応する実際の Ts 値 1666 を使用すると、この問題はもはや存在しません。この段落は無視してかまいません~)
これが今号の全内容です. 私の記事が好きなら, いいねして集めて, 友達と共有することを忘れないでください~