CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Custom Math function

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

Custom Math function
PostPosted: Thu Apr 15, 2004 11:07 am     Reply with quote

I have a lot of places in code where I need to perform scaling of a number. This is not a problem but I would like to reduce the math operation. Here is an example.

This is required only once.
Code:

Int16 Analog_Input_1_Low;
Int16 Analog_Input_1_High
Int16 Analog_Input_1_RAW;
Int32 Analog_Input_1_m;

   Analog_Input_1_m=Analog_Input_1_High-Analog_Input_1_Low;
   Analog_Input_1_m=0x10000000/Analog_Input_1_m;

This is required for each reading that is taken.
Code:

   Analog_Input_1_Reading=((int32)(Analog_Input_1_RAW-Analog_Input_1_Low) * Analog_Input_1_m) >> 16;


I want to write a function to perform the math with some improvements.
1. Don’t solve the lower 2 bytes of the multiply.
2. Place the function inline to prevent copy operations.
3. Build the shift operation into the function.

I have been looking to find a library with a 32x32 mult function I can re-write to do this. I haven’t been able to find anything.
valemike
Guest







comp.arch.embedded
PostPosted: Thu Apr 15, 2004 12:42 pm     Reply with quote

I have no code (yet), but supposedly Microchip's C18 compiler has 32x32 multiplies, AND the source code to go with it. If you download their demo from the microchip.com website, you might find what you're looking for.

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&threadm=200303101114.40179%40ned.bike-nomad.com&rnum=5&prev=/groups%3Fq%3D32x32%2Bmultiply%2BPIC%26ie%3DUTF-8%26oe%3DUTF-8%26hl%3Den
SteveS



Joined: 27 Oct 2003
Posts: 126

View user's profile Send private message

PostPosted: Fri Apr 16, 2004 7:07 am     Reply with quote

Can you give some more detail on what you need to do - like range of the the various values and accuracy looked for? I assume it's all unsigned? I had to do similiar math in a past project- I have to go find it.

- SteveS
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

PostPosted: Fri Apr 16, 2004 7:52 am     Reply with quote

SteveS wrote:
Can you give some more detail on what you need to do - like range of the the various values and accuracy looked for? I assume it's all unsigned? I had to do similiar math in a past project- I have to go find it.

- SteveS


I'm measuring the input from an analog source. For example I have a measurment that ranges from a low of 200 to a high of 800. To scale this reading from 0 to 4095 I use the formula shown. This method also works to scale an output or any other linear measurement from one range to another. I think this is something a lot of people do one way or another. In my example the value 0x10000000 determines the range of the functions output.
ThadSmith



Joined: 23 Feb 2004
Posts: 5
Location: Boulder, CO, USA

View user's profile Send private message

PostPosted: Thu Apr 22, 2004 4:41 pm     Reply with quote

Neutone wrote:
I'm measuring the input from an analog source. For example I have a measurment that ranges from a low of 200 to a high of 800. To scale this reading from 0 to 4095 I use the formula shown. This method also works to scale an output or any other linear measurement from one range to another. I think this is something a lot of people do one way or another. In my example the value 0x10000000 determines the range of the functions output.


In your example, you need to multiply by approximately 6.x.
With some pre-scaling and post-scaling, a 16x16-> 32 bit multiply would work. If you want custom, I can give you a 16x16->16 bit fractional multiply that would work with a simple prescale, but not postscale.

Thad


Last edited by ThadSmith on Fri Apr 23, 2004 11:16 am; edited 1 time in total
Neutone



Joined: 08 Sep 2003
Posts: 839
Location: Houston

View user's profile Send private message

PostPosted: Thu Apr 22, 2004 5:56 pm     Reply with quote

0x10000000 / (800 - 200) = 447392 // My fractional M value

447392 / 2^16 = 6.82666015625


When the analog input is 800

((800 - 200)*447392 ) / 2^16 = 4095.99609375

This is how I am doing this in software right now.
ThadSmith



Joined: 23 Feb 2004
Posts: 5
Location: Boulder, CO, USA

View user's profile Send private message

PostPosted: Fri Apr 23, 2004 11:12 am     Reply with quote

Neutone wrote:
0x10000000 / (800 - 200) = 447392 // My fractional M value

447392 / 2^16 = 6.82666015625


When the analog input is 800

((800 - 200)*447392 ) / 2^16 = 4095.99609375

This is how I am doing this in software right now.


I am assuming that you are trying to reduce the execution time of the calculation. If so, here is a fractional 16-bit procedure in C (tested in PCM) that runs faster by only retaining 16 bits in the product accumulator and by taking advantage of the limited numbrer of bits in one of the operands (600 in your example).

Code:

typedef int16        uint16_t;  /* C99 standard for unsigned 16 bit */
typedef signed int16 int16_t;   /* C99 standard for   signed 16 bit */

/* Function:    mpy16fs
** Description: This function multiplies two unsigned 16 bit values and
**              returns the scaled results.  It takes advantage of the
**              limited number of bits in one operand and has restrictions
**              on the scaling factor in order to produce quicker results.
**              Due to the technique used (right shifting of multiplicand)
**              there is some precision lost.
**              As abits decreases, the operation performs faster and
**              with greater accuracy.  The limit is determined by the
**              size of the operand a.
**
** Example:     Assume there are two operands in the known ranges:
**              a = 0 to 500 integer
**              bf = 0 to 10.0 fractional
**              abits can be set to 9 (9 bits maximum).
**              bf can be scaled by (1<<11), to maintain maximum precision.
**                bscaled = (uint16_t) (bf * (1<<11));
**                p = mpy16f (9, a, bscaled, 11);
**              This will return p ~= (uint16_t)(a*bf);
*/
uint16_t            /* a*bscaled >> shift   */
mpy16fs (
    byte        abits,  /* maximum number of significant bits in a,
                        ** 1..16                                    */
    uint16_t    a,      /* multiplier,   0..(1<<abits)-1            */
    uint16_t    bscaled,/* multiplicand, 0..0x7fff                  */
    byte        shift   /* post scaling, abits..abits+15            */
) {
    uint16_t prod = 0;
    shift -= abits;

    /* prescale multiplier for faster result */
    a <<= (16-abits);

    if ((int16_t)a < 0) prod = bscaled;
    bscaled >>= 1;

    do {
        if ((int16_t)(a <<= 1) < 0) prod += bscaled;
        bscaled >>= 1;
    } while (--abits);
    return prod >>= shift+1;
}


This takes about 280 cycles for a product, while the 32-bit version takes about 610. You can customize it with your abits and shift values to slightly reduce the execution time.

If the accuracy isn't good enough, there is another procedure that runs in about the same average time, but has higher worse case timing, which retains more precision.

Thad
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group