Java Operations in Math Equations - java

I am trying to write a program that calculates the distance of a projectile, but the distance returned is not coming out correct. I am familiar with operator precedence in Java, but I am not sure why I am not getting the correct distance. For angle = 22, velocity = 35, and height = 10 I expect to get 75.54 but instead I am getting 42.03.
Are there obvious mistakes in my code that are causing this?
public class FootballDistanceCalculator {
public static final double GRAVITATIONAL_ACCELERATION = 32.174;
/**
* Calculates the distance a projectile travels
*
* #param angle angle at which projectile is thrown in degrees
* #param velocity initial velocity of projectile in miles/hour
* #param height initial height of projectile in feet
* #return distance traveled by projectile in feet
*/
public static double calculateDistance(double angle, double velocity, double height) {
double angleRadians = Math.toRadians(angle);
double vCosineThetaOverG = (velocity * (Math.cos(angleRadians))) / GRAVITATIONAL_ACCELERATION ;
double vSinTheta = velocity * (Math.sin(angleRadians));
double vSinThetaSquared = (Math.pow(vSinTheta, 2));
double twoGravHeight = (2 * GRAVITATIONAL_ACCELERATION * height);
double radical = Math.sqrt((vSinThetaSquared + twoGravHeight));
double distance = vCosineThetaOverG * (vSinTheta + radical);
return distance;
}
}
This is the equation I am basing this program off of:
d = (v cos(θ) / g)(v sin(θ) + √(v sin(θ)2 + 2 g h))
v = velocity
g = gravitational acceleration
h = height
The problem turned out to be a units conversion issue as indicated in the comments.
I had to take my velocity parameter and multiply by feet per mile (5280) and divide by seconds per hour (3600) to get my units to match.

You are calculating in metric but your g constant is in feet per second per second.

Related

How do I calculate tilt-compensated yaw?

I've been struggling for some time now on how to correctly calculate the yaw angle from an IMU, but can't get it to work. I'm using the LSM9DS1, if that matters.
I already have proper values for roll and pitch. The value for yaw is also more or less correct until I start tilting the device. Therefore I have to implement some kind of tilt compensation.
I calculate the euler angles as follows:
double weight = 0.05f;
private void calculateEulerAngles() {
// Measured angle by the accelerometer
double rollXLMeasured = Math.atan2(this.accelerometer.getX(), this.accelerometer.getZ()) / 2 / Math.PI * 360;
double pitchXLMeasured = Math.atan2(this.accelerometer.getY() / 9.81f, this.accelerometer.getZ() / 9.81f) / 2 / Math.PI * 360;
// Adding a low pass filter
double rollXLFiltered = (1 - this.weight) * rollXLFilteredOld + this.weight * rollXLMeasured;
double pitchXLFiltered = (1 - this.weight) * pitchXLFilteredOld + this.weight * pitchXLMeasured;
this.rollXLFilteredOld = rollXLFiltered;
this.pitchXLFilteredOld = pitchXLFiltered;
// Calculating deltaTime
long time = System.nanoTime();
int difference = (int) ((time - this.deltaTime) / 1000000000);
this.deltaTime = time;
// Adding a complementary filter
this.roll = ((1 - this.weight) * (this.roll + this.gyroscope.getY() * difference)) + (this.weight * rollXLMeasured);
this.pitch = ((1 - this.weight) * (this.pitch - this.gyroscope.getX() * difference)) + (this.weight * pitchXLMeasured);
// Calculating yaw using the magnetometer and applying a low pass filter
double rollRadians = this.roll / 360 * (2 * Math.PI);
double pitchRadians = this.pitch / 360 * (2 * Math.PI);
double magnetometerXCompensated = (-this.magnetometer.getX() * Math.cos(rollRadians)) - (this.magnetometer.getY() * Math.sin(pitchRadians) *
Math.sin(rollRadians)) + (this.magnetometer.getZ() * Math.cos(pitchRadians) * Math.sin(rollRadians));
double magnetometerYCompensated = (this.magnetometer.getY() * Math.cos(pitchRadians)) + (this.magnetometer.getZ() * Math.sin(pitchRadians));
double yawMeasured = Math.atan2(magnetometerYCompensated, magnetometerXCompensated) / (2 * Math.PI) * 360;
double yawFiltered = (1 - this.weight) * yawFilteredOld + this.weight * yawMeasured;
this.yawFilteredOld = yawFiltered;
this.yaw = yawFiltered;
// Print roll, pitch and yaw for debug purposes
System.out.println(this.roll + ", " + this.pitch + ", " + this.yaw);
}
I don't include the whole code I use, since I think it's clear what the above code does and this is the part thats essential to the problem, I suppose.
And again, I get correct values, just not for yaw when I tilt the device. So there has to be an error concerning the math.
Do I have to do my calculations with the raw values, like the data thats inside the IMU, or use already processed data? For example this.accelerometer.getX() actually returns x_raw * 0.061f / 1000 * 9.81f with x_raw being the value stored inside the IMU and 0.061f being some coeffiecent. I basically copied the calculation from the Adafruit library, I'm not 100% sure why you have to multiply/divide those values though.
Also, you might have noticed that when I calculate the magnetometerXCompensated value I invert the x-axis. I do this, because the magnetometer axis aren't aligned with the acceleromter/gyroscope axis, so in order to align them I have to flip the x-axis.
Does anyone have an idea on how to solve this? I'm really tired of it not working properly, since I tried for quite a while now to solve it, but I'm not getting the results I wanted.
You can get all the equations from the next picture. The complimentary/Kalman filter is there in order to get less noise.

