I'd like to use my accelerometer in my car and with the accelerometer values, draw a trajectory in excel or any other platform with the origin in the first position value, that is the beginning of the path.
How can I achieve this? Please give me details I don't have any physics notion.
Please help, thanks in advance.
PS: I already programmed the SensorListener...
I have this for instance:
#Override
public void onSensorChanged(SensorEvent event){
if(last_values != null){
float dt = (event.timestamp - last_timestamp) * NS2S;
for(int index = 0 ; index < 3 ; ++index){
acceleration[index] = event.values[index];
velocity[index] += (acceleration[index] + last_values[index])/2 * dt;
position[index] += velocity[index] * dt;
}
vxarr.add(velocity[0]);
vyarr.add(velocity[1]);
vzarr.add(velocity[2]);
axarr.add(acceleration[0]);
ayarr.add(acceleration[1]);
azarr.add(acceleration[2]);
}
else{
last_values = new float[3];
acceleration = new float[3];
velocity = new float[3];
position = new float[3];
velocity[0] = velocity[1] = velocity[2] = 0f;
position[0] = position[1] = position[2] = 0f;
}
xarr.add(position[0]);
yarr.add(position[1]);
zarr.add(position[2]);
tvX.setText(String.valueOf(acceleration[0]));
tvY.setText(String.valueOf(acceleration[1]));
tvZ.setText(String.valueOf(acceleration[2]));
last_timestamp = event.timestamp;
}
but when I draw a circle with my phone I got this:
Sometimes I have just only negative values and sometimes I have just positive values, I never have negative AND positive values in order to have circle.
Acceleration is the derivative of speed by time (in other words, rate of change of speed); speed is the derivative of position by time. Therefore, acceleration is the second derivative of position. Conversely, position is the second antiderivative of acceleration. You could take the accelerometer measurements and do the double intergration over time to obtain the positions for your trajectory, except for two problems:
1) It's an indefinite integral, i.e. there are infinitely many solutions (see e.g. https://en.wikipedia.org/wiki/Antiderivative). In this context, it means that your measurements tell you nothing about the initial speed. But you can get it from GPS (with limited accuracy) or from user input in some form (e.g. assume the speed is zero when the user hits some button to start calculating the trajectory).
2) Error accumulation. Suppose the accelerometer error in any given direction a = 0.01 m/s^2 (a rough guess based on my phone). Over t = 5 minutes, this gives you an error of a*t^2/2 = 450 meters.
So you can't get a very accurate trajectory, especially over a long period of time. If that doesn't matter to you, you may be able to use code from the other answer, or write your own etc. but first you need to realize the very serious limitations of this approach.
How to calculate the position of the device using the accelerometer values?
Physicists like to think of the position in space of an object at a given time as a mathematical function p(t) with values ( x(t), y(t), z(t) ). The velocity v(t) of that object turns out to be the first derivative of p(t), and the acceleration a(t) nicely fits in as the first derivative of v(t).
From now on, we will just look at one dimension, the other two can be treated in the same way.
In order to get the velocity from the acceleration, we have to "reverse" the operation using our known initial values (without them we would not obtain a unique solution).
Another problem we are facing is that we don't have the acceleration as a function. We just have sample values handed to us more or less frequently by the accelerometer sensor.
So, with a prayer to Einstein, Newton and Riemann, we take these values and think of the acceleration function as a lot of small lines glued together. If the sensor fires often, this will be a very good approximation.
Our problem now has become much simpler: the (indefinite) integral (= antiderivative) to a linear function
f(t) = m*t + b is F(t) = m/2 * t^2 + b*t + c, where c can be chosen to satisfy the initial condition (zero velocity in our case) .
Let's use the point-slope form to model our approximation (with time values t0 and t1 and corresponding acceleration values a0 and a1):
a(t) = a0 + (a1 – a0)/(t1 – t0) * (t – t0)
Then we get (first calculate v(t0) + "integral-between-t0-and-t-of-a", then use t1 in place of t)
v(t1) = v(t0) + (a1 + a0) * (t1 – t0) / 2
Using the same logic, we also get a formula for the position:
p(t1) = p(t0) + (v(t1) + v(t0)) * (t1 – t0) / 2
Translated into code, where last_values is used to store the old acceleration values:
float dt = (event.timestamp - last_timestamp) * NS2S;
for(int index = 0 ; index < 3 ; ++index){
acceleration[index] = event.values[index];
float last_velocity = velocity[index];
velocity[index] += (acceleration[index] + last_values[index])/2 * dt;
position[index] += (velocity[index] + last_velocity )/2 * dt;
last_values[index] = acceleration[index];
}
**EDIT: **
All of this is only useful for us as long as our device is aligned with the world's coordinate system. Which will almost never be the case. So before calculating our values like above, we first have to transform them to world coordinates by using something like the rotation matrix from SensorManager.getRotationMatrix().
There is a code snippet in this answer by Csaba Szugyiczki which shows how to get the rotation matrix.
But as the documentation on getRotationMatrix() states
If the device is accelerating, or placed into a strong magnetic field, the returned matrices may be inaccurate.
...so I'm a bit pessimistic about using it while driving a car.
Related
Instead of typing it all out, here's a picture for you to see what I want. You know what they say, a picture is worth a thousand words.
What I have is p1, Θ, and d and speed, s of the projectile.
Speed:
From this I can deduce p2 using the equation p1.x * speed, p1.y * speed which are the co-ordenates for p2. From this I can calculate the distance using the equation |dx| + |dy|.
Distance
However, if I wasn't given speed, how would I be able to calculate the co-ordenates of p2 only using Θ, p1 and d?
Are there any other methods that would be the most efficent?
public double getDistanceTraveled() {
return Math.abs(x - oldX) + Math.abs(y - oldY);
} //use Manhattan aproach as it is more efficent than Euclidean
public double getSpeed() {
return getDistanceTraveled() / level.TICKS_PER_SECOND;
}
is what I am using at the moment. I realized that I had the variable time, so I was able to deduce p2 using this method:
d = |dx| + |dy|d = s / ts = t(|dx| + |dy|)
Not sure if this is that efficient though. Any suggestions to this problem, and just to repeat: I have the variables theta, p1, d and t and I have to find p2.
Efficency >>> Accuracy
If theta is the angle between line and y-axis.
Then you can calculate it with the following formulas.
Let P1 be the point (p1x, p1y). and P2 be the point (p2x, p2y)
p2x = p1x + d * sin(theta)
p2y = p1y + d * cos(theta)
If you use Math.sin(theta), then keep in mind that theta should be in radians. You can use Math.toRadian(degree) to get angle in radians.
You know what they say, a picture is worth a thousand words.
If you want efficiency, there's actually a much better approach than using the trig operations at all. Basically, since you already have d, the only thing you care about is the relative movement along x and y, which is defined by theta.
Knowing that, it's pretty trivial to just store unit vectors at whatever your required granularity is in a hashmap and multiply by d
After you've decided on your granularity, just pre-calculate a HashMap like so:
{0: [1, 0],
0.01: [0.99, 0.001], etc...
}
Then round the incoming number, see this question for details on making sure it matches your granularity. Then the calculation is just (in pseudo-code):
x = p1[0] + d * <HashMap>.getKey(angle)[0]
y = p2[1] + d * <HashMap>.getKey(angle)[1]
A HashMap lookup and a multiplication is WAY more efficient than even a single trig operation. Preliminary tests got me ~10x speedup but YMMV.
I am working on some code that calculates points on a 2 axis graph and I noticed that when the X or Y coordinate was value zero it slowed down. I spit out some debug and found that the scale of my coordinate value was continually growing. I thought passing the math context would make the return bigdecimal not be able to have a larger scale. I was hoping to limit the scale to my math context precision. This code shows what I am seeing.
MathContext mc = new MathContext(32);
BigDecimal xPos = new BigDecimal("0.0", mc);
for (int i = 0; i < 8; i++)
{
System.out.println("" + xPos + " scale=" + xPos.scale());
xPos = xPos.multiply(xPos, mc);
}
The scale continues to increase with each iteration. Am I incorrect in thinking that because I pass multiply a math context that it should limit the precision of the return?
Thanks for reading.
It's all explained in the BigDecimal API.
Operation Preferred Scale of Result
Add max(addend.scale(), augend.scale())
Subtract max(minuend.scale(), subtrahend.scale())
Multiply multiplier.scale() + multiplicand.scale()
Divide dividend.scale() - divisor.scale()
And it makes sense in a logarithmic sort of way.
I'm trying to write a GPS tracking (akin to a jogging app) on android and the issue of GPS location jitter has reared it's ugly head. When accuracy is FINE and accuracy is within 5 meters, the position is jittering 1-n meters per second. How do you determine or filter out this jitter from legitimate movement?
Sporypal etc apps clearly have some way they are filtering out this noise.
Any thoughts?
Could you just run the positions through a low pass filter?
Something of the order
x(n) = (1-K)*x(n-1) + K*S(n)
where
S is your noisy samples and x, the low pass filtered samples. K is a constant between 0 and 1 which you would probably have to experiment with for best performance.
Per TK's suggestion:
My pseudocode will look awfully C like:
float noisy_lat[128], noisy_long[128];
float smoothed_lat[128], smoothed_lon[128];
float lat_delay=0., lon_delay=0.;
float smooth(float in[], float out[], int n, float K, float delay)
{
int i;
for (i=0; i<n; i++) {
*out = *in++ * K + delay * (1-K);
delay = *out++;
}
return delay;
}
loop:
Get new samples of position in noisy_lat and noise_lon
// LPF the noise samples to produce smoother position data
lat_delay = smooth(noisy_lat, smoothed_lat, 128, K, lat_delay);
lon_delay = smooth(noisy_lon, smoothed_lon, 128, K, lon_delay);
// Rinse. Repeat.
go to loop:
In a nutshell, this is a simply a feedback integrator with a one-sample delay. If your input has low frequency white-ish noise on top of the desired signal, this integrator will average the input signal over time, thus causing the noise components to average out to near zero, leaving you with the desired signal.
How well it works will depend on how much noise your signal has and the filter feedback factor K. As I said before, you'll have to play around a bit with the value to see which value produces the cleanest, most desirable result.
Is it even that inaccurate? I re-implented the whole thing with Apfloat arbitrary precision and it made no difference which I should have known to start with!!
public static double bearing(LatLng latLng1, LatLng latLng2) {
double deltaLong = toRadians(latLng2.longitude - latLng1.longitude);
double lat1 = toRadians(latLng1.latitude);
double lat2 = toRadians(latLng2.latitude);
double y = sin(deltaLong) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(deltaLong);
double result = toDegrees(atan2(y, x));
return (result + 360.0) % 360.0;
}
#Test
public void testBearing() {
LatLng first = new LatLng(36.0, 174.0);
LatLng second = new LatLng(36.0, 175.0);
assertEquals(270.0, LatLng.bearing(second, first), 0.005);
assertEquals(90.0, LatLng.bearing(first, second), 0.005);
}
The first assertion in the test gives this:
java.lang.AssertionError:
expected:<270.0> but
was:<270.29389750911355>
0.29 seems to quite a long way off? Is this the formula i chose to implement?
If you've done what you seem to have done and done it correctly you have figured out the bearing of A from B along the shortest route from A to B which, on the surface of the spherical (ish) Earth is the arc of the great circle between A and B, NOT the arc of the line of latitude between A and B.
Mathematica's geodetic functions give the bearings, for your test positions, as 89.7061 and 270.294.
So, it looks as if (a) your calculation is correct but (b) your navigational skills need polishing up.
Are you sure this is due to numeric problems? I must admit, that I don't exactly know what you are trying to calculate, but when you dealing with angles on a sphere, small deviations from what you would expect in euclidian geometry.
java.lang.AssertionError: expected:<270.0> but was:<270.29389750911355>
This 0.29 absolute error represents a relative error of 0.1%. How is this "a long way off"?
Floats will give 7 significant digits; doubles are good for 16. Could be the trig functions or the degrees to radians conversion.
Formula looks right, if this source is to be believed.
If I plug your start and final values into that page, the result that they report is 089°42′22″. If I subtract your result from 360 and convert to degrees, minutes, and seconds your result is identical to theirs. Either you're both correct or you're both wrong.
My professor gave us an assignment to test the difference in runtimes and search sizes using linear & binary algorithms, and the data is to be graphed.
I have the search methods put the runtime & array sizes as Points in an ArrayList, which is then sent to the GraphResults class for plotting. I need to convert those data points into xy coordinates before. The search size is the x-axis and the runtime is the y axis
As the search sizes are fixed as a multiple of 128 and there are only 8 sizes, I used switch for calculating the x value, but am looking for a more efficient way to convert the runtimes into coordinates.
Right now, I'm using nested conditionals with 5 like this:
if (y<=1000) {
if (y<= 500) {
if (y<= 250) {
newy= yaxis-32; }//equals to 250ms category
else {
newy= yaxis-(32*2); }//500ms category
}
else if (y<=750) {
newy= yaxis-(32*3);} //750ms category
else {
newy= yaxis-(32*4);} //1000ms category
} //end of the 1000ms tests
Right now, the numbers that are over 5000ms require 7 tests. Is there a more efficient way to assign a number based on a number size?
As you are trying to determine the range of your measurement, you can divide the amount by the range size, followed by calculating the number you want to show in the graph.
Btw, in your code, you made a logic error, if the value is y <= 1000 the first condition evaluates to true, and the second for y <= 750 will never be evaluated.
Also it seems that the higher the value range, the lower your graph point. Is that as intended? (1000 -> ymax - 128 while 1 -> ymax - 32)
As an aside, if you want to compare values to uneven ranges, you can also do something like an array lookup (pseudo code):
int[] ranges = new int { 50, 500, 5000, 50000 };
for (int n = 0; n < ranges.length && value > ranges[n]; n++) {
}
int range = n;
int newy = yaxis - range * 32;
Note that the out-of-range index acts as the range found for a value that is bigger than the biggest value in your array.
How about newy = yaxis - 32 * ((y/250)% 8);?
I would reformat your code to something more like this:
newy = yaxis - 32 * ((y-1)/250 + 1);
This way, you're calculating the multiplier rather than choosing it manually.