Velocity Reviews > VHDL > Complex Multiply

# Complex Multiply

Ann
Guest
Posts: n/a

 01-14-2008
I am trying to write a sunction for complex multiplication of 2
complex numbers

function complex_multiply(a : signed; b: signed; c : signed; d:
signed) return signed;
(a + bi)(c + di) = [ac - bd] + [ad + bc]i.

I am not sure on how I would return the real and imaginary part of the
result. As per my understanding functions can return only one value.
How do i represent the inputs and outputs? I want to write code in
VHDL to be implemented on an FPGA.

Nicolas Matringe
Guest
Posts: n/a

 01-14-2008
Ann a écrit :
> I am trying to write a sunction for complex multiplication of 2
> complex numbers
>
> function complex_multiply(a : signed; b: signed; c : signed; d:
> signed) return signed;
> (a + bi)(c + di) = [ac - bd] + [ad + bc]i.
>
> I am not sure on how I would return the real and imaginary part of the
> result. As per my understanding functions can return only one value.
> How do i represent the inputs and outputs? I want to write code in
> VHDL to be implemented on an FPGA.

Hi
Define your complex number as an array of two signed numbers

type complex is array(0 to 1) of signed(your_range);

function complex_multiply(a : complex; b : complex) return complex;
(a(0) + a(1).i)(b(0) + b(0).i) = [a(0)b(0)-a(1)b(1)] + [a(0)b(1) +
a(1)b(0)]i

You could even overload the '*' operator for type complex

Nicolas

KJ
Guest
Posts: n/a

 01-14-2008
On Jan 14, 3:04*pm, Ann <(E-Mail Removed)> wrote:
> I am trying to write a sunction for complex multiplication of 2
> complex numbers
>
> function complex_multiply(a : signed; b: signed; c : signed; d:
> signed) return signed;
> (a + bi)(c + di) = [ac - bd] + [ad + bc]i.
>
> I am not sure on how I would return the real and imaginary part of the
> result. As per my understanding functions can return only one value.
> How do i represent the inputs and outputs? I want to write code in
> VHDL to be implemented on an FPGA.

Define a new complex record type...
type t_My_Complex_Type is record
Real: signed;
Imag: signed;
end record;

Now your function would be defined as

function complex_multiply(a, b : t_My_Complex_Type) return
t_My_Complex_Type is
variable RetVal: t_My_Complex_Type;
begin
RetVal.Real := a.real * b.real - a.imag * b.imag;
RetVal.Imag := a.real * b.imag + b.real * a.imag;
return(RetVal);
function complex_multiply;

If you're really feeling gutzy, you can instead call the function
"*" (with the double quotes) and you'll be defining an override for
the multiply operator so you could use your function like this...

C <= A * B;

C <= complex_multiply(A,B);

But I would suggest getting it working with the new type and seeing
how that all works first. Record types are synthesizable.

Kevin Jennings

Nicolas Matringe
Guest
Posts: n/a

 01-14-2008
KJ a écrit :
> On Jan 14, 3:04 pm, Ann <(E-Mail Removed)> wrote:
>> I am trying to write a sunction for complex multiplication of 2
>> complex numbers
>>
>> function complex_multiply(a : signed; b: signed; c : signed; d:
>> signed) return signed;
>> (a + bi)(c + di) = [ac - bd] + [ad + bc]i.
>>
>> I am not sure on how I would return the real and imaginary part of the
>> result. As per my understanding functions can return only one value.
>> How do i represent the inputs and outputs? I want to write code in
>> VHDL to be implemented on an FPGA.

>
> Define a new complex record type...
> type t_My_Complex_Type is record
> Real: signed;
> Imag: signed;
> end record;

Right, that's cleaner (more readable) than my solution with an array.

Nicolas

FPGA
Guest
Posts: n/a

 01-14-2008
On Jan 14, 3:34*pm, KJ <(E-Mail Removed)> wrote:
> On Jan 14, 3:04*pm, Ann <(E-Mail Removed)> wrote:
>
> > I am trying to write a sunction for complex multiplication of 2
> > complex numbers

>
> > function complex_multiply(a : signed; b: signed; c : signed; d:
> > signed) return signed;
> > (a + bi)(c + di) = [ac - bd] + [ad + bc]i.

>
> > I am not sure on how I would return the real and imaginary part of the
> > result. As per my understanding functions can return only one value.
> > How do i represent the inputs and outputs? I want to write code in
> > VHDL to be implemented on an FPGA.