Directional helix for game missiles

my math isnt too great but im trying to learn though..
What im trying to do is give my games missiles a helix rocket effect, but i dont know how to work the Sin and Cos to make the helix play out in the right direction..
This is a 3D game by the way:
The problem is, depending on which direction the missile faces, the helix looks warped or flat..
Whats the best way to mathematically calculate a helix based on the missiles X,Y,Z/direction?, ive been trying to figure it out for a long time :/
Thanks alot!
double x = radius * Math.cos(theta);
double y = radius * Math.sin(theta);
double z = radius * Math.cos(theta);
location.add(x,y,z);
missile.shootFlame(location,2);
location.subtract(x,y,z);
Basis vectors
you need the overall direction of missile as 3D vector let call it W. From it you need to get 2 another vectors U,V which are all perpendicular to each other. To get them you can exploit cross product. So:
make W unit vector
Just W = W/|W| so:
l=sqrt(Wx*Wx+Wy*Wy+Wz*Wz);
Wx/=l;
Wy/=l;
Wz/=l;
choose U as any direction non parallel to W
so start with U=(1.0,0.0,0.0) and if U==W choose U=(0.0,1.0,0.0). If you got anything to lock to use that as U direction so the coordinate system will not rotate with time (like Up,North,Sun ...)
U should be unit so if not normalize it just like in #1
compute V
It should be perpendicular to U,W so use cross product:
V = W x U
Cross product of unit vectors is also unit vector so no need to normalize.
recompute U
As we choose the U manually we need to make sure it is also perpendicular to V,W so:
U = V x W
Now we have 3 perpendicular basis vectors where U,V lies in plane of the helix screws and W is the overall movement direction.
If you do not know how to compute the cross product see:
Understanding 4x4 homogenous transform matrices look for [edit2].
Now the Helix is easy:
Defines
so we have U,V,W on top of that we need radius r [units], movement speed v [units/s], angular speed o [rad/s] time t>=0.0 [s] and start position P0.
Helix equation
What we need is equation returning actual position for time so:
ang = o*t;
P(t) = P0 + U*r*cos(ang) + V*r*sin(ang) + W*v*t;
rewritten to scalars:
ang = o*t;
x = P0x + Ux*r*cos(ang) + Vx*r*sin(ang) + Wx*v*t;
y = P0y + Uy*r*cos(ang) + Vy*r*sin(ang) + Wy*v*t;
z = P0z + Uz*r*cos(ang) + Vz*r*sin(ang) + Wz*v*t;
[edit1] as you are incompetent to copy paste and or changing my code correctly...
Vector w = loc.getDirection();
double wX = w.getX();
double wY = w.getY();
double wZ = w.getZ();
double l = Math.sqrt((wX * wX) + (wY * wY) + (wZ * wZ));
wX = wX / l;
wY = wY / l;
wZ = wZ / l;
w = new Vector(wX,wY,wZ); // you forget to change W and use it latter ...
Vector u = new Vector(0, 1.0, 0);
if (Math.abs(wX)<1e-3) // if U and W are the same chose different U
if (Math.abs(wZ)<1e-3)
u = new Vector(1.0, 0.0, 0);
Vector v = w.crossProduct(u);
u = v.crossProduct(w);
double radius = 10; // helix radius [units]
double speed = 2.00; // movement speed [unit/s]
double omega = 0.628; // angular speed [rad/s]
//double omega = 36.0; // angular speed [deg/s]
for (double i = 0; i < 100; i += 1.0) // time [s]
{
double angle = omega * i; // actual screw position [rad] or [deg]
double x = u.getX() * radius * Math.cos(angle) + v.getX() * radius * Math.sin(angle) + wX * speed * i;
double y = u.getY() * radius * Math.cos(angle) + v.getY() * radius * Math.sin(angle) + wY * speed * i;
double z = u.getZ() * radius * Math.cos(angle) + v.getZ() * radius * Math.sin(angle) + wZ * speed * i;
loc.add(x,y,z); // What is this? should not you set the x,y,z instead of adding?
//do work
loc.subtract(x,y,z); // what is this?
}
This should provide you with helix points with traveled linear distance
speed*imax = 2.0*100.0 = 200.0 units
And screws:
omega*imax/(2*Pi) ~= 0.628*100.0/6.28 ~= 10 screws // in case of sin,cos want [rad]
omega*imax/360.0 = 36.0*100.0/360 = 10.0 screws // in case of sin,cos want [deg]
Do not forget to rem in/out the correct omega line (I choose [rad] as that is what I am used that my math libs use). Not sure If I translated to your environment correctly there may be bugs like abs has different name or u = new Vector(1.0, 0.0, 0); can be done on intermediate or declaration of variable only etc which I do not know as I do not code in it.

