To convert a 90° system (alpha/beta) into a dq-system, the Park-Transformation is performed. The following logic can be used for Q15.16 fixed-point-signals:

VHDL
-- Park transformation (alpha/beta -> dq)
-- Christian Noeding, christian@noeding-online.de
-- https://chrisdevblog.com | https://github.com/xn--nding-jua
--
-- Released under GNU General Public License v3

LIBRARY ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity alpha_beta_to_dq is
	PORT
	(
		clk			: in std_logic;
		alpha			: in signed(31 downto 0); -- Q15.16
		beta			: in signed(31 downto 0); -- Q15.16
		theta			: in signed(31 downto 0); -- Q15.16 | values between 0 and 2*pi
		sync_in		: in std_logic;

		d				: out signed(31 downto 0);
		q				: out signed(31 downto 0);
		sync_out		: out std_logic
	);    
end alpha_beta_to_dq;

architecture behavioral of alpha_beta_to_dq is  
	signal state					: natural range 0 to 10 := 0;
	signal reset_cordic			: std_logic := '0';
	signal start_cordic			: std_logic := '0';

	signal cordic_mini_done 	: std_logic;
	signal sine, cosine 			: signed(15 downto 0) := (others => '0'); -- type: Q0.15
	signal sine_int, cosine_int : signed(31 downto 0) := (others => '0'); -- type: Q15.16
	signal theta_int				: signed(15 downto 0) := (others => '0'); -- type: Q0.15

	--signals for multiplier
	signal mult_in_a	:	signed(31 downto 0) := (others=>'0');
	signal mult_in_b	:	signed(31 downto 0) := (others=>'0');
	signal mult_out	:	signed(63 downto 0) := (others=>'0');
	signal mult_out_tmp	:	signed(31 downto 0) := (others=>'0');

	component cordic_mini is
	generic(
		XY_WIDTH    : integer := 16;	                        -- OUTPUT WIDTH
		ANGLE_WIDTH : integer := 16;                          -- ANGLE WIDTH
		STAGE       : integer := 14                           -- NUMBER OF ITERATIONS
	);
	port(
		clock      : in  std_logic;                           -- CLOCK INPUT
		angle      : in  signed (ANGLE_WIDTH-1 downto 0);     -- ANGLE INPUT from -360 to 360
		load       : in  std_logic;                           -- LOAD SIGNAL TO ENABLE THE CORE
		reset      : in  std_logic;                           -- ASYNC ACTIVE-HIGH RESET
		done       : out std_logic;                           -- STATUS SIGNAL TO SHOW WHETHER COMPUTATION IS FINISHED
		Xout       : out signed (XY_WIDTH-1 downto 0);        -- COSINE OUTPUT
		Yout       : out signed (XY_WIDTH-1 downto 0)         -- SINE OUTPUT
	);
	end component;
begin
	-- multiplier
	process(mult_in_a, mult_in_b)
	begin
		mult_out <= mult_in_a * mult_in_b;
	end process;

	process(clk)
	begin
		if (rising_edge(clk)) then
			if (sync_in = '1' and state = 0) then
				-- rescale theta from 0..2*pi to 0...+1 as cordic implementation accepts values between -1 to +1 and interpretes as -360 to +360
				mult_in_a <= shift_right(theta, 1); -- theta/2
				mult_in_b <= to_signed(5215, 32); -- 1/(2*pi) = 0.159149169921875
				
				state <= 1; -- start of state-machine
				
			elsif (state = 1) then
				theta_int <= resize(shift_right(mult_out, 15), 16); -- convert Q15.16 to Qx.15 of calculate (theta / (2 * pi))
				reset_cordic <= '1';
				start_cordic <= '0';
				
				state <= state + 1;
				
			elsif (state = 2) then
				-- stop resetting
				reset_cordic <= '0';
				
				state <= state + 1;

			elsif (state = 3) then
				-- start mini-cordic. As it takes 16 clocks to calculate we have to wait until it is ready
				start_cordic <= '1';
				
				state <= state + 1;

			elsif (state = 4 and cordic_mini_done = '1') then
				sine_int <= shift_left(resize(sine, 32), 1); -- convert Q0.15 into Q15.16
				cosine_int <= shift_left(resize(cosine, 32), 1); -- convert Q0.15 into Q15.16

				state <= state + 1;

			elsif (state = 5) then
				mult_in_a <= alpha;
				mult_in_b <= cosine_int;
				
				state <= state + 1;
				
			elsif (state = 6) then
				mult_out_tmp <= resize(shift_right(mult_out, 16), mult_out_tmp'length);
				mult_in_a <= beta;
				mult_in_b <= sine_int;
				
				state <= state + 1;
				
			elsif (state = 7) then
				d <= resize(mult_out_tmp + shift_right(mult_out, 16), 32);
				mult_in_a <= beta;
				mult_in_b <= cosine_int;
				
				state <= state + 1;
				
			elsif (state = 8) then
				mult_out_tmp <= resize(shift_right(mult_out, 16), mult_out_tmp'length);
				mult_in_a <= alpha;
				mult_in_b <= sine_int;
				
				state <= state + 1;
			
			elsif (state = 9) then
				q <= resize(mult_out_tmp - shift_right(mult_out, 16), 32);
				
				sync_out <= '1';

				state <= state + 1;

			elsif (state = 10) then
				sync_out <= '0';
				
				state <= 0;
			end if;
		end if;
	end process;

	cordic_sine_cos2 : cordic_mini
	port map (
		clock => clk, -- CLOCK INPUT
		angle => theta_int, -- ANGLE INPUT from -360 to 360 as Q0.15
		load  => start_cordic, -- LOAD SIGNAL TO ENABLE THE CORE
		reset => reset_cordic, -- ASYNC ACTIVE-HIGH RESET
		done  => cordic_mini_done, -- STATUS SIGNAL TO SHOW WHETHER COMPUTATION IS FINISHED
		Xout  => cosine, -- COSINE OUTPUT as Q0.15
		Yout  => sine -- SINE OUTPUT as Q0.15
	);
end behavioral;

Leave a comment

Your email address will not be published. Required fields are marked *