-- Quelle: -- http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity cart_to_polar is port ( clk : in std_ulogic; -- -- in range: -127 .. 127 in_enable : in std_ulogic; x_in : in signed( 7 downto 0); y_in : in signed( 7 downto 0); -- -- out range: 0 .. 128 (radius), -180 .. 180 (angle) radius_out : out unsigned( 7 downto 0); angle_out : out signed( 8 downto 0); out_enable : out std_ulogic ); end entity cart_to_polar; library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; -- only for precalculations architecture rtl of cart_to_polar is -- helper function -- radians -> degrees function degrees( value: in real) return real is variable result : real; begin result := value * 180.0 / MATH_PI; return result; end function degrees; -- scale this value for own pourpose constant scale : natural := 1; -- constant degree_0 : integer := scale * integer( round( degrees( arctan( 1.0 / 1.0)))); -- = 45° constant degree_1 : integer := scale * integer( round( degrees( arctan( 1.0 / 2.0)))); constant degree_2 : integer := scale * integer( round( degrees( arctan( 1.0 / 4.0)))); constant degree_3 : integer := scale * integer( round( degrees( arctan( 1.0 / 8.0)))); constant degree_4 : integer := scale * integer( round( degrees( arctan( 1.0 / 16.0)))); constant degree_5 : integer := scale * integer( round( degrees( arctan( 1.0 / 32.0)))); constant degree_6 : integer := scale * integer( round( degrees( arctan( 1.0 / 64.0)))); constant degree_7 : integer := scale * integer( round( degrees( arctan( 1.0 / 128.0)))); constant degree_180 : integer := scale * 180; constant factor : natural := 256; -- must be power of two, for simple calculation -- factors for gain correction constant no_gain : natural := integer( round( 1.000000 * real( factor))); constant gain_0 : natural := integer( round( 0.707107 * real( factor))); constant gain_1 : natural := integer( round( 0.632456 * real( factor))); constant gain_2 : natural := integer( round( 0.613572 * real( factor))); constant gain_3 : natural := integer( round( 0.608834 * real( factor))); constant gain_4 : natural := integer( round( 0.607648 * real( factor))); constant gain_5 : natural := integer( round( 0.607352 * real( factor))); constant gain_6 : natural := integer( round( 0.607278 * real( factor))); constant gain_7 : natural := integer( round( 0.607259 * real( factor))); type state_t is ( IDLE, Q_CHECK, CALC_1_1, CALC_1_2, CALC_1_4, CALC_1_8, CALC_1_16, CALC_1_32, CALC_1_64, CALC_1_128, GAINFIX, MULT, READY); signal state : state_t := IDLE; -- signal x : signed( 8 downto 0); signal y : signed( 8 downto 0); signal quadrant : natural range 1 to 4; signal sum_angle : signed( 8 downto 0); -- signal x_mul : unsigned( 15 downto 0); signal x_mul1 : unsigned( 15 downto 0); -- register for multiplication signal gain : natural range 0 to factor; begin process begin wait until rising_edge( clk); -- default out_enable <= '0'; -- FSM case state is when IDLE => if in_enable = '1' then x <= resize( x_in, x'length); y <= resize( y_in, y'length); state <= Q_CHECK; -- initalisation sum_angle <= to_signed( 0, sum_angle'length); gain <= no_gain; state <= Q_CHECK; end if; when Q_CHECK => if x >= 0 then if y >= 0 then quadrant <= 1; else quadrant <= 4; y <= - y; end if; else if y >= 0 then quadrant <= 2; x <= -x; else quadrant <= 3; x <= -x; y <= - y; end if; end if; state <= CALC_1_1; when CALC_1_1 => -- y can't be negative after Q_CHECK -- if y < 0 then -- x <= x - shift_right( y, 0); -- y <= y + shift_right( x, 0); -- sum_angle <= sum_angle - degree_0; -- elsif y > 0 then if y > 0 then x <= x + shift_right( y, 0); y <= y - shift_right( x, 0); sum_angle <= sum_angle + degree_0; gain <= gain_0; end if; state <= CALC_1_2; when CALC_1_2 => if y < 0 then x <= x - shift_right( y, 1); y <= y + shift_right( x, 1); sum_angle <= sum_angle - degree_1; gain <= gain_1; elsif y > 0 then x <= x + shift_right( y, 1); y <= y - shift_right( x, 1); sum_angle <= sum_angle + degree_1; gain <= gain_1; end if; state <= CALC_1_4; when CALC_1_4 => if y < 0 then x <= x - shift_right( y, 2); y <= y + shift_right( x, 2); sum_angle <= sum_angle - degree_2; gain <= gain_2; elsif y > 0 then x <= x + shift_right( y, 2); y <= y - shift_right( x, 2); sum_angle <= sum_angle + degree_2; gain <= gain_2; end if; state <= CALC_1_8; when CALC_1_8 => if y < 0 then x <= x - shift_right( y, 3); y <= y + shift_right( x, 3); sum_angle <= sum_angle - degree_3; gain <= gain_3; elsif y > 0 then x <= x + shift_right( y, 3); y <= y - shift_right( x, 3); sum_angle <= sum_angle + degree_3; gain <= gain_3; end if; state <= CALC_1_16; when CALC_1_16 => if y < 0 then x <= x - shift_right( y, 4); y <= y + shift_right( x, 4); sum_angle <= sum_angle - degree_4; gain <= gain_4; elsif y > 0 then x <= x + shift_right( y, 4); y <= y - shift_right( x, 4); sum_angle <= sum_angle + degree_4; gain <= gain_4; end if; state <= CALC_1_32; when CALC_1_32 => if y < 0 then x <= x - shift_right( y, 5); y <= y + shift_right( x, 5); sum_angle <= sum_angle - degree_5; gain <= gain_5; elsif y > 0 then x <= x + shift_right( y, 5); y <= y - shift_right( x, 5); sum_angle <= sum_angle + degree_5; gain <= gain_5; end if; state <= CALC_1_64; when CALC_1_64 => if y < 0 then x <= x - shift_right( y, 6); y <= y + shift_right( x, 6); sum_angle <= sum_angle - degree_6; gain <= gain_6; elsif y > 0 then x <= x + shift_right( y, 6); y <= y - shift_right( x, 6); sum_angle <= sum_angle + degree_6; gain <= gain_6; end if; state <= CALC_1_128; when CALC_1_128 => if y < 0 then x <= x - shift_right( y, 7); y <= y + shift_right( x, 7); sum_angle <= sum_angle - degree_7; gain <= gain_7; elsif y > 0 then x <= x + shift_right( y, 7); y <= y - shift_right( x, 7); sum_angle <= sum_angle + degree_7; gain <= gain_7; end if; state <= GAINFIX; when GAINFIX => x_mul1 <= resize( unsigned( x) * gain, x_mul1'length); -- quadrant correction state <= READY; if quadrant = 2 then sum_angle <= degree_180 - sum_angle; elsif quadrant = 3 then sum_angle <= sum_angle - degree_180; elsif quadrant = 4 then sum_angle <= - sum_angle; end if; state <= MULT; when MULT => -- pipeline stage for multiplier x_mul <= x_mul1; state <= READY; when READY => -- result output radius_out <= resize( x_mul / factor, radius_out'length); angle_out <= sum_angle; out_enable <= '1'; state <= IDLE; end case; end process; end architecture rtl;