Calculating slope using array issues

Hi guys new to the forum but I’m stuck and was hoping for some expertise. Now before I start I will say my coding knowledge is somewhat limited so please keep it simple on the replies or I’ll just be asking loads of stupid questions. So basically I’m trying to calculate the slope of a line using 2 reading for 2 different sensors spaced a set time apart. So the formula is
slope=(y2-y1)/(x2-x1)
Where x1 and y1 are the first reading from each sensor and x2 and y2 are the second reading. This is run in a loop using an array to store the first readings. I think I have it working right but when it calculates the slope is keeps rounding off to a integer and I don’t know why. Even when I set the float to 6 decimal places it still does it. I’ve only added serial print after each section to check the code. I’m sure this is some simple but I can’t figure it out or maybe I’ve just gone the completely wrong way with this program.
Thanks

const int numReadings = 4;

int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int slope = 0; // the average
int input1Pin = A0; // set A0 to input pin
int input1Value = 0;
int input2Pin = A1;
int input2Value = 0;
int shaftforce = 0;
int displacement = 0;
void setup()
{
// initialize serial communication with computer:
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
}
void loop() {
int sensor1Value = analogRead(A0);
float shaftforce = sensor1Value * (5.0/1023.0);
Serial.println(shaftforce);
int sensor2Value = analogRead(A1);
float displacement = sensor2Value * (5.0/1023.0);
Serial.println(displacement);
// read from the sensor:
readings[0] = (analogRead(A0));
Serial.println(readings[0]);
readings[2] = (analogRead(A1));
Serial.println(readings[2]);
delay (1000);
readings[1] = (analogRead(A0));
Serial.println(readings[1]);
readings[3] = (analogRead(A1));
Serial.println(readings[3]);
float slope = (readings[1]-readings[0])/(readings[3]-readings[2]);
Serial.println(slope, 6);

// if we’re at the end of the array…
if (index >= numReadings)
// …wrap around to the beginning:
index = 0;

// calculate the average:

// send it to the computer as ASCII digits

delay(1000); // delay in between reads for stability
}

Slope.jpg

float slope = (readings[1]-readings[0])/(readings[3]-readings[2]);

If the 2nd and 3rd elements happen to be equal, what happens?

520 - 616 = -96 834 - 798 = 36

-96/36 = -2

What's the problem?

Here's what I think:   float slope = (readings[1]-readings[0])/(readings[3]-readings[2]);This line calculates the value of the slope. All of the variables on the right hand side are integers, so the compiler does the whole calculation using integer math, yields an integer result, and dutifully assigns that integer to the float variable slope.

To fix this, you can cast either the numerator or the denominator of the fraction as float, like this:  float slope = (float)(readings[1]-readings[0])/(readings[3]-readings[2]);A purist might cast both as float.

Here's what else I think:

  • You should address the issue of a denominator of zero, as noted above.
  • You should use code tags to post your code. Any number of confusing things can happen when you don't.
  • You should read "How to use this forum ..., " posted as the first entry in all the many forums.

Finally, please note that you've declared slope twice: once as a global int, and once as a float local to loop(). I don't see that you ever use the global variable. You probably don't want it at all.

Shouldn’t one of the axis represent time?

 float slope = (readings[1]-readings[0])/(readings[3]-readings[2]);

The readings[] values are all stored as ints and unless you tell the compiler to use them differently the math done on the right hand side of the = will be done as ints. You tell the compiler how by using a cast and remember that inside of parens is a little domain where casts outside only get applied after being operated on.

int A = 1;
int B = 5;
Serial.println( A/B ); // prints 0

float C;
C = (float) A / (float) B; // C now == 0.2 or very close, floats are "funny" that way.

(float) above is the cast. Verb of cast is casting. "Casting" is short for "type casting".

Mixing data types without specifying how they are to interact is the cause of lots of hair loss and not just for newbs.

tmd3: To fix this, you can cast either the numerator or the denominator of the fraction as float, like this: float slope = (float)(readings[1]-readings[0])/(readings[3]-readings[2]);A purist might cast both as float.

