How to calculate orbit info (a, e, time to apo, time to peri, T) from pos and vel of object? - math

Im trying to make small 2d solar system orbit simulator as hobby project and im having some issues with finding orbital info. (a, e, time to apo, time to peri, T).
I have readen some infos, articles, laws and even found some intersting research articles but im having troubles with understanding these and connecting these together.
My issue is - i cant get any orbit info from object state. Or, better to say, i dont know how :)
I want to get current orbit info each tick.
I have simplified solar system model - objects being attracted by stars. Thats it. No interactions between stars or objects itself => stars are at constant position. In this very basic example - only one star and one object.
My formula is to find attraction force is:
var dist = object.getPos().dist(fromStar.getPos()); // distance to star, can be centerOfMass if needed.
return 1 / Math.pow(dist, 2) * object.getMass() * this.gravitationalConstant; //: F = 1 / dist^2 * M * G
and this is my acceleration formula:
public function getTotalAttractionVector(object: ObjectState): Vec2 {
var result = new Vec2();
for (star in stars) {
var dir = object.getPos().getDirectionTo(star.getPos()); // normalized
var force = this.getAttractionForce(object, star); // from the formula above
result.addMut(dir.mulScalarMut(force));
}
return result;
}
The info what i have at the starting of each tick:
1. current position, current vel. Both as vector.
2. position from last tick, vel from last tick.
3. center of mass of solar system.
4. object mass
5. G
6. F from formula above and acceleleration as vec
I also have roughly simulated predicted points for next n ticks, they arent very precise (since my simulation at the moment isnt depending on any kind dt) but maybe there way to use them.
Until, my closest approach is these formulas;
E = (v^2)/2 - G*M/r
where v - magnitude of a vel vector, M = mass of obj, r = distance to center of mass, in this case distance to single star, G = grav. constant
a = -G*M/2E
e = sqrt(1 - r^2/(a(2E + GM)))
With this approach, my semi major axis (a) value from the formula above is correct only as my orbit of a object is approaching to circular. In case if my orbit is elliptical or not circular, wrong values are occuring. For example, a = 500 while distance to star being more than 800. If im understanding the idea of semi major axis correct, this can not occur at all. So i guess this is wrong too.
Im sorry for my bad english and for little overload with info, but maybe someone can help me, show where my logical misstakes or maybe even rough idea do this correct. Thanks! :)

Related

Need help figuring out orbits in 2D for my game

