Need help in efficient code

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all
I need to implement function:
//************************************************
u08 a; //Start fade value
u08 b; //End fade value
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...
Help please!!!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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;
}
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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
long delta; //signed add/subtract
u08 start;
u08 end;
//
// calc the fade delta
//
delta = (long)(start<<16) - (long)(end <<16);
delta /= timeval; //timeval is the time you want the fade to take

//
// proccess this every time tick
//
acc+=delta; //increment/decrement the accumulator by the fade delta value
end = acc>>16; //return the current integer fade value

As you can see, for a number of channels there's a bit of processing. For speed, you'll need to do this in assembler and maybe use 24bits operations to save even more time. You can see why the large control desks have a bit of processing! 512 channels needs a big cpu. Going to a 32bit cpu will help tremendously.