## Sunday, August 28, 2011

### Six-Ports

## Saturday, August 27, 2011

### Six-port article for MUD

## Monday, August 8, 2011

### Qt4 built, building a GUI for SDRs

## Friday, July 22, 2011

### Numbering Scheme, looking for hybrid couplers and dividers, and MUD?

## Thursday, June 2, 2011

### FPGAs in space

-Michelle W5NYV

Potestatem obscuri lateris nescis.

## Saturday, May 28, 2011

### VHDL implementation compared to MATLAB model - overall success

Comparison with MATLAB results.

-Michelle W5NYV

## Thursday, May 19, 2011

### "What's Up With ARM"

thought it was interesting, largely agree with the author, and wanted to share

it with you guys.

http://www.linux.com/news/featured-blogs/171-jonathan-corbet/445344-whats-up-with-arm

Having got the beagleboard lab back up and running after the extended tour of

duty doing VHDL, I find that it is very true that getting Linux working on ARM

can be much more "some assembly required" than, say, a desktop. It's well worth

it, considering how powerful the ARM family is.

In order to develop something useful for MEP on ARM, there is quite a bit of

slogging to do through various rough edges. When experimenting with cameras and

video output, nothing ever really "quite worked", and the variety and

duplication mentioned in the article were in full evidence.

The current Angstrom build I'm working with was obtained from the Narcissus

Angstrom image builder. I used this because I simply could not get the demo

build of Angstrom to cleanly update from the package server. This sort of

obstacle can be really frustrating.

Here is the link to generate a build of Angstrom:

http://narcissus.angstrom-distribution.org/

This image boots, but I haven't gotten much farther than launching Firefox.

More soon!

-Michelle W5NYV

## Monday, May 9, 2011

### updated synthesizeable VHDL block - progress

I'm working with an adjusted numbering scheme in signed arithmetic to correct an

overflow problem (thanks to KB5MU, who helped identify).

This implementation, which is designed to be synthesizeable, is beginning to

function as intended. There is a factor of two error, but the compiled block

outputs I and Q.

With some data visualization, these might prove to be a passed-through I and

phase corrected Q at the output, with a massive gain overcorrection. I'll check

that tomorrow!

-Michelle W5NYV

## Friday, April 22, 2011

### VHDL update - IQ Gain and Phase correction, next blocks

to Curaçao, spring break shennanigans, and photographing a wedding.

I took the entity, architecture, and the testbench from the variable

(non-synthesizeable) version, and started a new workspace. The goal is to get

the register-based version working. When last I attempted this, I got incorrect

results from multiplication. I'm making another run at it to get this filter

ready for synthesis (when it's put into an FPGA, instead of just working as a

mathematical model).

If you're interested in working on VHDL for MEP, there is PLENTY of opportunity.

It doesn't even have to be VHDL. If you work in Verilog, and can synthesize the

block, then go for it.

I'm approaching this like a slow-growing bacteria that spreads to adjacent

blocks in the petri dish. The next block upstream is automatic gain control.

I've read the wikipedia article about AGC, but that's about as far as I've

gotten.

Article here:

http://en.wikipedia.org/wiki/Automatic_gain_control

Does anyone on the list have any experience with AGC design or analysis? I

understand why AGC is important, and I think I understand the trade-offs. I'm

not sure quite yet how to design a block that achieves AGC. Right now, the AGC

is modeled in the IQ correction block by simply dividing the incoming values of

the signals by the maximum expected value.

I'd like to replace that modeling with a block that does the AGC before the

samples are delivered to the filter.

The next block downstream is, I believe, the demodulator.

I have attached a pdf with the current snapshot of the IQ Gain and Phase code.

More soon,-Michelle W5NYV

Potestatem obscuri lateris nescis.

## Saturday, March 5, 2011

### IQ Correction VHDL update

I have a VHDL implementation of the IQ phase and gain correction algorithm