In a game that I'm making, the idea is that the mouse cursor is representing a center of mass and there are objects orbiting around it.
The cursor itself is not an object and there is no collision between the cursor and the objects.
The ideal method would be the one where I can enter x and y coordinates of the target, and maybe the orbit radius, and the object would go into orbit and would be accelerating constantly.
When I move the mouse, the object would follow; and when I stop it, it would fall back into the same orbit radius.
The objects acceleration should also be able to change so it gives an effect that the mouse has more or less mass.
I thought the best way to achieve this would probably be with vectors.
In the Projectile class I gave each projectile 4 fields: x coordinate, y coordinate, PVector speed and PVector acc (acceleration).
The first thing I tried is giving the object constant acceleration. Speed vector starts as zero, the acceleration vector is calculated, its magnitude is then set to some value and it is added to the speed vector.
This produced very large orbits, slow acceleration and when the mouse is moved, the orbit just became larger.
Next I tried making the acceleration increase when it is closer to the center of mass inspired by the actual planets. This did not work either. The orbits were still too large and not controllable. Kind o disappointed I tried making the acceleration constantly increasing which gave the best results. The orbit is now getting smaller, but it just keeps decreasing to some radius and then stops. This would be perfect if the radius at which it stops decreasing would be configurable, but no matter the parameters the orbit is always too large and the orbit size keeps decreasing frustratingly slowly. My guess is that the acceleration and speed somehow end up in an equilibrium, and then the orbit stops decreasing.
void move(float x,float y,float accm)
{
PVector target = new PVector(x, y);
PVector ball = new PVector(this.x, this.y);
acc = PVector.sub(target, ball);
acc.setMag(accm);
speed.add(acc);
println(acc.mag() + " " + speed.mag());
this.x = this.x + speed.x;
this.y = this.y + speed.y;
}
This is the function that gave the best results. The function is called in draw():
if(mousePressed == true)
{
for(i=0;i<nproj;i++)
{
a[i].move(mouseX, mouseY,k);
}
k += n;
}
k is the number given to the function and n is the rate at which acceleration increases. I tried many different acceleration magnitudes and different rates of acceleration and just couldn't figure it out. Nproj is the number of projectiles and a is the name of the projectile array.
I found that for k = 0 and n = 0.002 it gave the most reliable and stable results. If n is larger (around 0.01 or larger), the objects sometimes randomly flies off way further than expected, and it actually increases the orbit radius. As the acceleration increases this happens more often, and the object sometimes ends up off the screen and then it never comes back. I know that orbit radius doesn't exist because the orbits are elliptical, but it just makes it easier to explain.
Update:
This is what I came up with so far
void move(float x,float y,float accm)
{
PVector target = new PVector(x, y);
PVector ball = new PVector(this.x, this.y);
acc = PVector.sub(target, ball);
acc.setMag(accm);
vel.add(acc);
this.x = this.x + vel.x;
this.y = this.y + vel.y;
vel.limit(15);
}
and in draw()
if(mousePressed == true)
{
for(i=0;i<nproj;i++)
{
a[i].move(mouseX, mouseY,k);
}
k += n;
if(k > 25)
n = 0;
}
By limiting the velocity vector and constantly increasing acceleration vector, magnitude difference begins to increase and since the acceleration vector is increasing and the velocity vector is constant and acceleration vector points towards the target the sum of the vectors starts slowly pointing more and more towards the target. The condition if(k < 25) is there to limit the acceleration and by changing the limit of the acceleration you can change the orbit radius.
I think you probably would have gotten a quicker answer over at https://physics.stackexchange.com/ and framing your question as "how do I simulate gravity in a game?"
Anyway I will give it a try...
In the class Projectile I gave each projectile 4 fields: x coordinate, y coordinate PVector speed and PVector acc
Sounds good so far, except you don't need to store the acceleration vector with the object. You'll calculate a new acceleration vector for each object on each "tick" of your simulation.
I would use standard physics terminology here and call each object's vector velocity instead of speed.
Next I tried making the acceleration increase when it is closer to the center of mass inspired by the actual planets.
This behavior should just happen naturally if you use the right algorithm for calculating an orbit.
Your "sun" and the "planets" each have a mass. Masses attract each other with a gravitational force, which is F = G * m1 * m2 / d^2 from Wikipedia.
Remember that Force = mass * acceleration, and you have the acceleration as a = m * G / d^2 where m is the mass of the other object (in this case the sun), and d is the distance between the two objects. So the important part is that the acceleration of an object due to gravity varies with the distance squared between the two objects.
So your basic algorithm for a single tick of your simulation looks like this:
For each planet, calculate an acceleration vector
Use the distance to the "sun" squared as the magnitude of the acceleration vector (times a constant value that depends on your "gravitational constant" and your sun's mass), and the direction is of course the direction from the planet towards the sun
Add this acceleration vector to the velocity vector for the planet
Add the velocity vector to the (x, y) position of the planet to move it forward.
With appropriate values for the length of each simulation tick, the gravitational constant, and the sun's mass, this should start to look pretty reasonable.
Since you're assuming that the planets are all independent and cannot collide, you can just do the calculation independently for each planet.
However, I think the game might be more interesting with a more accurate simulation. In reality, every object has a gravitational force on every other object. This would mean looping over all pairs of objects and doing the same kind of acceleration/velocity/position calculation.
The point of the game could then be to get the "planets" from one side of the screen to the other, in increasingly difficult starting configurations as they are all affecting each other and moving in different directions.
In order to make all of this work well, it would be important to set the mass of the "sun" many times higher than the mass of the planets, and to choose a reasonable value for your gravitational constant based on the timing of your simulation. You'll have to play with these constants to find the best results.

Unity3D Linear interpolation from V1 to moving V2

I posted this question on the stack math site, but they are not too excited to see questions including programming. Anyway, now I am here :)
I have an object, which is located at MyTransform.position (Vector)
That object should follow the DesiredPosition (Vector), which is
moving in varius directions with a changing velocity
MaxDelayDistance (float) is the maximum distance my object is allowed
to have to the DesiredPosition.
DelayRecovery (float) are the seconds my object has in order to move
to the DesiredPosition if the MaxDelayDistance is reached.
Time.deltaTime (float) is a term we use to describe the time the last
frame update took. It's value is usually about 0.025f.
private Vector3 GetLerpedPosition(Vector3 DesiredPosition) {
//DesiredPosition now contains the goal
Vector3 dirToDesiredPosition = (DesiredPosition - MyTransform.position).normalized; //Direction to desired position
Vector3 lerpStart = DesiredPosition + (-dirToDesiredPosition * MaxDelayDistance); //Start the lerp at my farthest allowed position
float lerpCurrentT = Vector3.Distance(MyTransform.position, DesiredPosition) / Vector3.Distance(lerpStart, DesiredPosition); //My current fragtion (t) of the lerp
//Now I lerp from lerpStart to DesiredPosition using a calculated fraction
Vector3 result = Vector3.Lerp(
lerpStart,
DesiredPosition,
lerpCurrentT + (DelayRecovery / MaxDelayDistance * Vector3.Distance(MyTransform.position, DesiredPosition) * Time.deltaTime)
);
return result;
}
The main problem is that my object is not following the DesiredPosition smoothly.
It jumps from MaxDelayDistance to DesiredPosition and back.
Somehow the fraction (t) in my Lerp function always results in about 1.005 or about 0.001. Can you spot any problems in my approach?
I see several issue, and I'm not sure of the direction you have choose (at least never seen anything similar before).
Preamble:
Vector3.Distance(lerpStart, DesiredPosition)
this is a constant and is the radius around DesiredPosition.
Here's some problems I noticed:
Problem 1
lerpT is always >=1 for every point more distant more than MaxDelayDistance (outside the radius). So when an object is further distant than MaxDelayDistance it will be immediately moved to DesiredPosition.
Problem 2
DelayRecovery (float) are the seconds my object has in order to move
to the DesiredPosition if the MaxDelayDistance is reached.
Not sure of having completely understood your intricate lerp, btw the statement above seems to be false. DelayRecover is always taken in consideration while lerping despite its distance.
Problem 3
Possible division by zero when you are closed to DesiredPosition (* operator is evaluated before /)
Some considerations
I'll read with more attention your code, and I'll try to figure out the logic behind that. It's something I've never seen.
Some general approach for moving toward a given position:
If start and destination are known and fixed, than lerping (or an ease function) allow to control exactly the travel time incrementing t parameter from 0 to 1.
If destination is moving you can still smooth follow the target using lerp (maybe not the more correct use from a theoretical point of view, nor physical realistic but in any case effective). Lerp factor in this case is a kind of "speed toward the goal". Effectively linear proportional to the distance from the target.
Some physic based approach. Integrate. Define some kind of max speed and max acceleration and calculate the next position (eventually clamp to prevent overshooting and oscillation)
PID controllers. Lot of power, but I always found them hard to tweak.
Consider also to use Vector3.MoveToward, here's how it's implemented:
public static Vector3 MoveTowards(Vector3 current, Vector3 target, float maxDistanceDelta)
{
Vector3 a = target - current;
float magnitude = a.magnitude;
if (magnitude <= maxDistanceDelta || magnitude == 0f)
{
return target;
}
return current + a / magnitude * maxDistanceDelta;
}
Hope this helps.