Excellent guys thank you very much for the help, it's now giving me the accuracy I was looking for. Appreciate the other feedback too. The serial print is showing the correct number but if readings are equal to zero then 'nan' or 'inf' are printed, I take it this is due to me not dealing with the issue of zero value reading as you guys mentioned. I've tried to figure it out but I'm not having much joy so maybe one of you guys could help with this?

Thanks

adt222: ... dealing with the issue of zero ... help with this?

  • Calcualte the denominator
  • Check to see if it's zero
  • If it is, do something appropriate
  • Otherwise, proceed as usual

"Something appropriate" might be printing a message, like, "Look out! It's gonna blow!" or maybe shutting something down. or maybe just printing "undefined" instead of printing a number.

adt222:

tmd3: To fix this, you can cast either the numerator or the denominator of the fraction as float, like this: float slope = (float)(readings[1]-readings[0])/(readings[3]-readings[2]);A purist might cast both as float.

Excellent guys thank you very much for the help, it's now giving me the accuracy I was looking for. Appreciate the other feedback too. The serial print is showing the correct number but if readings are equal to zero then 'nan' or 'inf' are printed, I take it this is due to me not dealing with the issue of zero value reading as you guys mentioned. I've tried to figure it out but I'm not having much joy so maybe one of you guys could help with this?

Thanks

That is going to give you a float of the finished integer operation inside the parens. 1/5 would give 0.0 not 0.2. You need to divide float by float not int by int.

As noted above, you need to check for divide by 0 and perhaps return a very large value for slope.

Isn't slope only useful when one of the axis is linear? I'm genuinely curious. The readings are being timed but time is ignored in the graph. If x was time the zero denominator problem doesn't exist.

The OP is plotting displacement (y) against shaft force (x). If shaft force keeps increasing shouldn't he watch for regular intervals in shaft force then read displacement and plot? If shaft force isn't always rising wouldn't the resulting graph be a scatter graph? You can't find the slope of such a graph.

I'm really just curious.

Really good coding practices don't leave the possibility of a crash.

Murphy was an optimist.

GoForSmoke:   float slope = (float)(readings[1]-readings[0])/(readings[3]-readings[2]);

That is going to give you a float of the finished integer operation inside the parens.

Indeed. It casts the expression inside the parentheses as float. The parentheses, though, don't wrap the whole expression - they wrap only the numerator. With the numerator cast as float, the division is carried out in floating point.

1/5 would give 0.0 not 0.2.

I get a different result. Here's test code:

void setup() {
  int readings[] = { 0, 1, 0, 5 };
  Serial.begin(115200);
  float slope = (float)(readings[1]-readings[0])/(readings[3]-readings[2]);
  Serial.println(slope);
}
void loop() {}

Here's output:0.20as expected.

I should have taken more time on that.

Jimmy60: Isn't slope only useful when one of the axis is linear? I'm genuinely curious. The readings are being timed but time is ignored in the graph. If x was time the zero denominator problem doesn't exist.

The OP is plotting displacement (y) against shaft force (x). If shaft force keeps increasing shouldn't he watch for regular intervals in shaft force then read displacement and plot? If shaft force isn't always rising wouldn't the resulting graph be a scatter graph? You can't find the slope of such a graph.

I'm really just curious.

The idea is that each loop will return 4 values, which are essentially x1,y1,x2,y2. If you plotted these on a force vs. displacement graph, the 1's are your start point and the 2's as the end point, you'll end up with two point on the graph, join them with a line and dependent on the values, you'll get various results for the slope. I am using that slope to directly relate to material density, which I should have explained is what I am trying to asses. The shaft force is to do with the force placed on a shaft which is connected to a grasping mechanism, in this case I'm using the shaft force to measure the grasping force. The displacement is measuring the shaft position, so I'm working out the change in force for a set time period, in relation to the change in the shaft displacement for the same time period. Using this I can relate it to the density of the material that I am grasping. Low density material will give smaller changes in force with larger changes in shaft displacement while higher density material will give larger increase in force for smaller changes in shaft displacement. Not sure if that's any clearer but that's the thinking behind it.

Thanks

And when the shaft stops turning and delta-displacement is zero your numbers go to?