Trigonometry of a 3D "free" camera

I'm sorry if this question was asked before, I did search, and I did not find an answer.
My problem is, that I'd like to make movement on all 3 axes with the X and Y rotation of the camera being relevant.
This is what I did:
private static void fly(int addX, int addY){ //parameters are the direction change relative to the current rotation
float angleX = rotation.x + addX; //angle is basically the direction, into which we will be moving(when moving forward this is always the same as our actual rotation, therefore addX and addY would be 0, 0)
float angleY = rotation.y + addY;
float speed = (moveSpeed * 0.0002f) * delta;
float hypotenuse = speed; //the length that is SUPPOSED TO BE moved overall on all 3 axes
/* Y-Z side*/
//Hypotenuse, Adjacent and Opposite side lengths of a triangle on the Y-Z side
//The point where the Hypotenuse and the Adjacent meet is where the player currently is.
//OppYZ is the opposite of this triangle, which is the ammount that should be moved on the Y axis.
//the Adjacent is not used, don't get confused by it. I just put it there, so it looks nicer.
float HypYZ = speed;
float AdjYZ = (float) (HypYZ * Math.cos(Math.toRadians(angleX))); //adjacent is on the Z axis
float OppYZ = (float) (HypYZ * Math.sin(Math.toRadians(angleX))); //opposite is on the Y axis
/* X-Z side*/
//Side lengths of a triangle on the Y-Z side
//The point where the Hypotenuse and the Adjacent meet is where the player currently is.
float HypXZ = speed;
float AdjXZ = (float) (HypXZ * Math.cos(Math.toRadians(angleY))); //on X
float OppXZ = (float) (HypXZ * Math.sin(Math.toRadians(angleY))); //on Z
position.x += AdjXZ;
position.y += OppYZ;
position.z += OppXZ;
}
I only implement this method when moving forwards(parameters: 0, 90) or backwards(params: 180, 270), since movement can't happen on the Y axis while going sideways, since you don't rotate on the Z axis. ( the method for going sideways(strafing) works just fine, so I won't add that.)
the problem is that when I look 90 degrees up or -90 down and then move forward I should be moving only on the Y axis(vertically) but for some reason I also move forwards(which means on the Z axis, as the X axis is the strafing).
I do realize that movement speed this way is not constant. If you have a solution for that, I'd gladly accept it as well.
I think your error lies in the fact that you don't fully project your distance (your quantity of movement hypothenuse) on your horizontal plane and vertical one.
In other words, whatever the chosen direction, what you are doing right now is moving your point of hypothenuse in the horizontal plane X-Z, even though you already move it of a portion of hypothenuse in the vertical direction Y.
What you probably want to do is moving your point of a hypothenuse quantity as a total.
So you have to evaluate how much of the movement takes place in the horizontal plane and how much in the vertical axis. Your direction gives you the answer.
Now, it is not clear to me right now what your 2 angles represent. I highly recommend you to use Tait–Bryan angles in this situation (using only yawn and pitch, since you don't seem to need the rolling - what you call the Z-rotation), to simplify the calculations.
In this configuration, the yawn angle would be apparently similar to your definition of your angleY, while the pitch angle would be the angle between the horizontal plane and your hypothenuse vector (and not the angle of the projection in the plane Y-Z).
A schema to clarify:
With :
s your quantity of movement from your initial position P_0 to P_1 (hypothenuse)
a_y the yawn angle and a_p the pitch one
D_x, D_y, D_z the displacements for each axis (to be added to position, ie AdjXZ, OppYZ and OppXZ)
So if you look at this representation, you can see that your triangle in X-Z doesn't have s as hypotenuse but its projection s_xz. The evaluation of this distance is quite straightforward: if you place yourself in the triangle P_0 P_1 P_1xz, you can see that s_xz = s * cos(a_p). Which gives you:
float HypXZ = speed * Math.cos(Math.toRadians(angleP))); // s_xz
float AdjXZ = (float) (HypXZ * Math.cos(Math.toRadians(angleY))); // D_x
float OppXZ = (float) (HypXZ * Math.sin(Math.toRadians(angleY))); // D_z
As for D_y ie OppYZ, place yourself in the triangle P_0 P_1 P_1xz again, and you'll obtain:
float OppYZ = (float) (speed * Math.sin(Math.toRadians(angleP))); // D_y
Now, if by angleX you actually meant the angle of elevation as I suppose you did, then angleP = angleX and HypXZ = AdjYZ in your code.
With this correction, if angleX = 90 or angleX = -90, then
HypXZ = speed * cos(angleX) = speed * cos(90deg) = speed * 0;
... and thus AdjXZ = 0 and OppXZ = 0. No movement in the horizontal plane.
Note:
To check if your calculations are correct, you can verify if you actually move your point of the wanted quantity of movement (hypothenuse ie speed ie s). Using Pythagorean theorem:
s² = s_xz² + D_z² // Applied in the triangle P_0 P_1 P_1xz
= D_x² + D_y² + D_z² // Applied in the triangle P_0 P_1x P_1xz
With the definitions of the displacements given above:
D_x² + D_y² + D_z²
= (s * cos(a_p) * cos(a_y))² + (s * cos(a_p) * sin(a_y))² + (s * sin(a_p))²
= s² * (cos(a_p)² * cos(a_y)² + cos(a_p)² * sin(a_y)² + sin(a_p)²)
= s² * (cos(a_p)² * (cos(a_y)² + sin(a_y)²) + sin(a_p)²)
= s² * (cos(a_p)² * 1 + sin(a_p)²)
= s² * (cos(a_p)² + sin(a_p)²)
= s² * 1 // Correct
Hope it helped... Bye!

Converting distance (nautical miles) into degrees (Lat/Long)

I have entities in a simulation whose initial locations and paths are code using Java in decimal degrees. I need to scale the sensor radius (it's in nautical miles) and speed (nautical miles/hr) to match decimal degrees. The purpose is to visualize the sim in OpenMap and Google Earth.
I've seen How to convert Distance(miles) to degrees?, but the suggestions there don't work.
Any help is appreciated! I'm thinking it will involve using great circle distance formulas... but can't quite get it.
Ed Williams' Aviation Formula https://edwilliams.org/avform.htm is a good, and accessible, place to start. And I often reference http://movable-type.co.uk/scripts/latlong.html.
I am guessing that you need a vector of some sort (your question is a bit unclear).
What I use (in C, not Java) to calculate a fix-radial-distance is:
void polarToLatLong(double lat, double lon, double dist, double radial,
double *outlat, double *outlon) {
if (!dist) { // distance zero, so just return the point
*outlat = lat;
*outlon = lon;
}
else if (lat > 89.9999) { // North Pole singularity. Dist is in NM.
*outlat = 90 - dist / 60;
*outlon = fmod(radial + 180) - 180;
}
else { // normal case
double sinlat, coslon;
dist /= 3442; // = Earth's radius in nm (not WGS84!)
sinlat = Sin(lat) * cos(dist) + Cos(lat) * sin(dist) * Cos(radial);
*outlat = Arcsin(sinlat);
coslon = (cos(dist) - Sin(lat) * sinlat) / (Cos(lat) * Cos(*outlat));
*outlon = lon + (Sin(radial) >= 0 : -1 : 1) * Arccos(coslon);
}
}
In the above code Sin(), with an upper-case S, is just a wrapper of sin() for degrees:
#define CLAMP(a,x,b) MIN(MAX(a, x), b) // GTK+ GLib version slightly different
double Sin(double deg) {return sin(deg * (PI / 180));} // wrappers for degrees
double Cos(double deg) {return cos(deg * (PI / 180));}
double Arcsin(double x) {return asin(CLAMP(-1, x, 1)) * (180 / PI);}
double Arccos(double x) {return acos(CLAMP(-1, x, 1)) * (180 / PI);}

Java: Point rotation results are not accurate

I have the following code...
public class Point {
private double x;
private double y;
static private final double RADTODEG = 180.0d / Math.PI ;
static private final double DEGTORAD = Math.PI / 180.0d;
/**
* Rotates the point by a specific number of radians about a specific origin point.
* #param origin The origin point about which to rotate the point
* #param degrees The number of radians to rotate the point
*/
public void rotateByRadians(Point origin, double radians) {
double cosVal = Math.cos(radians);
double sinVal = Math.sin(radians);
double ox = x - origin.x;
double oy = y - origin.y;
x = origin.x + ox * cosVal - oy * sinVal;
y = origin.y + ox * sinVal + oy * cosVal;
}
/**
* Rotates the point by a specific number of degrees about a specific origin point.
* #param origin The origin point about which to rotate the point
* #param degrees The number of degrees to rotate the point
*/
public void rotateByDegrees(Point origin, double degrees) {
rotateByRadians(origin, degrees * DEGTORAD);
}
/**
* Rotates the point by the specified number of radians about the axis' origin (0,0). To rotate about a specific origin point, see rotateByRadians(Point, double)
* #param radians Measure of radians to rotate the point
*/
public void rotateByRadians(double radians) {
if(isEmpty()) // Since we're rotating about 0,0, if the point is 0,0, don't do anything
return;
double cosVal = Math.cos(radians);
double sinVal = Math.sin(radians);
double newx = x * cosVal - y * sinVal;
double newy = x * sinVal + y * cosVal;
x = newx;
y = newy;
}
/**
* Rotates the point by the specified number of degrees about to the axis' origin (0,0). To rotate about a specific origin point, see rotateByDegrees(Point, double)
* #param degrees Measure of degrees to rotate the point
*/
public void rotateByDegrees(double degrees) {
rotateByRadians(degrees * DEGTORAD);
}
The problem arises when given a point, say 0,200. Calling the rotation (about axis origin 0,0) for 180 degrees it should be (0, -200). The x coordinate shouldn't have changed. However, it ends up being (-2.4492935982947064E-14, -200). I tried using strictfp but it doesn't make a difference. This only affects the result if the coordinate being rotated is zero. Nonzero values work fine. Any ideas why this is not accurate?
The code is below:
Point p = new Point(0.0d, 200.0d);
p.rotateByDegrees(180.0d);
System.out.println(p);
Gives output:
shapelib.Point Object {x: -2.4492935982947064E-14 y: -200.0}
For better or for worse, that's just the way it is with floating point math. From http://mindprod.com/jgloss/floatingpoint.html:
"Think of float and double as representing physical measurements. No
one would complain if their cabinet maker made a desk 6.000000000001
feet long. Analogously, don’t complain about the inevitable tiny
errors in floating point arithmetic results e.g. Math. cos(
Math.toRadians( 90 ) ) not coming out bang on zero. ( If you want
perfection, use int, long, BigInteger or BigDecimal. )"
Float arithmetic is not fully accurate. Error of 10^-14 power is enough in most cases.
If you calculate Math.sin(Math.PI) you'll get 1.2246467991473532E-16. Why do you need to get precisely 0 in your case?
Both the provided answers so far are correct, but they're missing a fundamental point.
The range of possible values a floating point number can take on is not continuous. Rather, it has holes in it. So you can imagine that from 0.1 to 0.2, instead of there being an infinite amount of numbers, there are only a finite number.
That's most of the reason why floating point arithmetic is inaccurate. Computers can't exactly represent every real number you'd like. Instead, they can get to only some small epsilon away from the actual value.
As an example, you can't exactly represent the fraction 2 / 10. If you print out all the decimal places to this number, you'll find it something like 0.20000000000000001.
See here for a more thorough writeup: http://floating-point-gui.de/

Categories

Resources