Gravity's acceleration between two objects

So I am making a program, where you can have two objects (circles). I want them to orbit like planets around each other, but only in 2D.
I know that using Newtons Universal Law of Gravitation I can get the force between the two objects. I also know A = F / M. My question is how would I take the A from the previous equation and change it into a vector?
You need to use vector equations:
// init values (per object)
double ax=0.0,ay=0.0,az=0.0; // acceleration [m/s^2]
double vx=0.0,vy=0.0,vz=0.0; // velocity [m/s]
double x=0.0, y=0.0, z=0.0; // position [m]
double m=1.0; // mass [kg]
// iteration inside some timer (dt [seconds] period) ...
int i; double a,dx,dy,dz; // first compute acceleration
for (ax=0.0,ay=0.0,az=0.0,i=0;i<obj.num;i++)
if (obj[i]!=this) // ignore gravity from itself
{
dx=obj[i].x-x;
dy=obj[i].y-y;
dz=obj[i].z-z;
a=sqrt((dx*dx)+(dy*dy)+(dz*dz)); // a=distance to obj[i]
a=6.67384e-11*(obj[i].m*m)/(a*a*a); // a=acceleration/distance to make dx,dy,dz unit vector
ax+=a*dx; // ax,ay,az = actual acceleration vector (integration)
ay+=a*dy;
az+=a*dz;
}
vx+=ax*dt; // update speed via integration of acceleration
vy+=ay*dt;
vz+=az*dt;
x+=vx*dt; // update position via integration of velocity
y+=vy*dt;
z+=vz*dt;
Code is taken from here
obj[] is list of all your objects
obj.num is the count of them
I recommend to create object class with all the variables inside (ax,ay,az,...m), init them once and then continuously update (iteration) in some timer. If you want more accuracy then you should compute ax,ay,az for all objects first and only after update speed and position (to avoid change of position of objects during gravity computation). If you want to drive an object (like with truster) then just add its acceleration to ax,ay,az vector)
Now to setup an orbit just:
place planet object
must be massive enough and also set its position / velocity to what you want
place satellite
Initial position should be somewhere near planet. It should not be too massive. Init also speed vector with tangent direction to orbiting trajectory. If speed is too low it will collapse into planet and if speed is too high it will escape from planet otherwise will be orbiting (circle or ellipse)
timer
lower the interval better the simulation usually 10ms is OK but for massive and far objects is also 100ms and more OK. If you want particles or something then use 1ms (very dynamic sceene).
I strongly recommend to read this related QA:
Is it possible to make realistic n-body solar system simulation in matter of size and mass?
especially [edit3] about the integration precision and creating orbital data.
With two objects you are probably best using an ellipse which is the path the objects will follow about their common center of mass. Read Kepler's laws of planetary motion which gives the background.
If one object is a much greater mass than the other, i.e. a sun and a planet you can have one stationary and the other taking an elliptical path. The equation of the ellipse is given by
r = K e / ( 1 + e cos(theta))
K is a constant giving the size and e is the eccentricity. If you want an elliptical orbit have 0 < e < 1 the smaller it is the more circular the orbit. To get x, y coordinates from this use, x = r cos(theta), y = r sin(theta). The missing bit is time and how the angle is dependant on time. This is where the second and third laws come in. If a and b are the semi-major and semi-minor lengths of the ellipse, and P is the period then
0.5 * P * r^2 theta'= pi a b
theta' is the rate of change of angle with respect to time (d theta/d t). You can use this to get how much theta will change given a increase in time. First work out the current radius r0 given the current angle th0 if the time increment is δt then the angle increment δtheta is
δtheta = 2 pi * a * b / r^2 * δt
and the next angle is th0 + δtheta.
If the masses are of similar magnitude then see two body problem. Both objects will have elliptical orbits, there are two patterns which you can see in animations on that page. The ellipses will follow the same formula as above with the focus at the common center of mass.
If you have three object things get considerably harder and there are not generally neat solutions. See three body problem for this.

