How can I calculate the correct acceleration from a measured velocity?

I am using a moving average filter to get more stable results:

static float  v[5], a[5], a_sum, v_sum, prev_v;
static unsigned int lastTime, lastTime_2, n;

if((millis() - lastTime) > 10){                   // measure every ten milliseconds
     v_sum -= v[n];
     v[n] = measure();                            // delete oldest measurement, add new measurement
     v_sum += v[n];

    a_sum -= a[n];
    a[n] = (v[n] - prev_v) / 0.01;                // a = dv / dt
    a_sum += a[n];
    prev_v = v[n];
    
    n++;
    if(n > 4) n = 0;
    lastTime = millis();
  
}

if((millis() - lastTime_2) > 1000){
  Serial.println(a_sum / 5);
  lastTime_2 = millis()
}  

The results I am getting are not plausible, they are way too high. I think the way I am calculating the acceleration is wrong, but I don't know how exactly. Can somebody help me?

You need several things to calculate the acceleration:

  1. Displacement (S) i.e how far you have gone.
  2. Initial velocity (U) i.e how fast you were going at the start
  3. Final velocity (V) i.e what your speed was at the point in time being looked at

The equation for acceleration is then:

a = ( V2 - U2 ) / ( 2 * S)

Thank you for your input. I have tinkered a little more and found the solution:

  1. I didn't convert kph into m/s. The factor is 1 / 3.6 .
  2. The time in between measurements of 10 ms is too short. If you space the measurements out more to, say, 100 ms the results are more stable.

I don't take the initial velocity into account. My first measurement is wrong as a result but all the others are correct. That is good enough for my application.

For point 2, time is irrelevant - it's quite literally not in the equation :slight_smile: . If your V and S values are correct then your interval for checking doesn't matter. If it's not working at 10 ms then you should really determine why - is the S or V measurement not possible?

In terms of the initial velocity, it shouldn't matter if it's your first measurement or your last, it does need to be in there (unless it's zero). Either all your measurements should be correct, or you should be concerned that they are all incorrect.

huh?

acceleration is distance / sec /sec

isn't acceleration simply the change in velocity / time = (v1 - v0) / sec?

I've probably over complicated things there. The two equations are equivalent, one needs time the other needs distance.

don't understand how acceleration can not be based on time -- in fact time/time. pretty fundamental (unit analysis)

Time is in the final velocity. The equations for it are referred to as "SUVAT", I'm far from clever enough to have derived that myself :slight_smile:

huh?

basic stuff

so where's the equation for acceleration?

looks like the suvat equations use accelerations to calculate distance and velocity.

based on the first suvat equation

V = U + AT

acceleration is

A = (V - U)/T 
A = (v1 - v0) / sec

?

The final velocity is in m/s - so time is within that figure.

Post #2

Here's an example:

Start at 0m/s (U), travel 1.5m (S) end up at 6m/s2 (V).

a = (V^2 - U^2) / (2 * S)
a = 36 / 3
a = 12

The other "SUVAT" derivations tell us the time taken was 0.5s.

a = (v1 - v0) / sec
a = 6 / 0.5
a = 12

They are equivalent.

The OP has code that doesn't seem accurate on the time, so maybe it would work better for them to work off velocity and displacement.

but isn't the goal acceleration, m/s/s. not just something with time

ok. i see that the answers are the same
V^2 / S == (m/s) / m = m^2/s^s/m = m / s / s

A = (V^2 - U^2)/ (2S)

S   = V  T
1/T = (1/2) (V+U)/S       // avg velocity / distance

A = (V-U) / T
  = (V-U) * (V+U) / (2S)
  = (V^2 - U^2) / (2S)

but is the OP trying to calculate acceleration based on distance traveled? i just see measurements of velocity.

There must be distance in their code somewhere to get the velocity. The unkown is what "measure()" does. In their acceleration they are assuming a fixed 10ms despite the code allowing for a greater than that (also, shouldn't that check be ">=" 10 for it to be every 10ms?) which sent me off on my tangent of eliminating the time side of things. That would give them an accurate acceleration for their readings, without being influenced by other timings (if that makes sense, for example what if "measure()" takes 6ms to initialise before getting the velocity reading?).

In any case I think the OP has happily carried on at this point :slight_smile:

why?
i've showed you how to calculate A using dT

I think you've mixed up A(cceleration) and V(elocity). As far as I'm aware to get V without knowing S (displacement) you need to know A. Given the question is about finding A I'm assuming they don't already know it.

measure() gets you a float value for the current velocity.

The measurements are not logged anywhere, just shown on a display.
I use a = dv / dt for the acceleration and s = v(t) * dt for distance.

acceleration
velocity

the OP is wants to calculate A from measurements of V

Hi,
First column, second equation down.
v = u + at

PhysicsFormulas.pdf (1.0 MB)

a = (v - u)/t ; classic definition of acceleration.
acceleration is change in velocity over time , not distance.
acceleration units metres per second per second.

Tom... :smiley: :+1: :coffee: :australia:

looks like you want to replace v[n] with a value and then sum all the values in the array and divide by the number of values

corrected

here's a simpler approach using a leaky integration to average the velocity. no need to average the acceleration.
produces the following results on my laptop using random values

      vel   avgVel        acc
    0.840    0.840     84.019
    0.394    0.692    -14.860
    0.783    0.722      3.050
    0.798    0.748      2.545
    0.912    0.802      5.470
    0.198    0.601    -20.156
    0.335    0.512     -8.849
    0.768    0.598      8.535
    0.278    0.491    -10.659
    0.554    0.512      2.101

#include <stdio.h>
#include <stdlib.h>


float
update (
    float v, 
    int   dMsec )
{
    static float velLst = 0;
    static float vel    = 0;

    if (0 == vel)
        vel = v;
    else
        vel += (v - vel) / 3;        // averaging filter, leaky integration

    printf (" %8.3f  ", vel);


    float acc = (vel - velLst) * 1000 / dMsec;
    velLst = vel;

    return acc;
}


// -----------------------------------------------------------------------------
#define Dmsec   10

int
main ()
{
    for (int n = 0; n < 10; n++)  {
        float vel = 1.0 * random() / RAND_MAX;
        printf (" %8.3f", vel);
        printf (" %8.3f\n", update (vel, Dmsec));
    }
    return 0;
}

Are you using a 32-bit processor?!? If not, your 16-bit lastTime and lastTime_2 values will overflow after about 32 seconds.

Perhaps you should calculate acceleration on the SMOOTHED velocity, otherwise why smooth it?

  static float  v[5], a[5], a_sum, v_sum, prev_v;
  static unsigned long lastTime, lastTime_2;
  static int n;

  if ((millis() - lastTime) > 10)                   // measure every ten milliseconds
  {
    v_sum -= v[n];
    v[n] = measure();                            // delete oldest measurement, add new measurement
    v_sum += v[n];

    float v_avg = v_sum / 5;

    float acc = (v_avg - prev_v) / 0.01; // acc = dv / dt
    prev_v = v_avg;
    
    a_sum -= a[n];
    a[n] = acc;               
    a_sum += a[n];

    n++;
    if (n > 4) n = 0;
    lastTime = millis();
  }

  // Display value every second
  if ((millis() - lastTime_2) > 1000)
  {
    Serial.println(a_sum / 5);
    lastTime_2 = millis();
  }
}