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 W5NYV

library ieee;

use ieee.std_logic_1164.all;

use ieee.math_real.all;

use ieee.numeric_std.all;

entity IQGainPhaseCorrection_testbench is

end 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: process

variable angle : real;

variable local_x1 : real;

variable sgma : real :=0.01; --sigma of noise

variable amplitude : real := 1.0; --amplitude

variable freq : real := 0.03; --relative frequency

variable u_noise: real; --uniform distribution noise

variable n_noise: real := 0.0; --normal distribution noise

variable seed1 : positive := 10;

variable seed2 : positive := 200;

--loop controls

variable 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: process

variable angle : real;

variable local_y1 : real;

variable e1 : real := 0.1; --gain error

variable a1 : real := (10.0*math_pi)/180.0; --phase error of 10 degrees

variable sgma : real := 0.01; --sigma of noise

variable amplitude : real := 1.0; --amplitude

variable freq : real := 0.03; --relative frequency

variable u_noise: real; --uniformly distributed noise

variable n_noise: real := 0.0; --normally distributed noise

variable seed1 : positive := 1;

variable seed2 : positive := 2;

--loop controls

variable 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:process

begin

clk_tb <= not clk_tb;

wait for 50 ns;

end process;

end IQGainPhaseCorrection_testbench_arch;

## No comments:

Post a Comment