3 point smoothed curve

Hi guys

I am trying to create a 3 point smoothed curve. Application is engine fuel control - as rpm changes the engines efficiency changes and fuel delivered needs to match this efficiency curve.

Ive discovered fscale(), pow(), and a few other math functions but ive not had any success tweaking any of them to take the inputs i have to work with.

Currently i am using map() which gives me 2 straight lines between the 3 points but its not ideal.

ve

Input
RPM (X axis)

Variables
fuel-low
rpm-low
fuel-mid
rpm-mid
fuel-high
rpm-high

Output
fuel-result (Y axis, blue dot)

I have spent a good deal of time on websites like mycurvefit and reading about beizer curves and quadratic equations, but this is way over my head and am really hoping theres an arduino function/simple-ish solution that solves this for me. Any ideas?

Thanks.

By the time you have collected and processed your 3 points it will be too late to do any kind of feedback control

1 Like

I have all the time in the world, in this case
Timing non critical
I'll look into multimap, looks like a good option, cheers. Still open to other suggestions!

Three points are enough to fit a quadratic curve to the data. Here is a simple program that will do that (it can use more input points, if you have them).

// fit quadratic curve to x and y

float x[] = {0.0, 1.0, 2.0};
float y[] = {1.1, 3.5, 2.1};
float a = 0.0, b = 0.0, c = 0.0;

void fit_G( int N_points, float px[], float py[], float* a, float* b, float* c ) {

  int i;
  float S00, S10, S20, S30, S40, S01, S11, S21;
  float denom, x, y;
  S00 = S10 = S20 = S30 = S40 = S01 = S11 = S21 = 0;

  for (i = 0; i < N_points; i++) {
    x = px[i];
    y = py[i];
    S10 += x;
    S20 += x * x;
    S30 += x * x * x;
    S40 += x * x * x * x;
    S01 += y;
    S11 += x * y;
    S21 += x * x * y;
  }
  S00 = N_points;

  denom =   S00 * (S20 * S40 - S30 * S30) - S10 * (S10 * S40 - S20 * S30) + S20 * (S10 * S30 - S20 * S20);

  *c = (S01 * (S20 * S40 - S30 * S30) - S11 * (S10 * S40 - S20 * S30) + S21 * (S10 * S30 - S20 * S20)) / denom;
  *b = (S00 * (S11 * S40 - S30 * S21) - S10 * (S01 * S40 - S21 * S20) + S20 * (S01 * S30 - S11 * S20)) / denom;
  *a = (  S00 * (S20 * S21 - S11 * S30) - S10 * (S10 * S21 - S01 * S30) + S20 * (S10 * S11 - S01 * S20) ) / denom;

}

void setup() {

  Serial.begin(115200);
  delay(2000); //wait for connection
  Serial.println("Quadratic fit program");
  // find a, b, c for curve fit
  fit_G( 3, x, y, &a, &b, &c);
  Serial.print("a, b, c = ");
  Serial.print(a);
  Serial.print(", ");
  Serial.print(b);
  Serial.print(", ");
  Serial.println(c);

  Serial.println("Check: x, calculated y");
  for (int i = 0; i < 3; i++) {
    float yc = a * x[i] * x[i] + b * x[i] + c;
    Serial.print(x[i]);
    Serial.print(", ");
    Serial.println(yc);
  }
}

void loop() {}

Output from above:

Quadratic fit program
a, b, c = -1.90, 4.30, 1.10
Check: x, calculated y
0.00, 1.10
1.00, 3.50
2.00, 2.10

are you trying to doing something line a spline curve fitting?

See

where you can enter data and pick from a number of curve fitting functions.

I used RPM divided by 100 just to wrangle the numbers; thus is a quadratic fit:

HTH

a7

1 Like

Can this code be configured so that i can feed it an x value as an input, and it results a y value?

I have defined my 3 x and y values to create the curve using your code. How do i then feed the code an input value for the x-axis and have it give me a y-value as a result?

Said another way, ive defined the 3 red points in my image, but dont see how i can look up a fuelqty value (y) using an rpm input value (x) to find the blue point.

Thanks for taking the time

This in #5 above from @jremington lets you fit a quadratic curve. The points x and y used in the examp,e are here

float x[] = {0.0, 1.0, 2.0};
float y[] = {1.1, 3.5, 2.1};
float a = 0.0, b = 0.0, c = 0.0;

and the result

Quadratic fit program
a, b, c = -1.90, 4.30, 1.10

Means you can write a function

float fuelQuantity(float theRPM)
{
  return -1.9 * theRPM * theRPM + 4.3 * theRPM + 1.1;
}

Obvsly you'll want to put your own x, y pairs into the curve fitting code. Or use the website I linked in #7 above.

Your numbers are large on the output side so you'll get small coefficients, I used your RPM numbers divided by 100 or something like that.

a7

Reading off your chart I used these x, y pairs

10, 16
22, 60
30, 80
60, 70

as four points and used the curve fit site to caculate

   y = -0.06996 * x * x + 5.982 * x - 37.04;

The curve agrees nicely at least over the range you have provided.

a7

It already is, in this part, reposted here:

  Serial.println("Check: x, calculated y");
  for (int i = 0; i < 3; i++) {
    float yc = a * x[i] * x[i] + b * x[i] + c;
    Serial.print(x[i]);
    Serial.print(", ");
    Serial.println(yc);
  }

x[i] can be anything you want. I just used the original x values to show that it worked.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.