Fitting curves to data with an Arduino or Embedded hardware

Polynomial math

If you need to easily fit a curve to a given set of data on an Arduino, or other embedded device running C, there seems to be no obvious choice in libraries, so I developed my own simple library to do it.

Fitting a curve to a set of data is extremely useful if you’re interested in applying machine learning to time series data. This is where arduinoCurveFitting comes in!

https://github.com/Rotario/arduinoCurveFitting

This small library can be imported into your Arduino IDE and used to fit polynomial curves to a set of points with a max order of 20. Let’s have a quick recap on polynomial curves.

Polynomial Curves

These curves are defined by a mathematical function where y is a function of x. For example:

Second order polynomial: y = x²

2nd order polynomial function

Third order polynomial: y = x³ + 2x² +3

3rd order polynomial

The largest power of x (the small numbers above each x)denotes the function’s order, the higher the order, generally the more complex the curve. This also means the higher the order, the better your curve fits your data.

The number next to an x is called its coefficient, for example in y = 2x² the x² coefficient is 2. For the purpose of using these curves in machine learning and other applications, all that’s needed are the coefficients in the curve.

Curve fitting on a microcontroller

The Arduino curve fitting library can be downloaded from the Github link at the top of this page. Once you’ve installed it into the Arduino IDE using the “import library” function, you can start using it to fit curves to your data!

1 – Include necessary header

#include <curveFitting.h>

2 – Initialise data and choose order of polynomial

We have our data in an array of 50 points called x.

This is the array you should fill with your sensor data. In this example we’re going to generate some data in the program.

double x[50]; //fill this with your sensor data
Our X data

To use curveFitting, we need to create an array that will be populated with the coefficients from the curve fitting process. This array needs to be big enough to hold all the coefficients generated, which is the order of the curve you want plus one extra. Let’s use a simple 2nd order.

3 – Fit Curve

int order = 2;
double coeffs[order + 1];
double t[sizeof(x)/sizeof(double)];for (int i = 0; i < sizeof(x)/sizeof(double); i++){
    t[i] = i;
    x[i] = power(i, 2);
    //should generate function y = x^2}int ret = fitCurve(order, sizeof(x)/sizeof(double), t, x, sizeof(coeffs)/sizeof(double), coeffs);

Here fitCurve returns a number, where 0 means it ran correctly so we print out the coefficients.

4 – Print out coefficients

if (ret == 0){ //Returned value is 0 if no error
    uint8_t c = 'a';
    Serial.println("Coefficients are:");
    for (int i = 0; i < sizeof(coeffs)/sizeof(double); i++){
        Serial.printf("%c=%ft ",c++, coeffs[i]);
    }
}

Since our data was a perfect curve, the Serial data printed out is:

Coefficients are:
 a = 1.000
 b = 0.000
 c = 0.000

Putting these coefficients into:

y = ax² + bx + c

We get:

y = x²

Which is the function we used to populate the data before, our curve fitting algorithm works!

Next week we’ll be looking at machine learning applications for this library!

Email me info@workyourtech.com with your questions!

4 Replies to “Fitting curves to data with an Arduino or Embedded hardware

  1. Hello, to which variable should we assign the coordinates of the points on the curve?
    For example: A (0; 3) B (2; 1) C (4; 3)
    whose returned result would be: a = 0.5 b = -2 c = 3 or f (x) = 0.5 * x² -2 * x +3
    Thank you beforehand.
    cordially

    Bonjour, a quelle variable faut-il attribuer les coordonnées des points de la courbe ?
    Par exemple : A(0;3) B(2;1) C(4;3)
    dont le résultat retourné serait : a=0.5 b=-2 c=3 soit f(x)= 0.5*x² -2*x +3
    En vous remerciant d’avance.
    Cordialement

    1. Hi Kos,
      You have to allocate two arrays for your x and y values, in the case of fitting a curve to 3 points


      int order = 2;
      double coeffs[order + 1];
      float x = {0, 2, 4};
      float y = {3, 1, 3};
      int ret = fitCurve(order, sizeof(x)/sizeof(float), x, y, sizeof(coeffs)/sizeof(double), coeffs);

      Should give you the coefficients you’re looking for in the coeffs array!
      Any more questions don’t hesitate to ask!

  2. Hi, awesome library! Thanks for sharing. Could you point out in your code where I could add the option to fix the “Y” intercept point to some value, or zero in most cases. I believe it is a matter of fixing the last coefficient to the desired value.
    Best Regards!

Leave a Reply to Kos Cancel reply

Your email address will not be published. Required fields are marked *