FPGAでマルチレベルインバータ用の信号生成
0. はじめに
FPGAでマルチレベルインバータ用の信号を生成するのが目的です.今回は3レベルのレベルシフトPWM方式で行いましたが,適宜変更することでほかのレベル数でも可能です.
私は9レベルのインバータを作成して動作確認しました.(個人的な理由で公開できません)
- 仕様・環境
- モジュール構成
- シミュレーション
- まとめ
- 参考文献
1. 仕様・環境
- Windows 11 Education
- Quatus Prime Lite Edition 20.1.1
- 使用FPGA:10M08SAE144C8GES
2. モジュール構成
各モジュール構成は以下のようにしました.
- fd:分周器:FPGAのクロックを分周して正弦波生成用のトリガを生成
- singenerater:正弦波生成:csvファイルを読み込んで正弦波を生成
- threewavegenerater:三角波生成:キャリア信号を生成
- wavecomparater:比較器:正弦波とキャリア信号である三角波を比較してレベル信号を生成
- gatasignalgenerater:ゲート信号生成:レベル信号をもとにスイッチ素子に応じたゲート信号を生成
- deadtimeadder:デットタイム追加:デットタイム追加する
3. シミュレーション
Modelsimでシミュレーションをしました.作ったモジュールをインスタンスとして呼び出してつないだtop_moduleを作成してシミュレーションを行いました.(コードは付録にあります.)
波形を拡大すると,fetin[0]とfetin[3]をみると,設定通り400nsのデットタイムが入っていることがわかります.
4. まとめ
公開できるのはシミュレーションまでですが,多分うごくと思います.何かあったら連絡ください.
参考文献
付録:各モジュールコード
正弦波生成
あらかじめ作成したcsvを読み込んで正弦波を生成するコードです.trig信号を受けて読み込んだ値を出力します.やっていることはこの記事とほぼ同じです.
module singenerater
(
input wire trig,
output reg [7:0] sin_out
);
// パラメータ
parameter DATA_LEN = 256;
reg [7:0] sin_mem [0:DATA_LEN-1];
integer i;
// 出力用カウンタ
reg [7:0] addr;
initial begin
// CSVファイル読み込み
$readmemh("C:/XXXXX/sin.csv", sin_mem);//sin.csvの絶対パス
addr = 0;
end
always @(posedge trig ) begin
sin_out <= sin_mem[addr];
if (addr < DATA_LEN - 1)
addr <= addr + 1;
else addr <= 0;
end
endmodule
三角波生成
キャリア信号となる三角波の生成モジュールです.スイッチング周波数を20kHzとして設定しました.
キャリア信号はレベル数-1つ必要です.レベル数を変えたいときは適宜変えてください.
module threewavegenerator (
input wire clk,
output reg [7:0] wave0,
output reg [7:0] wave1
);
//1/(20k)s=2500cnt
reg [7:0] triangle = 0;
reg [15:0]clkcnt=0;//1/(50M)sごとに
always @(posedge clk) begin
clkcnt=clkcnt+1;
// 三角波の方向制御
if (clkcnt%(20)==0)begin//1/(20k*128)sごと2500/128=19.5cnt
if (clkcnt <1250 )//1/(20k*128)*(1/2)s以内のときカウントアップ
triangle = triangle +1;
else if(clkcnt >=1250 && clkcnt<2500)//1/(20k*128)*(1/2)s以上,1/(20k*128)s未満のときカウントダウン
triangle = triangle - 1;
else//1/(20k*128)sのときカウントリセット
clkcnt=0;
end
//triangle_debug=triangle;//debug用
// 各出力に異なるオフセットを加えてレベルシフト
wave0 = triangle + 0;
wave1 = triangle + 127;
end
endmodule
比較器
キャリア信号と正弦波を比較し,レベル信号を生成するモジュールです.こちらもレベル数に応じて適宜変更してください.
module wavecomparater(
input wire clk,
input wire [7:0] sin_signals,
input wire [7:0] threewave0,
input wire [7:0] threewave1,
//input wire [7:0] threewave2,
//...
//input wire [7:0] threewaveX, //X=level-1
output reg [2:0] levels,
output reg phasepositive
);
//threewaveX:Xの値が小さい方から
parameter modulation=1;
always @(posedge clk) begin
levels[0] <= (threewave0 > sin_signals*modulation) ? 1'b1 : 1'b0;
levels[1] <= ((threewave0 <= sin_signals*modulation) && (sin_signals*modulation < threewave1)) ? 1'b1 : 1'b0;
levels[2] <= (threewave1 <= sin_signals*modulation)? 1'b1 : 1'b0;
//levels[2] <= ((threewave1 <= sin_signals*modulation) && (sin_signals*modulation < threewave2)) ? 1'b1 : 1'b0;
//levels[3] <= ((threewave2 <= sin_signals*modulation) && (sin_signals*modulation < threewave3)) ? 1'b1 : 1'b0;
//...
//levels[X] <= (threewave(X-1) <= sin_signals*modulation) ? 1'b1 : 1'b0;
end
always @(posedge clk)begin
phasepositive<=(sin_signals>128*modulation)? 1'b1:1'b0;
end
endmodule
ゲート信号生成
レベル信号から各スイッチ素子のゲート信号を生成するモジュールです.これは作る回路によって変わるので,適宜変更してください.今回は3レベルインバータで,以下の回路で行います.
module gatesignalgenerater(
input wire clk,
input wire [2:0] levels,
//input wire phasepositive,
output reg [3:0]gate
);
always @(posedge clk)begin
if (levels[2] == 1) gate <= 4'b0101; // 1Vin, [1,3]
else if (levels[1] == 1) gate <= 4'b1100; // 0Vin, [3,4]
else if (levels[0] == 1) gate <= 4'b1010; // -1Vin, [2,4]
else gate <= 4'b0000;
end
endmodule
デットタイム追加
module deadtimeadder(
input wire clk,
input [3:0] gate,
output reg [3:0] fetin
);
parameter fetnum=4;
parameter comdeadtime = 20; // 20ns*X count
reg [5:0] deadtimecnt [fetnum:0];
integer i;
integer j;
initial begin
for (i = 0; i < fetnum; i = i + 1) deadtimecnt[i] = comdeadtime;
end
always @(posedge clk) begin
for (j = 0; j < fetnum; j = j + 1) begin
if (gate[j] == 1'b1) begin
if (deadtimecnt[j] > 0)begin
deadtimecnt[j] <= deadtimecnt[j] - 1;
fetin[j] <= 1'b0;
end
else
fetin[j] <= 1'b1;
end else begin
fetin[j] <= 1'b0;
deadtimecnt[j] <= comdeadtime;
end
end
end
endmodule
分周器
正弦波を読み込むタイミングでトリガ信号を生成する分周器です.
module fd(
input wire clk, // 50MHz クロック入力
output wire trig // 12.8kHz (50*256Hz) 出力
);
//12.8kHz (50*256Hz):1953
localparam DIVIDE_BY = 1953; // トグル周期(1/2周期)
reg [11:0] counter = 0; // 1953 < 2^12
reg trig_reg = 0;
always @(posedge clk) begin
if (counter == (DIVIDE_BY - 1)) begin
counter <= 0;
trig_reg <= ~trig_reg;
end else begin
counter <= counter + 1;
end
end
assign trig = trig_reg;
endmodule
シミュレーション用topmodule作成
シミュレーションのときのみ使うtop_moduleを作成しました.
module top_module (
input wire clk,
output wire [2:0] signal,
output wire [3:0]fetin,
output wire phasepos
);
wire [7:0] wave0, wave1;
wire [7:0] sin_out;
wire trig;
wire [2:0] levels;//[level-1:0]
wire phasepositive;
wire [3:0]gate;
// 三角波ジェネレータ
threewavegenerator u_threewavegenerator (
.clk(clk),
.wave0(wave0),
.wave1(wave1)
);
//分周器1
fd u_fd(
.clk(clk),
.trig(trig)
);
// 正弦波ジェネレータ
singenerater u_singenerater (
.trig(trig),
.sin_out(sin_out)
);
// 三角波と正弦波の比較器
wavecomparater u_wavecomparater (
.clk(clk),
.sin_signals(sin_out),
.threewave0(wave0),
.threewave1(wave1),
.levels(levels),
.phasepositive(phasepositive)
);
// gategenerater
gatesignalgenerater u_gatesignalgenerater(
.clk(clk),
.levels(levels),
.gate(gate)
);
//deadtime追加
deadtimeadder u_deadtimeadder(
.clk(clk),
.gate(gate),
.fetin(fetin)
);
assign signal = levels;
assign phasepos = phasepositive;
endmodule
Discussion