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


    经过近一周的调试与查错(不好意思我实在太菜了),才终于从MATLAB代码的基础上,实现了Verilog对SVPWM算法的实现,同时给出仿真的结果。

    目录

    1 主要思路

    2 模块代码

    2.1 my_SVPWM 模块

    2.2 Jud_sec 模块

    2.3 Cal_time 模块

    2.4 Switch_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β,输出是三个桥臂的控制信号。

    1. // SVPWM模块
    2. // Type : synthesizable
    3. // Standard: SystemVerilog 2005 (IEEE1800-2005)
    4. // 功能: 用来实现SVPWM,输入是Park 逆变换后的Vα与Vβ,输出是三个桥臂的控制信号
    5. // 包含四个部分:
    6. // 01 扇区判断
    7. // 02 矢量作用时间计算
    8. // 03 逆变器开关切换时间计算
    9. // 04 利用三角波改变开关状态
    10. // module my_SVPWM(
    11. // input wire clk, //时钟信号
    12. // input wire rstn, //复位信号
    13. // input wire in_en, //系统的输入使能信号
    14. // input wire signed [15:0] Valpha, //Park逆变换的结果Vα
    15. // input wire signed [15:0] Vbeta, //Park逆变换的结果Vβ
    16. // output wire pwm_a, //SVPWM的输出1 PWM_a
    17. // output wire pwm_b, //SVPWM的输出2 PWM_b
    18. // output wire pwm_c //SVPWM的输出3 PWM_c
    19. // );
    20. //下面的是调试版本,用来观察中间变量
    21. module my_SVPWM(
    22. input wire clk, //时钟信号
    23. input wire rstn, //复位信号
    24. input wire in_en, //系统的输入使能信号
    25. input wire signed [15:0] Valpha, //Park逆变换的结果Vα
    26. input wire signed [15:0] Vbeta, //Park逆变换的结果Vβ
    27. output wire pwm_a, //SVPWM的输出1 PWM_a
    28. output wire pwm_b, //SVPWM的输出2 PWM_b
    29. output wire pwm_c, //SVPWM的输出3 PWM_c
    30. output wire [3:0] n,
    31. output wire [3:0] sector,
    32. output wire Jug_sec_in_en,
    33. output wire signed [16:0] x,
    34. output wire signed [16:0] y,
    35. output wire signed [16:0] z,
    36. output wire Jug_sec_out_en,
    37. output wire signed [16:0] Tfirst,
    38. output wire signed [16:0] Tsecond,
    39. output wire signed [16:0] Tzero,
    40. output wire Cal_time_out_en,
    41. output wire signed [16:0] Tcm1,
    42. output wire signed [16:0] Tcm2,
    43. output wire signed [16:0] Tcm3,
    44. output wire Switch_time_out_en,
    45. output wire signed [11:0] Ts_cnt,
    46. output wire Tri_gener_out_en
    47. );
    48. // SVPWM的实例化过程------------------------------------------------------------------------------------------------------------
    49. // 00 实例化需要使用到的导线
    50. // wire [3:0] n;
    51. // wire [3:0] sector;
    52. // wire Jug_sec_in_en;
    53. // wire signed [16:0] x;
    54. // wire signed [16:0] y;
    55. // wire signed [16:0] z;
    56. // wire Jug_sec_out_en;
    57. // wire signed [16:0] Tfirst;
    58. // wire signed [16:0] Tsecond;
    59. // wire signed [16:0] Tzero;
    60. // wire Cal_time_out_en;
    61. // wire signed [16:0] Tcm1;
    62. // wire signed [16:0] Tcm2;
    63. // wire signed [16:0] Tcm3;
    64. // wire Switch_time_out_en;
    65. // wire signed [11:0] Ts_cnt;
    66. // wire Tri_gener_out_en;
    67. // 01 扇区判断--------------------------------------------------------------------------------------------------------------------------------------------------
    68. // 功能:利用当前的Valpha与Vbeta判断所在的扇区
    69. // 输入:Valpha Vbeta
    70. // 输出:扇区数字sector,以及相关参数N
    71. assign Jug_sec_in_en = Tri_gener_out_en || in_en;
    72. Jug_sec Jug_sec(
    73. .clk ( clk ), //时钟信号
    74. .rstn ( rstn ), //复位信号
    75. .in_en ( Jug_sec_in_en ), //输入有效信号
    76. .Valpha ( Valpha ), //Park逆变换的结果Vα (是有符号数,-32768~32767)
    77. .Vbeta ( Vbeta ), //Park逆变换的结果Vβ (是有符号数,-32768~32767)
    78. .n ( n ), //扇区计算中常用的N
    79. .sector ( sector ), //扇区的结果
    80. .x ( x ), //就是X
    81. .y ( y ), //就是Y
    82. .z ( z ), //就是Z
    83. .out_en ( Jug_sec_out_en ) //输出使能信号
    84. );
    85. // 02 矢量作用时间计算--------------------------------------------------------------------------------------------------------------------------------------------------
    86. // 功能:矢量作用时间计算
    87. // 输入: X,Y,Z三个变量以及N
    88. // 输出: 根据N判断出的时间长度
    89. Cal_time Cal_time(
    90. .clk ( clk ), //时钟信号
    91. .rstn ( rstn ), //复位信号
    92. .in_en ( Jug_sec_out_en ), //输入使能信号
    93. .x ( x ),
    94. .y ( y ),
    95. .z ( z ),
    96. .n ( n ),
    97. .Tfirst ( Tfirst ),
    98. .Tsecond ( Tsecond ),
    99. .Tzero ( Tzero ),
    100. .out_en ( ), //输出使能信号
    101. .out_en2 ( ),
    102. .out_en3 ( Cal_time_out_en )
    103. );
    104. // 03 计算逆变器开关切换的时间--------------------------------------------------------------------------------------------------------------------------------------------------
    105. // 功能:利用查表的方式,计算三个相开关切换的时间
    106. // 输入:
    107. // 输出:
    108. Switch_time Switch_time(
    109. .clk ( clk ), //时钟信号
    110. .rstn ( rstn ), //复位信号
    111. .in_en ( Cal_time_out_en ), //输入使能信号
    112. .n ( n ),
    113. .Tfirst ( Tfirst ),
    114. .Tsecond ( Tsecond ),
    115. .Tzero ( Tzero ),
    116. .Tcm1 ( Tcm1 ), //三个逆变器的切换时间
    117. .Tcm2 ( Tcm2 ),
    118. .Tcm3 ( Tcm3 ),
    119. .out_en ( ), //输出使能信号
    120. .out_en2 ( Switch_time_out_en )
    121. );
    122. // 04 产生三角波--------------------------------------------------------------------------------------------------------------------------------------------------
    123. // 功能:绘制三角波
    124. // 输入:
    125. // 输出:
    126. Tri_gener Tri_gener(
    127. .clk ( clk ), //输入时钟
    128. .rst ( rstn ), //复位信号
    129. .in_en ( Switch_time_out_en ), //输入使能信号
    130. .Ts_cnt ( Ts_cnt ), //Ts的计数器,用来产生一个周期为Ts=2*Tp的三角波
    131. .deta_clk ( Tri_gener_out_en ) //每次输出一个时钟,就给一个高电平
    132. );
    133. // 05 结合三角波,产生SVPWM结果
    134. // 功能:结合三角波,产生SVPWM的结果
    135. // 输入: 计算出来的输出波形切换时间Tcm1,Tcm2,Tcm3,以及当前的
    136. // 输出:
    137. reg signed [11:0] Tcm1_reg;
    138. reg signed [11:0] Tcm2_reg;
    139. reg signed [11:0] Tcm3_reg;
    140. always @(posedge clk)
    141. begin
    142. if(~rstn)
    143. begin
    144. Tcm1_reg <= 12'd3000;
    145. Tcm2_reg <= 12'd3000;
    146. Tcm3_reg <= 12'd3000;
    147. end
    148. else
    149. begin
    150. if(Switch_time_out_en)
    151. begin
    152. Tcm1_reg <= Tcm1;
    153. Tcm2_reg <= Tcm2;
    154. Tcm3_reg <= Tcm3;
    155. end
    156. end
    157. end
    158. assign pwm_a = (Ts_cnt >= Tcm1_reg) ? 1:0;
    159. assign pwm_b = (Ts_cnt >= Tcm2_reg) ? 1:0;
    160. assign pwm_c = (Ts_cnt >= Tcm3_reg) ? 1:0;
    161. endmodule

    2.2 Jud_sec 模块

    用来实现输入是Park 逆变换后的Vα与Vβ,输出扇区的值。

    这里需要注意的细节是,n的计算需要参考三个表达式,但是实际上只需要利用到表达式的具体符号,而不是数值。因此可以通过成乘法,来放大其中的小数部分,从而获得更加准确的正负符号判断。

    相应的,对于XYZ的计算,由于是需要具体数值的,并且对精度要求较高。怎么实现浮点数的运算呢?比较好的方法是先实现所有的乘法,在进行所有的除法,这样可以获得比较好的浮点数精度。

    1. // 用来实现扇区的判断
    2. // Type : synthesizable
    3. // Standard: SystemVerilog 2005 (IEEE1800-2005)
    4. // 功能: 用来实现输入是Park 逆变换后的Vα与Vβ,输出扇区的值
    5. module Jug_sec(
    6. input wire clk, //时钟信号
    7. input wire rstn, //复位信号
    8. input wire in_en, //输入有效信号
    9. input wire signed [15:0] Valpha, //Park逆变换的结果Vα (是有符号数,-32768~32767)
    10. input wire signed [15:0] Vbeta, //Park逆变换的结果Vβ (是有符号数,-32768~32767)
    11. output reg [3:0] n, //扇区计算中常用的N
    12. output reg [3:0] sector, //扇区的结果
    13. output reg signed [16:0] x, //就是X
    14. output reg signed [16:0] y, //就是Y
    15. output reg signed [16:0] z, //就是Z
    16. output reg out_en
    17. );
    18. //reg [16:0] Vref1; // 不需要定义,就是 Vbeta本身
    19. reg signed [16:0] Vref1;
    20. reg signed [16:0] Vref2;
    21. reg signed [16:0] Vref3;
    22. reg en_flag;
    23. reg flag2;
    24. //reg [16:0] y;
    25. //reg [16:0] z;
    26. wire signed [31:0] alphasqrt3;
    27. parameter Ts = 2048;
    28. parameter sqrt3Ts = 3547;
    29. parameter Vdc = 10;
    30. //parameter temp = sqrt3Ts/Vdc;
    31. always@(posedge clk)
    32. begin
    33. if(en_flag)
    34. begin
    35. out_en <= 1'd1;
    36. end
    37. else
    38. begin
    39. out_en <= 1'd0;
    40. end
    41. end
    42. always @(posedge clk)
    43. begin
    44. if(~rstn)
    45. begin
    46. end
    47. else
    48. begin
    49. end
    50. end
    51. always @(*)
    52. begin
    53. if(~rstn)
    54. begin
    55. n <= 4'b0000;
    56. end
    57. else
    58. begin
    59. n[2:0]<= {~Vref3[16], ~Vref2[16], ~Vbeta[15]};
    60. end
    61. end
    62. always@(*)
    63. if(~rstn)
    64. begin
    65. Vref1 <= 17'd0;
    66. Vref2 <= 17'd0;
    67. Vref3 <= 17'd0;
    68. x <= 17'd0;
    69. y <= 17'd0;
    70. z <= 17'd0;
    71. sector <= 4'b0000;
    72. en_flag<= 1'd0;
    73. flag2 <= 1'd0;
    74. end
    75. else
    76. begin
    77. if(flag2)
    78. begin
    79. flag2 <= 1'd0;
    80. case(n) //通过符号来判断
    81. 4'd3: //3
    82. begin
    83. sector <= 4'd1;
    84. en_flag<= 1'd1;
    85. end
    86. 4'd1:
    87. begin
    88. sector <= 4'd2;
    89. en_flag<= 1'd1;
    90. end
    91. 4'd5:
    92. begin
    93. sector <= 4'd3;
    94. en_flag<= 1'd1;
    95. end
    96. 4'd4:
    97. begin
    98. sector <= 4'd4;
    99. en_flag<= 1'd1;
    100. end
    101. 4'd6:
    102. begin
    103. sector <= 4'd5;
    104. en_flag<= 1'd1;
    105. end
    106. 4'd2:
    107. begin
    108. sector <= 4'd6;
    109. en_flag<= 1'd1;
    110. end
    111. default:
    112. begin
    113. sector <= 4'd0;
    114. en_flag<= 1'd0;
    115. end
    116. endcase
    117. end
    118. if(out_en)
    119. begin
    120. en_flag<= 1'd0;
    121. end
    122. if(in_en)
    123. begin
    124. //实现高精度的方法,先计算所有的乘法,最后计算除法!
    125. //对于只需要计算符号的,不需要除以分母啦
    126. Vref1 <= Vbeta;
    127. Vref2 <= (-1*Vbeta*512 + Valpha*887);///1024; //这一步,相当于alphasqrt3*根号三去掉后面的几位就是实现了除以255(新策略,都乘以256,再除以512)
    128. Vref3 <= (-1*Vbeta*512 - Valpha*887);///1024;
    129. x <= sqrt3Ts*(Vbeta)/Vdc;
    130. y <= (sqrt3Ts*Vbeta*512 + sqrt3Ts*Valpha*887)/(1024*Vdc); //这里与Vref是差倍数的
    131. z <= (sqrt3Ts*Vbeta*512 - sqrt3Ts*Valpha*887)/(1024*Vdc);
    132. flag2 <= 1'd1;
    133. end
    134. end
    135. //将输入的值乘以443,代表根号3,乘以256的就代表乘以1
    136. // mul1 mul1(
    137. // .dataa ( Valpha ), //输入的Vα
    138. // .result ( alphasqrt3 ) //输出的值,根号3alpha
    139. // );
    140. endmodule

    2.3 Cal_time 模块

    利用输入的XYZ,计算时间的长度。

    1. // 计算时间的长度
    2. // Type : synthesizable
    3. // Standard: SystemVerilog 2005 (IEEE1800-2005)
    4. // 功能: 利用输入的XYZ,计算时间的长度
    5. module Cal_time(
    6. input wire clk, //时钟信号
    7. input wire rstn, //复位信号
    8. input wire in_en, //输入使能信号
    9. input wire signed [16:0] x,
    10. input wire signed [16:0] y,
    11. input wire signed [16:0] z,
    12. input wire [3:0] n,
    13. output reg signed [16:0] Tfirst,
    14. output reg signed [16:0] Tsecond,
    15. output reg signed [16:0] Tzero,
    16. output reg out_en, //输出使能信号
    17. output reg out_en2,
    18. output reg out_en3,
    19. output reg signed [30:0] temp2,
    20. output reg signed [30:0] temp3,
    21. output reg signed [30:0] temp
    22. //output reg flag2
    23. );
    24. parameter Tp = 1024; //开关周期的一半,对应等腰三角形底边的一半
    25. parameter Ts = 2048;
    26. //reg signed [30:0] temp2;
    27. //reg signed [30:0] temp3;
    28. reg flag2;
    29. //wire signed [30:0] temp;
    30. //assign =
    31. always @(posedge clk)
    32. begin
    33. if(in_en)
    34. begin
    35. flag2 <= 1'd1;
    36. end
    37. if(~rstn)
    38. begin
    39. Tfirst <= 17'd0;
    40. Tsecond <= 17'd0;
    41. temp2 <= 31'd0;
    42. temp3 <= 31'd0;
    43. flag2 <= 1'd0;
    44. out_en <= 1'd0;
    45. out_en2 <= 1'd0;
    46. out_en3 <= 1'd0;
    47. Tzero <= 17'd0;
    48. temp <= 31'd0;
    49. end
    50. else
    51. Tzero <= (Ts - Tfirst - Tsecond)/2;
    52. begin
    53. if(flag2)
    54. begin
    55. flag2 <= 1'd0;
    56. case(n)
    57. 4'd1:begin
    58. Tfirst <= z;
    59. Tsecond <= y;
    60. out_en <= 1'd1;
    61. end
    62. 4'd2:begin
    63. Tfirst <= y;
    64. Tsecond <= -1*x;
    65. out_en <= 1'd1;
    66. end
    67. 4'd3:begin
    68. Tfirst <= -1*z;
    69. Tsecond <= x;
    70. out_en <= 1'd1;
    71. end
    72. 4'd4:begin
    73. Tfirst <= -1*x;
    74. Tsecond <= z;
    75. out_en <= 1'd1;
    76. end
    77. 4'd5:begin
    78. Tfirst <= x;
    79. Tsecond <= -1*y;
    80. out_en <= 1'd1;
    81. end
    82. 4'd6:begin
    83. Tfirst <= -1*y;
    84. Tsecond <= -1*z;
    85. out_en <= 1'd1;
    86. end
    87. default:
    88. begin
    89. Tfirst <= 17'd0;
    90. Tsecond <= 17'd0;
    91. out_en <= 1'd0;
    92. end
    93. endcase
    94. end
    95. if(out_en)
    96. begin
    97. out_en <= 1'd0;
    98. out_en2<= 1'd1;
    99. end
    100. if(out_en2)
    101. begin
    102. out_en2 <= 1'd0;
    103. out_en3 <= 1'd1;
    104. end
    105. if(out_en3)
    106. begin
    107. out_en3 <= 1'd0;
    108. end
    109. end
    110. if(Tfirst + Tsecond > Ts)
    111. begin
    112. //temp2 <= Ts*Tfirst;
    113. //temp3 <= Ts*Tsecond;
    114. Tfirst <= Ts*Tfirst/(Tfirst + Tsecond);
    115. Tsecond <= Ts*Tsecond/(Tfirst + Tsecond);
    116. end
    117. end
    118. endmodule

    2.4 Switch_time 模块

    利用时间长度信息,计算具体的开关切换时刻。

    1. // 计算逆变器信号改变的时间
    2. // Type : synthesizable
    3. // Standard: SystemVerilog 2005 (IEEE1800-2005)
    4. // 功能: 利用时间长度信息,计算具体的开关切换时刻。
    5. module Switch_time(
    6. input wire clk, //时钟信号
    7. input wire rstn, //复位信号
    8. input wire in_en, //输入使能信号
    9. input wire [3:0] n,
    10. input wire signed [16:0] Tfirst,
    11. input wire signed [16:0] Tsecond,
    12. input wire signed [16:0] Tzero,
    13. output reg signed [16:0] Tcm1, //三个逆变器的切换时间
    14. output reg signed [16:0] Tcm2,
    15. output reg signed [16:0] Tcm3,
    16. output reg out_en, //输出使能信号
    17. output reg out_en2 //延迟一拍
    18. );
    19. wire signed [16:0] Ta_wire;
    20. wire signed [16:0] Tb_wire;
    21. wire signed [16:0] Tc_wire;
    22. assign Ta_wire = Tzero/2;
    23. assign Tb_wire = Ta_wire + Tfirst/2;
    24. assign Tc_wire = Tb_wire + Tsecond/2;
    25. reg signed [16:0] Ta;
    26. reg signed [16:0] Tb;
    27. reg signed [16:0] Tc;
    28. reg flag2;
    29. always @(*)
    30. begin
    31. if(!rstn)
    32. begin
    33. Ta <= 17'd0;
    34. Tb <= 17'd0;
    35. Tc <= 17'd0;
    36. end
    37. else
    38. begin
    39. Ta <= Ta_wire;
    40. Tb <= Tb_wire;
    41. Tc <= Tc_wire;
    42. end
    43. if(out_en2)
    44. begin
    45. Ta <= 17'd0;
    46. Tb <= 17'd0;
    47. Tc <= 17'd0;
    48. end
    49. end
    50. always @(posedge clk) //
    51. begin
    52. if(in_en)
    53. begin
    54. flag2 <= 1'd1;
    55. end
    56. if(!rstn)
    57. begin
    58. Tcm1 <= 17'd0;
    59. Tcm2 <= 17'd0;
    60. Tcm3 <= 17'd0;
    61. flag2 <= 1'd0;
    62. out_en <= 1'd0;
    63. out_en2 <= 1'd0;
    64. end
    65. else
    66. begin
    67. if(flag2)
    68. begin
    69. // Ta <= Tzero/2;
    70. // Tb <= Ta + Tfirst/2;
    71. // Tc <= Tb + Tsecond/2;
    72. case(n)
    73. 4'd1:begin
    74. Tcm1 <= Tb;
    75. Tcm2 <= Ta;
    76. Tcm3 <= Tc;
    77. out_en <= 1'd1;
    78. end
    79. 4'd2:begin
    80. Tcm1 <= Ta;
    81. Tcm2 <= Tc;
    82. Tcm3 <= Tb;
    83. out_en <= 1'd1;
    84. end
    85. 4'd3:begin
    86. Tcm1 <= Ta;
    87. Tcm2 <= Tb;
    88. Tcm3 <= Tc;
    89. out_en <= 1'd1;
    90. end
    91. 4'd4:begin
    92. Tcm1 <= Tc;
    93. Tcm2 <= Tb;
    94. Tcm3 <= Ta;
    95. out_en <= 1'd1;
    96. end
    97. 4'd5:begin
    98. Tcm1 <= Tc;
    99. Tcm2 <= Ta;
    100. Tcm3 <= Tb;
    101. out_en <= 1'd1;
    102. end
    103. 4'd6:begin
    104. Tcm1 <= Tb;
    105. Tcm2 <= Tc;
    106. Tcm3 <= Ta;
    107. out_en <= 1'd1;
    108. end
    109. default:
    110. begin
    111. Tcm1 <= Tb;
    112. Tcm2 <= Ta;
    113. Tcm3 <= Tc;
    114. out_en <= 1'd0;
    115. end
    116. endcase
    117. end
    118. if(out_en)
    119. begin
    120. out_en <= 1'd0;
    121. flag2 <= 1'd0;
    122. end
    123. if(out_en)
    124. begin
    125. out_en2 <= 1'd1;
    126. end
    127. if(out_en2)
    128. begin
    129. out_en2 <= 1'd0;
    130. // Ta <= 17'd0;
    131. // Tb <= 17'd0;
    132. // Tc <= 17'd0;
    133. flag2 <= 1'd0;
    134. out_en <= 1'd0;
    135. end
    136. end
    137. end
    138. endmodule

    2.5 Tri_gener 模块

    产生三角波,便于确定当前所处的时刻。其中的变量CYCLE_NUM可以用来控制仿真的时候,SVPWM输出的具体循环数量。

    1. // 三角波生成模块
    2. // Type : synthesizable
    3. // Standard: SystemVerilog 2005 (IEEE1800-2005)
    4. // 功能: 产生三角波,便于确定当前所处的时刻。
    5. module Tri_gener(
    6. input wire clk, //输入时钟
    7. input wire rst, //复位信号
    8. input wire in_en, //输入使能信号
    9. // output reg Ts_cp, //对PGFS输入时钟进行同步化后的时钟,提供给Ts累加的脉冲
    10. output reg signed [11:0] Ts_cnt, //Ts的计数器,用来产生一个周期为Ts=2*Tp的三角波
    11. output reg deta_clk //每次输出一个时钟,就给一个高电平
    12. );
    13. ///三角波产生//
    14. reg [16:0] adder; //Ts有关的相位累加器
    15. reg Ts_dir; //Ts的计数器的计数方向
    16. reg flag2;
    17. reg signed [5:0] cycle_num; //计数完成了多少个周期
    18. parameter Tp = 1024, //开关周期的一半
    19. pfs= 10000; //频率控制输入,5000:7K,10000:15K,20000:30K
    20. parameter CYCLE_NUM = 3;
    21. ///三角波产生//
    22. // always @(posedge clk) //相位累加器,溢出信号提供给周期循环计数器
    23. // begin
    24. // if(!rst)
    25. // begin
    26. // adder <= 17'b0;
    27. // Ts_cp <= 1'b0;
    28. // end
    29. // else
    30. // begin
    31. // adder <= adder + pfs;
    32. // if(adder[16])
    33. // begin
    34. // Ts_cp <= 1'b1;
    35. // adder[16] <= 1'b0;
    36. // end
    37. // else
    38. // Ts_cp <= 1'b0;
    39. // end
    40. // end
    41. always @(posedge clk)
    42. begin
    43. if(in_en)
    44. begin
    45. flag2 <= 1'd1;
    46. end
    47. if(!rst)
    48. begin
    49. Ts_cnt <= 12'd0;
    50. Ts_dir <= 1'b1;
    51. deta_clk <= 1'b0;
    52. flag2 <= 1'd0;
    53. cycle_num<= 1'd0;
    54. end
    55. else
    56. begin
    57. if(cycle_num == CYCLE_NUM)
    58. flag2 <= 1'd0;
    59. if(flag2)
    60. begin
    61. if(Ts_dir)
    62. Ts_cnt <= Ts_cnt + 12'b1;
    63. else
    64. Ts_cnt <= Ts_cnt - 12'b1;
    65. if( Ts_cnt == Tp-1 ) //注意是非阻塞赋值
    66. begin
    67. Ts_dir <= 1'b0;
    68. end
    69. if( Ts_cnt == 1 ) //注意是非阻塞赋值
    70. begin
    71. Ts_dir <= 1'b1;
    72. end
    73. if( Ts_cnt == 1 && ~Ts_dir)
    74. begin
    75. deta_clk <= 1'b1;
    76. cycle_num <= cycle_num + 1'b1;
    77. end
    78. else
    79. begin
    80. deta_clk <= 1'b0;
    81. end
    82. end
    83. end
    84. end
    85. endmodule

    2.6 测试模块

    这个是对整体模块的测试代码,可以在里面设置Vα与Vβ的值,在Quartus中进行仿真验证。

    1. // Copyright (C) 2018 Intel Corporation. All rights reserved.
    2. // Your use of Intel Corporation's design tools, logic functions
    3. // and other software and tools, and its AMPP partner logic
    4. // functions, and any output files from any of the foregoing
    5. // (including device programming or simulation files), and any
    6. // associated documentation or information are expressly subject
    7. // to the terms and conditions of the Intel Program License
    8. // Subscription Agreement, the Intel Quartus Prime License Agreement,
    9. // the Intel FPGA IP License Agreement, or other applicable license
    10. // agreement, including, without limitation, that your use is for
    11. // the sole purpose of programming logic devices manufactured by
    12. // Intel and sold by Intel or its authorized distributors. Please
    13. // refer to the applicable agreement for further details.
    14. // *****************************************************************************
    15. // This file contains a Verilog test bench template that is freely editable to
    16. // suit user's needs .Comments are provided in each section to help the user
    17. // fill out necessary details.
    18. // *****************************************************************************
    19. // Generated on "06/27/2022 19:37:37"
    20. // Verilog Test Bench template for design : my_SVPWM
    21. //
    22. // Simulation tool : ModelSim (Verilog)
    23. //
    24. `timescale 1 ps/ 1 ps
    25. module my_SVPWM_vlg_tst();
    26. // constants
    27. // general purpose registers
    28. reg eachvec;
    29. reg clk;
    30. reg rstn;
    31. reg in_en;
    32. // test vector input registers
    33. reg [15:0] Valpha;
    34. reg [15:0] Vbeta;
    35. // wires
    36. wire Cal_time_out_en;
    37. wire Jug_sec_in_en;
    38. wire Jug_sec_out_en;
    39. wire Switch_time_out_en;
    40. wire [16:0] Tcm1;
    41. wire [16:0] Tcm2;
    42. wire [16:0] Tcm3;
    43. wire [16:0] Tfirst;
    44. wire Tri_gener_out_en;
    45. wire signed [11:0] Ts_cnt;
    46. wire [16:0] Tsecond;
    47. wire [16:0] Tzero;
    48. wire [3:0] n;
    49. wire pwm_a;
    50. wire pwm_b;
    51. wire pwm_c;
    52. wire [3:0] sector;
    53. wire [16:0] x;
    54. wire [16:0] y;
    55. wire [16:0] z;
    56. parameter half_cycle = 10;
    57. // assign statements (if any)
    58. my_SVPWM i1 (
    59. // port map - connection between master ports and signals/registers
    60. .Cal_time_out_en(Cal_time_out_en),
    61. .Jug_sec_in_en(Jug_sec_in_en),
    62. .Jug_sec_out_en(Jug_sec_out_en),
    63. .Switch_time_out_en(Switch_time_out_en),
    64. .Tcm1(Tcm1),
    65. .Tcm2(Tcm2),
    66. .Tcm3(Tcm3),
    67. .Tfirst(Tfirst),
    68. .Tri_gener_out_en(Tri_gener_out_en),
    69. .Ts_cnt(Ts_cnt),
    70. .Tsecond(Tsecond),
    71. .Tzero(Tzero),
    72. .Valpha(Valpha),
    73. .Vbeta(Vbeta),
    74. .n(n),
    75. .pwm_a(pwm_a),
    76. .pwm_b(pwm_b),
    77. .pwm_c(pwm_c),
    78. .sector(sector),
    79. .x(x),
    80. .y(y),
    81. .z(z),
    82. .clk(clk),
    83. .rstn(rstn),
    84. .in_en(in_en)
    85. );
    86. // my_SVPWM i1 (
    87. // .clk(clk), //时钟信号
    88. // .rstn(rstn), //复位信号
    89. // .in_en(in_en), //系统的输入使能信号
    90. // .Valpha(Valpha), //Park逆变换的结果Vα
    91. // .Vbeta(Vbeta), //Park逆变换的结果Vβ
    92. // .pwm_a(pwm_a), //SVPWM的输出1 PWM_a
    93. // .pwm_b(pwm_b), //SVPWM的输出2 PWM_b
    94. // .pwm_c(pwm_c) //SVPWM的输出3 PWM_c
    95. // );
    96. initial
    97. begin
    98. // code that executes only once
    99. // insert code here --> begin
    100. clk = 0;
    101. forever begin
    102. #half_cycle clk = 1;
    103. #half_cycle clk = 0;
    104. end
    105. // --> end
    106. $display("Running testbench");
    107. end
    108. initial
    109. begin
    110. rstn = 1;
    111. #5 rstn = 0;
    112. #10 rstn = 1;
    113. end
    114. initial
    115. begin
    116. Valpha = 16'd10;
    117. Vbeta = 16'd10;
    118. end
    119. initial
    120. begin
    121. in_en = 0;
    122. #90 in_en = 1;
    123. #20 in_en = 0;
    124. end
    125. always
    126. // optional sensitivity list
    127. // @(event1 or event2 or .... eventn)
    128. begin
    129. // code executes for every event on sensitivity list
    130. // insert code here --> begin
    131. @eachvec;
    132. // --> end
    133. end
    134. 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计数值的大小代替了具体的周期长度。


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

  • 相关阅读:
    对线性插值的理解
    Java刷题面试系列习题(十)
    百度地图——地图找房功能
    搭建 GPT-2 模型训练环境
    Opencv中的GrabCut图像分割
    Java文件操作
    k8s自定义Endpoint实现内部pod访问外部应用
    vue下载Excel文件
    主动获取用户的ColaKey接口
    亚马逊加湿器UL998测试报告,测试项目
  • 原文地址:https://blog.csdn.net/Alex497259/article/details/125502416