I have a chart in excel that represents some value over a one day period. So I add the reference function and I get something like this:
y = 1E-13x6 - 2E-10x5 + 8E-08x4 - 1E-05x3 + 0,0004x2 + 0,0275x + 8,414
A mesure in my data set is:
09:36:21 => 5,27
The firts thing I need to know is how to transform the timestamp into a value to give to the function. After some cell value transforming I've found out that excel gives timestamps a representation between 0.00000 and 0.99999, so for example 09:36:21 is 0.400243055555556. Then I've coded a little java test script:
double x = 0.400243055555556;
double x6 = (1*Math.pow(10, -13))*Math.pow(x, 6);
double x5 = (2*Math.pow(10, -10))*Math.pow(x, 5);
double x4 = (8*Math.pow(10, -8))*Math.pow(x, 4);
double x3 = (1*Math.pow(10, -5))*Math.pow(x, 3);
double x2 = (4*Math.pow(10, -4))*Math.pow(x, 2);
double y = x6 - x5 + x4 - x3 + x2 + 0.0275*x + 8.414;
But after executing this script I get y = 8.425070122712738. So this is obviously not working. I must say that all the values in the chart range from 5 to 12.
I'm obviously doing something wrong, but I don't know what. Maybe I've coded the function badly, or maybe the x I'm choosing is not a right value, but something is wrong. Can anyone help?
Update: My code wasn't that good, what duffymo suggested worked better. But the problem was that Excel was giving my the wrong tendendy line. I've managed to get the good one using a scatter graph.
I would not recommend coding it this way - roundoff could be an issue.
I would recommend Horner scheme:
I coded it this way and got the same answer that you did:
public class Horner
{
public static final NumberFormat DEFAULT_FORMAT = new DecimalFormat("0.000");
public static void main(String[] args)
{
double [] a = { 8.414, 0.0275, 0.0004, -1.0e-5, 8.0e-8, -2.0e-10, 1.0e-13 };
for (double x = 0.0; x < 1.0; x += 0.05)
{
double y = a[0] + x*(a[1] + x*(a[2] + x*(a[3] + x*(a[4] + x*(a[5])))));
System.out.println("x = " + DEFAULT_FORMAT.format(x) + " y = " + DEFAULT_FORMAT.format(y));
}
}
}
Here's the result I get. The higher order terms aren't doing much good; the coefficients are small, and when you raise a fraction to a power it diminishes the effect even more.
x = 0.000 y = 8.414
x = 0.050 y = 8.415
x = 0.100 y = 8.417
x = 0.150 y = 8.418
x = 0.200 y = 8.420
x = 0.250 y = 8.421
x = 0.300 y = 8.422
x = 0.350 y = 8.424
x = 0.400 y = 8.425
x = 0.450 y = 8.426
x = 0.500 y = 8.428
x = 0.550 y = 8.429
x = 0.600 y = 8.431
x = 0.650 y = 8.432
x = 0.700 y = 8.433
x = 0.750 y = 8.435
x = 0.800 y = 8.436
x = 0.850 y = 8.438
x = 0.900 y = 8.439
x = 0.950 y = 8.440
Still not what you want, but I think the coding is far simpler.
Related
I have a Line that has a Start and End coordinate on the earth.
I'm trying to place perpendicular points on each side of the Start point length distance away.
Originally I thought I could
Get the Slope of the line
Determine the slope for the perpendicular Line at the start point
Solve for x and y
Coordinate p1 = Ppoint(start, end, length);
Coordinate p2 = Ppoint(start, end, -(length));
public static Coordinate Ppoint(Coordinate start, Coordinate end, double length){
double slope = getSlope(start, end);
double pSlope;
if(slope != 0)
{
pSlope = -(1/slope);
}
else
{
pSlope = 0;
}
double b = start.y + (-(pSlope * start.x));
double x = (start.x + length);
double y = (pSlope * x) + b;
Return new Coordinate(x,y);
}
I think there's a problem with doing math on lat/lon and accounting for their ranges and this doesn't account for the earth not being flat.
Is there better way to approach this ?
You should probably not attempt to do this sort of maths on a sphere (while it can be made to work, it is hard and slow).
Assuming that length is of the order of 10s-100s of kilometres you should reproject your problem to a "flat" surface centred on the start point and use Euclidean maths on a plane.
Fortunately, GeoTools provides handy automatic projections for just this problem. Here x & y are the coordinate of the start point (lon==x, lat==y):
String code = "AUTO:42001," + y + "," + x;
// System.out.println(code);
CoordinateReferenceSystem auto = CRS.decode(code);
// System.out.println(auto);
MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84,
auto);
MathTransform rTransform = CRS.findMathTransform(auto, DefaultGeographicCRS.WGS84);
You can then use the transform object to convert your points to the new projection:
Geometry g3 = JTS.transform(g1, transform);
do whatever maths you need and then transform back to lat, lon using rTransform
So to adapt this to your problem.
Coordinate start = new Coordinate(1.0, 51.0);
Coordinate end = new Coordinate(2.0, 52.0);
double length = 10000;
GeometryFactory gf = new GeometryFactory();
double x = start.getX();
double y = start.getY();
String code;
if(CRS.getAxisOrder(DefaultGeographicCRS.WGS84).equals(AxisOrder.EAST_NORTH)) {
code = "AUTO:42001," + x + "," + y;
} else {
code = "AUTO:42001," + y + "," + x;
}
CoordinateReferenceSystem auto = CRS.decode(code);
MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto);
MathTransform rTransform = CRS.findMathTransform(auto, DefaultGeographicCRS.WGS84);
Point pStart = gf.createPoint(start);
Point pEnd = gf.createPoint(end);
Point ptStart = (Point) JTS.transform(pStart, transform);
Point ptEnd = (Point) JTS.transform(pEnd, transform);
Coordinate p1 = pPoint(ptStart.getCoordinate(), ptEnd.getCoordinate(), length);
Point tPoint = gf.createPoint(p1);
Point p = (Point) JTS.transform(tPoint, rTransform);
System.out.println(p);
which gives me POINT (1.2643 47.6531) which looks wrong to me! You may need to check the maths in the pPoint method.
Earth is not flat ?
Ok, there is this website that will explain better than me how to do with sphere. What you are looking for is this : Destination point given start point, distance & bearing
You could also change your coordinate system to a flat coordinate system, it's not a shame.
https://epsg.io/
I am coding a game and want a projectile to go from one location to the next moving at intervals every frame.
I've been playing around with the slope-intercept method of determining things and I'm getting close, but I am stuck.
Here is my code so far:
animationFrame = refresh;
double x, y, xPerF; //Values for drawing
double m, b; //Value for slope and y-intercept
double x1, x2, y1, y2; //Values for the targets
x1 = getCenterX();
x2 = Canvas.target[shotTarget].getCenterX();
y1 = getCenterY();
y2 = Canvas.target[shotTarget].getCenterY();
xPerF = Point2D.distance(x1, y1, x2, y2)/animationSpeed;
//Calculate slope
if(x2>x1) m = (y2-y1)/(x2-x1);
else if(x2<x1) m = (y1-y2)/(x1-x2);
else m = 0;
//Calculate the y-intercept
b = m * x1 - y1;
if(b<0) b = -b + Canvas.myHeight;
else {
b -= Canvas.myHeight;
if(b<0) b = -b;
}
//Calculate the x value
if(x1>x2) x = x1 - (xPerF * animationFrame);
else if(x1<x2) x = x1 + (xPerF * animationFrame);
else x = x1;
//Calculate the y value
if(m!=0) y = (m * x + b) - Canvas.myHeight;
else {
if(y1>y2) y = y1 - (xPerF * animationFrame);
else y = y1 + (xPerF * animationFrame);
}
g.fillOval((int) x - 15, (int) y - 15, 30, 30);
//Debugging
System.out.println("Frame " + animationFrame + " of " + animationSpeed + " | " + y + " = " + m + " * " + x + " + " + b + " | at speed of " + xPerF);
Updated
I expect the animation to end at the target location, but it always either overshoots or is right on target. It mainly overshoots when the target is pretty kind of straight above the tower, give or take a few x co-ordinates. I have worked this out to be a quadrant 1 x-y plane and I believe the problem I have now lies with how I am calculating my slope. Thanks!
Outdated
Here is a mini applet to demonstrate: https://drive.google.com/file/d/1fCTFJzulY1fcBUmdV6AXOd7Ol1g9B3lo/view?usp=sharing
Click on each target to target it
I believe your approach is fundamentally flawed. It is prone to rounding errors which might be a source for overshoots. It is also hard to make work well under real world where your application is not the only one so CPU might be in high demand and some frames might be skipped, and so on. The better approach is to use time rather than frames as the main driver of the events. Your main method drawScene accepts current time as one of its arguments. When any animation starts, you save the time when it started. Then, the job becomes much easier. For example for linear animation it would be something like this:
double animationPart = (currentTime - animationStartTime) / totalAnimationDuration;
// fix rounding error
if (animationPart > 1.0)
animationPart = 1.0;
double xCur = xStart * (1.0 - animationPart) + xEnd * animationPart;
double yCur = yStart * (1.0 - animationPart) + yEnd * animationPart;
P.S. the "time" doesn't have to be real time, it might be some other "game time" if it somehow makes more sense but still this approach is IMHO much easier to implement correctly.
Update
I'd say that the overall code quality is rather bad. Concerns are badly separated, there are a lot of magic numbers, and global static things. For example, having to two bullets in flight will be not easy to implement in this code.
There are also some real bugs in animation code. Some obvious bugs are:
xPerF is calculated wrongly. You divide the Euclidean distance instead of just difference in the X-coordinate.
Logic for the y is flawed. At least you should add m * (x - x1) instead of m * x. But it still won't cover the case of a vertical shoot (i.e. the case when the X-coordinate is not changed at all). If you want to go this way, you should use xPerF and yPerF and get rid of the m and the related if's.
This might or might not fix the animation issues (at list you still will have a potential for rounding errors). I'd still say that changing your shoot to something like
public void shootTarget(int target) {
shotTarget = target;
shotTime = animationFrame;
}
and then using
double animationPart = ((double) (animationFrame - shotTime)) / animationSpeed;
as suggested above is a better way. Note: this is only a stub because in your real code you for some reason regularly assign 0 to refresh and thus to animationFrame so it won't work that easy.
Answer
I figured it out. Instead of calculating the coordinates with slope-intercept method, I simply calculated the intervals I would have to increment y and x per frame and incremented them based on the frame of the animation.
double x, y, xPerF, yPerF; //Values for drawing
double x1, x2, y1, y2; //Values for the targets
x1 = getCenterX();
x2 = Canvas.target[shotTarget].getCenterX();
y1 = getCenterY();
y2 = Canvas.target[shotTarget].getCenterY();
xPerF = (Math.max(x1, x2) - Math.min(x1, x2))/animationSpeed;
yPerF = (Math.max(y1, y2) - Math.min(y1, y2))/animationSpeed;
if(x1>x2) x = x1 - xPerF * animationFrame;
else if(x1<x2) x = x1 + xPerF * animationFrame;
else x = x1;
if(y1>y2) y = y1 - yPerF * animationFrame;
else if(y1<y2) y = y1 + yPerF * animationFrame;
else y = y1;
g.fillOval((int) x - 15, (int) y - 15, 30, 30);
My algorithm checks the relative position between two lines at this point I'm sure the lines are concurrents and want to return the point of intersection. I'm using this formula to not have linear systems:
My problem is when the input lines are as follows:
r: X= (8,1,9) + λ(2,-1,3) s: X (3,-4,4) + µ(1,-2,2) I hope the output is (-2, 6, -6) but is (7.6, 1.2, 8.4). Does anyone have any idea why this occurs?
My method
public Point3D intersectingLines(Line lineOne, Line lineTwo) {
double x = lineOne.getPoint().getX() - lineTwo.getPoint().getX();
double y = lineOne.getPoint().getY() - lineTwo.getPoint().getY();
double z = lineOne.getPoint().getZ() - lineTwo.getPoint().getZ();
Vector3D pointsDifference = new Vector3D(x, y, z);
Vector3D second = pointsDifference.crossProduct(lineTwo.getVector());
Vector3D first = lineOne.getVector().crossProduct(lineTwo.getVector());
double lambda = first.getNorm() / second.getNorm();
double xIntersectionOne = lineOne.getPoint().getX() + (lambda * lineOne.getVector().getX());
double yIntersectionOne = lineOne.getPoint().getY() + (lambda * lineOne.getVector().getY());
double zIntersectionOne = lineOne.getPoint().getZ() + (lambda * lineOne.getVector().getZ());
double xInLineTwo = (xIntersectionOne - lineTwo.getPoint().getX()) / lineTwo.getVector().getX();
double yInLineTwo = (yIntersectionOne - lineTwo.getPoint().getY()) / lineTwo.getVector().getY();
double zInLineTwo = (zIntersectionOne - lineTwo.getPoint().getZ()) / lineTwo.getVector().getZ();
//Here I check if the point is even correct or lambda must be negative to obtain the correct point
if (xInLineTwo == yInLineTwo && xInLineTwo == zInLineTwo) {
return new Point3D(xIntersectionOne, yIntersectionOne, zIntersectionOne);
} else {
xIntersectionOne = lineOne.getPoint().getX() + (-1 * lambda * lineOne.getVector().getX());
yIntersectionOne = lineOne.getPoint().getY() + (-1 * lambda * lineOne.getVector().getY());
zIntersectionOne = lineOne.getPoint().getZ() + (-1 * lambda * lineOne.getVector().getZ());
return new Point3D(xIntersectionOne, yIntersectionOne, zIntersectionOne);
}
}
The main problem is in the equation the other tests had no difference but that particular equation yes. The equation is in "reverse" order so got lambda = |0,2| and not lambda = |5|.
And another problem was noted in the comment's David Wallace where the condition checks equality of doubles type.
See more
I am new to work by CPLEX. My simplified optimization problem is:
objective function:
Maximize z1 + z2 + z3
Subject to:
c1: x1 - 3 x2 + x3 <= 30
c2: x1 + x2 + x3 >= z1
...
Bounds
x1=[0,1]
x2=[0,1]
...
To model this problem, my code is:
public static void main(String[] args) {
try {
IloCplex cplex = new IloCplex();
IloNumVar[] z = cplex.numVarArray(3, 0.0, 1.0);
IloLinearNumExpr objectiveExpr = cplex.linearNumExpr();
IloLinearNumExpr constraintExpr1 = cplex.linearNumExpr();
IloLinearNumExpr constraintExpr3 = cplex.linearNumExpr();
IloNumVar[] x = cplex.numVarArray(3, 0.0, 1.0);
for (int i = 1; i < 3; i++){
objectiveExpr.addTerm(1, z[i]);
}
IloObjective obj = cplex.maximize(objectiveExpr);
cplex.add(obj);
constraintExpr1.addTerm(1, x[1]);
constraintExpr1.addTerm(-3, x[2]);
constraintExpr1.addTerm(1, x[3]);
cplex.addLe(constraintExpr1, 30);
constraintExpr2.addTerm(-1, x[1]);
constraintExpr2.addTerm(1, x[2]);
constraintExpr2.addTerm(1, x[3]);
cplex.addGe(constraintExpr2, z[1]);
.
.
.
}
catch (IloException e){
System.err.println("Concert exception '" + e + "' caught");
}
}
The generated model of this code is:
objective function:
Maximize x1 + 2 x2 + 3 x3
Subject To:
c1: x7 - 3 x8 + x9 <= 30
c2: - x1 - x7 + x8 + x9 <= 0
Bounds
0 <= x1 <= 1
...
If it starts to model the constraints from x4 instead of x7, I could distinguish x and z easily.
Unlike David, I do know CPLEX for about 17 years, but I also don't understand what your problem is. Can you explain in what way the generated model is different from what you expected - we can probably work this out ourselves, but it seems daft for potentially many of us to have to spend extra time understanding your problem when you could explain better.
Can I suggest that you name your variables and constraints using setName(...) so that you can see better what is happening in the generated model.
I need to calculate the linear acceleration based on the accelerometer, gyroscope and magnetometer. I found an application for android, which does exactly what I want to achieve:
https://play.google.com/store/apps/details?id=com.kircherelectronics.fusedlinearacceleration.
https://github.com/KEOpenSource/FusedLinearAcceleration
I'm trying to port it to a pure java. Because some elements of the code are based on virtual sensors (Gravity Sensor), I would like to achieve the same result by compute direction of gravity based on three basic sensors. I read that the force of gravity can be calculated using the Low Pass Filter (same as Android < 4.0), but this method does not give very accurate results.
From android 4.0, the force of gravity on each axis is calculated using sensor fusion. I found the code responsible for these measurements, but it is written in the CPP:
https://github.com/android/platform_frameworks_base/blob/ics-mr1/services/sensorservice/GravitySensor.cpp
Method used there is called "getRotationMatrix". The same method in SensorManager.java class: https://gitorious.org/android-eeepc/base/source/9cb3e09ec49351401cf19b5ae5092dd9ca90a538:core/java/android/hardware/SensorManager.java#L1034
public static boolean getRotationMatrix(float[] R, float[] I,
float[] gravity, float[] geomagnetic) {
// TODO: move this to native code for efficiency
float Ax = gravity[0];
float Ay = gravity[1];
float Az = gravity[2];
final float Ex = geomagnetic[0];
final float Ey = geomagnetic[1];
final float Ez = geomagnetic[2];
float Hx = Ey*Az - Ez*Ay;
float Hy = Ez*Ax - Ex*Az;
float Hz = Ex*Ay - Ey*Ax;
final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
if (normH < 0.1f) {
// device is close to free fall (or in space?), or close to
// magnetic north pole. Typical values are > 100.
return false;
}
final float invH = 1.0f / normH;
Hx *= invH;
Hy *= invH;
Hz *= invH;
final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az);
Ax *= invA;
Ay *= invA;
Az *= invA;
final float Mx = Ay*Hz - Az*Hy;
final float My = Az*Hx - Ax*Hz;
final float Mz = Ax*Hy - Ay*Hx;
if (R != null) {
if (R.length == 9) {
R[0] = Hx; R[1] = Hy; R[2] = Hz;
R[3] = Mx; R[4] = My; R[5] = Mz;
R[6] = Ax; R[7] = Ay; R[8] = Az;
} else if (R.length == 16) {
R[0] = Hx; R[1] = Hy; R[2] = Hz; R[3] = 0;
R[4] = Mx; R[5] = My; R[6] = Mz; R[7] = 0;
R[8] = Ax; R[9] = Ay; R[10] = Az; R[11] = 0;
R[12] = 0; R[13] = 0; R[14] = 0; R[15] = 1;
}
}
if (I != null) {
// compute the inclination matrix by projecting the geomagnetic
// vector onto the Z (gravity) and X (horizontal component
// of geomagnetic vector) axes.
final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
if (I.length == 9) {
I[0] = 1; I[1] = 0; I[2] = 0;
I[3] = 0; I[4] = c; I[5] = s;
I[6] = 0; I[7] =-s; I[8] = c;
} else if (I.length == 16) {
I[0] = 1; I[1] = 0; I[2] = 0;
I[4] = 0; I[5] = c; I[6] = s;
I[8] = 0; I[9] =-s; I[10]= c;
I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
I[15] = 1;
}
}
return true;
}
takes four arguments:
float [] R, float [] I, float [] gravity, float [] Geomagnetic.
One of them is just gravity... The code I'm working on currently is similar to
https://github.com/KEOpenSource/FusedLinearAcceleration/blob/master/FusedLinearAcceleration/src/com/kircherelectronics/fusedlinearacceleration/sensor/LinearAccelerationSensor.java,
with the exception of methods that refer to SensorManager. These are copied from android source:
https://gitorious.org/android-eeepc/base/source/9cb3e09ec49351401cf19b5ae5092dd9ca90a538:core/java/android/hardware/SensorManager.java.
I did not found any examples of how implement this in Java.
So my question is: How I can implement method (in java), based only on three basic sensors, which returns me array of gravity direction (x, y, z), similar to Android one, but without using Android API.
Gravity is a steady contribution in the accelerometer signals (x, y & z).
So, logically, to isolate the gravity values in function of time, just low-pass filter the 3 accelerometer signals, at a frequency of 2Hz, for example.
A simple FIR would do the job.
On this site
I calculated the following coefficients:
[0.000381, 0.001237, 0.002634, 0.004607, 0.007100, 0.009956, 0.012928,
0.015711, 0.017987, 0.019480, 0.020000, 0.019480, 0.017987, 0.015711,
0.012928, 0.009956, 0.007100, 0.004607, 0.002634, 0.001237, 0.000381]
based on those caracteristics:
Fa=0Hz, Fb=1Hz, Length=21Pts, Fs=100Hz, Att=60dB.
You will get a signal that will be the three values of gravity in function of time.
You can find here some FIR explaination and Java implementation.
What you want is the rotation matrix (SensorManager.getRotationMatrix). Its last three components (i.e. rotation[6], rotation[7], rotation[8]) are the vector that points straight up, thus the direction to the center of the earth is the negative of that. To subtract gravity from your accelerometer reading just multiply that vector by g (~9.8m/s^2, though you might want to know that more precisely).