Solving a 3rd order polynomial

Here's a challenge for the community, how do I solve a 3rd order polynomial on the the Zero? And before anyone asks, this is not homework but for a company prototype.

I am reading a TI ADS122U04 ADC connected to resistance level sensor that has a some non-linearity to it. Because of the non-linearity I need my Zero to process the raw ADC value into a corrected level reading. I used Excel and determined that the linearization formula is:

y=237.27x3-5426.1x2-135810x-98691

where y is equal to the ADC value and x is equal to the level reading in inches. It's easy enough to plug this formula into Excel or my calculator and have them solve for x, now I just need the Zero to run this math in real time.

y=237.27x3-5426.1x2-135810x-98691

Depending on your definition of "real time", how about:

float y(float x) {
  return 237.27*x*x*x - (5426.1*x*x + 135810.0*x + 98691);
}

Avoid using pow() for integer exponents; it's over-complicated and unnecessarily slow.
Are you sure about that polynomial? I expect most corrections to be approximately linear, while your y(0) = - 98691
What are you expecting the input range to be?

Should you not use the inverse function? After all you are looking for x, not for y....

I am only reading the sensor value once every 30 seconds so not exact in real time :slight_smile:

I'm pretty sure about the polynomial, it was generated by Excel and when you plug in the ADC decimal reading it does calculate the the correct height reading within a 1/10th of a inch.

The reason behind y(0) = - 98691 is that there is a slight imbalance in the Wheatstone bridge that causes ADC to dip into the negative range slightly when the sensor is sitting at 0 inches. When calculating the equation I intentionally had Excel calculate the intercept starting at the lowest value. I do have another sensor that stays positive the whole. This is really just a manufacturing issue I have to work out to ensure the bridge is balanced better.

And I did look at using the inverse function, I couldn't even type it into this posting it had so many exponents and square roots.

Please give the ADC output range, as well as the range in inches. I inspected your equation and it looks wrong to me, as it can only yeld big negative values.....which of course happens with all negative signs after the X^3 term.

I flipped a sign typing on the forum, that's why it looks wrong. The correct equation is:

y=237.27x3 - 5426.1x2 + 135810x - 98691

The math works for ADC codes -98691 through 6494291, which translate to a 1-32" sensor range.

@westfw Now I have to ask you, how do I actually use that code you posted? It's a little beyond my experience level.

I do not see how you can input ADC values 0 to 6,494,291 into Arduino zero.... Would not be more feasible to go into Arduino with the raw sensor analog values, scrapping the ADC?

The correct equation is:
y=237.27x3 - 5426.1x2 + 135810x - 98691
The math works for ADC codes -98691 through 6494291, which translate to a 1-32" sensor range.

Still looks wrong to me. y(0) is -98691, which is not in the range of 1 to 32...

@westfw Now I have to ask you, how do I actually use that code you posted? It's a little beyond my experience level.

Really? It is basic function usage. Here it is in a test sketch...

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

float polyAdjust(float x)
{
  return 237.27*x*x*x - 5426.1*x*x + 135810.0*x - 98691;
}
void loop() {
  // put your main code here, to run repeatedly:
  Serial.println(polyAdjust(-90000));
  Serial.println(polyAdjust(-40000));
  Serial.println(polyAdjust(0));
  Serial.println(polyAdjust(10000));
  delay(30000);
}

The 3rd order equation now works correctly, as tested in Excel.

However I do not understand why use the ADC, when setting, for example, 12 bit of read resolution, a resolution of 32/4096 = 0.0078" (0.25 mm) can be easily achived.

Also consider that the 3rd order equation given by Excel does not provide absolute precision, but is just an approximation whose error (it can be tested) will probably be greater (especially at high values of X) than 0.0078".

Finally I do not know how one could enter the raw values 0 to 6,494,291 into Arduino Zero.

@westfw I'm flat out embarrassed I didn't recognize that was just a function.

@glovisol The Zero uses a 32 bit processor so it's more than capable of handling a 24bit number like 6,494,291. The reason I can't use the internal ADC is because I am working with a 5VDC sensor... I would probably destroy the processor if I attached the sensor to it.

  1. The 5V max sensor output can be easily handled by reducing the sensor output (with a 2 resistor voltage divider) to 2.5 V max. With this you would lose just 1 bit resolution.

  2. Of course the Zero can handle the proposed figures. What I do not know (and would be grateful if you explained) how you enter this data: as a microvolt voltage? Or perhaps writing to the serial monitor?

I'm not entering any data, everything is coming from the ADC.

How is the ADC connected to the ZERO?