EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Optimize pow() function

Started by pozz September 22, 2016
I have to convert voltage measure (Volt) into power (Watt).  As you 
know, the physics says I need to square the voltage measure.

I have to calibrate the mathematical law and I have two points:
0W -> 0V
<nominal power> -> <voltage at nominal power>

That could be enough, but we noticed a different relation between volt 
and watt at intermediate points. I, as the software engineer, have to 
try to compensate differences from the theory, without increasing 
complexity during calibration.

My idea is to calibrate the exponent: it is normally 2.00, but I can 
calibrate from 1.00 to 3.00.
In this way, the two old calibration points are the same as before.  So 
the exponent (the third calibration measure) can be changed at last.

The problem is pow() function with double arguments takes a lot of time 
to finish.  Do you suggest a mathematical method to reduce its complexity?


uint16_t power_nominal = 1500;   // In Watt
uint16_t volt_nominal;   // Volt measured at nominal power
signed uint8_t exp_corr = -100 to +100;
double exp = 2.00 + exp_corr;

uint16_t volt = adc_convert(...);  // Actual volt measure
double alpha = (double)power_nominal / pow((double)volt_nominal, exp);
uint32_t watt = alpha * pow((double)volt, exp);


alpha can be pre-calculated, because power_nominal, volt_nominal and exp 
are constant (after calibration). The last instruction is the problem.
On 9/22/2016 6:36 AM, pozz wrote:
> I have to convert voltage measure (Volt) into power (Watt). As you know, the > physics says I need to square the voltage measure. > > I have to calibrate the mathematical law and I have two points: > 0W -> 0V > <nominal power> -> <voltage at nominal power> > > That could be enough, but we noticed a different relation between volt and watt > at intermediate points. I, as the software engineer, have to try to compensate > differences from the theory, without increasing complexity during calibration. > > My idea is to calibrate the exponent: it is normally 2.00, but I can calibrate > from 1.00 to 3.00. > In this way, the two old calibration points are the same as before. So the > exponent (the third calibration measure) can be changed at last. > > The problem is pow() function with double arguments takes a lot of time to > finish. Do you suggest a mathematical method to reduce its complexity? > > > uint16_t power_nominal = 1500; // In Watt > uint16_t volt_nominal; // Volt measured at nominal power > signed uint8_t exp_corr = -100 to +100; > double exp = 2.00 + exp_corr; > > uint16_t volt = adc_convert(...); // Actual volt measure > double alpha = (double)power_nominal / pow((double)volt_nominal, exp); > uint32_t watt = alpha * pow((double)volt, exp); > > > alpha can be pre-calculated, because power_nominal, volt_nominal and exp are > constant (after calibration). The last instruction is the problem.
No, the "problem" lies in your transducer/measurement error. The definition of a "watt" (power) doesn't change just because your observations of that APPARENT relationship (V ~ W) "has issues". Perhaps your load's characteristics are changing as a function of operating point. Or, nonlinearities in your measurement system. Or, ... Ask yourself WHY the exponent needs to be changed. I suggest you don't have an accurate model of your load and its excitation. Until you do, how will you know that this is the CORRECT means of compensating your model to agree with your observations?
On Thu, 22 Sep 2016 15:36:11 +0200, pozz wrote:

> I have to convert voltage measure (Volt) into power (Watt). As you > know, the physics says I need to square the voltage measure.
Only if you're talking about voltage applied to a resistive load. There's a lot of loads that aren't purely resistive.
> I have to calibrate the mathematical law and I have two points: > 0W -> 0V <nominal power> -> <voltage at nominal power> > > That could be enough, but we noticed a different relation between volt > and watt at intermediate points. I, as the software engineer, have to > try to compensate differences from the theory, without increasing > complexity during calibration. > > My idea is to calibrate the exponent: it is normally 2.00, but I can > calibrate from 1.00 to 3.00. > In this way, the two old calibration points are the same as before. So > the exponent (the third calibration measure) can be changed at last. > > The problem is pow() function with double arguments takes a lot of time > to finish. Do you suggest a mathematical method to reduce its > complexity? > > > uint16_t power_nominal = 1500; // In Watt uint16_t volt_nominal; // > Volt measured at nominal power signed uint8_t exp_corr = -100 to +100; > double exp = 2.00 + exp_corr; > > uint16_t volt = adc_convert(...); // Actual volt measure double alpha = > (double)power_nominal / pow((double)volt_nominal, exp); uint32_t watt = > alpha * pow((double)volt, exp); > > > alpha can be pre-calculated, because power_nominal, volt_nominal and exp > are constant (after calibration). The last instruction is the problem.
As already suggested, the first thing to do is determine what's wrong with your measurement and fix it. Assuming you can't do that, the first thing that I'd suggest is to use interpolation or a curve fit to a number of measured points. Interpolation is easy -- just store a number of calibration points and then use linear, quadratic, or cubic interpolation between them. Even cubic interpolation should be quicker than using pow. Alternately, fit a function y = A + B * x + C * x^2 + D * x^3 to your calibration points, and store A, B, C & D in memory. -- Tim Wescott Control systems, embedded software and circuit design I'm looking for work! See my website if you're interested http://www.wescottdesign.com
Il giorno gioved&igrave; 22 settembre 2016 17:01:51 UTC+2, Tim Wescott ha scritto:

> function y = A + B * x + C * x^2 + D * x^3 to your calibration points, > and store A, B, C & D in memory.
and the use the alternate form: y = A + x *(B + x *(C + x*D)) to calculate the thing, so you need less operations. Bye Jack
On Thu, 22 Sep 2016 08:08:38 -0700, Jack wrote:

> Il giorno gioved&igrave; 22 settembre 2016 17:01:51 UTC+2, Tim Wescott ha > scritto: > >> function y = A + B * x + C * x^2 + D * x^3 to your calibration points, >> and store A, B, C & D in memory. > > and the use the alternate form: > > y = A + x *(B + x *(C + x*D)) > > to calculate the thing, so you need less operations. > > Bye Jack
Definitely. Unless you're doing the computations with an ADSP 21xx chip, in which case you can code up my original function into a hardware loop, with one set of registers doing a MAC and another register doing z = z * x at each iteration. Very handy, if you happen to need to do it. (The ADSP 21xx core is a frustrating chip to write optimized code for. It has a buttload of registers, each of which does two or three things, and no two of which do the _same_ set of things. So you'll be coding along, and have to go back a dozen instructions just to (ferinstance) use x2 instead of x1, so that when you get to where you are you don't need to juggle data around.) -- Tim Wescott Wescott Design Services http://www.wescottdesign.com I'm looking for work -- see my website!
Tim Wescott <seemywebsite@myfooter.really> wrote:

> On Thu, 22 Sep 2016 08:08:38 -0700, Jack wrote: > > > Il giorno gioved&#4294967295; 22 settembre 2016 17:01:51 UTC+2, Tim Wescott ha > > scritto: > > > >> function y = A + B * x + C * x^2 + D * x^3 to your calibration points, > >> and store A, B, C & D in memory. > > > > and the use the alternate form: > > > > y = A + x *(B + x *(C + x*D)) > > > > to calculate the thing, so you need less operations. > > > > Bye Jack > > Definitely. Unless you're doing the computations with an ADSP 21xx chip, > in which case you can code up my original function into a hardware loop, > with one set of registers doing a MAC and another register doing z = z * > x at each iteration. Very handy, if you happen to need to do it. > > (The ADSP 21xx core is a frustrating chip to write optimized code for. > It has a buttload of registers, each of which does two or three things, > and no two of which do the _same_ set of things. So you'll be coding > along, and have to go back a dozen instructions just to (ferinstance) use > x2 instead of x1, so that when you get to where you are you don't need to > juggle data around.)
or you can let the C compiler do the job for you ;) Bye Jack -- Yoda of Borg am I! Assimilated shall you be! Futile resistance is, hmm?
Den torsdag den 22. september 2016 kl. 21.12.25 UTC+2 skrev Jack:
> Tim Wescott <seemywebsite@myfooter.really> wrote: > > > On Thu, 22 Sep 2016 08:08:38 -0700, Jack wrote: > > > > > Il giorno gioved&#283; 22 settembre 2016 17:01:51 UTC+2, Tim Wescott ha > > > scritto: > > > > > >> function y = A + B * x + C * x^2 + D * x^3 to your calibration points, > > >> and store A, B, C & D in memory. > > > > > > and the use the alternate form: > > > > > > y = A + x *(B + x *(C + x*D)) > > > > > > to calculate the thing, so you need less operations. > > > > > > Bye Jack > > > > Definitely. Unless you're doing the computations with an ADSP 21xx chip, > > in which case you can code up my original function into a hardware loop, > > with one set of registers doing a MAC and another register doing z = z * > > x at each iteration. Very handy, if you happen to need to do it. > > > > (The ADSP 21xx core is a frustrating chip to write optimized code for. > > It has a buttload of registers, each of which does two or three things, > > and no two of which do the _same_ set of things. So you'll be coding > > along, and have to go back a dozen instructions just to (ferinstance) use > > x2 instead of x1, so that when you get to where you are you don't need to > > juggle data around.) > > or you can let the C compiler do the job for you ;) >
the adsp21xx c compiler was horrible, but assembler was very human readable
On Thu, 22 Sep 2016 21:12:21 +0200, Jack wrote:

> Tim Wescott <seemywebsite@myfooter.really> wrote: > >> On Thu, 22 Sep 2016 08:08:38 -0700, Jack wrote: >> >> > Il giorno gioved&igrave; 22 settembre 2016 17:01:51 UTC+2, Tim Wescott ha >> > scritto: >> > >> >> function y = A + B * x + C * x^2 + D * x^3 to your calibration >> >> points, >> >> and store A, B, C & D in memory. >> > >> > and the use the alternate form: >> > >> > y = A + x *(B + x *(C + x*D)) >> > >> > to calculate the thing, so you need less operations. >> > >> > Bye Jack >> >> Definitely. Unless you're doing the computations with an ADSP 21xx >> chip, >> in which case you can code up my original function into a hardware >> loop, with one set of registers doing a MAC and another register doing >> z = z * x at each iteration. Very handy, if you happen to need to do >> it. >> >> (The ADSP 21xx core is a frustrating chip to write optimized code for. >> It has a buttload of registers, each of which does two or three things, >> and no two of which do the _same_ set of things. So you'll be coding >> along, and have to go back a dozen instructions just to (ferinstance) >> use x2 instead of x1, so that when you get to where you are you don't >> need to juggle data around.) > > or you can let the C compiler do the job for you ;)
I pity the poor bastard who's called upon to do a good job making an optimizing compiler for that chip. It's the answer to the question "How can an instruction set _not_ be orthogonal?" -- Tim Wescott Wescott Design Services http://www.wescottdesign.com I'm looking for work -- see my website!
Il 22/09/2016 16:17, Don Y ha scritto:
 > On 9/22/2016 6:36 AM, pozz wrote:
 >> I have to convert voltage measure (Volt) into power (Watt).  As you
 >> know, the
 >> physics says I need to square the voltage measure.
 >>
 >> I have to calibrate the mathematical law and I have two points:
 >> 0W -> 0V
 >> <nominal power> -> <voltage at nominal power>
 >>
 >> That could be enough, but we noticed a different relation between volt
 >> and watt
 >> at intermediate points. I, as the software engineer, have to try to
 >> compensate
 >> differences from the theory, without increasing complexity during
 >> calibration.
 >>
 >> My idea is to calibrate the exponent: it is normally 2.00, but I can
 >> calibrate
 >> from 1.00 to 3.00.
 >> In this way, the two old calibration points are the same as before.
 >> So the
 >> exponent (the third calibration measure) can be changed at last.
 >>
 >> The problem is pow() function with double arguments takes a lot of
 >> time to
 >> finish.  Do you suggest a mathematical method to reduce its complexity?
 >>
 >>
 >> uint16_t power_nominal = 1500;   // In Watt
 >> uint16_t volt_nominal;   // Volt measured at nominal power
 >> signed uint8_t exp_corr = -100 to +100;
 >> double exp = 2.00 + exp_corr;
 >>
 >> uint16_t volt = adc_convert(...);  // Actual volt measure
 >> double alpha = (double)power_nominal / pow((double)volt_nominal, exp);
 >> uint32_t watt = alpha * pow((double)volt, exp);
 >>
 >>
 >> alpha can be pre-calculated, because power_nominal, volt_nominal and
 >> exp are
 >> constant (after calibration). The last instruction is the problem.
 >
 > No, the "problem" lies in your transducer/measurement error.
 > The definition of a "watt" (power) doesn't change just because your
 > observations of that APPARENT relationship (V ~ W) "has issues".
 >
 > Perhaps your load's characteristics are changing as a function
 > of operating point.  Or, nonlinearities in your measurement system.
 > Or, ...
 >
 > Ask yourself WHY the exponent needs to be changed.  I suggest you
 > don't have an accurate model of your load and its excitation.
 > Until you do, how will you know that this is the CORRECT means of
 > compensating your model to agree with your observations?


I know the problem is in the poor quality of the transducer, but I'm 
only in charge of the software and the hardware engineer can't fix it 
(often the software solves hardware issues).

So I need a more complex law. The quadratic law (one parameter) can be 
calibrated with a single measure (nominal value). The generic power law 
(exponent not exactly equals to 2, two parameters) needs two calibration 
measures and has a nice feature: it's very simple to calibrate in two steps.

The input section has an hardware calibration, a simple digital trimmer.
So the first step is to calculate the power from the measured voltage 
with the following formula:
   P = Pn / (Vn ^ 2) * (V ^ 2)
where Pn is the nominal power and Vn is the voltage needed at nominal 
power.  The user increase/decrease the trimmer pot until the correct 
power is displayed.

Second step. Change the power to another value (half of nominal power, 
for example). If the transducer works as in theory, the measured power 
is correct. Otherwise the user increase/decrease the exponent until the 
power displayed is correct. The power is calculated as:
   P = Pn / (Vn ^ exp) * (V ^ exp)

After the second step, we are sure the first calibration point is yet 
valid, because that formula is correct when V=Vn, even if exp isn't 2.


If I use the linear law P=AV^2+BV, I think the two calibration steps 
aren't indipendent: the operator should execute two measures, the system 
should save the two couples (P,V) and only after that calculate A and B 
coefficients.


It seems to me the exponentiation law is simpler during calibration.
Il 22/09/2016 16:17, Don Y ha scritto:> [...]
 > Until you do, how will you know that this is the CORRECT means of
 > compensating your model to agree with your observations?

I don't need the CORRECT means, but only a sufficiently good means of 
compensanting a not ideal system.


The 2024 Embedded Online Conference