Sinyal İşlemede Konvolüsyon İşleminin VHDL ile Gerçeklenmesi

Bu kısma kadar olan örneklerde genelde sayısal tasarımla alakalı uygulamalar gerçekleştirdik. Uygulamalarla VHDL ile ilgili kullanım şekillerini ve tasasrım yollarını göstermeye çalıştık.

Bu örnekte ise temel bir işaret işleme uygulamasına geçiş yapıyoruz. Bu kısımda bahsedilen kavramları anlayabilmek için temel seviyede işaret işleme ile alakalı konuların bilinmesi gerekmektedir. Bu bölüme devam etmeden önce lütfen işaret işleme ile alakalı kaynakları gözden geçriniz.

İşaret işlemede çok kullanışlı olan araçlardan biri de konvolüsyon işlemidir. Konvolusyon, giriş sinyali ve doğrusal sistemin dürtü tepki (impulse response) fonksiyonu bilindiğinde çıkış işaretini bulmaya yarayan bir işlemdir. Sistemin dürtü tepki fonksiyonu ‘in N tane çarpanlı bir sonlu filtre olduğunu varsayarsak, giriş işareti  sonsuz uzunlukta olduğu durumda dahi, filtrenin çıkış işareti  konvolüsyon işlemi ile aşağıda verilen deknklemde gösterilmiştir.

Dürtü tepki fonksiyonu katsayıları ve katsayıların sayısı tasarım aşamsından önce belirlenmelidir. Örneğin sonlu dürtü yanıtlı bir (N -1). dereceden filtrenin katsayısı N adettir. Bu tepki fonksiyonu için tasarımda N uzunluğunda bellek bloğu (h) ayrılması gerekmektedir.

Giriş işaretinin dürtü tepki fonksiyonu ile konvolüsyon işleminin yapılabilmesi için dürtü fonksiyonu katsayıları uzunluğunda giriş örneğinin saklaması gerekmektedir. Yukarıda verilen filtre örneği için N uzunluğunda bellek bloğu (x) ayrılması gerekmektedir. Giriş sinyali hafıza bloğu ile dürtü tepki fonksiyonunun katsayılarının bulunduğu bellek bloğu ile konvolüsyon işlemi, Şekil 1’de gösterilmiştir.

Şekil 1 Konvolüsyon işlemi

Örnek 1: Aşağıda sinyal işleme uygulamaları için katsayıların yüklenembilme özelliğine sahip ve konvolüsyon işlemi yapan konvolusyon_signal.vhd VHDL kodu verilmiştir. Uygulamada konvolüsyon işlemi için kullanıcı kendi oluşturduğu dürtü tepki fonksiyonun katsayılarını, katsayı hafıza bloğuna yükleyebilmektedir. Bu özellik ile konvolusyon_signal varlığı farklı dütrü tepki fonksiyonlarının gerçeklenebilmesine olanak sağlamaltadır.

konvolusyon_signal varlığına ilişkin generic tanımlamaları 8-13. satırlar arasında yapılmaktadır.

  • 9. satırda tanımlı VERI_UZUNLUGU parametresi ile giriş data uzunluğu belirlenmektedir.
  • 10. satırda tanımlı KATSAYI parametresi ile konvolüsyon için kullılacak katsayıların sayısı tanımlanmaktadır.
  • 11. satırda tanımlı KATSAYI_UZUNLUGU parametresi ile katsayıların data uzunluğu belirlenmektedir.
  • 12. satırda tanımlı KATSAYI_CARPIM paramatresi ise hesaplanan katsayıların 2’nin kaçıncı kuvveti ile çarpıldığını belirtmektedir. Bu parametre filtre çıkışında kullanılmaktadır.

konvolusyon_signal varlığına ilişkin port tanımlama işlemleri 14-26. satırlarda yapılmaktadır. 37. satırda KATSAYI_UZUNLUGU bit uzunluğunda ve KATSAYI boyunda tip tanımlama işlemi yapılarak konvolüsyon katsayılarının saklanacağı bellek tipi oluşturulmuştur. 

40. satırda VERI_UZUNLUGU bit uzunluğunda KATSAYI boyunda tip tanımlama işlemi yapılarak giriş datalarının saklanacağı bellek tipi oluşturulmuştur.

Giriş datalarının saklanma işleminde giriş örnek datası belleğin 0. adresine yazılacak şekilde tasarım yapılmıştır. Bu nedenle 43-52. satırlarda tanımlı fonksiyon ile giriş datalarının tutulduğu bellekte dataların sağa kaydırma işlemi gerçekleştirilmektedir.

