DSPRelated.com
Forums

multiplication (by 0.1, 0.5, 0.7, 1.3 ...) in fixed point arithmetic

Started by Stefan Huber August 25, 2004
Hello, 
I have to port following 2 code lines from floating to fixed point:

ytotmax = MAX( yampl[c1], ytotmax );   
yampl[c1] = MAX( G * ytotmax, yampl[c1] );  

All variables are floatings, yampl is a buffer, ytotmax is a temp
variable and G a weighting factor.

For the further problem explanation, ul always stands for unsigned
long. For scaling from floating point to fixed point, I do following:
First, I looked at lots of our test files and searched for the biggest
floating point value to scale underneath smaller 1.

So, the biggest floating point value is 1042056.6 which I scale with
0x0100000h to 0.99378263950347900:

temp_d = y_ampl[x] / Divisor = 1042056.6 / 0x0100000h =
0.99378263950347900

This value, stored as a double, will be scaled to fixed-point with
#define LVHF_MAX_32 0x07FFFFFFF:

temp_ul = temp_d * LVHF_MAX_32 = 0.99378263950347900 * 0x07FFFFFFF =
2134131967

Everything is OK. Now the problem, the G-value, which is 0.5 and which
could also be expressed as a division by 2 value:

double_G = float_G / Divisor = 0.5 / 0x0100000h =
4.7683715820312500e-007
ul_G = double_G * LVHF_MAX_32 = 1023

Fine.
But when I do now a max-comparison, it won't work right, because

ybuf_ul[x] = MAX( G * aValue_ul, ybuf_ul[x] );

the expression G * aValue_ul is now different, in floating point G was
0.5 and the result of the multiplication was always smaller then the
former aValue_float, but now, it's a multiplication by 1023 and
aValue_ul is not smaller, it's a bigger value then before. OK, the
radix-point has changed and the range of values is different, but how
to take this into account?

OK, I remember some expressions like (for the TI C55xx platform):

MAC uns(*AR0-),*CDP, AC2 :: MAC uns(*AR1-),*CDP, AC3
MAC *(AR0-T1), *CDP+, AC2>>#16 :: MAC *(AR1-T1), *CDP+, AC3>>#16 

where after an multiply/accumulate the results was shifted to the
right, so is this my problem in understanding, in G * aValue_ul I also
have to do a right-shift?

But which one, OK if G is 0.5 it's a right shift by 2, but G can also
be 0.1, 0.6, 1.754, ...

Thanks a lot for understanding and helping in my problem.

Lovely greetz from Stefan
Hello.

The first thing I found in your description was that convertig G as a
weighting factor to fixed point is wrong. Your conversion by using the
scheme

fixed = float /0x0100000 *0x7FFFFFFF

would result for G*value in

(fixed)G*value = (float)G * (float)value /0x100000^2 *0x7FFFFFFF^2.

That's where your multiplication error comes from.

I have a question concerning your task: why fixed point? Do you have
to port the task on a fixed point CPU? If so, there are floating point
libraries for some fixed point processors available in the internet. I
know of projects using open libraries for the PIC processors. But be
careful, these are using a large amount of programming memory. The
other way could be to develop your own floating point format, either
by using the float-format with exponent and mantissa or by putting a
virtual comma into your 32Bit-word. The bits left from the comma are
the integer part of your number, the right hand part is the fraction.
There are a lot of methods to be found describing this.

Hope this helps.

--------------
Heiko Marx
DSP Engineer
www.sinusmess.de
Hello Heiko,
I fixed the problem inside the assembler code, it's porting an
existing project in C to a TI C55x platform, so the scaling was
already done, but nobody told me while having this problem. Thanx for
help, Stefan