3D space Box to Box collision prediciton

I am developing a collision prediction system (language is really irrevelant here) and I am looking for a way to predict collision of two objects' hitboxes after a given time. The variables I have are:
1st entity
2nd entity
1st and 2nd entity Maximum and Minimum XYZ of the entity's bounding box (the "highest" corner and the "lowest" corner)
1st and 2nd entity velocity (we assume its constant)
Time
What I have tried so far was calculating the plausable entity position after given time then based on that calculating the hitboxes max and min positions for both entities and checking if for these positions collision happened. The way I did it consisted of very many loops and was incredibly inefficient, though I didn't use any math formula since I have not found one.
There is one on StackOverflow, but for 2D collision prediction and you can find it here.
I would like someone to help me extend this to 3D space.
Here's how I would do it. First, find the interval in time during which the X-coordinates of the two boxes overlap. You can do this by solving two linear equations in t, representing the times when the X-coordinates are just touching:
Minimum X of entity 1 at time t = Maximum X of entity 2 at time t
Maximum X of entity 1 at time t = Minimum X of entity 2 at time t
Let me know if you want help setting that part up!
Now, solve the same problem for the Y-coordinates. If the interval for Y doesn't intersect the interval for X, the boxes don't collide. If the intervals do intersect, take the intersection and keep going.
Solve the problem for the Z-coordinates to get another interval. If the interval for Z doesn't intersect the interval for X and Y, the boxes don't collide. If the intervals do intersect, take the intersection.
Now you have an interval in time [t1, t2] that represents all points in time when all three coordinates of the boxes overlap -- in other words, all points in time when the boxes overlap! So t1 is the point in time when they collide.
(Another approach would be to replace the hitboxes with ellipsoids and solve a quadratic equation like in the other StackOverflow thread. However, the math is actually harder in that case. Using axis-aligned boxes means you can break down the problem into each coordinate independently and stick to linear equations.)
Edit: By request, here's how to set up the linear equations.
struct Entity
{
float x1; // Minimum value of X
float x2; // Maximum value of X
float vx; // Velocity in X
// etc.
};
Entity entity1;
Entity entity2;
// Find the interval during which the X-coordinates overlap...
// TODO: Handle the case Entity1.vx == Entity2.vx!!!
// Solve for Entity1.x1 + t * Entity1.vx = Entity2.x2 + t * Entity2.vx
// t * Entity1.vx - t * Entity2.vx = Entity2.x2 - Entity1.x1
// t * (Entity1.vx - Entity2.vx) = Entity2.x2 - Entity1.x1
float timeXa = (Entity2.x2 - Entity1.x1) / (Entity1.vx - Entity2.vx);
// And the other side...
// Entity1.x2 + t * Entity1.vx = Entity2.x1 + t * Entity2.vx
// t * Entity1.vx - t * Entity2.vx = Entity2.x1 - Entity1.x2
// t * (Entity1.vx - Entity2.vx) = Entity2.x1 - Entity1.x2
float timeXb = (Entity2.x1 - Entity1.x2) / (Entity1.vx - Entity2.vx);
float timeXMin = std::min(timeXa, timeXb);
float timeXMax = std::max(timeXa, timeXb);
Then do the same thing for Y and Z, and intersect the time intervals. Note that I may have made some silly sign errors, and I didn't handle the equal-velocity case, which can cause a division by zero. You'll want to throw some quick unit tests at the final code to make sure that it gives reasonable results.