working. This implementation isn't synthesizeable in logic (yet), but it will be

as soon as I figure out why signed multiplication gives the wrong result.

Since I have a version that is working (with some of the internal math done with

variables instead of registers) I'm taking the opportunity to work on gain and

phase lock and the creation of "corrected" I and Q signals.

I is passed along with a filter delay, and corrected Q is passed along.

This part needs to be done regardless of how the internals of the correction

block are implemented.

If you haven't visited the opencores.com site, then you might want to drop by

and check it out. We're in there!

IQ Phase and Gain Correction is the name of the project and our page is

http://opencores.com/project,iqcorrection

I'll have today's cut of code up there after a celebratory lunch.

More soon (phase and gain lock signals in progress)

-Michelle W5NYV

Potestatem obscuri lateris nescis.

## Tuesday, February 22, 2011

### Package that makes normally distributed random numbers from uniform numbers

takes the uniform distribution random numbers and uses the central limit theorem

to give an (approximately) normal distribution. Here's the package:

library ieee;

use ieee.std_logic_1164.all;

use ieee.math_real.all;

use ieee.numeric_std.all;

use work.random_int.all;

--by MEP 22 February 2011

--usage:

--this is a function, which means it can be on the right-hand side

--of an assignment. It returns a mean-zero random number from a

--normal distribution. The argument is a real number that indicates

--the standard deviation desired.

--

--random_noise(sigma);

--

package normal_distribution_random_noise is

function random_noise (

sigma : real)

return real;

end package normal_distribution_random_noise;

package body normal_distribution_random_noise is

function random_noise (

sigma : real

)

return real is

--variables

variable u_noise: real; --uniform distribution noise

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

variable seed1 : positive;

variable seed2 : positive;

begin

--obtain a uniformly distributed random number

uniform(seed1, seed2, u_noise);

--report "Random uniform noise is " & real'image(u_noise) & ".";

for normal_count in 0 to 12 loop

--Turn the uniform distributed number

--into a normally distributed number

--by using the central limit theorem.

--Make it mean zero and make it have

--the range of the uniform numbers

--that it is composed from.

n_noise := n_noise + u_noise;

end loop;

n_noise := n_noise - (0.5)*(real(12)); --normal distribution with a mean

of zero

--report "Random normal noise is " & real'image(n_noise) & ".";

n_noise := n_noise/(real(12));

--report "Random normal noise using range of uniform is " &

real'image(n_noise) & ".";

n_noise := sigma*n_noise;

return n_noise;

end function random_noise;

end package body normal_distribution_random_noise;

### Package that creates I and Q samples to test the IQ Correction block

use ieee.std_logic_1164.all;

use ieee.math_real.all;

use ieee.numeric_std.all;

use work.normal_distribution_random_noise.all;

--by MEP 22 February 2011

--usage:

--these are functions, which means they can be on the right-hand side

--of an assignment. These functions create an I and Q sample.

--The arguments are

--a natural number standing for the index of the sample,

--a real number that provides a way to have many samples per period,

--a real number standing for the standard deviation of the normally distributed

noise added to the sample,

--a real number standing for the amplitude of the signal,

--a natural number indicating the width of the vector holding the returned

value,

--a real number indicating the gain error of Q with respect to I,

--and a real number indicating the phase error of Q with respect to I

--

--create_I_sample(n_dat, freq, sgma, amplitude, return_width);

--create_Q_sample(n_dat, freq, sgma, amplitude, return_width, e1, a1);

--

package create_sample is

function create_I_sample(

n_dat : integer;

freq : real;

sgma : real;

amplitude : real;

return_width : natural)

return signed;

function create_Q_sample(

n_dat : integer;

freq : real;

sgma : real;

amplitude : real;

return_width : natural; --x1_tb'LENGTH

e1 : real; --gain error

a1 : real) --phase error

return signed;

end package create_sample;

package body create_sample is

