## Need help in efficient code

5 posts / 0 new
Author
Message

Hello all
I need to implement function:
//************************************************
u16 percent,maxpercent;

result = a-(a-b)*(percent/maxpercent);
//************************************************
What it has to do is give me fade effect from value a to value b.
percent/maxpercent changes from 0 to 1.
I need this code to work as fast as possible, becase I have to operate with arrays of starting values and end values.
Current implementation is too slow, maybe somebody have an idea how can I improve the algoritm...

Pre-compute (b*(percent/maxpercent)) once at the beginning, then subtract
(add?) that value on successive steps.

Thanks, this is what I've done so far:

static u08 cross_fade(u08 A, u08 B, u16 progress, u16 max_progress)
{
if(max_progress > 255)
{ // If max_progress is big then run the necessary code - 43us
if(A > B)
return A - (unsigned long)(A-B)*progress/max_progress;
else
return A + (unsigned long)(B-A)*progress/max_progress;
}
else
{ //If max_progress is small then run the faster code - 14us
if(A > B)
return A - (unsigned int)(A-B)*progress/max_progress;
else
return A + (unsigned int)(B-A)*progress/max_progress;
}
}

Questions:
1) What is the typical change in "progress" between calls to crossfade() ? Is it always incremented by 1?

2) What is the typical value for max_progress? Is it a constant?

3) Are you trying optimize the average runtime or the maximum runtime of crossfade; is it in an interrupt routine?

crossfade() can be made more efficient by removing the division operation. There are several ways to do it, depending on how crossfade() is used and complicated you want to make it:

A) If max_progress is a constant, implement it as a power of two and use a right bit-shift instead of the division.

B) If delta_progress is constant, use some more fixed point math. Save the result of crossfade as a non-integer and have a non-integer constant increment [ delta_progress*(B-A)/max_progress ]

C) If delta_progress is constant, use a generalization of Bresenham's line-drawing algorithm to interpolate from A to B over time.

--Brian

The lighting consoles I worked on used DSP processors to do this for 512 channels.

For this to work without integer rounding problems, you need to use fixed point arithmetic. This is not quite as complex as it sounds. Whilst your start and end values are bytes, you need to have some fractional storage. Thus your end value and increment/decrement value have to be larger than a byte - maybe you'll need to use a long. The fractional part I talk about is implied as it can be the lower 16 bits of the long integer. So you need to shift the result values when you store and retrieve them.

long acc; //our accumulator. we use a 16 bit fraction
u08 start;
u08 end;
//