68-77. satırlarda tanımlı process ile konvolüsyon katsayılarının belleğe yazılma işlemi yapılmaktadır. Katsayı ve katsayı adres bilgisi ile birlikte aktif sinyali olması durumunda katsayı değeri r_katsayi_bellek sinyalinde ilgili adresadresteki yerine yazılmaktadır.

79-104. satırlarda tanımlı process’de data aktif sinyali ile f_Bellek_kaydir fonksiyonu çağrılarak r_data_bellek sinyali dataları sağa kayırdama işlemi yapılır ve giriş datası ilgili yerine yazılır. Data yazma işleminin tamamlanması ile birlikte r_hesap_basla sinyali aktif edilerek 106-144. satırlarda tanımlı process’de tanımlı konvolüsyon işlemi başlatılır.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_SIGNED.all;
use IEEE.STD_LOGIC_ARITH.all;
use work.ornekler_paket.all; 
 
entity konvolusyon_sinyal is
  Generic(
    VERI_UZUNLUGU : integer := 24;
    KATSAYI : integer := 5;
    KATSAYI_UZUNLUGU : integer := 8;
    KATSAYI_CARPIM : integer := 3
  );
  Port (
    in_clk : in std_logic;
    in_rst : in std_logic;
    in_en : in std_logic;
    in_katsayi_vld : in std_logic;
    in_katsayi_addr : in std_logic_vector(log2_int(KATSAYI) downto 0);
    in_katsayi_data : in std_logic_vector(KATSAYI_UZUNLUGU - 1 downto 0);
    in_data : in std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    in_data_vld : in std_logic;
    out_data : out std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    out_data_vld : out std_logic;
    out_calisiyor : out std_logic   
  );
end konvolusyon_sinyal;

architecture Behavioral of konvolusyon_sinyal is

  type t_Kayma_Ctrl is (BOSTA, DATA_KAYDIR);
  signal r_Kayma_Ctrl : t_Kayma_Ctrl := BOSTA;

  type t_Filtre_Hesap is (BOSTA, HESAPLA, TAMAM);
  signal r_Filtre_Hesap : t_Filtre_Hesap := BOSTA;

  type t_katsayi_bellek is array (0 to KATSAYI - 1 ) of std_logic_vector(KATSAYI_UZUNLUGU - 1 downto 0);
  signal r_katsayi_bellek : t_katsayi_bellek := (others => (others => '0'));

  type t_data_bellek is array (0 to KATSAYI - 1 ) of std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
  signal r_data_bellek : t_data_bellek := (others => (others => '0'));

  function f_Bellek_Kaydir(r_data_bellek : t_data_bellek; in_data : std_logic_vector(VERI_UZUNLUGU - 1 downto 0)) return t_data_bellek is
    variable v_data_bellek : t_data_bellek;
  begin
    v_data_bellek := r_data_bellek;
    for n_i in KATSAYI - 2 downto 0 loop
        v_data_bellek(n_i + 1) := v_data_bellek(n_i);
    end loop;
    v_data_bellek(0) := in_data;
    return v_data_bellek;       
  end f_Bellek_Kaydir;

  signal r_hesap_basla : std_logic := '0';
  signal r_data : std_logic_vector(VERI_UZUNLUGU - 1 downto 0) := (others => '0');
  signal r_toplam : std_logic_vector(VERI_UZUNLUGU + KATSAYI_UZUNLUGU + log2_int(KATSAYI) - 1 downto 0) := (others => '0');
  signal r_data_out : std_logic_vector(VERI_UZUNLUGU - 1 downto 0) := (others => '0');
  signal r_data_out_vld : std_logic := '0';
  signal r_calisiyor : std_logic := '0';
  signal n_i : integer := 0;

begin

  out_data <= r_data_out;
  out_data_vld <= r_data_out_vld;
  out_calisiyor <= r_calisiyor;

  process(in_clk, in_rst)
  begin
    if in_rst = '1' then
      r_katsayi_bellek <= (others => (others => '0'));
    elsif rising_edge(in_clk) then
      if in_katsayi_vld = '1' then
        r_katsayi_bellek(conv_integer(in_katsayi_addr)) <= in_katsayi_data;               
      end if;
    end if;
    end process;
 
  process(in_clk, in_rst)
  begin
    if in_rst = '1' then
      r_Kayma_Ctrl <= BOSTA;
      r_data_bellek <= (others => (others => '0'));
      r_hesap_basla <= '0';
      r_data <= (others => '0');
 
    elsif rising_edge(in_clk) then
      r_hesap_basla <= '0';
      case r_Kayma_Ctrl is
        when BOSTA =>
          if in_data_vld = '1' then
            r_data <= in_data;
            r_Kayma_Ctrl <= DATA_KAYDIR;
          end if;
 
        when DATA_KAYDIR =>
          r_data_bellek <= f_Bellek_Kaydir(r_data_bellek, r_data);
          r_Kayma_Ctrl <= BOSTA;
          r_hesap_basla <= '1';
        
  when others => NULL;   
      end case;
  end if;
