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 sınır aralığında tanımlı CORDIC algoritması genel ifadesi verilmiştir.

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

ei 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ı μ 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 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ı θ‘yı vermelidir. Aşağıda verilen denklemde tanımlı S parametresi -1, 1 değerlerini almaktadır.

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

Yukarıdaki ifadeleri kullanarak denklemi güncellediğimizde

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

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;
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. Kendisinin izni ile konu anlatımında bilgiler kullanılmıştır.