VHDL ile Kayan Noktalı Sayılarda Çarpma İşleminin Gerçeklenmesi

Bu yazımızda kayan noktalı sayılarda çarpma işlemini pipeline mimaride fonksiyonlar ile gerçekleştirilmesini anlatacağız.

Kayan noktalı sayılarda dört işlemle ilgili detaylı yazımıza buradan ulaşabilirsiniz.

Yazıda çarpma işlemlerine ait gösterilen tüm adımlar birer fonksiyon olarak tanımlanmıştır.

Aşağıda VHDL dili kullanılarak kayan noktalı sayılarda çarpma işlemini gerçekleştiren fonksiyon kodları verilmiştir. Koddan da görüleceği üzere ilk olarak işaret biti tanımlama işlemleri gerçekleştirilmektedir. Burada saklayıcı amacı ile değerin saklnamasının nedeni pipeline mimarini işletilebilmesidir. İkinci kısımda ise çarpan değerinin hesaplandığı fonksiyonlar ve üçüncü kısımda bu mantis değerinin hesaplandığı fonksiyonlar gösterilmiştir.

Sabit atamalarında kullanılan g_e üst değerinin saklanacağı bit sayısını, g_f ise mantis değerinin saklanacağı bit sayısını göstermektedir.

Bu fonksiyonlarda sıfırla çarpma, sonsuzla çarpma gibi bazı kontroller eksik bırakılmıştır.

.....
constant g_e : natural := 8;
constant g_f : natural := 23;
.....
.....

out_rslt <= r_s_rslt & r_e_rslt & r_f_rslt;

-- işaret bitini belirle
r_s_rslt <= r_s_rslt_reg ;
r_s_rslt_reg <= sign_bit_calc_m_d(in_a_nmb(in_a_nmb'high), in_b_nmb(in_b_nmb'high));

-- üst kısımların hesaplanma işlemleri
r_exp_add_rslt <= exp_calc_m(in_a_nmb(g_e + g_f - 1 downto g_f), in_b_nmb(g_e + g_f - 1 downto g_f));

