IQ Phase and Gain Correction - Testbench

22/02/2011

Listen "IQ Phase and Gain Correction - Testbench"

Episode Synopsis

Below is the testbench for the IQ Phase and Gain Correction. As you can see, there's a lot more going on in the testbench than in the block for the algorithm. This is because the testbench has to generate the test signals and provide the clock and establish the various settings for the test, and that all adds up in this case to more lines of code. On the list of improvements is to move the I and Q signal creation into a procedure. This encapsulates code and will make the testbench a lot more readable. Another obvious improvement is to figure out exactly why the gain correction isn't working yet. More soon,-Michelle W5NYVlibrary ieee;use ieee.std_logic_1164.all;use ieee.math_real.all;use ieee.numeric_std.all; entity IQGainPhaseCorrection_testbench isend entity;architecture IQGainPhaseCorrection_testbench_arch of IQGainPhaseCorrection_testbench is--declare the DUT as a component.component IQGainPhaseCorrection is generic(width :natural); port( clk :in std_logic; x1 :in signed(width downto 0); y1 :in signed(width downto 0); gain_error :out signed(width downto 0); gain_lock :out bit; phase_error :out signed(width downto 0); phase_lock :out bit; corrected_x1 :out signed(width downto 0); corrected_y1 :out signed(width downto 0) ); end component;--provide signals to run the DUT.signal clk_tb : std_logic := '0';signal x1_tb : signed(31 downto 0);signal y1_tb : signed(31 downto 0);signal gain_error_tb : signed(31 downto 0);signal gain_lock_tb : bit;signal phase_error_tb : signed(31 downto 0);signal phase_lock_tb : bit;signal corrected_x1_tb : signed(31 downto 0);signal corrected_y1_tb : signed(31 downto 0);begin --connect the testbench signal to the component DUT:IQGainPhaseCorrection generic map( width => 31 ) port map( clk => clk_tb, x1 => x1_tb, y1 => y1_tb, gain_error => gain_error_tb, gain_lock => gain_lock_tb, phase_error => phase_error_tb, phase_lock => phase_lock_tb, corrected_x1 => corrected_x1_tb, corrected_y1 => corrected_y1_tb ); --create x1 and y1. MTreseler says, "sin in vhdl I use use ieee.math_real.all and cast to integer."CREATE_X1_I: processvariable angle : real;variable local_x1 : real;variable sgma : real :=0.01; --sigma of noisevariable amplitude : real := 1.0; --amplitudevariable freq : real := 0.03; --relative frequencyvariable u_noise: real; --uniform distribution noisevariable n_noise: real := 0.0; --normal distribution noise variable seed1 : positive := 10;variable seed2 : positive := 200;--loop controlsvariable make_normal_count : integer := 12;variable n_dat : integer := 4;variable int_x1: integer;begin for n_dat_count in 0 to n_dat loop --make a random number uniform(seed1, seed2, u_noise); report "Random uniform noise in I creation is " & real'image(u_noise) & "."; for normal_count in 0 to make_normal_count loop --turn the uniform distributed number --into a normally distributed number --by using the central limit theorem. n_noise := n_noise + u_noise; end loop; n_noise := n_noise - (0.5)*(real(make_normal_count)); --normal distribution with a mean of zero report "Random normal noise in I creation is " & real'image(n_noise) & "."; n_noise := n_noise/(real(make_normal_count)); --max values reduced? report "Random normal noise (normalized?) in I creation is " & real'image(n_noise) & "."; local_x1 := amplitude*cos(2.0*math_pi*(real(n_dat_count))*freq) + sgma*(n_noise); --local_x1 := cos(2.0*math_pi*(real(n_dat_count))*freq); --simpler version --AGC scaling local_x1 := local_x1/(1.01); report "local_x1 is " & real'image(local_x1) & "."; --x1_tb <= local_x1; --somehow get real turned into signed. -- 1. rescale to 0..(nearly)4096, find integer part --int_x1 := INTEGER(TRUNC(local_x1*4294967296.0)); -- from random_vector int_x1 := integer(trunc(local_x1*(2.0**31.0))); --scaled report "integer version of x1 is " & integer'image(int_x1) & "."; -- 2. convert to signed x1_tb <= (to_signed(int_x1, x1_tb'LENGTH)); end loop; wait; end process CREATE_X1_I;CREATE_Y1_Q: processvariable angle : real;variable local_y1 : real;variable e1 : real := 0.1; --gain errorvariable a1 : real := (10.0*math_pi)/180.0; --phase error of 10 degreesvariable sgma : real := 0.01; --sigma of noisevariable amplitude : real := 1.0; --amplitudevariable freq : real := 0.03; --relative frequencyvariable u_noise: real; --uniformly distributed noisevariable n_noise: real := 0.0; --normally distributed noisevariable seed1 : positive := 1;variable seed2 : positive := 2;--loop controlsvariable make_normal_count : integer := 12;variable n_dat : integer := 4;variable int_y1: integer;begin for n_dat_count in 0 to n_dat loop --make a random number uniform(seed1, seed2, u_noise); report "Random uniform noise in I creation is " & real'image(u_noise) & "."; for normal_count in 0 to make_normal_count loop --turn the uniform distributed number --into a normally distributed number --by using the central limit theorem. n_noise := n_noise + u_noise; end loop; n_noise := n_noise - (0.5)*(real(make_normal_count)); n_noise := n_noise/(real(make_normal_count)); --reduce size of noise report "Random normal noise in I creation is " & real'image(n_noise) & "."; n_noise := n_noise/(real(make_normal_count)); --max values reduced? report "Random normal noise (normalized?) in I creation is " & real'image(n_noise) & "."; local_y1 := amplitude*(1.0 + e1)*cos(2.0*math_pi*(real(n_dat_count))*freq + a1) + sgma*(n_noise); --AGC scaling local_y1 := local_y1/(1.01); --int_y1 := INTEGER(TRUNC(local_y1*4294967296.0)); -- from random_vector int_y1 := integer(trunc(local_y1*(2.0**31.0))); --scaled report "integer version of y1 is " & integer'image(int_y1) & "."; -- 2. convert to signed y1_tb <= (to_signed(int_y1, y1_tb'LENGTH)); end loop; wait; end process CREATE_Y1_Q;DRIVE_CLOCK:processbegin clk_tb <= not clk_tb; wait for 50 ns;end process;end IQGainPhaseCorrection_testbench_arch;