>
> Define a new complex record type...
> type t_My_Complex_Type is record
> * *Real: *signed;
> * *Imag: signed;
> end record;
>
> Now your function would be defined as
>
> function complex_multiply(a, b : t_My_Complex_Type) return
> t_My_Complex_Type is
> * *variable RetVal: t_My_Complex_Type;
> begin
> * RetVal.Real := a.real * b.real - a.imag * b.imag;
> * RetVal.Imag := a.real * b.imag + b.real * a.imag;
> * return(RetVal);
> function complex_multiply;
>
> If you're really feeling gutzy, you can instead call the function
> "*" (with the double quotes) and you'll be defining an override for
> the multiply operator so you could use your function like this...
>
> C <= A * B;
>
>
> C <= complex_multiply(A,B);
>
> But I would suggest getting it working with the new type and seeing
> how that all works first. *Record types are synthesizable.
>
> Kevin Jennings

It gave me errors. The result would be twice as long as the lengths of
a or b. So RetVal cannot be of type t_My_Complex_Type. I did the
following and it is compiling fine.

type t_My_Complex_Type is record
Real: signed(31 downto 0);
Imag: signed(31 downto 0);
end record;

type Result_Complex_Type is record
Real: signed(63 downto 0);
Imag: signed(63 downto 0);
end record;

function complex_multiply(a, b : t_My_Complex_Type) return
Result_Complex_Type is
variable RetVal: Result_Complex_Type;
begin
RetVal.Real := a.real * b.real - a.imag * b.imag;
RetVal.Imag := a.real * b.imag + b.real * a.imag;
return(RetVal);
end function complex_multiply;

How do i simulate this? What should be the type of a and b in the
simulation file. Should they be 64 bit vectors each ?

KJ
Guest
Posts: n/a

 01-15-2008

"FPGA" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
On Jan 14, 3:34 pm, KJ <(E-Mail Removed)> wrote:
> On Jan 14, 3:04 pm, Ann <(E-Mail Removed)> wrote:
>
> > I am trying to write a sunction for complex multiplication of 2
> > complex numbers

>
> > function complex_multiply(a : signed; b: signed; c : signed; d:
> > signed) return signed;
> > (a + bi)(c + di) = [ac - bd] + [ad + bc]i.

>
> > I am not sure on how I would return the real and imaginary part of the
> > result. As per my understanding functions can return only one value.
> > How do i represent the inputs and outputs? I want to write code in
> > VHDL to be implemented on an FPGA.

>
> Define a new complex record type...
> type t_My_Complex_Type is record
> Real: signed;
> Imag: signed;
> end record;
>
> Now your function would be defined as
>
> function complex_multiply(a, b : t_My_Complex_Type) return
> t_My_Complex_Type is
> variable RetVal: t_My_Complex_Type;
> begin
> RetVal.Real := a.real * b.real - a.imag * b.imag;
> RetVal.Imag := a.real * b.imag + b.real * a.imag;
> return(RetVal);
> function complex_multiply;
>
> If you're really feeling gutzy, you can instead call the function
> "*" (with the double quotes) and you'll be defining an override for
> the multiply operator so you could use your function like this...
>
> C <= A * B;
>
>
> C <= complex_multiply(A,B);
>
> But I would suggest getting it working with the new type and seeing
> how that all works first. Record types are synthesizable.
>
> Kevin Jennings

> It gave me errors. The result would be twice as long as the lengths of
> a or b. So RetVal cannot be of type t_My_Complex_Type. I did the
> following and it is compiling fine.

Well it depends on just how much precision you think you need in the
calculation. I'm guessing that 32 bits would've been enough. The range for
each of the elements of the complex type should be made to be large enough
to handle whatever range of complex numbers that you plan to be able to use.
That being the case, all that is needed then is to strip off the lower bits
of the result as shown below

