# Fitting curves to data with an Arduino or Embedded hardware 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²

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

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; //fill this with your sensor 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!

## 11 Replies to “Fitting curves to data with an Arduino or Embedded hardware”

1. Kos says:

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. Rowan Easter-Robinson says:

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. Gabriel says:

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!

3. Tregix says:

Hello,
Thanks for this library. I would like to know if it could easily be modified to fit a decaying Sin function: a+b.exp(-c.t).sin(d.t+e) ? Or do one needs a different algorithm. Thanks a lot.
Best regards.

1. Rowan Easter-Robinson says:

Hi Nicolas, I’ve had a look at this and it’s pretty nontrivial. Is this something to do with control theory?

1. Tregix says:

Sorry for the late reply. No it is for analyzing physics data generated by a mechanical oscilator. Thank you for looking at it.

1. Rowan Easter-Robinson says:

Hi Tregix,
No problem. I’ll have a look at trying to implement some Non-linear least squares regression using this algo (http://people.duke.edu/~hpgavin/ce281/lm.pdf).

I’m pretty busy with uni work right now, but should be free come May. I’ll let you know how it goes! If it works, then it should allow any non-linear function to be used.
Rowan

1. Rowan Easter-Robinson says:

Hi Tregix, I’ve got a working algorithm in Julia, for my own learning, it seems to work fairly well given good guesses for first parameters, can you confirm if you can make a good guess at the sine wave parameters before you fit the data to it?

4. Nicola says:

Dear Rowan,
I’ve got a nice problem for you. I am working on an irrigation system and I am looking to use mainly 3 sensors to monitor how much water to give, such as DHT (air humidity and temperature) a photodiode(light) and a soil capacitor(soil moisture). The main parameter would of course be soil moisture, but this sensors tends to degrade pretty easily, so I would like to use the other parameters to build a kind of predicting model, using the first cycles of measurements. So if at a certain point the measured soil moisture and the predicted one disagree significantly the Arduino will be able to give an error message/ignore the soil moisture sensor reading.
So my question is: any idea how I could implement this thing in my code? any library suggestion to use?

Thanks a lot
Nicola

1. Rowan Easter-Robinson says:

Hi Nicola,
That’s an interesting problem! Sounds like you’d want to build a regression model, using the soil capacitor as your truth value. If you can, I would suggest building this model “offline” (https://stats.stackexchange.com/questions/897/online-vs-offline-learning), after gathering lots of data from different scenarios.
If you’d like any help – send me an email and we can discuss it.
Rowan