Jump to content

[SOLVED] Cancel unintantional vertical speed change


Recommended Posts

Hello,

i am trying to script an engine, that will (partially) cancel the unintentional change of vertical speed (like pull of gravity) and leave the v-speed added by engines as it is/was. The closest i did come to this goal is:

Vector3d forceneut = FlightGlobals.getGeeForceAtPosition(vessel.GetWorldPos3D());
forceneut = forceneut.normalized * -((forceneut.magnitude*2/10)*Time.fixedDeltaTime);
foreach(Part p in vessel.parts)
{
	p.rigidbody.AddForce(forceneut,ForceMode.Acceleration);
}

Unfortunately the v-speed is still decreasing.

What i want to accomplish:

- Flying in any direction, any location, at any horizontal speed, vertical speed (v-Speed) = 0 m/s and pointing up/down = 0°    => v-Speed should remain 0 m/s

- Speed changes by engines, lift force, ... should not be influenced

What am i missing?

 

Thx

Edited by Big-IN
SOLVED
Link to comment
Share on other sites

With that line i hope to calculate how much speed and vector pointing away from the MainCelestialBody has to be added, to maintain the current vertical velocity and still orbit the MainCelestialBody.

There was (at least) one mistake in the calculation:

forceneut = forceneut.normalized * -((forceneut.magnitude*2/10)*Time.fixedDeltaTime);

changed to

forceneut = forceneut.normalized * -((forceneut.magnitude*forceneut.magnitude/10)*Time.fixedDeltaTime);

Now it works mostly. Am also not entirely sure why. With that calculation the v-Speed is decreasing.

Unfortunately if i use "forceneut.magnitute * Time.fixedDeltaTime", the v-Speed start to increase.

Link to comment
Share on other sites

13 hours ago, Big-IN said:

changed to

you normalize some vector, then multiply it on negative of it's magnitude squared (?), divided by 10 (??) and multiplied on delta time (???). Is there an idea behind it, or you just combine opeartions and literals in random order?

Answer two questions for yourself:

What does v-speed = const mean for v-acceleration?
What does FlightGlobals.getGeeForceAtPosition(vessel.GetWorldPos3D()); return?

Edited by Boris-Barboris
Link to comment
Share on other sites

Yes, my calculation before is a bit random.

10 hours ago, Boris-Barboris said:

Answer two questions for yourself:

What does v-speed = const mean for v-acceleration?
What does FlightGlobals.getGeeForceAtPosition(vessel.GetWorldPos3D()); return?

v-speed = should be magnitude of v-velocity (v) in m/s.

The FilightGlobals.getGeeForceAtPosition(vessel.GetWorldPos3d()) does return the gravitational acceleration (a) in m/s/s at the position of the vessel. To convert the acceleration (m/s/s) to velocity (m/s), the acceleration has to be multiplyed by a time delta. (Found that after a long search.) In case of calculation in onFixedUpdate, the Time.fixedDeltaTime() (fdt) should be used.

After reconsidering the calculation i came up with this formula to cancel gravity:

v(-g) = a(g) * -fdt => v(g) - v(-g) = 0 => gravitational acceleration canceled
(-fdt = fdt * -1)

Without gravity, the vessel does drift away because of centrifugal force (did not think about that one before). For completeness: the formula for centrifugal acceleration is a(c) = v^2/r .

v(c) = a(c) * fdt = v(vessel)^2 / r * fdt
v(c) - v(c) = 0 => centrifugal acceleration canceled

My curren code looks like this:

//*****************************************************************************
// Copyright (c) 2016 by Big-IN
// This code is Licensed under the Apache License, Version 2.0 (the "License");
// http://www.apache.org/licenses/LICENSE-2.0
/*****************************************************************************

// geeacc = acceleration down at vessel position in m/s/s
Vector3d geeacc = FlightGlobals.getGeeForceAtPosition(vessel.GetWorldPos3D());

// radius = distance between vessel and center of mainBody
double radius = vessel.altitude+vessel.mainBody.Radius;

// centacc = acceleration up by centrifugal forces in m/s/s
Vector3d centacc = Math.Pow(FlightGlobals.ship_obtSpeed,2.0) / radius;

// vneut = speed up in m/s required to conter gravitational - and centrifugal acceleration
Vector3d vneut = geeacc.normalized * -(geeacc.magnitude - centacc.magnitude);

// apply vneut to every part
foreach(Part p in vessel.parts)
{
	p.rigidbody.AddForce(forceneut,ForceMode.Acceleration);
}

I believe only air resistance is not canceled. The centrifugal forces are canceled in the up and down direction. Will have to find a way to cancel centrifugal force only when it is in the outward direction.

Thank you for your help.

 

Edited by Big-IN
time delta Removed, RevealAltitude changed to Radius
Link to comment
Share on other sites

47 minutes ago, Big-IN said:

Found that after a long search

Oh, I understand now, you don't really feel comfortable with kinematics.

Position is a vector. When position of a body changes, we can divide that change (also a vector) by the time interval - we get velocity with this. Velocity describes, how fast the position is changing. Same with acceleration - it describes how fast the velocity is changing.

Wikipedia articles on velocity and acceleration can give you very good insight.

You want your engine to cancel out "unwanted changes in v-speed". That means, that you may want to cancel out gravity-like forces in vertical projection. Let's leave aero forces out of scope, it's actually much harder to do.

Those forces you want to cancel consist of three components - gravity itself, centrifugal and coriolis acceleration. Their vector sum can be found in vessel.graviticAcceleration field. It's acceleration, vector.

If you want to cancel only it's vertical component, you need to do:

Vector3d planet2ves = (vessel.position - vessel.MainBody.position).normalized;   // unity vector, directed towards zenith
Vector3d counterAcceleration = -planet2ves * Vector3d.Dot(planet2ves, vessel.graviticAcceleration);  // project on it

and then apply counterAcceleration to every part the same way you do (addForce). You apply acceleration, not changes in velocity. Acceleration is not a velocity change.

Edited by Boris-Barboris
Link to comment
Share on other sites

12 hours ago, Boris-Barboris said:

Oh, I understand now, you don't really feel comfortable with kinematics.

Yes, usually i do programming, not physics.

12 hours ago, Boris-Barboris said:

Those forces you want to cancel consist of three components - gravity itself, centrifugal and coriolis acceleration. Their vector sum can be found in vessel.graviticAcceleration field. It's acceleration, vector.

If you want to cancel only it's vertical component, you need to do:


Vector3d planet2ves = (vessel.position - vessel.MainBody.position).normalized;   // unity vector, directed towards zenith
Vector3d counterAcceleration = -planet2ves * Vector3d.Dot(planet2ves, vessel.graviticAcceleration);  // project on it

and then apply counterAcceleration to every part the same way you do (addForce). You apply acceleration, not changes in velocity. Acceleration is not a velocity change.

Unfortunately i could not find any graviticAcceleration property in a vessel object. Are you sure, it is called like that?

Also 'am not sure, why the coriolis acceleration has also to be canceled. By what i understand, coriolis acceleration is the change in surface velocity occurring when a vessel is moving to or from the center of orbit.

I have done some changes in the calculation.

*** Code Removed: No longer needed. ***

There is the wrong assumption, the centre of centrifugal force is the mainBody. That is not necessarily the case. Unfortunately i don't know how it should be calculated. How can it be done?

 

EDIT:

Checked the vessel properties again. Could it be the case, that all required forces are avaliable in "vessel.gForce ", "vessel.CentrifugalAcc" and "vessel.CoriolisAcc"? If that is true, they only have to be added up and multiplied by -1. The result can be applied by AddForce with ForceMode.Acceleration .

EDIT:

Easy calculation:

Vector3d forecancel = -(vessel.gForce+vessel.CentrifugalAcc+vessel.CoriolisAcc);
foreach (Part p in vessel.parts)
{
	p.rigidbody.AddForce(forcecancel, Force.Acceleration);
}

Many thanks to Boris-Barboris.

Edited by Big-IN
Link to comment
Share on other sites

1 hour ago, Big-IN said:

If that is true, they only have to be added up and multiplied by -1. The result can be applied by AddForce with ForceMode.Acceleration .

That is true for KSP 1.1.2 and previous, API has changed recently afaik.

Edited by Boris-Barboris
Link to comment
Share on other sites

2 hours ago, Big-IN said:

Easy calculation:

Now, you might notice, that if you fly horizontally you'll still have your v-speed increased. Depending on what you want from your mod, you may want to create your own centrifugal acceleration to keep v-speed, not only the reference frame one (the one in vessel properties, wich accounts for planet rotation). You can easily get it from vessel.horizontalSrfSpeed squared, divided by distance from vessel to planet center. Direct it down, to the planet core.

Edited by Boris-Barboris
Link to comment
Share on other sites

Distance from vessel to planet is also known as orbit radius. Unfortunately a vessel permanently hovering closer to the poles would not have it's orbit around the celestial body. Instead the calculation must account for the axis of rotation. Any idea how that one can be calculated?

Link to comment
Share on other sites

8 hours ago, Big-IN said:

Distance from vessel to planet is also known as orbit radius

It is not orbit radius. Orbit radius is orbit radius (besides, only circular orbits have radii, others have semi-major and semi-minor axes).

I'm talking about vessel.position - vessel.MainBody.position. Just use the thing from my previous post, I'll explain it later if still needed.

Edited by Boris-Barboris
Link to comment
Share on other sites

  • 2 weeks later...

It has been some time (few weeks) since my programming for KSP. In the mean time i did rethink my approach at the problem.

Now i do believe it's better to start with a vessel without any orbital speed. In such a case only the "True" gravity has to be canceled. The formula for gravitational acceleration formula is:

g = GM/r^2

g = gravitational acceleration (toward the CelestialBody) (m/s^2)
G = Gravitational Constant
M = Mass of main CelestialBody
r = distance between CelestialBoty and the vessel

In case of KSP the

 gravmag = FlightGlobals.getGeeForceAtPosition(vessel.GetWorldPos3D()).magnitude;

does give the right value.

Without gravity the vessel would continue movement in a straight line. To counter this, some additional centripetal acceleration is required. The formula for Centripetal acceleration is:

a = v^2/r

a = acceleration (away from the main CelestialBody) (m/s^2)
v = orbital speed of the vessel (in any horizontal direction)
r = distance between the vessel and main CelestialBody

The resulting function looks like this:

private void GravityNeutralisation()
{
  if(dNPower) return;		//dNPower > 0

  double radius = (vessel.GetWorldPos3D()-vessel.mainBody.position).magnitude;

  double horvel = (vessel.obt_velocity-vessel.upAxis*Vector3d.Dot(vessel.upAxis,vessel.obt_velocity)).magnitude;
  double centacc = (horvel*horvel)/radius;
  double gravmag = FlightGlobals.getGeeForceAtPosition(vessel.GetWorldPos3D()).magnitude;

  if (gravmag>centacc)
  {
    // geeneut = vessel.upAxis*gravmag + (-vessel.upAxis*centacc);
    // geeneut = vessel.upAxis*gravmag - vessel.upAxis*centacc);
    geeneut = vessel.upAxis * (gravmag - centacc);
    geeneut = geeneut * dNPower;		// dNPower is for percentage of neutralisation (0.0 = Off, 1.0 = Max)
    foreach (Part p in this.vessel.parts)
    {
      if ((p.physicalSignificance == Part.PhysicalSignificance.FULL) && (p.rigidbody != null))
      {
      	p.rigidbody.AddForce(geeneut, ForceMode.Acceleration);
      }
    }
  }
}

Still don't see, where the Coriolis Acceleration is applied.

Edited by Big-IN
Link to comment
Share on other sites

What do you mean where? Vessel, moving from equator towards pole will experience coriolis acceleration in surface reference frame. You can ignore it, it's small and barely noticible, but it is already precalculated in vessel fields and there is no price for using it.

if (gravmag>centacc)

why?

Other than that, looks fine.

Link to comment
Share on other sites

The neutralisation is only ment as "hovering" support. By comparing gravmag and cntacc

if (gravmag>centacc)

the result should be limited to this purpose only.

When the orbital velocity is increasing, centacc is also increasing. When the gravmag == centacc, that means, the vessel is moving at orbital velocity. No further support is required. If the vessel accelerate further ( centacc > gravmag ), the vessel is speeding away from the celestial body, by it's own velocity. At least that's the theory. Did not have the chance to test this.

Edited by Big-IN
Link to comment
Share on other sites

While for development and test purposes there is no ressource usage, neutralisation will affect the consumption in the end. No need wasting ressources if not (really) necessary.

Thank you for your help.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...