Search code examples
javac#accelerometer

Converting acceleration over time to velocity or speed in code


I have acceleration data from a sensor. X Y & Z. I move the senor in the Y axis. Mostly in a straight line. So I ignore x & z.

From the sensor documentation 5.2.1 Acceleration output:

ax=((AxH<<8)|AxL)/32768*16g(g is Gravity acceleration,9.8m/s2)

ay=((AyH<<8)|AyL)/32768*16g(g is Gravity acceleration,9.8m/s2)

az=((AzH<<8)|AzL)/32768*16g(g is Gravity acceleration,9.8m/s2)

The data is in (m/s2)

I need a simple calculation that java or C# can take easily. I want to write something in code that calculates the acceleration over time to maximum velocity and average velocity. I need a "speed" value that I can display. For Ex. Max speed 12MPH and Average Speed 8MPH.

--EDIT with better data moving it 12 inches --This is the working code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CalculateSpeed
{
    public class Program
    {
        public static void Main(string[] args)
        {

            List<TimeAccelData> timeVsAccelerationData = new List<TimeAccelData>();

            timeVsAccelerationData.Add(new TimeAccelData() { Time = 910.614, Acceleration = 0.0001 });//not  Moving
            timeVsAccelerationData.Add(new TimeAccelData() { Time = 910.655, Acceleration = 0.0025 });//Moving
            timeVsAccelerationData.Add(new TimeAccelData() { Time = 910.655, Acceleration = 0.0045 });
            timeVsAccelerationData.Add(new TimeAccelData() { Time = 910.655, Acceleration = 0.0098 });
            timeVsAccelerationData.Add(new TimeAccelData() { Time = 910.684, Acceleration = 0.0059 });
            timeVsAccelerationData.Add(new TimeAccelData() { Time = 910.684, Acceleration = 0.0079 });
            timeVsAccelerationData.Add(new TimeAccelData() { Time = 910.684, Acceleration = 0.0094 });
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.684, Acceleration = 0.0186});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.684, Acceleration = 0.0357});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.684, Acceleration = 0.0582});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.684, Acceleration = 0.0611});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.695, Acceleration = 0.1368});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.714, Acceleration = 0.1207});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.729, Acceleration = 0.1661});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.734, Acceleration = 0.1632});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.747, Acceleration = 0.1627});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.754, Acceleration = 0.1788});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.764, Acceleration = 0.3746});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.816, Acceleration = 0.4893});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.82, Acceleration = 0.5806});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.82, Acceleration = 0.627});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.849, Acceleration = 0.565});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.849, Acceleration = 0.5899});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.849, Acceleration = 0.5968});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.849, Acceleration = 0.6632});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.849, Acceleration = 0.6749});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.849, Acceleration = 0.7237});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.849, Acceleration = 0.7511});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.866, Acceleration = 0.692});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.9, Acceleration = 0.7227});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.902, Acceleration = 0.7384});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.902, Acceleration = 0.6436});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.908, Acceleration = 0.6959});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.915, Acceleration = 0.5738});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.929, Acceleration = 0.4796});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.935, Acceleration = 0.3443});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.949, Acceleration = 0.1803});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 910.952, Acceleration = 0.0601});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.012, Acceleration = -0.1332});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.014, Acceleration = -0.3554});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.015, Acceleration = -0.5414});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.015, Acceleration = -0.6908});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.017, Acceleration = -0.7807});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.018, Acceleration = -0.9779});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.031, Acceleration = -0.8061});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.066, Acceleration = -0.9692});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.11, Acceleration = -1.0146});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.11, Acceleration = -1.5878});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.11, Acceleration = -1.0785});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.11, Acceleration = -1.1225});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.11, Acceleration = -1.1557});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.11, Acceleration = -1.0395});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.113, Acceleration = -0.9071});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.115, Acceleration = -0.4555});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.129, Acceleration = -0.3305});
            timeVsAccelerationData.Add(new TimeAccelData() {Time = 911.136, Acceleration = -0.3266});
            timeVsAccelerationData.Add(new TimeAccelData() { Time = 911.164, Acceleration = 0.002 });//STOPPED MOVING

        //initial speed = 0.0001 and distance = 0.
        var distance = RiemannIntegration(new List<TimeAccelData>(RiemannIntegration(timeVsAccelerationData, 0).ToArray()),0).Last().Acceleration;
        //distance equals 0.028999999999996362 meters to inches = 1.1417322834644237
        //fixed the double integration and now the value is lower
        //distance equals 0.02675412494998913
        }

        public static IEnumerable<TimeAccelData> RiemannIntegration(List<TimeAccelData> xy, double initialValue)
        {
            var res = initialValue;
            yield return (new TimeAccelData() {Time = xy[0].Time, Acceleration = initialValue});

            for (var i = 1; i < xy.Count; i++)
            {
                res += (xy[i].Time - xy[i - 1].Time) * (xy[i].Acceleration + xy[i - 1].Acceleration) / 2;
                yield return (new TimeAccelData() {Time = xy[i].Time, Acceleration = res});
            }
        }

        public class TimeAccelData
        {
            public double Time { get; internal set; }
            public double Acceleration { get; internal set; }
        }
    }
}

Solution

  • Velocity is the integration of acceleration. If the initial velocity is 0, then you could evaluate the velocity with a Riemann integral(*); the area of the acceleration function.

    For a general function fx you could do:

    public static double RiemannIntegration
        (Func<double, double> fx,
         double x0,
         double x1,
         double step)
    {
        var previous = x0;
        var res = 0d;
        var semiStep = step / 2;
    
        for (var x = x0 + step; x < x1; x += step)
        {
            res += semiStep * (fx(x) + fx(previous));
            previous = x;
        }
    
        res += (x1 - previous) / 2 * (fx(x1) + fx(previous));
        return res;
    }
    

    But maybe a more specific implementation is more useful for your scenario; given a sequence of (t, acc) data, evaluate the Riemann integral with a variable step defined by each t. This implementation considers a linear variation of the acceleration inside each interval:

    public static double RiemannIntegration(
        (double X, double Y)[] xy)
    {
        var res = 0d;
    
        for (var i = 1; i < xy.Length; i++)
        {
            res += (xy[i].X - xy[i - 1].X) * (xy[i].Y + xy[i - 1].Y) / 2;
        }
    
        return res;
    }
    

    UPDATE: Based on your comments, you ultimately want to evaluate the distance covered. You can do this by integrating two times the acceleration, but in order to do that, you actually need to return integrated curves, not total values. The following implementation will do that:

    public static IEnumerable<(double X, double Y)> RiemannIntegration(
        (double X, double Y)[] xy, double initialValue)
    {
        var res = initialValue;
        yield return (xy[0].X, initialValue);
    
        for (var i = 1; i < xy.Length; i++)
        {
            res += (xy[i].X - xy[i - 1].X) * (xy[i].Y + xy[i - 1].Y) / 2;
            yield return (xy[i].X, res);
        }
    }
    

    And now to evaluate distance form acceleration data you'd do:

    var timeVsAccelerationData = new[] { (t0, a0), (t1, a1), ... };
    
    //initial speed and distance are zero.
    var distance = RiemmanIntegral(RiemannIntegral(
        timeVsAccelerationData, 0).ToArray(), 0).Last().Y;
    

    (*) The proposed algorithm isn't exactly the Riemann integral, I'm using trapezoidal areas, Riemann integral really uses rectangular areas with a height equal to the function value in the center of the time interval.