function create_I_sample(

n_dat : integer;

freq : real;

sgma : real;

amplitude : real;

return_width : natural) --x1_tb'LENGTH

return signed is

variable local_x1 : real;

variable int_x1: integer;

variable returned_x1 : signed(return_width downto 0);

begin

local_x1 := amplitude*sin(2.0*math_pi*(real(n_dat))*freq) +

random_noise(sgma);

--report "local_x1 inside CREATE_I_SAMPLE function is " &

real'image(local_x1) & ".";

--AGC scaling. Scaling factor is maximum value the signal can take.

local_x1 := local_x1/(1.11);

--report "local_x1 after AGC inside CREATE_I_SAMPLE function is " &

real'image(local_x1) & ".";

int_x1 := integer(trunc(local_x1*((2.0**31.0)-1.0))); --scaled

--report "integer version of x1 inside CREATE_I_SAMPLE function is " &

integer'image(int_x1) & ".";

returned_x1 := (to_signed(int_x1, return_width+1));

return returned_x1;

end function;

function create_Q_sample(

n_dat : integer;

freq : real;

sgma : real;

amplitude : real;

return_width : natural; --x1_tb'LENGTH

e1 : real; --gain error

a1 : real)

return signed is

variable local_y1 : real;

variable int_y1: integer;

variable returned_y1 : signed(return_width downto 0);

begin

local_y1 := amplitude*(1.0 + e1)*cos(2.0*math_pi*(real(n_dat))*freq +

a1) + random_noise(sgma);

--report "local_y1 first created CREATE_Q_SAMPLE function is " &

real'image(local_y1) & ".";

--AGC scaling. Scaling factor is maximum value the signal can take.

local_y1 := local_y1/(1.11);

--report "local_y1 after AGC inside CREATE_Q_SAMPLE function is " &

real'image(local_y1) & ".";

int_y1 := integer(trunc(local_y1*((2.0**31.0)-1.0))); --scaled

--report "integer version of y1 inside CREATE_Q_SAMPLE function is " &

integer'image(int_y1) & ".";

returned_y1 := (to_signed(int_y1, return_width+1));

return returned_y1;

end function;

end package body create_sample;

### IQ Phase Gain Correction testbench

use ieee.std_logic_1164.all;

use ieee.math_real.all;

use ieee.numeric_std.all;

use work.normal_distribution_random_noise.all;

use work.create_sample.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 clk_tb_delayed : 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_delayed,

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 I and Q. MTreseler says, "sin in vhdl I use use ieee.math_real.all and

cast to integer."

CREATE_I_Q_SAMPLES: process (clk_tb) is

--for both I and Q

variable n_dat : integer := 0;

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

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

variable amplitude : real := 1.0; --amplitude

--for Q

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

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

begin

