FPGAでパルス密度変調(デルタシグマ変調)

#デルタシグマ変調器

以前に固定小数点(符号部1bit,整数部15bit,少数部32bit)で2次デルタシグマ変調器を設計した際のコードを公開します。デルタシグマ変換器はPWMやPCMなどの変調の一種で，出力段に電力バッファと低域通過フィルタを設置してDAC ICなしでのDA変換ができます。
電力増幅用途でインバータレグの制御用に設計しているのでデッドタイム追加回路も組み込まれていますが，ユニポーラ増幅器であれば取り外しても動作します。
Timer.vhdというサブモジュールでスイッチング周波数を変更できます。

```dsm.vhd
library IEEE;
use ieee.std_logic_1164.all;
use ieee.std_logic_signed.all;

entity DS2LV is
port(
    clk :   in  std_logic;
    ena:    in  std_logic;
    vref_u: in  std_logic_vector(47 downto 0);
    vref_v: in  std_logic_vector(47 downto 0);
    vref_w: in  std_logic_vector(47 downto 0);
    gate:   out std_logic_vector( 5 downto 0)
);
end DS2LV;

architecture RTL of DS2LV is

--S15Q32: 48 bits; 1sign, 15integer, 32decimal

component timer is
generic(cmax: std_logic_vector(11 downto 0) :=x"3e7");
port(clk : in std_logic; ena: in std_logic; tp: out std_logic);
end component;

constant v_amp:   std_logic_vector(47 downto 0) :=x"000c00000000";    --12

signal tp5us:       std_logic :='0';
signal cnt:         std_logic_vector(7 downto 0) :=(others=>'0');
constant cntmax:    std_logic_vector(7 downto 0) :=x"0f";
constant switch:    std_logic_vector(7 downto 0) :=x"01";
constant deadtime:  std_logic_vector(7 downto 0) :=x"0b";

signal vref_u_z0:  std_logic_vector(47 downto 0) :=(others=>'0');
signal vref_v_z0:  std_logic_vector(47 downto 0) :=(others=>'0');
signal vref_w_z0:  std_logic_vector(47 downto 0) :=(others=>'0');

signal qt_u_z1:     std_logic_vector(47 downto 0) :=(others=>'0');
signal qt_v_z1:     std_logic_vector(47 downto 0) :=(others=>'0');
signal qt_w_z1:     std_logic_vector(47 downto 0) :=(others=>'0');
signal qt_u_z1_db:  std_logic_vector(47 downto 0) :=(others=>'0');
signal qt_v_z1_db:  std_logic_vector(47 downto 0) :=(others=>'0');
signal qt_w_z1_db:  std_logic_vector(47 downto 0) :=(others=>'0');
signal qt_u_z2:     std_logic_vector(47 downto 0) :=(others=>'0');
signal qt_v_z2:     std_logic_vector(47 downto 0) :=(others=>'0');
signal qt_w_z2:     std_logic_vector(47 downto 0) :=(others=>'0');

signal ds_u_ref:    std_logic_vector(47 downto 0) :=(others=>'0');
signal ds_v_ref:    std_logic_vector(47 downto 0) :=(others=>'0');
signal ds_w_ref:    std_logic_vector(47 downto 0) :=(others=>'0');

constant qt_lim:    std_logic_vector(47 downto 0) := x"008000000000";   -- 128
signal qt_satu:     std_logic_vector(47 downto 0) :=(others=>'0');

signal mode_u:      std_logic_vector( 1 downto 0) :=(others=>'0');
signal mode_v:      std_logic_vector( 1 downto 0) :=(others=>'0');
signal mode_w:      std_logic_vector( 1 downto 0) :=(others=>'0');
signal gate_u:      std_logic_vector( 1 downto 0) :=(others=>'0');
signal gate_v:      std_logic_vector( 1 downto 0) :=(others=>'0');
signal gate_w:      std_logic_vector( 1 downto 0) :=(others=>'0');

begin

--Timer
timer_5us:  timer generic map(cmax=>x"1f3") port map(clk=>clk,ena=>ena,tp=>tp5us);

process(clk) begin
    if clk'event and clk='1' then
        if ena='0' then cnt<=(others=>'0');
        else if tp5us='1' then cnt<=(others=>'0');
        elsif cnt=cntmax then cnt<=cnt; else cnt<=cnt+'1'; end if; end if;
    end if;
end process;

process(clk) begin
    if clk'event and clk='1' then
        --Sampling & Hold for Input
        if ena='0' then 
            vref_u_z0 <= (others=>'0'); vref_v_z0 <= (others=>'0'); vref_w_z0 <= (others=>'0');
        else
            if cnt=x"01" then vref_u_z0 <= vref_u; else vref_u_z0 <= vref_u_z0; end if;
            if cnt=x"01" then vref_v_z0 <= vref_v; else vref_v_z0 <= vref_v_z0; end if;
            if cnt=x"01" then vref_w_z0 <= vref_w; else vref_w_z0 <= vref_w_z0; end if;
        end if;    
    end if;
end process;

qt_u_z1_db <= qt_u_z1(47) & qt_u_z1(45 downto 0) & '0';
qt_v_z1_db <= qt_v_z1(47) & qt_v_z1(45 downto 0) & '0';
qt_w_z1_db <= qt_w_z1(47) & qt_w_z1(45 downto 0) & '0';

process(clk) begin
    if clk'event and clk='1' then
        if cnt=deadtime+x"02" then
            ds_u_ref <= vref_u_z0 + qt_u_z1_db - qt_u_z2;
            ds_v_ref <= vref_v_z0 + qt_v_z1_db - qt_v_z2;
            ds_w_ref <= vref_w_z0 + qt_w_z1_db - qt_w_z2;
        else
            ds_u_ref <= ds_u_ref; ds_v_ref <= ds_v_ref; ds_w_ref <= ds_w_ref;
        end if;

        if ena='0' then
            qt_u_z1 <= (others=>'0'); qt_v_z1 <= (others=>'0'); qt_w_z1 <= (others=>'0');
            qt_u_z2 <= (others=>'0'); qt_v_z2 <= (others=>'0'); qt_w_z2 <= (others=>'0');
        elsif cnt=deadtime+x"03" then
            if ds_u_ref(47)='0' then qt_u_z1 <= ds_u_ref - v_amp; else qt_u_z1 <= ds_u_ref + v_amp; end if;
            if ds_v_ref(47)='0' then qt_v_z1 <= ds_v_ref - v_amp; else qt_v_z1 <= ds_v_ref + v_amp; end if;
            if ds_w_ref(47)='0' then qt_w_z1 <= ds_w_ref - v_amp; else qt_w_z1 <= ds_w_ref + v_amp; end if;
            qt_u_z2 <= qt_u_z1; qt_v_z2 <= qt_v_z1; qt_w_z2 <= qt_w_z1;
        else
            qt_u_z1 <= qt_u_z1; qt_v_z1 <= qt_v_z1; qt_w_z1 <= qt_w_z1;
            qt_u_z2 <= qt_u_z2; qt_v_z2 <= qt_v_z2; qt_w_z2 <= qt_w_z2;
        end if;

    end if;
end process;

process(clk) begin
    if clk'event and clk='1' then

        --Mode FIFO
        if cnt=deadtime+x"03" then mode_u <= mode_u(0) & ds_u_ref(47); mode_v <= mode_v(0) & ds_v_ref(47); mode_w <= mode_w(0) & ds_w_ref(47);
        else mode_u <= mode_u; mode_v <= mode_v; mode_w <= mode_w; end if;
        
        --Deadtime implementation
        ----DO NOT CHANGE mode_x between cnt=switch to cnt=deadtime!
        if ena='0' then
            gate_u <= "00"; gate_v <= "00"; gate_w <= "00"; 
        elsif cnt=switch then
            case mode_u is when "00" => gate_u <= "10"; when "11" => gate_u <= "01"; when others => gate_u <= "00"; end case;
            case mode_v is when "00" => gate_v <= "10"; when "11" => gate_v <= "01"; when others => gate_v <= "00"; end case;
            case mode_w is when "00" => gate_w <= "10"; when "11" => gate_w <= "01"; when others => gate_w <= "00"; end case;
        elsif cnt=deadtime then
            case mode_u(0) is when '0' => gate_u <= "10"; when '1' => gate_u <= "01"; when others => gate_u <= gate_u; end case;
            case mode_v(0) is when '0' => gate_v <= "10"; when '1' => gate_v <= "01"; when others => gate_v <= gate_v; end case;
            case mode_w(0) is when '0' => gate_w <= "10"; when '1' => gate_w <= "01"; when others => gate_w <= gate_w; end case;
        else gate_u <= gate_u; gate_v <= gate_v; gate_w <= gate_w; end if;
            
    end if;
end process;

    --Gate signal
    gate <= gate_u & gate_v & gate_w;

end RTL;
```
```Timer.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;

entity timer is
generic(cmax: std_logic_vector(11 downto 0) :=x"3e7");
port(clk : in std_logic; ena: in std_logic; tp: out std_logic);
end timer;

architecture RTL of timer is
signal cnt: std_logic_vector(11 downto 0) :=(others=>'0');
begin
tp <= '1' when cnt=cmax else '0';
process(clk) begin
    if clk'event and clk='1' then
        if ena='0' then cnt<=(others=>'0');
        elsif cnt=cmax then cnt<=(others=>'0');
        else cnt<=cnt+'1'; end if;
    end if;
end process;
end RTL;
```