- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello i am trying to use the cordic core { http://opencores.org/project,cordic }
with no sucess. Say i have a complex number of 4 + 5i. I have inserted 1000 as the Xi input and 1001 as the Yi input But the r2p_corproc is returning me wrong R and A values. It should be r = 6.4031 angle = 0.8961 {matlab} but instead i get r= 103 a= 146811 My test bench is :SIGNAL real_i : signed(15 downto 0) := "00000000"& "00000100" ;
SIGNAL imag_i : signed(15 downto 0) := "00000000"& "00000101" ;
SIGNAL ena_r_i : std_logic := '1';
SIGNAL rst_negado : std_logic := '1';
SIGNAL result_ang_o : unsigned(19 downto 0);
SIGNAL result_mag_o : signed(19 downto 0) ;
SIGNAL test_clk: std_logic := '0';
-- component instatiation
component rl131 is
port(
clk_i : in std_logic;
rst_i_n : in std_logic;
ena_i : in std_logic;
Real_i : in signed(15 downto 0);
Imag_i : in signed(15 downto 0);
Rout_o : out unsigned(19 downto 0);
Aout_o : out signed(19 downto 0)
);
end component;
BEGIN
dut : rl131
port map(
clk_i => test_clk,
ena_i => ena_r_i,
rst_i_n => rst_negado,
Real_i => real_i,
Imag_i => imag_i,
Rout_o => result_ang_o,
Aout_o => result_mag_o);
test_clk <= not test_clk after clkperiod/2;
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
the outputs are 20 bits, 16 bits integer and 4 bits fraction so:
magnitude of 103 (67 in hex) means 6.7 and Angle of 146811 (23d7b) i.e 23d7.b degrees = 9175 and this wraps 25 times to 175 degrees. your figure of .8961 is in rads I believe so becomes .8961 * 180/pi = 51 degrees. So at least magnitude seems working. The angle may not actually have been meant to be wrapped up, it then does not need 16 bits for integer part (range is 0 to 360) i.e. only 9 bits may represent it and the rest 11 bits as fraction hence A = 146811/2^11 = 72 degrees which I think is a bit better than 175 !!! The documentation is poor or the code does not work I am afraid.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi kas thanks for the help but it is 6.4375 and not 6.7 :P
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>> magnitude of 103 (67 in hex) means 6.7
Additional info: 6.7 in fixed decimal (16.4) representation is the real value of 6.4375. In binary representation 103 = 1100111 or 0000000000000110.0111 in fixed decimal (16.4). Taking the last 4 digits as the fractional part gives: 0 * (0.5) + 1 * (0.25) + 1 * (0.125) + 1 * (0.0625) = .4375, so you have a fixed point representation of 6.4375 which is slightly over matlab's result of 6.4031. A 6.6 fixed decimal (16.4) value is a real value of 6.375 which is slightly under, but closer to the actual result from matlab. I think the cordic routine isn't expected to get the last fractional digit perfect, so it appears that may be working for your r value. I haven't tried to analyze the angle portion, nor do I know how at this point in time.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
lol, aparado. you posted while I was trying to figure out the angle portion....I lied....I tried to analyze it. :)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks nails. true, 7 out of 16 is 7/16 = .4375
The angle seems wrong completely- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A second thought about angle. It could be that representation is such that 2^16 = 360 degrees hence in your case 9175 => 360 * 9175/2^16
= 50.4 degrees , very close to Matlab of 51.3 degrees- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ok now i am trying to do my own CORDIC core to have the magnitude and phase value or a real/imaginary phasor.
I am following this algorithm: http://www.dspguru.com/dsp/faqs/cordic and trying to make a RTL out of it. My matlab code is working and is the followingfunction v = cordic(real, imaginaria,n)
% This function computes v = (beta in radians)
% using n iterations. Increasing n will increase the precision.
multiplier = 2^22;
tmp_real = 0;
if (real < 0)
tmp_real = real;
if imaginaria > 0
real = imaginaria;
imaginaria = -tmp_real;
acc_phase_rads = -(pi/2)* multiplier ;
else
real = -imaginaria;
imaginaria = tmp_real;
acc_phase_rads = pi/2 * multiplier;
end;
else
acc_phase_rads = 0;
end;
% Initialization of tables of constants used by CORDIC
% need a table of arctangents of negative powers of two, in radians:
% angles = atan(2.^-(0:27));
% and a table of products of reciprocal lengths of vectors :
ka = 1;
for j=1:n;
Kvalues(j) = ka
angles(j) = atan(ka)
ka = ka * 0.5;
end;
for l=1:n;
K = Kvalues(l) * multiplier;
phase_rads = angles(l) * multiplier;
tmp_real = real;
if (imaginaria >=0)
real = (real*multiplier + imaginaria * K)/multiplier;
imaginaria = (multiplier*imaginaria - tmp_real * K)/multiplier;
acc_phase_rads = (acc_phase_rads - phase_rads );
else
real = (real*multiplier - imaginaria * K)/multiplier;
imaginaria = (imaginaria*multiplier + tmp_real * K)/multiplier;
acc_phase_rads = (acc_phase_rads + phase_rads);
end;
end;
result_phase_rads = -acc_phase_rads/multiplier
result_mag = real * (1/1.6468)
return
My VHDL code at the moment is the following
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_signed.all;
-- entity declaration
entity cordic_V1 is
port(
-- system signals
clk_i : in std_logic;
rst_i_n : in std_logic;
-- interface signals
ena_i : in std_logic;
real_i : in std_logic_vector(31 downto 0);
imag_i : in std_logic_vector(31 downto 0);
fase_o : out std_logic_vector(31 downto 0);
mag_o : out std_logic_vector(31 downto 0);
finish_cordic : out std_logic
);
end cordic_V1;
begin
angulo_inst : angulo_atan
port map(
clk_i => clk_i,
rst_i_n => rst_i_n,
indice_i => std_logic_vector(indice),
angulo_o => angulo_indice);
ganho_inst : ganho_k
port map(
clk_i => clk_i,
rst_i_n => rst_i_n,
indice_i => std_logic_vector(indice_2),
ganho_o => ganho_indice);
fase_o <= std_logic_vector (fase_o_reg(31 downto 0));
mag_o <= std_logic_vector (mag_o_reg(31 downto 0));
finish_cordic <= finish_cordic_reg;
-- State machine process
process (rst_i_n, clk_i) is
begin
if (rst_i_n = '0') then
...
elsif rising_edge(clk_i) then
state_core <= state_core_next;
indice <= indice_next;
indice_2 <= indice_2_next;
parte_real <= parte_real_next;
parte_imaginaria <= parte_imaginaria_next;
temp_parte_real <= temp_parte_real_next;
fase_o_reg <= fase_o_reg_next;
mag_o_reg <= mag_o_reg_next;
phase_rads <= phase_rads_next;
acc_phase_rads <= acc_phase_rads_next;
K_reg <= K_reg_next;
tmp_mult_im_k <= tmp_mult_im_k_next;
tmp_mult_re_k <= tmp_mult_re_k_next;
tmp_operacoes_reg <= tmp_operacoes_reg_next;
tmp_operacoes_acc_reg <= tmp_operacoes_acc_reg_next;
finish_cordic_reg <= finish_cordic_reg_next;
end if;
end process;
process (state_core, indice, indice_2, parte_real, parte_imaginaria, temp_parte_real,
fase_o_reg, mag_o_reg, phase_rads, acc_phase_rads, K_reg, tmp_mult_im_k,
tmp_mult_re_k, tmp_operacoes_reg, tmp_operacoes_acc_reg, real_i, imag_i, ganho_indice, angulo_indice, finish_cordic_reg)
begin
state_core_next <= state_core;
indice_next <= indice;
indice_2_next <= indice_2;
p...
case state_core is
when INIT =>
-- initialize all the registers
indice_next <= (others => '0');
i...
state_core_next <= CORRIGE_Q_P1;
when CORRIGE_Q_P1 =>
parte_real_next <= real_i & ZERO_STUFF;
parte_imaginaria_next <= imag_i & ZERO_STUFF;
state_core_next <= CORRIGE_Q_P2;
when CORRIGE_Q_P2 =>
if parte_real(52) = '1' then
temp_parte_real_next <= parte_real;
state_core_next <= CORRIGE_Q_P3;
else
acc_phase_rads_next <= (others => '0');
state_core_next <= CALCULA_CORDIC_P1;
end if;
when CORRIGE_Q_P3 =>
if parte_imaginaria(52) = '0' then
parte_imaginaria_next <= not (temp_parte_real) ;--+ 1;
else
parte_real_next <= not (parte_imaginaria);-- + 1;
end if;
state_core_next <= CORRIGE_Q_P4;
when CORRIGE_Q_P4 =>
if parte_imaginaria(52) = '0' then
parte_real_next <= parte_imaginaria;
parte_imaginaria_next <= parte_imaginaria + 1;
acc_phase_rads_next <= "111111111" & pi_2 & ZERO_STUFF; -- -pi_2
else
parte_real_next <= parte_real + 1;-- + 1;
parte_imaginaria_next <= temp_parte_real;
acc_phase_rads_next <= "000000000" & pi_2 & ZERO_STUFF;
end if;
state_core_next <= CALCULA_CORDIC_P1;
when CALCULA_CORDIC_P1 =>
K_reg_next <= "000000000" & ZERO_STUFF & ganho_indice;
phase_rads_next <= "000000000" & ZERO_STUFF & angulo_indice;
temp_parte_real_next <= parte_real;
state_core_next <= CALCULA_CORDIC_P2;
--tmp_operacoes_reg acc real
--tmp_operacoes_acc_reg acc imaginario
when CALCULA_CORDIC_P2 =>
tmp_mult_im_k_next <= parte_imaginaria * K_reg;
tmp_mult_re_k_next <= temp_parte_real * K_reg;
state_core_next <= CALCULA_CORDIC_P2_1;
when CALCULA_CORDIC_P2_1 =>
if tmp_mult_im_k(105) = '0' then
tmp_mult_im_k_next <= ZERO_STUFF & tmp_mult_im_k(105 downto ZERO_STUFF'length);
tmp_mult_re_k_next <= ZERO_STUFF & tmp_mult_re_k(105 downto ZERO_STUFF'length) ;
else
tmp_mult_im_k_next <= ONE_STUFF & tmp_mult_im_k(105 downto ZERO_STUFF'length);
tmp_mult_re_k_next <= ONE_STUFF & tmp_mult_re_k(105 downto ZERO_STUFF'length) ;
end if;
state_core_next <= CALCULA_CORDIC_P3;
when CALCULA_CORDIC_P3 =>
if parte_imaginaria(52) = '0' then
tmp_operacoes_reg_next <= parte_real + tmp_mult_im_k;
tmp_operacoes_acc_reg_next <= parte_imaginaria - tmp_mult_re_k;
acc_phase_rads_next <= acc_phase_rads - phase_rads;
else
tmp_operacoes_reg_next <= parte_real - tmp_mult_im_k;
tmp_operacoes_acc_reg_next <= parte_imaginaria + tmp_mult_re_k;
acc_phase_rads_next <= acc_phase_rads + phase_rads;
end if;
state_core_next <= CALCULA_CORDIC_P4;
when CALCULA_CORDIC_P4 =>
if tmp_operacoes_reg(52) = '0' then
parte_real_next <= ZERO_STUFF & tmp_operacoes_reg(52 downto ZERO_STUFF'length);
else
parte_real_next <= ONE_STUFF & tmp_operacoes_reg(52 downto ZERO_STUFF'length);
end if;
if tmp_operacoes_acc_reg(52) = '0' then
parte_imaginaria_next <= ZERO_STUFF & tmp_operacoes_acc_reg(52 downto ZERO_STUFF'length);
else
parte_imaginaria_next <= ONE_STUFF & tmp_operacoes_acc_reg(52 downto ZERO_STUFF'length);
end if;
state_core_next <= CALCULA_CORDIC_P5;
when CALCULA_CORDIC_P5 =>
if indice < 24 then
indice_next <= indice + 1;
indice_2_next <= indice_2 + 1;
state_core_next <= CALCULA_CORDIC_P6;
elsif indice = 24 then
state_core_next <= FIM_P1;
end if;
when CALCULA_CORDIC_P6 =>
state_core_next <= CALCULA_CORDIC_P1;
when FIM_P1 =>
fase_o_reg_next <= not (ZERO_STUFF & acc_phase_rads(52 downto 21));
-- mag_o_reg_next <= parte_real;
-- finish_cordic <= '1';
state_core_next <= FIM_P2;
when FIM_P2 =>
fase_o_reg_next <= fase_o_reg + 1;
mag_o_reg_next <= parte_real;
finish_cordic_reg_next <= '1';
state_core_next <= INIT;
when others =>
state_core_next <= INIT;
end case;
end process;
end rtl_cordic;
any help is really welcome, i am having problem with negative angles in the middle of my calculos...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What kind of problems exactly? And just a remark:
--- Quote Start --- use ieee.numeric_std.all; use ieee.std_logic_signed.all; --- Quote End --- This is a bad idea, mixing numeric_std with one of the non standard std_logic_(un)signed gives weird results and problems. You'd better only include the numeric_std library and use the unsigned/signed types each time you need to do an arithmetic operation.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- What kind of problems exactly? And just a remark:This is a bad idea, mixing numeric_std with one of the non standard std_logic_(un)signed gives weird results and problems. You'd better only include the numeric_std library and use the unsigned/signed types each time you need to do an arithmetic operation. --- Quote End --- Actually it doesnt, its std_logic_arith and numeric_std that clash. but you shouldnt be using std_logic_signed because it allows you to treat std_logic_vectors as signed integers, when the signed type is far more appropriate.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What's the difference?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Also i am trying to represent these numbers in binary:
-0.5 -0.86 How can i represent them? I am using fixed point and shifting my number 2^22 times;;- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The main problem with using arithmetic on std_logic_vectors, is that you don't know at first glance when reading the code if you are dealing with signed or unsigned numbers. Sure for know you know what you wrote, but your code could end up copy/pasted in another file, where std_logic_vectors are supposed to be unsigned instead, or you could even have to deal with unsigned and signed values in the same code. Using the unsigned and signed types wakes the code more readable, more reusable and can reduce mistakes.
As for the binary numbers, even if real arithmetic operations aren't synthesizable, you can still use real constants in your code. Something like: --- Quote Start --- constant MyNum : integer := integer(0.85*(2**22)); --- Quote End --- Or if using vectors and declaring more constants, something like (assuming you are using 23 bit signed numbers, to have a scaling factor of 2^22): --- Quote Start --- constant VectorsSize : natural := 23; constant ScalingFactor : real := real(2**(VectorsSize-1)); constant MyVector : signed := to_signed(integer(0.85*ScalingFactor),VectorsSize); --- Quote End --- If you need to do a lot of conversions, you could also define a function to do that instead. There is also a new fixed point library in VHDL, but I haven't tried it yet.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Daix. Now i understand.
However i can't multipliy a std_logic_vector (or a signed) for an integer. Can i? And does this := to_signed(integer(0.85*ScalingFactor),VectorsSize) ; work? Is it sinthetizable? I think i saw this on the fixed_point lib i tried the following:
constant um_terco : signed (40 downto 0) := to_signed(integer(0.3333),41);
signal Va1_real : std_logic_vector (117 downto 0);
signal temp_fasor_real8 : std_logic_vector (76 downto 0);
Va1_real = std_logic_vector(um_terco * signed(temp_fasor_real8))
where temp-fasor_real8 = 1773 in binary however the result was 0..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You can multiply a signed/unsigned with an integer with the numeric_std library. Be careful with multiplying fixed point vectors though, as you will need to shift the result back.
As for your 0 result, it is because with this assignment: --- Quote Start --- constant um_terco : signed (40 downto 0) := to_signed(integer(0.3333),41); --- Quote End --- 0.3333 is converted to the integer 0. You forgot to multiply 0.3333 by the scaling factor.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
with the fixed point library, you dont need to worry about scaling factors:
constant UM_TERCO : sfixed := to_sfixed(0.3333, N-1, -M); --N integer bits, M fractional
signal temp_fasor_real8 : sfixed(A downto 0)
signal Va_real : signed(N+A-1 downto -M);
Va_real <= temp_fasor_real8 * UM_TERCO;
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page