if (clk_tb'event and clk_tb = '1') then

x1_tb <= create_I_sample(n_dat, freq, sgma, amplitude, 31);

y1_tb <= create_Q_sample(n_dat, freq, sgma, amplitude, 31, e1, a1);

n_dat := n_dat + 1;

end if;

end process CREATE_I_Q_SAMPLES;

DRIVE_CLOCK:process

begin

wait for 50 ns;

clk_tb <= not clk_tb;

clk_tb_delayed <= not clk_tb_delayed after 1 ns;

end process;

end IQGainPhaseCorrection_testbench_arch;

### IQ Phase Gain Correction architecture

--signal declarations

--phase error estimate accumulator

signal reg_1:signed(width downto 0) := (others => '0');

--gain error estimate accumulator

signal reg_2:signed(width downto 0) := (0 => '1', others => '0');

--Phase Offset Adjustment Applied to y1

signal y2:signed(width downto 0) := (others => '0');

--Gain and Phase Adjustment Applied to y1

signal y3:signed(2*width+1 downto 0) := (others => '0');

signal x1y2:signed(2*width+1 downto 0):= (others => '0');

signal mu_1:signed(width downto 0):= (others => '0');

signal x1x1y3y3:signed(width downto 0):= (others => '0');

signal mu_2:signed(width downto 0):= (others => '0');

signal reg_1x1:signed(2*width+1 downto 0):= (others => '0');

signal y3y3: signed(4*width+3 downto 0):= (others => '0');

signal x1x1: signed(2*width+1 downto 0):= (others => '0');

begin

correction : process (clk) is

begin

if clk'event and clk = '1' then

--phase error estimate, step size set to 0.000244

--which is achieved with a shift right by 12.

reg_1x1 <= reg_1 * x1; --clock 0

y2 <= y1 - reg_1x1(2*width+1 downto width+1); --clock 1

x1y2 <= x1 * y2; --clock 2

mu_1 <= shift_right(x1y2(2*width+1 downto width+1),12); --step size

applied. --clock 3

reg_1 <= reg_1 + mu_1; --clock 4

phase_error <= reg_1; --update phase error estimate. --clock 5

--gain error estimate, step size set to 0.000122

--which is achieved with a shift right by 13.

y3 <= y2 * reg_2; --clock 0 --63 downto 0 n*32 - 1, n = 2

x1x1 <= x1 * x1; --clock 0 --63 downto 0

y3y3 <= y3 * y3; --clock 1 --127 downto 0 n*32 -1, n = 4 to

n = 3

x1x1y3y3 <= (abs(x1x1(2*width+1 downto width+1))) - (abs(y3y3(4*width+3

downto 3*width+3))); --clock 2

mu_2 <= shift_right(x1x1y3y3, 13); --clock 3

reg_2 <= reg_2 + mu_2; --clock 4

gain_error <= reg_2; --update gain error estimate. --clock 5

end if;

end process;

end IQGainPhaseCorrection_beh;

### IQ Phase Gain Correction entity

use ieee.std_logic_1164.all;

use ieee.std_logic_arith;

use ieee.numeric_std.all;

entity 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 IQGainPhaseCorrection;

### IQ Phase and Gain Correction - Testbench

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;

### IQ Phase and Gain Correction

is the entity and architecture below.

In the testbench, the phase correction works (with some amount of oscillation),

but the gain correction increases without bound. Trying to track that down

today. I'll post the testbench next in a separate email.

library ieee;

use ieee.std_logic_1164.all;

use ieee.std_logic_arith;

use ieee.numeric_std.all;

entity 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 IQGainPhaseCorrection;

architecture IQGainPhaseCorrection_beh of IQGainPhaseCorrection is

--signal declarations

--phase error estimate accumulator

signal reg_1:signed(width downto 0) := (others => '0');

--gain error estimate accumulator

signal reg_2:signed(width downto 0) := (0 => '1', others => '0');

--Phase Offset Adjustment Applied to y1

signal y2:signed(width downto 0) := (others => '0');

--Gain and Phase Adjustment Applied to y1

signal y3:signed(2*width+1 downto 0) := (others => '0');

signal x1y2:signed(2*width+1 downto 0):= (others => '0');

signal mu_1:signed(width downto 0):= (others => '0');

signal x1x1y3y3:signed(width downto 0):= (others => '0');

signal mu_2:signed(width downto 0):= (others => '0');

signal reg_1x1:signed(2*width+1 downto 0):= (others => '0');

signal y3y3: signed(4*width+3 downto 0):= (others => '0');

signal x1x1: signed(2*width+1 downto 0):= (others => '0');

begin

correction : process (clk) is

begin

if clk'event and clk = '1' then

--phase error estimate, step size set to 0.000244

--which is achieved with a shift right by 12.

reg_1x1 <= reg_1 * x1; --clock 0

y2 <= y1 - reg_1x1(2*width+1 downto width+1); --clock 1

x1y2 <= x1 * y2; --clock 2

mu_1 <= shift_right(x1y2(2*width+1 downto width+1),12); --step size

applied. --clock 3

reg_1 <= reg_1 + mu_1; --clock 4

phase_error <= reg_1; --update phase error estimate. --clock 5

--gain error estimate, step size set to 0.000122

--which is achieved with a shift right by 13.

y3 <= y2 * reg_2; --clock 0 --63 downto 0 n*32 - 1, n = 2

x1x1 <= x1 * x1; --clock 0 --63 downto 0

y3y3 <= y3 * y3; --clock 1 --127 downto 0 n*32 -1, n = 4 to

n = 3

x1x1y3y3 <= (abs(x1x1(2*width+1 downto width+1))) - (abs(y3y3(4*width+3

downto 3*width+3))); --clock 2

mu_2 <= shift_right(x1x1y3y3, 13); --clock 3

reg_2 <= reg_2 + mu_2; --clock 4

gain_error <= reg_2; --update gain error estimate. --clock 5

end if;

end process;

end IQGainPhaseCorrection_beh;

## Thursday, February 17, 2011

### VHDL experience so far

Gain correction algorithm. I'll publish a cut of it in a separate email.

What I wanted to share was a few very brief observations about learning VHDL.

The actual description of what you want to accomplish may take much less time

than constructing a test that really tests what you have designed.

VHDL projects are usually broken down into components, which are the blocks that

implement your function, and testbenches, which (as the name implies) are

constructed logic that proves the block that implements the function does

what you intended to tell it to do.

So far, the proportion of time spent designing the block that implements the

function vs. designing the testbench for it is about 4:1. I don't expect this to

change throughout the remaining 5 weeks of the course.

VHDL is very strongly typed, and most of the issues I've had so far have been

getting used to this. Once you get the hang of it, it does get better, and makes

it easy to catch most errors.

We're using the student version of Aldec Active-HDL for the development

environment. I have to say I like it a bit more than the Xilinx ISE webpack, but

the differences are minor, and the Aldec license is good for only a year at a

time.

More soon!-Michelle W5NYV

Potestatem obscuri lateris nescis.

## Saturday, February 12, 2011

### Software-defined radio ideas

on SDR. What would you want to hear about? I'm focusing on software and

processing."

Tom Rondeau is giving a talk with fred harris, a well-known DSP lecturer and

professor at SDSU.

Balister offered, "Explain the difference between a collection of functions that

do operations and a framework providing structure for using them."

What do you all think? What are the current concerns in software-defined radio

design? I have some ideas, but I'm very interested in what you all think.

-Michelle W5NYV

## Sunday, January 23, 2011

### Pressing on with IQ Correction algorithm - vhdl entity and architecture update

of the IQ Correction algorithm.

It compiled after solving some trouble I had with implmenting shifts. Standard

logic vectors can't be shifted, but signed vectors can be. So converting, then

shifting, then converting back did the trick.

More soon,

-Michelle W5NYV

library ieee;

use ieee.std_logic_1164.all;

use IEEE.std_logic_signed.all;

use ieee.numeric_std.all;

entity IQGainPhaseCorrection is

generic(input_width:natural:=15;

output_width:natural:=31);

port(

clk :in std_logic;

x1 :in std_logic_vector(input_width downto 0);

y1 :in std_logic_vector(input_width downto 0);

gain_error :out std_logic_vector(output_width downto 0);

phase_error :out std_logic_vector(output_width downto 0)

);

end IQGainPhaseCorrection;

architecture IQGainPhaseCorrection_beh of IQGainPhaseCorrection is

--signal declarations

--phase error calculation

signal reg_1:std_logic_vector(input_width downto 0);

signal reg_1_sv:std_logic_vector(input_width downto 0);

--gain error calculation

signal reg_2:std_logic_vector(input_width downto 0);

signal reg_2_sv:std_logic_vector(input_width downto 0);

--Phase Offset Corrected

signal y2:std_logic_vector(2*input_width downto 0);

--Gain and Phase Offset Corrected

signal y3:std_logic_vector(input_width downto 0);

signal x1y2:signed(2*input_width downto 0);

signal mu_1:signed(2*input_width downto 0);

signal x1x1y3y3:signed(4*input_width downto 0);

signal mu_2:signed(2*input_width downto 0);

begin

correction : process

begin

wait until clk'event and clk = '1';

--phase error estimate, step size set to 0.000244

y2 <= y1 - reg_1 * x1;

--reg_1_sv <= reg_1;

x1y2 <= signed(x1 * y2); --have to convert to signed to use shift.

mu_1 <= shift_right(x1y2,12); --step size applied.

reg_1 <= reg_1 + std_logic_vector(mu_1); --convert back to std_logic_vector.

phase_error <= reg_1; --update phase error estimate.

--gain error estimate, step size set to 0.000122

y3 <= y2 * reg_2;

--reg_2_sv <= reg_2;

x1x1y3y3 <= signed(abs((x1)*(x1)) - abs((y3)*(y3))); --have to convert to signed to use shift.

mu_2 <= shift_right(x1x1y3y3, 13); --step size applied.

reg_2 <= reg_2 + std_logic_vector(mu_2); --convert back to std_logic_vector.

gain_error <= reg_2; --update gain error estimate.

end process;

end IQGainPhaseCorrection_beh;

## Wednesday, January 19, 2011

### IQ Correction Model - proposed plotting change, question about absolute values

More soon! -Michelle W5NYV

## Sunday, January 16, 2011

### IQ Correct entity and architecture files - update

gain and phase correction algorithm.

more soon!

-Michelle W5NYV

## Thursday, January 13, 2011

### IQ Correction entity, architecture update

generic(input_width:natural:=12;

output_width:natural:=7);

port(

clk:in bit;

x1:in bit_vector(input_width downto 0);

y1:in bit_vector(input_width downto 0);

gain_error:out bit_vector(output_width downto 0);

phase_error:out bit_vector(output_width downto 0)

);

end IQGainPhaseCorrection;

architecture IQGainPhaseCorrection_beh of IQGainPhaseCorrection is

begin

--as long as there are samples, do a loop

correction : process is

--local variables

variable count_value : natural := 0;

--phase error calculation

variable reg_1:bit_vector(7 downto 0):=00000000;

variable reg_1_sv:bit_vector(7 downto 0):=00000000;

--gain error calculation

variable reg_2:bit_vector(7 downto 0):=00000001;

variable reg_2_sv:bit_vector(7 downto 0):=00000000;

--SNR scaling?

constant mu_1:real:=0.0002;

constant mu_2:real:=0.0001;

--Phase Offset Corrected

variable y2:bit_vector(7 downto 0):=00000000;

--Gain and Phase Offset Corrected

variable y3:bit_vector(7 downto 0):=00000000;

begin

loop

wait until clk;

y2(nn) = y1(nn)-reg_1*x1(nn);

reg_1_sv(nn) = reg_1;

reg_1 = reg_1 + mu_1*x1(nn)*y2(nn);

y3(nn) = y2(nn)*reg_2;

reg_2_sv(nn) = reg_2;

reg_2 = reg_2+mu_2*(abs(x1(nn))^2 - abs(y3(nn))^2);

end loop;

end process correction;

end IQGainPhaseCorrection_beh;

Attached are the entity and architecture for the IQ Correction algorithm, as

well as the original MATLAB model.

I added a clock to the entity, and started the architecture. The architecture is

"sketch" stage, but you can see where I'm going with it.

Got some advice from Ken Easton on how to handle the types, and we're set to

talk again about how best to handle memory.

more soon! -Michelle W5NYV

## Tuesday, January 11, 2011

### VHDL entity for the IQ Gain and Phase Correction algorithm (Tuesday Challenge!)

generic(input_width:natural:=7;

output_width:natural:=7);

port(

x1:in bit_vector(input_width downto 0);

y1:in bit_vector(input_width downto 0);

gain_error:out bit_vector(output_width downto 0);

phase_error:out bit_vector(output_width downto 0)

);

end IQGainPhaseCorrection;

Hi Everyone,

Here's the entity:

--------------------------

entity IQGainPhaseCorrection is

generic(input_width:natural:=7;

output_width:natural:=7);

port(

x1:in bit_vector(input_width downto 0);

y1:in bit_vector(input_width downto 0);

gain_error:out bit_vector(output_width downto 0);

phase_error:out bit_vector(output_width downto 0)

);

end IQGainPhaseCorrection;

--------------------------

An entity in VHDL is the interface to the outside world. It's equivalent to the

list of pins of an IC that you might want to use in a project.

Here, there are two inputs, the I and Q signals, and two outputs, the gain error

and the phase error between the two signals, so that the errors can be

corrected.

The "generic" keyword allows parameters in VHDL to be set. You can see that

there's an input width and an output width. It allows flexibility and reuse in

VHDL.

My question: Is 8-bit widths for both reasonable?

## Monday, January 10, 2011

### IQ Correction Algorithm - beginning

Attached is the IQ Correction MATLAB model written by Bob McGwier, and the

output figures it produced after I got it working in Octave.

Two signals, x1 and y1, are created in this model. They represent I and Q

signals. Both have noise added to them (random, normal distribution, mean zero,

0.01 standard deviation).

Whenever we implement a circuit that handles I and Q, we expect to get

differences between I and Q that are due to the implementation. In this model,

y1 has a fixed gain error and a fixed phase error. The IQ correction algorithm

determines the gain error and phase error. Neat!

Running the model under Octave, I got the following when the model attempted to

draw figure 3:

octave-3.2.3:3> IQCorrectGain_Phase

error: `kaiser' undefined near line 92 column 4

error: called from:

error: /Users/w5nyv/Dropbox/MEP/IQCorrectGain_Phase.m at line 92, column 3

octave-3.2.3:3>

That particular section of the model is:

figure(3)

subplot(3,1,1)

ww=kaiser(1024,12)';

ww=ww/sum(ww);

tt=n_dat-1023:n_dat;

plot(-0.5:1/1024:0.5-1/1024,fftshift(20*log10(abs(fft((x1(tt)+1i*y1(tt)).*ww)))))

% z=zeros(1,1024);

% for kk=1:1024

% z(kk)=(x1(tt(kk))+1i*y1(tt(kk)))*ww(kk);

% end

% plot(-0.5:1/1024:0.5-1/1024,fftshift(20*log10(abs(fft(z)))))

grid on

axis([-0.5 0.5 -140 10])

title('Output Spectrum with Gain and Phase Offset')

The kaiser reference is to a windowing function. It looked like I needed to

install an extra windowing package for Octave! Octave is a free and open source

version of MATLAB.

On the Mac,

sudo port install octave-windows

worked just fine on the desktop, and the model ran with the original MATLAB

kaiser window function.

However, a dependency wouldn't easily install on the laptop. I tried to build

from source, but running the port command again (port is somewhat similar to

opkg, git, svn etc) it still hung up on a particular dependency.

Through the power of Twitter, Bob recommended changing to another windowing

function (from kaiser to blackman-harris, which appears to be called just

blackman in Octave) and that seemed to do the trick. Since this particular

function is just to present the data, it's a bit less critical than having to

use an alternate function in the filter itself.

This is a good example of what is sometimes necessary when using Octave instead

of MATLAB. While Octave shadows MATLAB very closely, it's not an identical twin.

The very next step is to write a tutorial about the filter so that the math pops

right out at you.

The next step after that is to write the filter in VHDL. All are welcome to

participate, critique, troubleshoot! If you have experience (or want some) in

writing VHDL, here is a chance. :+)

More soon,

-Michelle W5NYV

Potestatem obscuri lateris nescis.