CORDIC complex magnitude

From Hamsterworks Wiki!

Revision as of 09:41, 1 August 2019 by User (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This FPGA Project was finished in August 2019

As well as calculating trigonometric functions (sine, cosine...) CORDIC can be used to calculate the magnitude of complex values.

Here is this combined with the Hilbert Transform to calculate the envelope of real samples.

Complex+envelope.png

Source files

This only does a few iterations, and doesn't correct for the CORDIC gain.

NOTE: I am pretty sure this has range errors - some inputs might cause an integer overflow (and therefore an error!)

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity magnitude is
    Port ( 
        clk           : in std_logic;
        x_in          : in std_logic_vector;
        y_in          : in std_logic_vector;
        x_out         : out std_logic_vector := (others => '0');
        y_out         : out std_logic_vector := (others => '0');
        magnitude_out : out std_logic_vector := (others => '0') -- Accurate to 5 bits or so
    );
end magnitude;

architecture Behavioral of magnitude is

    type a_x is array(0 to 5) of signed(x_in'high+1 downto 0);
    type a_y is array(0 to 5) of signed(y_in'high+1 downto 0);
    type a_x_delay is array(0 to 5) of std_logic_vector(x_in'high downto 0);
    type a_y_delay is array(0 to 5) of std_logic_vector(y_in'high downto 0);
    
    signal x : a_x := (others => (others => '0'));
    signal y : a_y := (others => (others => '0'));
    signal x_delay : a_x_delay := (others => (others => '0'));
    signal y_delay : a_y_delay := (others => (others => '0'));
    
begin

    magnitude_out <= std_logic_vector(y(5));
    x_out <= x_delay(x_delay'high);
    y_out <= y_delay(y_delay'high);

process(clk)
    begin
        if rising_edge(clk) then
            if x(4) >= 0 then
                -- x(5) is not needed
                y(5) <= y(4) + x(4)(x(4)'high downto 4);
            else
                -- x(5) is not needed
                y(5) <= y(4) - x(4)(x(4)'high downto 4);
            end if;
            
            if x(3) >= 0 then
                x(4) <= x(3) - y(3)(y(3)'high downto 3);
                y(4) <= y(3) + x(3)(x(3)'high downto 3);
            else
                x(4) <= x(3) + y(3)(y(3)'high downto 3);
                y(4) <= y(3) - x(3)(x(3)'high downto 3);
            end if;
            
            if x(2) >= 0 then
                x(3) <= x(2) - y(2)(y(2)'high downto 2);
                y(3) <= y(2) + x(2)(x(2)'high downto 2);
            else
                x(3) <= x(2) + y(2)(y(2)'high downto 2);
                y(3) <= y(2) - x(2)(x(2)'high downto 2);
            end if;
            
            if x(1) >= 0 then
                x(2) <= x(1) - y(1)(y(1)'high downto 1);
                y(2) <= y(1) + x(1)(x(1)'high downto 1);
            else
                x(2) <= x(1) + y(1)(y(1)'high downto 1);
                y(2) <= y(1) - x(1)(x(1)'high downto 1);
            end if;
            
            if x(0) >= 0 then
                x(1) <= x(0) - y(0)(y(0)'high downto 0);
                y(1) <= y(0) + x(0)(x(0)'high downto 0);
            else
                x(1) <= x(0) + y(0)(y(0)'high downto 0);
                y(1) <= y(0) - x(0)(x(0)'high downto 0);
            end if;
            
            if y_in(y_in'high) = '1' then
                x(0) <= signed(x_in(x_in'high) & x_in);
                y(0) <= signed(to_signed(0,y_in'length+1)-signed(y_in));
            else
                x(0) <= signed(x_in(x_in'high) & x_in);
                y(0) <= signed(y_in(y_in'high) & y_in);
            end if;
            
            -- Delay to output the inputs, so they are aligned with the magnitudes
            x_delay(1 to 5) <= x_delay(0 to 4);
            y_delay(1 to 5) <= y_delay(0 to 4);
            x_delay(0) <= x_in;
            y_delay(0) <= y_in;
        end if;
    end process;
 end Behavioral;

Updated tb_hilbert_transformer.vhd

ALso get Hilber_transformer.vhd from Hilbert Transform

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
ENTITY tb_hilbert_transformer IS
END tb_hilbert_transformer;
 
ARCHITECTURE behavior OF tb_hilbert_transformer IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT hilbert_transformer
    PORT(
         clk : IN  std_logic;
         real_in : IN  std_logic_vector(9 downto 0);
         real_out : OUT  std_logic_vector(10 downto 0);
         imag_out : OUT  std_logic_vector(10 downto 0)
        );
    END COMPONENT;

    COMPONENT magnitude is
        Port ( 
            clk           : in std_logic;
            x_in          : in std_logic_vector;
            y_in          : in std_logic_vector;
            x_out         : out std_logic_vector := (others => '0');
            y_out         : out std_logic_vector := (others => '0');
            magnitude_out : out std_logic_vector := (others => '0') -- Accurate to 5 bits or so
        );
    end COMPONENT;
        
   signal clk           : std_logic := '0';
   signal real_in       : std_logic_vector(9 downto 0) := (others => '0');
   signal real_out      : std_logic_vector(10 downto 0);
   signal imag_out      : std_logic_vector(10 downto 0);
   signal x_out         : std_logic_vector(10 downto 0);
   signal y_out         : std_logic_vector(10 downto 0);
   signal magnitude_out : std_logic_vector(11 downto 0);
   constant clk_period : time := 10 ns;
 
BEGIN
 
   uut: hilbert_transformer PORT MAP (
          clk => clk,
          real_in => real_in,
          real_out => real_out,
          imag_out => imag_out
        );

uut2: magnitude 
        Port map( 
          clk => clk,
          y_in => real_out,
          x_in => imag_out,
          x_out => x_out,
          y_out => y_out,
          magnitude_out => magnitude_out
        );

   -- Clock process definitions
   clk_process :process
   begin
      clk <= '0';
      wait for clk_period/2;
      clk <= '1';
      wait for clk_period/2;
   end process;
 

   -- Stimulus process
   stim_proc: process
   begin      
      -- hold reset state for 100 ns.
      wait for 100 ns;   
      wait for clk_period*10;
      
      real_in <= std_logic_vector(to_signed(   1,10));
      wait for 10 ns;    

      for i in 1 to 5 loop
          real_in <= std_logic_vector(to_signed(   0,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 38,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 71,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 92,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 100,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 92,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 71,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 38,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(   0,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-38,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-71,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-92,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-100,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-92,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-71,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-38,10));
          wait for 10 ns;   
      end loop;

      for i in 1 to 10 loop
         real_in <= std_logic_vector(to_signed(   0,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed( 141,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed( 200,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed( 141,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed(   0,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed(-141,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed(-200,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed(-141,10));
         wait for 10 ns;   
      end loop;

      for i in 1 to 10 loop
         real_in <= std_logic_vector(to_signed(   0,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed( 173,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed( 173,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed(   0,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed(-173,10));
         wait for 10 ns;   
         real_in <= std_logic_vector(to_signed(-173,10));
         wait for 10 ns;   
      end loop;

      for i in 1 to 5 loop
          real_in <= std_logic_vector(to_signed(   0,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 71,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 100,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed( 71,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(   0,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-71,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-100,10));
          wait for 10 ns;   
          real_in <= std_logic_vector(to_signed(-71,10));
          wait for 10 ns;   
      end loop;

      real_in <= std_logic_vector(to_unsigned(  0,10));
      wait;
   end process;
END;

Personal tools