📑

FPGAでマルチレベルインバータ用の信号生成

に公開

0. はじめに

FPGAでマルチレベルインバータ用の信号を生成するのが目的です.今回は3レベルのレベルシフトPWM方式で行いましたが,適宜変更することでほかのレベル数でも可能です.

私は9レベルのインバータを作成して動作確認しました.(個人的な理由で公開できません)

  1. 仕様・環境
  2. モジュール構成
  3. シミュレーション
  4. まとめ
  5. 参考文献

1. 仕様・環境

  • Windows 11 Education
  • Quatus Prime Lite Edition 20.1.1
  • 使用FPGA:10M08SAE144C8GES

2. モジュール構成

各モジュール構成は以下のようにしました.

blocks

  • fd:分周器:FPGAのクロックを分周して正弦波生成用のトリガを生成
  • singenerater:正弦波生成:csvファイルを読み込んで正弦波を生成
  • threewavegenerater:三角波生成:キャリア信号を生成
  • wavecomparater:比較器:正弦波とキャリア信号である三角波を比較してレベル信号を生成
  • gatasignalgenerater:ゲート信号生成:レベル信号をもとにスイッチ素子に応じたゲート信号を生成
  • deadtimeadder:デットタイム追加:デットタイム追加する

3. シミュレーション

Modelsimでシミュレーションをしました.作ったモジュールをインスタンスとして呼び出してつないだtop_moduleを作成してシミュレーションを行いました.(コードは付録にあります.)
simresult1

波形を拡大すると,fetin[0]とfetin[3]をみると,設定通り400nsのデットタイムが入っていることがわかります.
simresult2

4. まとめ

公開できるのはシミュレーションまでですが,多分うごくと思います.何かあったら連絡ください.

参考文献

https://zenn.dev/nihinihikun/articles/1519a57e4e0c7f

付録:各モジュールコード

正弦波生成

あらかじめ作成した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レベルインバータで,以下の回路で行います.
circuit

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

デットタイム追加

S_1S_2が同時にONになると,ショート状態となり,回路が破壊されてしまうので,デットタイムを追加する必要があります.今回は400 nsのデットタイムを追加しました.

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