## 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.