Calculus? Need help solving for a time-dependent variable given some other variables

Long story short, I'm making a platform game. I'm not old enough to have taken Calculus yet, so I know not of derivatives or integrals, but I know of them. The desired behavior is for my character to automagically jump when there is a block to either side of him that is above the one he's standing on; for instance, stairs. This way the player can just hold left / right to climb stairs, instead of having to spam the jump key too.
The issue is with the way I've implemented jumping; I've decided to go mario-style, and allow the player to hold 'jump' longer to jump higher. To do so, I have a 'jump' variable which is added to the player's Y velocity. The jump variable increases to a set value when the 'jump' key is pressed, and decreases very quickly once the 'jump' key is released, but decreases less quickly so long as you hold the 'jump' key down, thus providing continuous acceleration up as long as you hold 'jump.' This also makes for a nice, flowing jump, rather than a visually jarring, abrupt acceleration.
So, in order to account for variable stair height, I want to be able to calculate exactly what value the 'jump' variable should get in order to jump exactly to the height of the stair; preferably no more, no less, though slightly more is permissible. This way the character can jump up steep or shallow flights of stairs without it looking weird or being slow.
There are essentially 5 variables in play:
h -the height the character needs to jump to reach the stair top<br>
j -the jump acceleration variable<br>
v -the vertical velocity of the character<br>
p -the vertical position of the character<br>
d -initial vertical position of the player minus final position<br>
Each timestep:<br>
j -= 1.5; //the jump variable's deceleration<br>
v -= j; //the jump value's influence on vertical speed<br>
v *= 0.95; //friction on the vertical speed<br>
v += 1; //gravity<br>
p += v; //add the vertical speed to the vertical position<br>
v-initial is known to be zero<br>
v-final is known to be zero<br>
p-initial is known<br>
p-final is known<br>
d is known to be p-initial minus p-final<br>
j-final is known to be zero<br>
j-initial is unknown<br>
Given all of these facts, how can I make an equation that will solve for j?
tl;dr How do I Calculus?
Much thanks to anyone who's made it this far and decides to plow through this problem.
Edit: Here's a graph I made of an example in Excel.
I want an equation that will let me find a value for A given a desired value for B.
Since the jump variable decreases over time, the position value isn't just a simple parabola.
There are two difficulties in play here. The first is that you don't actually have j -= 1.5, you have j = max(0, j - 1.5). That throws somewhat of a wrench into calculations. Also, your friction term v *= 0.95 makes direct solution difficult.
I would suggest using a lookup table for this. You can precalculate the desired a for each possible b, by trial and error (e.g. binary search on the values of a that give you the required b). Store the results in a table and just do a simple table lookup during the game.
After extensive use of Excel 2010 and its Seek Goal function, I was able to make a table of values, and Excel gave me an approximate trendline and equation for it, which I tweaked until it worked out. The equation is j = 3.35 * h ^ 0.196, where j is the initial jump force and h is the height required to jump. Thanks for your help.
If I neglect the friction term, and assume that j reaches zero before v reaches zero, I get after a page of calculations that:
b = 1/(8*(deceleration^2)*gravity)*j0^4 - 1/(6*deceleration^2)*j0^3
the solution to this is quite long, but equal approximately (for 10 < b < 400) to:
j0 = (10*(deceleration^2)*gravity*b)^0.25

Resources