end process;
 
process(in_clk, in_rst)
begin
    if in_rst = '1' then
        r_Filtre_Hesap <= BOSTA;
        r_toplam <= (others => '0');
        r_data_out_vld <= '0';
        r_data_out <= (others => '0');
        r_calisiyor <= '0';
        n_i <= 0;
 
    elsif rising_edge(in_clk) then
        r_data_out_vld <= '0';
        case r_Filtre_Hesap is
            when BOSTA =>
                r_calisiyor <= '0';
                if r_hesap_basla = '1' and in_en = '1' then
                    r_Filtre_Hesap <= HESAPLA;
                    r_calisiyor <= '1';
                end if;
 
            when HESAPLA =>
                r_toplam <= r_toplam + sxt((r_data_bellek(n_i)) * (r_katsayi_bellek(KATSAYI - 1 - n_i)), r_toplam'length);
                n_i <= n_i + 1;
                if n_i = KATSAYI - 1 then
                    n_i <= 0;
                    r_Filtre_Hesap <= TAMAM;
                end if;
 
            when TAMAM =>                           
                r_toplam <= (others => '0');
                r_calisiyor <= '0';
                r_data_out_vld <= '1';
                r_data_out <= r_toplam(KATSAYI_CARPIM + VERI_UZUNLUGU - 1 downto KATSAYI_CARPIM);
                r_Filtre_Hesap <= BOSTA;
 
            when others => NULL;
        end case;
    end if;
end process;     
 
end Behavioral;

Örnekte tanımlı ornekler_paket.vhd paket dosyası VHDL’de ROM Bloğu oluşturma yazımızda verilmiştir.

konvolusyon_signal varlığının benzetiminin yapılabilmesi için aşağıda tb_konvolusyon_signal.vhd VHDL sınama kodu verilmiştir. Kodda tanımlı alçak geçiren süzgeç parametreleri öncelikle konvolusyon_signal varlığına yazılmaktadır. Yazma işleminin bitiminde konvolusyon hesaplama işlemi aktif hale gelmektedir. konvolusyon_signal varlığına giriş olarak 10 Hz ve 10 Khz frekansında iki sinüs sinyalinin toplamı100 KHz ile örneklenerek verilmiştir. Şekil 2’den de görüleceği üzere ornek_data sinyali’nin giriş olarak verildiği konvolusyon_signal varlığı çıkışında elde edilen out_data sinyali incelendiğinde filtreleme işlemi başarılı bir şekilde gerçekleştirilmiştir.

Şekil 2 Alçak geçiren filtre uygulaması

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.STD_LOGIC_ARITH.all;
use work.ornekler_paket.all; 
use std.textio.ALL;
 
entity tb_konvolusyon_signal is
end tb_konvolusyon_signal;
 
architecture Behavioral of tb_konvolusyon_signal is
  component konvolusyon_sinyal is
  Generic(
    VERI_UZUNLUGU : integer := 24;
    KATSAYI : integer := 5;
    KATSAYI_UZUNLUGU : integer := 8;
    KATSAYI_CARPIM : integer := 3
  );
  Port (
    in_clk : in std_logic;
    in_rst : in std_logic;
    in_en : in std_logic;
    in_katsayi_vld : in std_logic;
    in_katsayi_addr : in std_logic_vector(log2_int(KATSAYI)  downto 0);
    in_katsayi_data : in std_logic_vector(KATSAYI_UZUNLUGU - 1 downto 0);
    in_data : in std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    in_data_vld : in std_logic;
    out_data : out std_logic_vector(VERI_UZUNLUGU - 1 downto 0);
    out_data_vld : out std_logic;
    out_calisiyor : out std_logic   
  );
  end component;
 
  constant CLK_PERIOD : time := 10 ns;
  constant ORNEKLEME_PERIOD : time := 10 us;
  constant VERI_YOLU : string := "C:\sin.txt";
  constant VERI_UZUNLUGU : integer := 24;
  constant KATSAYI : integer := 17;
  constant KATSAYI_UZUNLUGU : integer := 8;
  constant KATSAYI_CARPIM : integer := 7;   
 
  signal in_clk : std_logic  := '0';
  signal ornekleme_clk : std_logic := '0';
  signal ornek_data : std_logic_vector(23 downto 0) := (others => '0');
  signal clk_domain : std_logic_vector(3 downto 0) := (others => '0');
  signal son_data : std_logic := '0';
  signal in_rst : std_logic := '0';
  signal in_en : std_logic := '0';
  signal in_katsayi_vld : std_logic := '0';
  signal in_katsayi_addr : std_logic_vector(log2_int(KATSAYI) downto 0) := (others => '0');
  signal in_katsayi_data : std_logic_vector(KATSAYI_UZUNLUGU - 1 downto 0) := (others => '0');
  signal in_data : std_logic_vector(VERI_UZUNLUGU - 1 downto 0) := (others => '0');
  signal in_data_vld : std_logic := '0';
  signal out_data : std_logic_vector(VERI_UZUNLUGU - 1 downto 0) := (others => '0');
  signal out_data_vld : std_logic := '0';
  signal out_calisiyor : std_logic := '0';

  type t_Katsayi_Kontrol is  (BOSTA, YUKLE);
  signal r_Katsayi_Kontrol : t_Katsayi_Kontrol := BOSTA;
 
  type t_Filtre_Katsayi is array (0 to KATSAYI - 1) of integer;
  signal r_Filtre_Katsayi : t_Filtre_Katsayi := (1, 2, 3, 5, 8, 10, 13, 14, 15, 14, 13, 10, 8, 5, 3, 2, 1);
 
  signal katsayi_yukle : std_logic := '0';
  signal n_i : integer := 0;
 
begin
 
  process
  begin
    in_clk <= '1';
    wait for CLK_PERIOD / 2;
    in_clk <= '0';
    wait for CLK_PERIOD / 2;      
  end process;
 
  process
  begin
    ornekleme_clk <= '1';
    wait for ORNEKLEME_PERIOD / 2;
    ornekleme_clk <= '0';
    wait for ORNEKLEME_PERIOD / 2;      
  end process;
 
  process
  begin
    katsayi_yukle <= '0';
    wait for CLK_PERIOD * 2;
    katsayi_yukle <= '1';
    wait for CLK_PERIOD ;
    katsayi_yukle <= '0';
    wait;
  end process;   
 
  process (ornekleme_clk)
    file dosya : text open read_mode is VERI_YOLU ;
    variable satir : line;
    variable data : integer;
  begin 
  if rising_edge(ornekleme_clk) then
      if not(endfile(dosya)) then
          readline(dosya, satir);
          read(satir, data);
          ornek_data <= conv_std_logic_vector(data, 24) ;               
          son_data <= '0';
      else
          ornek_data <= conv_std_logic_vector(0, 24) ;
          son_data <= '1';
      end if;                   
  end if;
end process;
 
process(in_clk)
begin
if rising_edge(in_clk) then
    clk_domain <= clk_domain(2 downto 0) & ornekleme_clk;
end if;
end process;
 
process (in_clk)
begin 
if rising_edge(in_clk) then
    if son_data = '0' and clk_domain(3 downto 2) = "01" then
        in_data_vld <= '1' ;
        in_data <= ornek_data ;
    else
        in_data_vld <= '0' ;
        in_data <= (others=>'0') ;
    end if;                   
end if;
end process;
 
process(in_clk)
begin
if rising_edge(in_clk) then  
    in_katsayi_vld <= '0';
    case r_Katsayi_Kontrol is
    when BOSTA =>
        if katsayi_yukle = '1' then
            r_Katsayi_Kontrol <= YUKLE;
        end if;
    
    when YUKLE =>
        in_katsayi_vld <= '1';
        in_katsayi_addr <= conv_std_logic_vector(n_i, log2_int(KATSAYI) + 1);
        in_katsayi_data <= conv_std_logic_vector( r_Filtre_Katsayi(n_i), KATSAYI_UZUNLUGU);
        if n_i = KATSAYI - 1 then
            r_Katsayi_Kontrol <= BOSTA;
            n_i <= 0;
            in_en <= '1';
        else
            n_i <= n_i + 1;
        end if;
    when others => NULL;
    end case;
end if;
end process;           
 
konvolusyon_sinyal_map :  konvolusyon_sinyal
Generic map(
VERI_UZUNLUGU => VERI_UZUNLUGU,
KATSAYI => KATSAYI,
KATSAYI_UZUNLUGU => KATSAYI_UZUNLUGU,
KATSAYI_CARPIM => KATSAYI_CARPIM
)
Port map(
in_clk => in_clk,
in_rst => in_rst,
in_en => in_en,
in_katsayi_vld => in_katsayi_vld,
in_katsayi_addr => in_katsayi_addr,
in_katsayi_data => in_katsayi_data,
in_data => in_data,
in_data_vld => in_data_vld,
out_data => out_data,
out_data_vld => out_data_vld,
out_calisiyor => out_calisiyor 
);
end Behavioral;

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir