From linear to exponential PWM output

Hi,

Anyone with more knowledge then I have at the present moment about the following?
A trigger handle moves from 0 to 100% in 0 to 255 steps which present the X-axis.
The Y-axis presents the output (PWM) that has the values ranging from 0 to 100% so too 0 to 255.
So currently the output value is linear to the position of the trigger handle.
Now I like to make this output not linear but exponential in both directions so negative and positive in relation to the position of the trigger handle.
The value of making the linear line curved is coming from a byte length variable called speedcurveValue and the final output byte length variable is called speedfinalValue.

With google I found the equation for a straight line is "y = mx + b", in which "m" and "b" are constants.
So simple as it looks exponential equation is "y = axb", in which "a" and "b" are constants.
If "b" = 1, then this is simply a straight line with a y-intercept of zero and a slope equal to "a" (in this case, 1). If "b" is greater than 1, then the graph curves upward. If "b" is less than 1 but greater than 0, then the graph flattens out
So how can I rework the formula so the output depending on the trigger position is making an exponential out output with calculate in either directions.

So 1 to 1,5 to get negative exponential and 1 to 0,5 to get positive exponential

Any help in the right direction would be swell.

Thanks, Paco

So simple as it looks exponential equation is "y = axb", in which "a" and "b" are constants.

Most equations are written with spaces between the variables and operands. The use of superscripts is important, too.

It really isn't clear what you are trying to do, with negative values. The Arduino doesn't do negative voltages. The Arduino doesn't do anything but constant PWM values.

Perhaps if you drew a picture of what you are trying to accomplish, with properly labeled X and y axes, it would make more sense.

Hi Paul,

Here the requested graph with the current linear and the negative and positive exponential curve.
I hope this clear things up.
If not let me know

Paco

Hi,

I can guess what this is for.

it's a common adjustment on RC controllers, it increases or decreases sensitivity around the throttle and steering centre points. It looks like a simple function that but my maths is way to rusty to attempt a definition.

A naive implementation would be to use a sine function with an offset, if you move the offset forwrd, you get the r shaped curve, if you move it back, you get the j shaped part of the curve. I am certain there is a better method but this might help other grasp what you are after, unless I am mistaken.

Duane B

rcarduino.blogspot.com

You are talking about "exponential" but actually mean "power law". Exponential would be y = a^x, you are talking x^a, for some constant a.

You want something like

  float y = a * pow (x, b) ;

In your graph what you call negative isn't negative, its powers between 0 and 1. Negative powers are infinite at x=0. What you call positive is powers greater than 1.

This is quadratic, not exponential.
For the "negative" curve you can use: y = x * x / 255.0;
For the "positive" curve use: y = sqrt(x * 255.);

Pete

We've established its a power law with the power potentially varying from 0.5 to 1.5 at least, controlled by an 8 bit variable called speedcurveValue.

  float x = analogRead (inpin) / 1024.0 ;
  float y = pow (x, speedcurveValue / 128.0) ;  // assume speedcurveValue is 128 * the power
  analogWrite (outpin, (int) (y * 255)) ;

Is the sort of thing I believe to flesh out previous answer.

Suggestion - Put some numbers in a spreadsheet. Make an input columm and an output column. Your ADC input values go from 0-1023, and your PWM output values go from 0-255. At this point we don't know the formula or exponent, so just put-in the approximate "answer" you want. And, don't start-out with all 256 output values... 20 or 25 should be enough. If it makes it easier, put-in values from 0-100 for both the input and output. You can scale/tweak for the real values later.

Now, make a 3rd column an stick a formula in it. Just experiment with the exponential formula 'till you get numbers close to the answers you want. Excel can make a graph too, if that helps you to compare the calculated values with what you ideally want.

There are a couple of ways to handle negative values. If we are talking about negative voltages, that has to be done in hardware. To get a negative value (in software) from the ADC, you can simply subtract 512 (or 511) from the reading (then "half-way" will read zero). Same thing on the output-side. half-way is 128 (or 127). I'm not sure if this will be necessary, but you can use different formulas for the "positive" and "negative" values, if it makes things easier.

For exponents, Excel uses POWER(), and the Arduino uses pow(), and they are used slightly-differently. So, check the Excel help file & Arduino language reference.

if my math still works at this late hour, negative curves are in general:

y = pow(x, n) / pow(255, n-1);

n=0 => y = x^0 / 255^-1 => y = 255 flatliner :wink:
n=1 => y = x^1 / 255^0 => y = x
n=2 => y = x^2 / 255^1 => y= x^2/255;
n=3 => y = x^3 / 255^2

n=3.14159 is also possible

the positive curves a

y = pow(x * pow(255, n-1), 1/n);

n=1 => y = x;
n=2 => y = (x * 255)^0.5
n=3 => y = (x * 255^2)^0.33333

(please verify in excel ...)

Whow,

Thanks for all suggestions sofar from all of you.

Duane is 50% right. The word exponential is to be found in many rc controllers fr many years to control the power output as shown in the graph.
But in this case it is not for the RC world but for the slotcar world.

For the user for now it is not needed to know how the exp curve runs exactly.
Slot racers are people who are working a lot with the feel of the interaction of the car in the slot and things they do with the trigger.
They are not so interested by the real figures they dial in.
However my slotrace controller project is in the end to show all figures and values they use on PC or Android Mobilephone or tablet by BT.

Although the word negative is used I know the Arduino cant do anything with negative values.
We do not want to output negative values but we want curves that are expected to be different then the linear striagth line when they are following the value of the trigger.

For extra info.
We take the value from a contactless linear hall sensor and map that to 0 to 255

What is mend with negative is the way the curve behaves compared to the linear straigth line.
So if the curve goes below the linear straight line it is a negative curve value.

Here some code:

// control the outputs with output cross block function  to prevent speed and brake to be ON together 
      sensorValue = analogRead(sensorspeedPin); // read the raw value from the linear hall sensor:
      sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);// apply the calibration to the sensor reading
      if (sensorValue > 250) {sensorValue = 255;} // to make sure full 100% PWM value is reached even if sensor value is not 100%
      speedValue = map(sensorValue, deathbandValue, 255, 0, 255);
         
      speedvalueWorked = map(speedValue, sensorMin, sensorMax, speedstartValue, 255); // added startspeed value
      >>>>>>>> speedcurveValue = speedvalueWorked with the quotation to calculate the exponential power curve // added speedcurve value
      speedfinalValue = speedcurvevalue
      if (sensorValue > deathbandValue) {analogWrite(pwmoutspeedPin, speedfinalValue); analogWrite(pwmoutbrakePin, 0);} // startspeed and curve included
      else
      {analogWrite(pwmoutspeedPin, 0); analogWrite(pwmoutbrakePin, brakeValue); digitalWrite(ledPin, HIGH);}

The triggerhandle use a deathband around the 0 point to be sure the mechanical tolerances are taken out.
As long as the sensorvalue is inside the deathband value the breaks are ON. Deathband variable in byte length is adjustable from 0 to 15.
As soon as the sensorvalue is outside the deathband zone the PWM output is activated.
You can add startspeed so the motor does not start at 0 but at a higher value depending on the motor charactristics.
If the speed curve is linear the motor will follow that straight line from lets say startspeed 45 to 255.
When the speed curve is an other value this straight line must be curved.

I hope this clears up more (if not let me know) and other can benefit from it in other projects.

will work on it and let you know th results.
Other tips and tricks are always welcome.

Paco

Ok. I've read everybody. MarkT has equation right. No need for variable exponent though.
Try this first to verify the math is what you want. It is exponential gamma correction with "gamma" being the exponent.
Then you can change gamma to, say 0.5 or 0.75.
When you have the curve you want use real input for x instead of the loop index.

float gamma = 1.5;
for (x=0; x<256; x++)
{
float normx = x / 255.0;
float normy = pow (normx, gamma);
int y = (int) (0.5 + normy * 255);

serial.print("x: ");
serial.print(x, DEC);
serial.print(" y: ");
serial.println(y, DEC);
}

Another suggestion. Since this curve is to be applied repeatedly, there is no sense wasting time always computing the correction with slow floating point math. Build a table as an array of ints. Fill it properly in the setup code, using the gamma value you have chosen.
Then as you need it, use tableCorrection[x] instead of x. Much faster; no floating point involved.

indeed a table version is much faster and can be stored in progmem. Only drawback of a table is that one cannot use a dynamic (adjusted) gamma factor.

Another option is multiMap - http://arduino.cc/playground/Main/MultiMap - approach any graph with multiple linear lookup tables.

Hi,

I looked into the extra suggestions.
Getting more confused as my knowledge in this, is way below the things you guys offer.
Willing to learn so I started with the Excel option to see the proposed curves.
Now here again some expect one to build things as easy as it sounds. :slight_smile:

I can create collums and graphs in Excel but putting the fourmula and copy them to the cells is the tricky part.
I have done it manually but know this could be performed automaticly.
Probably used the wrong formula.

Paco

formula y=squareb.xlsx (14.2 KB)

IN Excel you can show the formula in the graph which you need to convert to code.

Select the line in the graph an right mouse you have options to select trend-line(?) [don't have an English Excel here ]

OK,

Got Excel working with copying formulas.
Now when I use Rob his formula just as an example y = pow(x, n) / pow(255, n-1)
then the result is not what we are aming at.
The final last result Y should always be 255 when X is 255 too.
With the suggestion from techylah I converted the Arduino formula to excel but there same result.
Where do I go wrong?

Paco

formula pow255.xlsx (15.9 KB)

formula pow255 techyla.xlsx (16.2 KB)

I am unable to open either of the xlsx files, (at least with Bytescout XLS viewer). Can someone check that they are valid?

To put the conversion into a single equation:

curvedvalue = floor(0.5 + pow(value/255.0, 0.5) * 255);

As value goes from 0 to 255, curvedvalue also goes from 0 to 255, but in an exponentially curved way.
For example, if value is 64 ( 1/4) , curvedvalue should come out 128 (1/2).

This might help debug.
64 / 255 = 0.251
pow(0.251, 0.5) = 0.5001
0.5001 * 255 = 127.75
floor (0.5 + 127.75) = 128

Note that though your input and output values are integers, the intermediate calculations must be floating point.
Important only for your Arduino code, not the spreadsheet.

a quick look at the sheet:

The formula =($B7^$D$5)/(255^ $D$5-1 ) should be =($B7^$D$5)/(255^ ($D$5-1) )

Thank both,

Rob was on it.

I saved it as older excel version.

Will try to get it in Arduino form now.

formula pow255 techyla correct.xls (33.5 KB)

=($B7^$D$5)/(255^ ($D$5-1) )

float val = pow(input, n) / pow(255, n-1);

n = <0..1>
n = 1
n = <1..-->

when n = <0..1> it is the mirror image of 1/n

e.g. 0.25 and 4 are mirrored in y=x