RetVal.Real := (a.real * b.real - a.imag * b.imag)(a'range);
RetVal.Imag := (a.real * b.imag + b.real * a.imag)(a'range);

<snip>
> How do i simulate this? What should be the type of a and b in the
> simulation file. Should they be 64 bit vectors each ?

a and b need to be whatever width you need them to be to give you whatever
precision you need for your calculations. Whether that's 5 bits, 8 bits, 32
bits or something else I can't say since I don't know what precision you

Kevin Jennings

pontus.stenstrom@gmail.com
Guest
Posts: n/a

 01-15-2008
On 14 Jan, 21:04, Ann <(E-Mail Removed)> wrote:
> I am trying to write a sunction for complex multiplication of 2
> complex numbers
>
> function complex_multiply(a : signed; b: signed; c : signed; d:
> signed) return signed;
> (a + bi)(c + di) = [ac - bd] + [ad + bc]i.
>
> I am not sure on how I would return the real and imaginary part of the
> result. As per my understanding functions can return only one value.
> How do i represent the inputs and outputs? I want to write code in
> VHDL to be implemented on an FPGA.

Note that you can save a multiplier:
ac-bd = a(c-d) + d(a-b)
and if (c,d) is a constant, you can precompute (c-d) and (c+d).

Pontus

KJ
Guest
Posts: n/a

 01-15-2008
Slight correction to previous post. Instead of

RetVal.Real := (a.real * b.real - a.imag * b.imag)(a'range);
RetVal.Imag := (a.real * b.imag + b.real * a.imag)(a'range);

It should be

RetVal.Real := (a.real * b.real - a.imag * b.imag)
(a.real'range);
RetVal.Imag := (a.real * b.imag + b.real * a.imag)
(a.imag'range);

KJ

Ann
Guest
Posts: n/a

 01-17-2008
On Jan 15, 7:32*am, KJ <(E-Mail Removed)> wrote:
> Slight correction to previous post. *Instead of
>
> * * *RetVal.Real := (a.real * b.real - a.imag * b.imag)(a'range);
> * * *RetVal.Imag := (a.real * b.imag + b.real * a.imag)(a'range);
>
> It should be
>
> * * *RetVal.Real := (a.real * b.real - a.imag * b.imag)
> (a.real'range);
> * * *RetVal.Imag := (a.real * b.imag + b.real * a.imag)
> (a.imag'range);
>
> KJ

Thanks a bunch. I will try this out.

Jonathan Bromley
Guest
Posts: n/a

 01-18-2008
On Mon, 14 Jan 2008 21:20:29 +0100, Nicolas Matringe wrote:

>Ann a écrit :
>> I am trying to write a sunction for complex multiplication of 2
>> complex numbers

>Define your complex number as an array of two signed numbers
> type complex is array(0 to 1) of signed(your_range);

The problem with that approach, and also if you try
to use a record...

type complex_r is record
Re: signed(your_range);
Im: signed(your_range);
end record;

.... is that "your_range" must be fixed at the outset.

There is an alternative approach.

type complex_bit is record
Re: std_logic;
Im: std_logic;
end record;
type complex is array (natural range <>) of complex_bit;

Now I can choose the width of my complex numbers easily:

...
variable complex_8: complex(7 downto 0);
variable complex_16: complex(15 downto 0);
...

Doing arithmetic then becomes just a little messy, but
it's easy enough to write a package that does the job.
The key is a group of functions to extract real and
imaginary parts from the complex object, and to compose
complex values from existing real and imaginary parts:

function Re(c: complex) return signed is
variable result: signed(c'range);
begin
for i in c'range loop
result(i) := c(i).Re;
end loop;
return result;
end;
(and, of course, similarly for Im)

function to_complex(Re: signed; Im: signed := "0")
return complex is
constant width: positive := max(Re'length, Im'length);
variable norm_Re, norm_Im: signed(width-1 downto 0);
variable c: complex(width-1 downto 0);
begin
norm_Re := resize(Re, width);
norm_Im := resize(Im, width);
for i in c'range loop
c(i) := (norm_Re(i), norm_Im(i));
end loop;
return c;
end;

function to_complex(Re: integer; Im: integer; bits: positive)
return complex is
begin
end;

These functions are pretty clumsy, but will synthesize to
nothing more than a bunch of wires, so that's OK. And then
you can easily overload the arithmetic operators...

function "+"(L, R: complex) return complex is
begin
end;

function "*"(L, R: complex) return complex is
begin
Im(L) * Re(R) + Re(L) * Im(R) );
end;

Once again, fully synthesisable. "*" will return an
appropriately widened result, and you can then pick
whatever bits you need from that wide product.

You'll also need resize(), ability to do arithmetic
between complex and scalar values (both integer and
signed), and a few other things. Writing a good
arithmetic package is non-trivial.

All this stuff can go into a package. If your synth
tool can cope with numeric_std and records, it can cope
with this. Yes, I know simulation will be a little slow
because of all the packing and unpacking of bits into
the complex data type, but I reckon that's a small price
to pay for the convenience and regularity of this sort
of thing:

...
use work.complex_pkg.all;
...
variable A, B, result : complex(7 downto 0);
variable product16 : complex(15 downto 0);
...
product16 := A*B;
result := product16(15 downto ;

I have most of this done already; would people find it
useful if I were to work it up in detail? (Oh, and
would I get some of the credit for the assignments?)
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.