-- 
r_e_rslt <= exp_update_m(r_exp_add_rslt, r_mant_mul_rslt(r_mant_mul_rslt'high));

--çarpan kısmının hesaplanması
r_mant_mul_rslt    <=  mantissa_calc_m(in_a_nmb(g_f - 1 downto 0), in_b_nmb(g_f - 1 downto 0));

-- 
r_f_rslt <= mant_update_m(r_mant_mul_rslt, r_mant_mul_rslt(r_mant_mul_rslt'high));

Bu fonksiyon iki sayının çarpımı sonucunda elde edilecek sayının işaret biti değerini döndürmektedir.

function sign_bit_calc_m_d( a_sign, b_sign : std_logic) return std_logic is
begin
    return a_sign xor b_sign;
end sign_bit_calc_m_d;

Bu fonksiyon iki sayının çarpımı sonucunda üst kısmını hesaplama sonucunu döndürmektedir.

function exp_calc_m(a_exp, b_exp : std_logic_vector(g_e - 1 downto 0)) return std_logic_vector is
begin
    return (a_exp + b_exp - conv_std_logic_vector(2**(g_e - 1) - 1, g_e));
end exp_calc_m;

Bu fonksiyon çarpanlarn çarpımı sonucuna göre nihai üst değerini döndürmektedir.

function exp_update_m(exp_add : std_logic_vector(g_e - 1 downto 0); mant_bit : std_logic) return std_logic_vector is
begin
    if mant_bit = '0' then
        return exp_add;
    else
        return exp_add + 1;
    end if;
end exp_update_m;

Bu fonksiyon çarpanlarn çarpımı sonucuna döndürmektedir.

function mantissa_calc_m(a_mant, b_mant : std_logic_vector(g_f - 1 downto 0)) 
        return std_logic_vector is
    variable mant_mul_rslt : std_logic_vector(2 * g_f + 1 downto 0) := (others => '0');     
begin
    mant_mul_rslt := ('1' & a_mant) * ('1' & b_mant);
    return mant_mul_rslt(mant_mul_rslt'high downto mant_mul_rslt'high - g_f - 1);
end mantissa_calc_m;    

Bu fonksiyon çarpanlarn çarpımı sonucunun nihai değerini döndürmektedir.

function mant_update_m(mant_mul : std_logic_vector(g_f + 1 downto 0); mant_bit : std_logic) return std_logic_vector is
begin
    if mant_bit = '0' then
        return mant_mul(mant_mul'high - 2 downto mant_mul'high - g_f - 1 );			
    else
        return mant_mul(mant_mul'high - 1 downto mant_mul'high - g_f);
    end if;		
end mant_update_m;

Parçaçık Sürü Optimizasyon Algoritması ile Yapay Sinir Ağı Eğitimi

Bu yazımızda Parçacık Sürü Optimizasyon (PSO) algoritması ile Yapay Sinir Ağı eğitimi hakkında bilgi vereceğiz. PSO ile ilgili detaylı bilgileri linke tıklayarak ulaşabilirsiniz.

PSO algoritmasında en önemli aşamaların ilki Yapay Sinir Ağı ağırlık ve eşik parametrelerin parçacıklarda tanımlanmasıdır. Bu yazıda literatürde sıklıkla tercih edilen Çok Katmanlı Algılayıcı tipi YSA referans alınmıştır. Aşağıdaki denklemde i. parçacık için R adet girişe sahip, gizli katmanda ise T hücreye sahip ve 1 çıkışa sahip ÇKA’nın ağıtlıkların ve eşiklerin yerleşimine ait örnek gösterilmiştir.

Bu bilgiler doğrultusunda kodlama işlemi için öncelikle her bir parçacık için başlangıç pozisyon ve hız değerlerinin atanması gerekmektedir. Başlangıcta parçacıkların yerel en iyi konumu , başlangıç pozisyonu olarak atanır (4.-6. satırlar).

Daha sonra başlangıç değerleri için uygunluk değeri hesaplamaları yapılır (10. satır). bu işlemi takiben belirlen iterasyon değerleri arasında öncelikle parçacıkların pozisyonları güncellenir (14. satır) . Güncelleme işlemi sonucunda oluşan yeni pozisyonlara ait yeni uygunluk değerleri hesaplanır (17. satır). Daha sonra yeni uygunluk değerleri referans alınarak yerel en iyi pozisyonlar güncellenir ve daha sonra yerel en iyi pozisyonlar içerisinde küresel en iyi belirlenir (21- 25. satırlar).

function [GLOBAL_BEST min_data] = PSO_TRAIN(Train_Input, Train_Output, NoParam, NoParticle, Iteration, Max_Limit, ...
                                 NoInput, NoHidden, NoOutput)
                            
PARTICLE = rand(NoParticle, NoParam);
BEST_PARTICLE = PARTICLE;
VELOCITY = rand(NoParticle, NoParam);
GLOBAL_BEST = zeros(1, NoParam);      


FITNESS_VALUE_old = Fitness_Valeu(Train_Input, Train_Output, NoParticle, PARTICLE,...
             NoInput, NoHidden, NoOutput);
         
for n_i = 1 : Iteration
    [PARTICLE VELOCITY] = UPDATE_BLOCK(PARTICLE, BEST_PARTICLE,  VELOCITY, ...
                          GLOBAL_BEST, NoParticle);
    
    FITNESS_VALUE = Fitness_Valeu(Train_Input, Train_Output, NoParticle, PARTICLE,...
             NoInput, NoHidden, NoOutput);
    
    
    ind = find(FITNESS_VALUE < FITNESS_VALUE_old);
    FITNESS_VALUE_old(ind) = FITNESS_VALUE(ind);
    BEST_PARTICLE(ind, : ) = PARTICLE(ind, : );
    [min_data(n_i) min_ind] = min(FITNESS_VALUE_old);
    GLOBAL_BEST = BEST_PARTICLE(min_ind, : );
     
end

Fitness_Valeu fonksiyonunda öncelikli olarak parçacıkların pozisyonları ÇKA’ya ait ağırlık ve eşik değerlerine dönüştürülür. Daha sonra ise giriş veri seti kullanılarak ağ çıkışında elde edilen çıkış ile çıkış veri seti kullanılarak uygunluk değeri hesaplanır.

function E_n = Fitness_Valeu(Input_Data, Output_Data, NoFood, Foods_Pos,...
               NoInput, NoHidden, NoOutput)
           
Point_1 = 1;
Point_2 = NoInput * NoHidden;
Point_3 = NoInput * NoHidden + NoHidden;
Point_4 = NoInput * NoHidden + NoHidden + ...
          NoHidden * NoOutput;
Point_5 = NoInput * NoHidden + NoHidden + ...
          NoHidden * NoOutput + NoOutput;           

for n_i = 1 : NoFood
    w_1 = reshape(Foods_Pos(n_i, Point_1 : Point_2), NoHidden, NoInput);
    b_1 = reshape(Foods_Pos(n_i, Point_2 + 1 : Point_3), NoHidden, 1);
    w_2 = reshape(Foods_Pos(n_i, Point_3 + 1 : Point_4), NoHidden, NoOutput);
    b_2 = reshape(Foods_Pos(n_i, Point_4 + 1 : Point_5), NoOutput, 1);    
    E_n(n_i) = 0;
    for n_j = 1 : length(Input_Data)
        in_data = Input_Data(n_j, : );
        NN_output = MLP(in_data', w_1, b_1, w_2, b_2);
        E_n(n_i) = E_n(n_i) + 0.5 * (Output_Data(n_j) - NN_output)^2;
    end
end

Aşağıda ÇKA için oluşturulan fonksiyon kodu verilmiştir.

function NN_output = MLP(in_data, w_1, b_1, w_2, b_2)

    Hidden_Add = w_1 * in_data  + b_1;
    Hidden_output = 0.5 * (1 +  Hidden_Add ./ (1 + abs(Hidden_Add)));
    NN_output = w_2' * Hidden_output  + b_2;
 

Bu fonksiyon ile parçacıkların pozisyonları ve hızlarının güncellenmesi işlemi yapılmaktadır.

function [PARTICLE VELOCITY] = UPDATE_BLOCK(PARTICLE, BEST_PARTICLE,  ...
              VELOCITY, GLOBAL_BEST, g_PARTICLE)
    
    for n_i = 1 : g_PARTICLE
        VELOCITY(n_i, : )= 0.76 * (VELOCITY(n_i, : ) ... 
            + 2.1 * rand * (BEST_PARTICLE(n_i, : ) - PARTICLE(n_i, : )) ...
            + 2.1 * rand * (GLOBAL_BEST - PARTICLE(n_i, : )));
   
    end
    
    VELOCITY = min(VELOCITY, 1.0 * ones(size(VELOCITY)));
    VELOCITY = max(VELOCITY,-1.0 * ones(size(VELOCITY)));
    
    PARTICLE = PARTICLE + VELOCITY;

Örnek uygulama olarak EXOR problemi kullanılarak PSO ile YSA eğitimine ait kod aşağıda verilmiştir. Eğitim sonucunda elde edilen uygunluk değeri değişimi aşağıdaki grafikte gösterilmitşir.

clc, clear all, close all;


% MLP structure
%% Number of Parameter
NoInput = 2;
NoHidden = 3;
NoOutput = 1;

NoParam = NoInput * NoHidden + NoHidden + ...
          NoHidden * NoOutput + NoOutput;

% PSO parameter
%% Iteration
Iteration = 200;
Max_Limit = 100;

%% Colony Size
NoParticle =  100;

%% EXOR Problem
Train_Input = [0 0;
               0 1;
               1 0;
               1 1];
           
Train_Output = [0; 1; 1; 0];           


%Iteration = 200;
[glbl_best FITNESS_VALUE] = PSO_TRAIN(Train_Input, Train_Output, NoParam, NoParticle, Iteration, Max_Limit, ...
                                 NoInput, NoHidden, NoOutput);
figure, plot(FITNESS_VALUE)
xlabel('Iteration')


Point_1 = 1;
Point_2 = NoInput * NoHidden;
Point_3 = NoInput * NoHidden + NoHidden;
Point_4 = NoInput * NoHidden + NoHidden + ...
          NoHidden * NoOutput;
Point_5 = NoInput * NoHidden + NoHidden + ...
          NoHidden * NoOutput + NoOutput;
      
w_1 = reshape(glbl_best(Point_1 : Point_2), NoHidden, NoInput);
b_1 = reshape(glbl_best(Point_2 + 1 : Point_3), NoHidden, 1);
w_2 = reshape(glbl_best(Point_3 + 1 : Point_4), NoHidden, NoOutput);
b_2 = reshape(glbl_best( Point_4 + 1 : Point_5), NoOutput, 1);  
%     
Test_Output = MLP(Train_Input', w_1, b_1, w_2, b_2)   

VHDL ile CORDIC Algoritmasının Gerçeklenmesi : Dairesel Açı Dönüşümü

Trigonometrik fonksiyonların bilgisayar tarafından hesaplanabilmesi için, 1959 yılında Jack Volder tarafından ortaya sürülen CORDIC algoritması, 1971 yılında J.S. Walther tarafından hiperbolik ve üstel fonksiyonlar, logaritma, karekök hesaplamaları yapabilecek şekilde geliştirilmiştir .

Aşağıda verilen denklemde -\pi/2\leq\theta<\pi/2 sınır aralığında tanımlı CORDIC algoritması genel ifadesi verilmiştir.

Yukarıdaki denklemde tanımlı d^i parametresi, aşağıdaki denklemde gösterildiği gibi z_i değerinin pozitif veya negatif olmasına göre -1 veya 1 değerini almaktadır.

e_i parametresi dairesel, doğrusal ve hiperbolik hesaplamaları yapan her denklem için farklı değer almaktadır. Dairesel dönüşüm için tanımlı eşitlik

Doğrusal dönüşüm için tanımlı eşitlik

Hiperbolik dönüşüm için kullanılan eşitlik

denklemlerde gösterilmiştir.gösterilmiştir.

Yukarıda verilen ilk denklemde tanımlı \mu parametresi yapılacak hesaplama tekniğine göre değer alan sabit parametredir. Bu değerler aşağıdaki tabloda gösterilmiştir. Her dönüşüm tipi döndürme ve vektörel olmak üzere iki çözüm moduna sahiptir.

Dairesel açı dönüşüm işlemlerinde, yukarıda verilen tablodan da görüleceği üzere \mu parametre değeri 1 olmaktadır. Dairesel açı dönüşüm işlemlerinde döndürme modu kullanılarak direkt olarak sinüs ve kosinüs değerleri dolaylı olarak ise tanjant ve kotanjant değerleri elde edilebilmektedir. Vektörel modda ise kartezyen koordinat değerlerinin polar koordinat değerlerine dönüşümü yapılmaktadır.

Döndürme Modu (Rotation Mod)

Döndürme modunda dairesel açı dönüşüm işlemlerinde temel amaç yazıda ilk verdiğimiz denklemde z tanımlanandeğişkeni değerini sıfıra yaklaştırmaktadır .

Döndürme modda dairesel açı dönüşümü, vektörün i. anındaki pozisyonu ile (i+1). anındaki pozisyonu arasındaki açı değeri θ sıfırlanana kadar kaydırma işlemlerinin gerçekleştirilmesiyle yapılmaktadır. Aşağıda verilen eşitlikle döndürme modda dairesel açı dönüşüm işlemi gerçekleştirilmektedir.

i. adım ile (i+1). adım arasında gerçekleştirilecek döndürme işlemi açı değeri aşağıda verilen gibi hesaplanır.

Bütün adımlardaki açıların toplamı döndürme açısı \theta ’yı vermelidir. Aşağıda verilen denklemde tanımlı S parametresi {-1, 1} değerlerini almaktadır.

Bu bilgiler doğrultusunda tan\theta_i değeri aşağıdaki gibi ifade edilmektedir.

Yukarıdaki ifadeleri kullanarak denklemi güncellediğimizde

Yukarıdaki eşitlikte tanımlanan K_i değişkeni aşağıdaki gibi hesaplanır.

K_i parametresi iteratif süreç içerisinde ihmal edilebilir ve daha sonra bir ölçekleme faktörü olarak uygulanabilir

Aşağıda döndürme modunda sinüs ve cosinüs değerlerini hesplayan VHDL kodları verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.MATH_REAL.ALL;

entity cordic_v1 is
    generic(
        ITERTATION : integer := 16;
        VALUE_SIZE : integer := 16;
        MUL_COEFF : integer := 18; -- 2^MULL_COEFF;
        DATA_SIZE : integer := 24 -- DATA_SIZE > MUL_COEFF +2
    );
    Port ( 
        in_clk : in std_logic;
        in_rst : in std_logic;
        in_strt : in std_logic;
        in_teta : in std_logic_vector(DATA_SIZE - 1 downto 0);  
        out_cos_data : out std_logic_vector(DATA_SIZE - 1 downto 0); 
        out_sin_data : out std_logic_vector(DATA_SIZE - 1 downto 0);
        out_data_vld : out std_logic
    );
end cordic_v1;

architecture Behavioral of cordic_v1 is
    
    type t_Cordic_values is array (0 to VALUE_SIZE - 1) of real;
    type t_Int_data is array (0 to VALUE_SIZE - 1) of integer;
    type t_Std_Logic_Vector_data is array (0 to VALUE_SIZE - 1) of std_logic_vector(DATA_SIZE - 1 downto 0);
    type t_V_vector is array (0 to 1) of std_logic_vector(DATA_SIZE - 1 downto 0);
    
    function f_Calc_K_values(VALUE_SIZE : integer) return t_Cordic_values is
        variable v_K_values : t_Cordic_values;
    begin
        v_K_values(0) := 1.0 / sqrt(2.0);
        for n_i in 1 to VALUE_SIZE - 1 loop
            v_K_values(n_i) := v_K_values(n_i - 1) * (1.0 / sqrt(1.0 + 2.0**(-2.0 * real(n_i))));
        end loop;
        return v_K_values;
    end f_Calc_K_values;
    
    function f_Calc_Angels(VALUE_SIZE : integer) return t_Cordic_values is
        variable v_K_angels : t_Cordic_values;
    begin     
        for n_i in 0 to VALUE_SIZE - 1 loop
            v_K_angels(n_i) := arctan(2.0**(-1.0 * real(n_i)));
        end loop;
        return v_K_angels;
    end f_Calc_Angels;
    
    function f_Conv_Real_to_Int(r_Cordic_values : t_Cordic_values; VALUE_SIZE, MUL_COEFF : integer ) return t_Int_data is
        variable v_Int_data : t_Int_data;
    begin
        for n_i in 0 to VALUE_SIZE - 1 loop 
            v_Int_data(n_i) := integer(r_Cordic_values(n_i) * real(2**MUL_COEFF));
        end loop;
        return v_Int_data;        
    end f_Conv_Real_to_Int;     
    
    function f_Conv_Int_to_Std_Logic_Vector(r_Int_values : t_Int_data; VALUE_SIZE, DATA_SIZE : integer ) return t_Std_Logic_Vector_data is
        variable v_Std_Logic_Vector_data : t_Std_Logic_Vector_data;
    begin
        for n_i in 0 to VALUE_SIZE - 1 loop 
            v_Std_Logic_Vector_data(n_i) := conv_std_logic_vector(r_Int_values(n_i), DATA_SIZE);
        end loop;
        return v_Std_Logic_Vector_data;        
    end f_Conv_Int_to_Std_Logic_Vector;       
    
    function f_min_index(VALUE_SIZE, ITERTATION : integer ) return integer is
    begin
        if VALUE_SIZE < ITERTATION then
            return VALUE_SIZE;
        else
            return ITERTATION;
        end if;            
    end f_min_index;        

    constant r_K_values : t_Cordic_values := f_Calc_K_values(VALUE_SIZE);
    constant r_Angels : t_Cordic_values := f_Calc_Angels(VALUE_SIZE);
    constant r_K_values_int : t_Int_data := f_Conv_Real_to_Int(r_K_values, VALUE_SIZE, MUL_COEFF);
    constant r_Angels_int : t_Int_data := f_Conv_Real_to_Int(r_Angels, VALUE_SIZE, MUL_COEFF);
    constant r_K_values_SLV_data : t_Std_Logic_Vector_data := f_Conv_Int_to_Std_Logic_Vector(r_K_values_int, VALUE_SIZE, DATA_SIZE);
    constant r_Angels_SLV_data : t_Std_Logic_Vector_data := f_Conv_Int_to_Std_Logic_Vector(r_Angels_int, VALUE_SIZE, DATA_SIZE);
    constant r_K_n : std_logic_vector(DATA_SIZE - 1 downto 0) :=  r_K_values_SLV_data(f_min_index(VALUE_SIZE, ITERTATION) - 1);
    constant r_PI : real := 3.14159_26535_89793_23846;
                                                          -- Value of pi
    signal r_V_vector : t_V_vector :=(conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE), 
                                      conv_std_logic_vector(0 * 2** MUL_COEFF, DATA_SIZE));
    signal r_POW_of_2 : std_logic_vector(DATA_SIZE - 1 downto 0) := 
                                      conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE) ; 
    signal r_Angel : std_logic_vector(DATA_SIZE - 1 downto 0) := r_Angels_SLV_data(0);
    
    signal r_teta : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_sigma : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_factor : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_teta_delta : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_V_new_0 : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_V_new_1 : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');    
    
    signal r_sin_data : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_cos_data : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
        
    signal r_data_vld : std_logic := '0';
    signal r_neg_flg : std_logic := '0';
    
    type t_Cordic_Cntrl is (IDLE, CHK_ANGLE, CHK_SIGMA, CALC_FACTOR, CALC_NEW_V, SET_NEW_V, UPDATE_PARAM, MUL_CONSTANT, DONE);
    signal r_Cordic_Cntrl : t_Cordic_Cntrl := IDLE;  
    signal n_i : integer := 0;  

begin

    out_sin_data <= r_sin_data;
    out_cos_data <= r_cos_data;
    out_data_vld <= r_data_vld;
    
    process(in_clk, in_rst, in_strt)
    begin
        if in_rst = '1' then
            r_Cordic_Cntrl <= IDLE;
            r_V_vector <= (conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE), 
                           conv_std_logic_vector(0 * 2** MUL_COEFF, DATA_SIZE));
            r_POW_of_2 <=  conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE) ; 
            r_Angel <= r_Angels_SLV_data(0);
            r_teta <= (others => '0');
            r_teta_delta <= (others => '0'); 
            r_sigma <= (others => '0');
            r_factor <= (others => '0'); 
            r_V_new_0 <= (others => '0');
            r_V_new_1 <= (others => '0');
            r_sin_data <= (others => '0'); 
            r_cos_data <= (others => '0');
            r_data_vld <= '0';
            r_neg_flg <= '0';
            n_i <= 0;
            
        elsif rising_edge(in_clk) then
            r_data_vld <= '0';
            case r_Cordic_Cntrl is  
                when IDLE =>
                    if in_strt = '1' then
                        r_teta <= in_teta; 
                        r_V_vector <= (conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE), 
                                       conv_std_logic_vector(0 * 2** MUL_COEFF, DATA_SIZE));
                        r_POW_of_2 <=  conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE) ; 
                        r_Angel <= r_Angels_SLV_data(0);
                        r_Cordic_Cntrl <= CHK_ANGLE;                     
                    end if;
                
                when CHK_ANGLE =>
                    if r_teta < conv_std_logic_vector(integer(((-r_PI/2.0) * real(2**MUL_COEFF))), DATA_SIZE) then
                        r_teta <= r_teta + conv_std_logic_vector(integer(((r_PI) * real(2**MUL_COEFF))), DATA_SIZE); 
                        r_neg_flg <= '1';                  
                    elsif r_teta > conv_std_logic_vector(integer(((r_PI/2.0) * real(2**MUL_COEFF))), DATA_SIZE) then
                        r_teta <= r_teta - conv_std_logic_vector(integer(((r_PI) * real(2**MUL_COEFF))), DATA_SIZE);
                        r_neg_flg <= '1';
                    end if;
                    r_Cordic_Cntrl <= CHK_SIGMA;
                
                when CHK_SIGMA =>    
                    if r_teta < 0 then
                        r_sigma <= (conv_std_logic_vector(-1 * 2** MUL_COEFF, DATA_SIZE));
                    else
                        r_sigma <= (conv_std_logic_vector(1 * 2** MUL_COEFF, DATA_SIZE));
                    end if;
                    r_Cordic_Cntrl <= CALC_FACTOR;
                    
                when CALC_FACTOR =>
                    r_factor <= r_sigma * r_POW_of_2;   
                    r_Cordic_Cntrl <= CALC_NEW_V;
                    
                when CALC_NEW_V => 
                    r_V_new_0 <= conv_std_logic_vector(2**MUL_COEFF, DATA_SIZE) *  r_V_vector(0) - 
                                 r_V_vector(1) * r_factor(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF); 
                                      
                    r_V_new_1 <= conv_std_logic_vector(2**MUL_COEFF, DATA_SIZE) *  r_V_vector(1) + 
                                 r_V_vector(0) * r_factor(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);   
                    r_Cordic_Cntrl <= SET_NEW_V;
                    
                when SET_NEW_V =>
                     r_V_vector(0) <= r_V_new_0(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);   
                     r_V_vector(1) <= r_V_new_1(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
                     r_teta_delta <= r_sigma * r_Angel; 
                     r_Cordic_Cntrl <= UPDATE_PARAM;
                     
                when UPDATE_PARAM =>     
                    r_teta <= r_teta - r_teta_delta(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
                    r_POW_of_2 <= '0' & r_POW_of_2(DATA_SIZE - 1 downto 1);
                    if n_i + 2 > VALUE_SIZE then
                        r_Angel <= '0' & r_Angel(DATA_SIZE - 1 downto 1);
                        
                    else
                        r_Angel <= r_Angels_SLV_data(n_i + 1);
                    end if;
                    if n_i = ITERTATION - 1 then
                        n_i <= 0;
                        r_Cordic_Cntrl <= MUL_CONSTANT;
                    else
                        n_i <= n_i + 1;
                        r_Cordic_Cntrl <= CHK_ANGLE;
                    end if;
                
                when MUL_CONSTANT =>
                    r_V_new_0 <= r_V_vector(0) * r_K_n;
                    r_V_new_1 <= r_V_vector(1) * r_K_n;
                    r_Cordic_Cntrl <= DONE;
                    
                when DONE =>  
                    if r_neg_flg = '1' then
                        r_cos_data <= not r_V_new_0(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF) + 1;
                        r_sin_data <= not r_V_new_1(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF) + 1;
                        r_neg_flg <= '0';
                    else
                        r_cos_data <= r_V_new_0(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
                        r_sin_data <= r_V_new_1(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);                                            
                    end if;
                    r_data_vld <= '1';
                    r_Cordic_Cntrl <= IDLE;          
                when others => NULL;
            end case;
        end if;
        
    end process;
    
end Behavioral;

Aşağıda döndürme modunda sinüs ve cosinüs değerlerini hesaplayan cordic_v1.vhd VHDL kodunun benzetimini yapılabilmesi için oluşturulmuş sınama kodları verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.MATH_REAL.ALL;


entity tb_cordic is
end tb_cordic;

architecture Behavioral of tb_cordic is

    component cordic_v1
        generic(
            ITERTATION : integer := 2;
            VALUE_SIZE : integer := 8;
            MUL_COEFF : integer := 12; -- 2^MULL_COEFF;
            DATA_SIZE : integer := 16 -- DATA_SIZE > MUL_COEFF
        );
        Port ( 
            in_clk : in std_logic;
            in_rst : in std_logic;
            in_strt : in std_logic;
            in_teta : in std_logic_vector(DATA_SIZE - 1 downto 0);  
            out_cos_data : out std_logic_vector(DATA_SIZE - 1 downto 0); 
            out_sin_data : out std_logic_vector(DATA_SIZE - 1 downto 0);
            out_data_vld : out std_logic
        );
    end component;    
    
    constant CLK_PERIOD : time := 10 ns;
    constant r_PI : real := 3.14159_26535_89793_23846;
    
    constant ITERTATION : integer := 24;
    constant VALUE_SIZE : integer := 24;
    constant MUL_COEFF : integer := 24; -- 2^MULL_COEFF;
    constant DATA_SIZE : integer := 29; -- DATA_SIZE > MUL_COEFF +2    
    signal in_clk : std_logic := '0';
    signal in_strt : std_logic := '0';
    signal in_teta : std_logic_vector(DATA_SIZE - 1 downto 0);
    signal n_i : integer := 0;
    signal r_sin_data : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_cos_data : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_data_vld : std_logic := '0';
    type t_Cntrl is (SET_TETA,WAIT_DATA, DONE );
    signal r_Cntrl : t_Cntrl := SET_TETA;
    signal r_data_cos_real : real := 0.0;
    signal r_data_sin_real : real := 0.0;
    signal r_mse_cos : real := 0.0;
    signal r_mse_sin : real := 0.0;
    
begin
    
    process
    begin
        in_clk <= '1';
        wait for CLK_PERIOD / 2;
        in_clk <= '0';
        wait for CLK_PERIOD / 2;                
    end process;
    
    process(in_clk)
    begin
        if rising_edge(in_clk) then
            in_strt <= '0';
            case r_Cntrl is
                when SET_TETA =>
                    in_teta <= conv_std_logic_vector(integer(((real(n_i) * r_PI/6.0) * real(2**MUL_COEFF))), DATA_SIZE);
                    in_strt <= '1';
                     r_Cntrl <= WAIT_DATA;
                when WAIT_DATA =>
                    if r_data_vld = '1' then
                        r_data_cos_real <= real(conv_integer(r_cos_data)) / real(2**MUL_COEFF);
                        r_data_sin_real <= real(conv_integer(r_sin_data)) / real(2**MUL_COEFF);
                        
                        r_mse_cos <= r_mse_cos + (cos(real(n_i) * r_PI/6.0) - (real(conv_integer(r_cos_data)) / real(2**MUL_COEFF)))**2.0 / 6.0;
                        r_mse_sin <= r_mse_sin + (sin(real(n_i) * r_PI/6.0) - (real(conv_integer(r_sin_data)) / real(2**MUL_COEFF)))**2.0 / 6.0;
                        if n_i = 5 then
                            r_Cntrl <= DONE;
                            n_i <= 0;                           
                        else
                            r_Cntrl <= SET_TETA;
                            n_i <= n_i + 1;
                        end if;
                        
                    end if;
                when DONE =>
                    null;
                when OTHERS => NULL;    
            end case;
        end if;
        
    end process;


    cordic_map : cordic_v1 generic map(
        ITERTATION => ITERTATION,
        VALUE_SIZE => VALUE_SIZE,
        MUL_COEFF => MUL_COEFF, -- 2^MULL_COEFF;
        DATA_SIZE => DATA_SIZE -- DATA_SIZE > MUL_COEFF + 2
    )
    port map(
        in_clk => in_clk,
        in_rst => '0',
        in_strt => in_strt,
        in_teta => in_teta, 
        out_cos_data => r_cos_data,
        out_sin_data => r_sin_data,
        out_data_vld => r_data_vld
    );
    
    


end Behavioral;

Vektörel Mod (Vectorial Mod)

Vektörel dairesel açı dönüşüm işlemlerinde temel amaç yazımızda verilen ilk denklemde tanımlanan y değişkeni değerini sıfıra yaklaştırmaktır .

Başlangıç değerleri x=1 ve z=0 seçildiği durumda kartezyen koordinat değerlerimin polar koordinat değerlerine dönüşümü yapılmaktadır .

K_i parametresi aşağıdaki gibi hesaplanmaktadır.

Aşağıda vektörel modda genlik ve açı değerlerini hesplayan VHDL kodları verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.MATH_REAL.ALL;

entity cordic_rec2pol is
    generic(
		ITERTATION : integer := 20;
		VALUE_SIZE : integer := 20;
		MUL_COEFF : integer := 18; -- 2^MULL_COEFF;
		DATA_SIZE : integer := 24 -- DATA_SIZE > MUL_COEFF +2
	);
	port(
		in_clk : in std_logic;
		in_rst : in std_logic;
		in_strt : in std_logic;
		in_data_real : in std_logic_vector(DATA_SIZE - 1 downto 0);
		in_data_imag : in std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_r : out std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_phase : out std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_vld : out std_logic
	);
	
end cordic_rec2pol;

architecture Behavioral of cordic_rec2pol is
    
    constant c_PI : real := 3.14159_26535_89793_23846;   
    type t_Cordic_values is array (0 to VALUE_SIZE - 1) of real;
    type t_Std_Logic_Vector_data is array (0 to VALUE_SIZE - 1) of std_logic_vector(DATA_SIZE - 1 downto 0);
    type t_Int_data is array (0 to VALUE_SIZE - 1) of integer;
	
    function f_Conv_Real_to_Int(r_Cordic_values : t_Cordic_values; VALUE_SIZE, MUL_COEFF : integer ) return t_Int_data is
        variable v_Int_data : t_Int_data;
    begin
        for n_i in 0 to VALUE_SIZE - 1 loop 
            v_Int_data(n_i) := integer(r_Cordic_values(n_i) * real(2**MUL_COEFF));
        end loop;
        return v_Int_data;
        
    end f_Conv_Real_to_Int;   	
	
    function f_Conv_Int_to_Std_Logic_Vector(r_Int_values : t_Int_data; VALUE_SIZE, DATA_SIZE : integer ) return t_Std_Logic_Vector_data is
        variable v_Std_Logic_Vector_data : t_Std_Logic_Vector_data;
    begin
        for n_i in 0 to VALUE_SIZE - 1 loop 
            v_Std_Logic_Vector_data(n_i) := conv_std_logic_vector(r_Int_values(n_i), DATA_SIZE);
        end loop;
        return v_Std_Logic_Vector_data;
        
    end f_Conv_Int_to_Std_Logic_Vector;   	
	
    -- ****
    function f_Calc_tp_values(VALUE_SIZE : integer) return t_Cordic_values is
        variable v_tp_values : t_Cordic_values;
    begin
        v_tp_values(0) := 1.0;
        v_tp_values(1) := 1.0;
        v_tp_values(2) := 1.0;        
        for n_i in 3 to VALUE_SIZE - 1 loop
            v_tp_values(n_i) := v_tp_values(n_i - 1) / 2.0;
        end loop;
        return v_tp_values;
    end f_Calc_tp_values;
    
    constant c_tp_values : t_Cordic_values := f_Calc_tp_values(VALUE_SIZE);
    constant c_tp_int_values : t_Int_data := f_Conv_Real_to_Int(c_tp_values, VALUE_SIZE, MUL_COEFF);
	constant c_tp_std_values : t_Std_Logic_Vector_data := f_Conv_Int_to_Std_Logic_Vector(c_tp_int_values, VALUE_SIZE, DATA_SIZE);
	
    -- ****
    -- ****
    function f_Calc_atantp_values(c_tp_values : t_Cordic_values  ;VALUE_SIZE : integer) return t_Cordic_values is
        variable v_atantp_values : t_Cordic_values;
    begin
        v_atantp_values(0) := c_PI / 4.0;
        v_atantp_values(1) := c_PI / 4.0;
        v_atantp_values(2) := c_PI / 4.0;        
        for n_i in 3 to VALUE_SIZE - 1 loop
            v_atantp_values(n_i) :=  arctan(c_tp_values(n_i));
        end loop;
        return v_atantp_values;
    end f_Calc_atantp_values;
    
    constant c_atantp_values : t_Cordic_values := f_Calc_atantp_values(c_tp_values, VALUE_SIZE);
	constant c_atantp_int_values : t_Int_data := f_Conv_Real_to_Int(c_atantp_values, VALUE_SIZE, MUL_COEFF);
	constant c_atantp_std_values : t_Std_Logic_Vector_data := f_Conv_Int_to_Std_Logic_Vector(c_atantp_int_values, VALUE_SIZE, DATA_SIZE);
    -- ****    
    -- ****
    function f_Calc_K_values(c_atantp_values : t_Cordic_values; VALUE_SIZE : integer) return real is
        variable v_K : real;
    begin
        v_K := sqrt(2.0) / 4.0;     
        for n_i in 3 to VALUE_SIZE - 1 loop
            v_K := v_K * cos(c_atantp_values(n_i));
        end loop;
        return v_K;
    end f_Calc_K_values;
    
    constant c_K : real := f_Calc_K_values(c_atantp_values, VALUE_SIZE);
	constant c_K_std : std_logic_vector(DATA_SIZE - 1 downto 0) := conv_std_logic_vector(integer(c_K * real(2**MUL_COEFF)), DATA_SIZE);
    -- ****      
	
    type t_Cordic_Cntrl is (IDLE, SET_TX, MUL_PARAM, ADD_PARAM, CHK_ITER, MUL_CONSTANT, DONE);
    signal r_Cordic_Cntrl : t_Cordic_Cntrl := IDLE;  	
	
	signal r_Z : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_TX : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_real : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_r : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_real_mul : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_real_add : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_imag : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_phase : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
	signal r_data_imag_add : std_logic_vector(2 * DATA_SIZE - 1 downto 0) := (others => '0');
	signal n_i : integer range 0 to VALUE_SIZE := 0;
	signal r_data_vld : std_logic := '0';
    
begin

	out_data_r <= r_data_r;
	out_data_phase <= r_data_phase;
	out_data_vld <= r_data_vld;

    process(in_clk, in_rst, in_strt)
    begin
        if in_rst = '1' then
            r_Cordic_Cntrl <= IDLE;
			r_Z <= (others => '0');
			r_TX <= (others => '0');
			r_data_real <= (others => '0');
			r_data_r <= (others => '0');
			r_data_real_add <= (others => '0');
			r_data_real_mul <= (others => '0');
			r_data_imag <= (others => '0');
			r_data_phase <= (others => '0');
			r_data_imag_add <= (others => '0');
            r_data_vld <= '0';
			n_i <= 0;
            
        elsif rising_edge(in_clk) then
            r_data_vld <= '0';
            case r_Cordic_Cntrl is  
                when IDLE =>				
                    if in_strt = '1' then
						r_Z <= (others => '0');
						r_TX <= (others => '0');
						r_data_real <= in_data_real;
						r_data_imag <= in_data_imag;
						n_i <= 0;
                        r_Cordic_Cntrl <= SET_TX;                     
                    end if;
                
                when SET_TX =>
					r_TX <= r_data_real;
					r_Cordic_Cntrl <= MUL_PARAM;  
					
				when MUL_PARAM =>	
					r_data_real_add <= r_data_imag * c_tp_std_values(n_i);
					r_data_imag_add <= r_TX * c_tp_std_values(n_i);
					r_Cordic_Cntrl <= ADD_PARAM; 
					
				when ADD_PARAM =>	
					if r_data_imag(r_data_imag'high) = '1' then
						r_data_real <= r_data_real - r_data_real_add(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
						r_data_imag <= r_data_imag + r_data_imag_add(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
						r_Z <= r_Z - c_atantp_std_values(n_i);
					else
						r_data_real <= r_data_real + r_data_real_add(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
						r_data_imag <= r_data_imag - r_data_imag_add(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
						r_Z <= r_Z + c_atantp_std_values(n_i);					
					end if;
					r_Cordic_Cntrl <= CHK_ITER; 

				when CHK_ITER =>		
					if n_i = ITERTATION - 1 then
                        n_i <= 0;
                        r_Cordic_Cntrl <= MUL_CONSTANT;
                    else
                        n_i <= n_i + 1;
                        r_Cordic_Cntrl <= SET_TX;
                    end if;
                
                when MUL_CONSTANT =>
                    r_data_real_mul <= r_data_real * c_K_std;
                    r_Cordic_Cntrl <= DONE;
                    
                when DONE =>  
					r_data_vld <= '1';
                    r_data_r <= r_data_real_mul(MUL_COEFF + DATA_SIZE - 1 downto MUL_COEFF);
					r_data_phase <= r_Z;
                    r_Cordic_Cntrl <= IDLE;          
					
                when others => NULL;
            end case;
        end if;
        
    end process;

end Behavioral;

Aşağıda vektörel modda genlik ve açı değerlerini hesaplayan cordic_rec2pol.vhd VHDL kodunun benzetimini yapılabilmesi için oluşturulmuş sınama kodları verilmiştir.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_SIGNED.ALL;
use IEEE.MATH_REAL.ALL;

entity tb_cordic_rec_pol is
end tb_cordic_rec_pol;

architecture Behavioral of tb_cordic_rec_pol is

	component cordic_rec2pol
    generic(
		ITERTATION : integer := 2;
		VALUE_SIZE : integer := 8;
		MUL_COEFF : integer := 12; -- 2^MULL_COEFF;
		DATA_SIZE : integer := 16 -- DATA_SIZE > MUL_COEFF +2
	);
	port(
		in_clk : in std_logic;
		in_rst : in std_logic;
		in_strt : in std_logic;
		in_data_real : in std_logic_vector(DATA_SIZE - 1 downto 0);
		in_data_imag : in std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_r : out std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_phase : out std_logic_vector(DATA_SIZE - 1 downto 0);
		out_data_vld : out std_logic
	);
	end component;
	
    constant CLK_PERIOD : time := 10 ns;
    constant r_PI : real := 3.14159_26535_89793_23846;
    
    constant ITERTATION : integer := 24;
    constant VALUE_SIZE : integer := 24;
    constant MUL_COEFF : integer := 24; -- 2^MULL_COEFF;
    constant DATA_SIZE : integer := 30; -- DATA_SIZE > MUL_COEFF +2    
    signal in_clk : std_logic := '0';
    signal in_strt : std_logic := '0';
    signal in_data_real : std_logic_vector(DATA_SIZE - 1 downto 0);
	signal in_data_imag : std_logic_vector(DATA_SIZE - 1 downto 0);
    signal n_i : integer := 0;
    signal r_data_r : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0'); 
    signal r_data_phase : std_logic_vector(DATA_SIZE - 1 downto 0) := (others => '0');
    signal r_data_vld : std_logic := '0';
    type t_Cntrl is (SET_TETA,WAIT_DATA, DONE );
    signal r_Cntrl : t_Cntrl := SET_TETA;
    signal r_data_r_real : real := 0.0;
    signal r_data_phase_real : real := 0.0;
    
    signal r_mse_mag : real := 0.0;
    signal r_mse_teta : real := 0.0;


begin

    
    process
    begin
        in_clk <= '1';
        wait for CLK_PERIOD / 2;
        in_clk <= '0';
        wait for CLK_PERIOD / 2;                
    end process;
	
	process(in_clk)
    begin
        if rising_edge(in_clk) then
            in_strt <= '0';
            case r_Cntrl is
                when SET_TETA =>
                    in_data_real <= conv_std_logic_vector( integer(real(n_i) / 5.0 * real(2**MUL_COEFF)), DATA_SIZE);
					in_data_imag <= conv_std_logic_vector( integer(real(5 - n_i) / 5.0 * real(2**MUL_COEFF)), DATA_SIZE);
                    in_strt <= '1';
                     r_Cntrl <= WAIT_DATA;
                when WAIT_DATA =>
                    if r_data_vld = '1' then
                        r_data_r_real <= real(conv_integer(r_data_r)) / real(2**MUL_COEFF);
                        r_data_phase_real <= real(conv_integer(r_data_phase)) / real(2**MUL_COEFF);
                        r_mse_mag  <= r_mse_mag + (sqrt((real(n_i)/5.0)**2 + (real(5 - n_i) / 5.0)**2) -
                         (real(conv_integer(r_data_r)) / real(2**MUL_COEFF)))**2.0 / 6.0;
                        
                        r_mse_teta <= r_mse_teta + (arctan(real(5 - n_i), real(n_i)) -
                         (real(conv_integer(r_data_phase)) / real(2**MUL_COEFF)))**2.0 / 6.0;
                        
                        
                        if n_i = 5 then
                            r_Cntrl <= DONE;
                            n_i <= 0;                           
                        else
                            r_Cntrl <= SET_TETA;
                            n_i <= n_i + 1;
                        end if;
                        
                    end if;
                when DONE =>
                    null;
                when OTHERS => NULL;    
            end case;
        end if;
	end process;

	cordic_rec2pol_map : cordic_rec2pol generic map(
        ITERTATION => VALUE_SIZE,
        VALUE_SIZE => VALUE_SIZE,
        MUL_COEFF => MUL_COEFF, -- 2^MULL_COEFF;
        DATA_SIZE => DATA_SIZE -- DATA_SIZE > MUL_COEFF + 2
    )
    port map(
        in_clk => in_clk,
        in_rst => '0',
        in_strt => in_strt,
        in_data_real => in_data_real, 
		in_data_imag => in_data_imag, 
        out_data_r => r_data_r,
        out_data_phase => r_data_phase,
        out_data_vld => r_data_vld
    );
    
	
end Behavioral;

NOT: Bu yazıda, Suhap ŞAHİN, Burcu Kır Savaş, “Jenerik CORDIC Algoritmasının FPGA’DA Donanımsal Gerçeklenmesi”,  Sakarya Üniversitesi Fen Bilimleri Enstitüsü Dergisi, 27 (1), 2017, çalışmadan direk alıntı yapılmış ve faydalanılmıştır. Dr. Suhap Şahin aynı zamanda doktora tez Hocam’dır. Kendisinin izni ile konu anlatımında bilgiler kullanılmıştır.

MATLAB ile Zaman-Frekans Değişiminin Gösterilmesi

MATLAB ile zaman ile frekans değişimlerini gözlemlemek amacı ile spectogram fonksiyonu sıklıkla tercih edilmektedir. Bu yazıda kendi spektogram fonksiyonunumuzu oluşturup gösterimini gerçekleştireceğiz. Aşağıda mySpectogram fonksiyonu giriş verisine ait zaman-frekans değişimlerini örnekleme frekansı, FFT boyutu ve örtüşme değerlerine bağlı olarak hesaplamaktadır.

  1. function [oData X Y] = mySpectogram(iData,f_s,FFT_size,FFT_overlap)
  2. FFT_res = f_s / FFT_size;
  3. [X, Y] = meshgrid( 0 : FFT_res : (FFT_size / 2 - 1) * FFT_res,...
  4. ((1 - FFT_overlap) * FFT_size : (1 - FFT_overlap) *...
  5. FFT_size : length(i_Data) - FFT_overlap * FFT_size ) / f_s) ;
  6. X = X / 1000;
  7. Y = Y;
  8. n_j = 0;
  9. for n_i = 1 : (1 - FFT_overlap) * FFT_size : length(iData) - FFT_size
  10. n_j = n_j + 1;
  11. Data = iData(n_i : n_i + FFT_size - 1);
  12. oData(n_j, :) = abs(fft(Data, FFT_size));
  13. end

Aşağıda verilen kodda 1 KHz örnekleme frekansında 1 sn’lik 50 Hz frekansında sinüs sinyalinin zaman frekans değişimi gösterilmektedir.

1 saniyelik 50 Hz frekasnında sinüs sinyali

Aşağıda verilen grafiktende görüleceği üzere tüm zaman boyunca 50 Hz’lik bir sinyal mevctur.

  1. f_s = 1e3;
  2. FFT_size = 2^8;
  3. FFT_overlap = 0.5;
  4. FFT_res = f_s / FFT_size;
  5. f= 50;
  6. n_t = 1/f_s : 1/f_s : 1;
  7. Data = sin(2 * pi * n_t * f);
  8. n_t = (1 : length(Data)) / f_s;
  9. figure, plot(n_t, Data);
  10. xlabel('Saniye');
  11. title('Data');
  12. grid on;
  13. [oData X Y] = mySpectogram(Data,f_s,FFT_size,FFT_overlap);
  14. figure, pcolor(X, Y, oData(:, 1 : FFT_size / 2))
  15. shading interp
  16. xlabel('Frekans (Hz)');
  17. ylabel('Saniye');

MATLAB ile FFT Alma İşlemi

MATLAB ile bir boyutlu FFT alma işlemlerinin gerçekleştirilmesinde fft komutu kullanılmaktadır. FFT sonuçlarının gösteriminde yaşanan en büyük sorunlardan biri sonuçlarda gösterilen freknas binlerinin hangi frekans değerine karşılık geldiğidir. Bu durum FFT çözünürlüğünün bulunması ile yani, örnekleme frekansının FFT boyutuna bölünmesi ile gerçekleştirilrimektedir (Kodda 4. satır).

FFT analizi sonucunda elde edilen frekans bilgisi 14. satırdaki gibi hesaplanmaktadır.

Aşağıda verilen kodda oluşturulan 1 sn’lik 20 KHz’lik sinüs sinyalinin FFT çıktısı hesaplanmıitır.

  1. f_s = 100e3;
  2. FFT_size = 2^14;
  3. FFT_res = f_s / FFT_size;
  4. f= 20e3;
  5. n_t = 1/f_s : 1/f_s : 1;
  6. Data = sin(2 * pi * n_t * f);
  7. n_t = (1 : length(Data)) / f_s;
  8. figure, plot(n_t, Data);
  9. xlabel('Saniye');
  10. title('Data');
  11. grid on;
  12. Data_fft = 2 * abs(fft(Data, FFT_size)) / FFT_size;
  13. n_f = FFT_res * (0 : length(Data_fft) / 2 - 1);
  14. figure, plot(n_f, Data_fft(1 : length(Data_fft) / 2));
  15. xlabel('Frekans (Hz)');
  16. title('Data FFT');
  17. grid on;