TWiki > RisePrivate Web>StickyBotController? >InterpolateOptimization (21 Apr 2007, MarkCutkosky)
There are a couple different techniques used to optimize the code for speed. One is to minimize the number of divisions. Another is to unroll the for loop. Finally, I used only static variables, because their location in RAM is fixed and therefore the reference in code is also fixed.

The linear interpolation takes on the form:

Where the time variables are repesented by unsigned 16-bit numbers and the position variables are represented by unsigned 8-bit numbers.

In order to perform the division only once, a fractional representation of is required. Considering that the end result is a 8-bit number and the maximum number handled by the C18 complier is 32-bit, we can use a 24-bit fractional representation. If we consider 0x01000000 to be equal to one, then we can use the lower bytes as fractions and discard them after the operation.

Using this, we perform the operation:

static unsigned long divisor = 0x01000000 / (unsigned long)(time_final - time_initial);

Doing the casting after the subtraction to ensure proper wrapping. Since the static keyword is used, the location of divisor in memory is fixed, which can speed up the code. The registers are fixed so their values in memory can be hard coded by the complier/linker.

Unrolling the for loop means the code

for(i = 0; i < 5; i++)
   Value[i] = Numerator[i] * divisor;
is replaced by
Value[0] = Numerator[0] * divisor;
Value[1] = Numerator[1] * divisor;
Value[2] = Numerator[2] * divisor;
Value[3] = Numerator[3] * divisor;
Value[4] = Numerator[4] * divisor;

Which is trading program size for speed. Note: you must turn off function optimization or the complier will re-roll the loop.

The final bit of ompitization is the access of the most significant byte from the 32-bit number.

We can't use

MSByte = Value / 0x01000000;
as it will call the division subroutine

If we use

MSByte = Value >> 24;
it will perform a series of shifts.

The best way is to use pointers.

MSByte = *(((unsigned char *)(&Value)) + 3);

The &Value operation will find the address of Value in memory. The C18 compiler is little-endian which means that the location of Value corresponds to the least significant byte. To provide access to the 8-bit numbers, the pointer is cast to (unsigned char *). By adding 3 to the pointer, this shifts the address up by three 8-bit spots to get the most significant byte. The * operator accesses the byte and places it into MSByte. This operation disassembles into a single MOVFF operation.

-- SalomonTrujillo - 20 Jun 2006

  • interpolate.c: Source code for linear interpolatation optimization

 
This site is powered by the TWiki collaboration platformCopyright &© by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback