Jump to content

What is Vessel.verticalSpeed actually measuring


Recommended Posts

In the course of tracking down an issue today, I found that the value returned by vessel.verticalSpeed does not match that of a manually calculated "rate of change of altitude". The difference between the two values is tiny (probably inconsequential for any mod other than Pilot Assistant) but it has me questioning where the number comes from.

This is my manual calculation which has resolved the offset that kept appearing when using my altitude hold. It is simply the rate of change in altitude over the previous frame


[COLOR=#008000]// run every physics frame[/COLOR]
vertSpeed = (thisVessel.altitude - lastAltitude) / TimeWarp.fixedDeltaTime;
lastAltitude = thisVessel.altitude;

Logging the difference between ^^ and vessel.verticalSpeed results in a noticeable difference, particularly at high speed (a half meter offset that won't go away is very noticeable when altitude is being precisely controlled)

  • At 20km and 1300m/s surface velocity, the highest measured diff was 0.1175m/s and an offset of 0.03-0.04m/s was consistently present
  • Squad's value is always greater than mine at a constant altitude

So if Squad isn't measuring the rate of change of altitude, what are they measuring? (Answered)

Edited by Crzyrndm
Link to comment
Share on other sites

That's because Squad's value measures instantaneous velocity. You are mesuring average velocity over a period of (short) time. This is why yours will nearly always be inferior. Your method also implies a bunch of potential floating point imprecisions.

Basically, vertical velocity is the magnitude of the projection of the velocity vector on the vertical vector. That's all. In code, that would be something like:

Vector3d vertical = (this.vessel.GetWorldPos3D() - this.vessel.mainBody.position).normalized; //alternatively this.vessel.upAxis should work
Vector3d velocity = this.vessel.rootPart.Rigidbody.velocity + Krakensbane.GetFrameVelocity(); //That's basically also this.vessel.obt_velocity
double vertSpeed = Vector3d.Dot(velocity, vertical) //Instantaneous vertical speed

Note: I'm *guessing* this is what squad does, because that would be the most sane way to calculate instantaneous vertical velocity when you know the velocity vector.

EDIT: cleaned the code a bit. Realized I didn't need to project on the vertical axis and then get the magnitude if the vector is normalized.

Edited by stupid_chris
Link to comment
Share on other sites

This is why yours will nearly always be inferior.

My method should be inferior for stated reasons (*duh* on the instantaneous vs. averaging...) but is still giving results that are within acceptable margins.

On the other hand, Squad's vertical speed says the vessel has a vertical velocity of 0.05m/s even when the altitude is slowly decreasing for 10+ frames before and after that value is recorded (offset is consistent, not a spike)

I'll check out the difference between the velocity vector and the two values shortly...

Link to comment
Share on other sites

My method should be inferior for stated reasons (*duh* on the instantaneous vs. averaging...) but is still giving results that are within acceptable margins.

On the other hand, Squad's vertical speed says the vessel has a vertical velocity of 0.05m/s even when the altitude is slowly decreasing for 10+ frames before and after that value is recorded (offset is consistent, not a spike)

I'll check out the difference between the velocity vector and the two values shortly...

Then Squad screwed something up. Apply the code I wrote above (I'd calculate everything manually as I did), it should give you the real value.

Link to comment
Share on other sites

Apply the code I wrote above (I'd calculate everything manually as I did), it should give you the real value.

The result from your code is a small improvement on Squad's value, but it still displays a consistent slight offset of about 0.02m/s compared to the expected value based on changes in altitude. Using the surface relative velocity was significantly worse (0.07-0.08m/s) for some reason. Both tests were run with a very consistent altitude and speed and only my original test method is consistently giving results that match the altitude data.

Raw data can be found here (18km tab is the comparison of the three data sets and has the most consistent altitude, 15km was testing the effects of velocity on the error, 20km uses static conditions but doesn't include the suggested method and the altitude hold was not particularly well tuned)

Edited by Crzyrndm
Link to comment
Share on other sites

I'll copy paste a comment line I added in Mechjeb to not forget about it

"egg found out that vessel.pos is actually 1 frame in the future while vessel.obt_vel is not"

I have a feeling this is relevant here.

Link to comment
Share on other sites

I dont know what your reference is for the *right* vertical speed, but the method you first used is flawed, because you're averaging. Regardless, I think the problem is because of floating point imprecision, and because the velocity vector is not *stable*. I think the solution is to do like Mechjeb: you need a moving average. If you need that much precision, then thatd probably the best solution.

Link to comment
Share on other sites

I'll copy paste a comment line I added in Mechjeb to not forget about it

"egg found out that vessel.pos is actually 1 frame in the future while vessel.obt_vel is not"

I have a feeling this is relevant here.

If that's true, it's probably the root cause (pending testing for confirmation). It would angle the up vector very slightly forwards and add a tiny amount of horizontal velocity to the measurement. Fits with my observations of increasing error with increasing speed.

EDIT

Using the last up Vector produces a negative offset of similar magnitude to the value squad reports. The average of the two *might* be the value I need, but I don't feel like using two wrong values to make one that might be right :D

I dont know what your reference is for the *right* vertical speed, but the method you first used is flawed, because you're averaging. Regardless, I think the problem is because of floating point imprecision, and because the velocity vector is not *stable*. I think the solution is to do like Mechjeb: you need a moving average. If you need that much precision, then thatd probably the best solution.

In my case, no, any calculation from velocity vectors is not going to work because they do not go to zero when the rate of change in altitude goes to zero (I can guarantee that value is <10mm/s over a period of several minutes.). That particular behaviour is an absolute neccesity for the altitude control system used by Pilot Assistant to produce expected behaviour.

I could maybe store the last upVector and see if that works (E: It doesn't), but failing that I will be sticking with the method that is accurate if a little less precise.

EDIT

Statistics comparing results from my last test (35500 samples) for anyone interested (control system using "Avg VS" input)

rhkrE2Z.png

Edited by Crzyrndm
Link to comment
Share on other sites

Well potato. I think I figured out where the error comes from. The velocity vector is calculated from the root part of the vessel, but the up vector is calculated from the CoM of the vessel. What that does is that in the cases where the root part is in front CoM (i.e. planes as in your tests, the up vector is not actually the right up vector. The tiny longitudinal differencr betwern both positions will cause the orthogonal prohprojection to have a value greater than 0 even when not climbing, because the up vector is actually drawn backwards. This will nearly always cause a superior value At all times. Thats the problem. Im on my phone rn but ill write a snippet of code later that should work. All in all, *always* trust vectors. If vectors are not giving you the right answer, you did something wrong. Using an averaged speed would potentially give unexpected results you definitely do not want if precision is this important.

Link to comment
Share on other sites

Precision isn't amazingly important, accuracy is. Any constant offset just cannot be tolerated

Don't worry about writing the code, with a possible cause identified I can handle the logic :P

Edited by Crzyrndm
Link to comment
Share on other sites

Meh, not like it's hard. If If it doesn't mind for it to be based on the root part, something like:

Vector3d vertical = (this.vessel.rootPart.transform.position - this.vessel.mainBody.position).normalized;
Vector3d velocity = this.vessel.rootPart.Rigidbody.velocity + Krakensbane.GetFrameVelocity();
verticalSpeed = Vector3d.Dot(vertical, velocity);

Should do the job.

Link to comment
Share on other sites

Well, I know where Squad's number came from now. vertSpeed3 exactly matches that of vessel.verticalSpeed (calculating the up vector through the root part, offset by one frame). Neither calculation meets the requirement of zero vertical speed with a constant altitude.

lastVertical = vertical;
vertical = (thisVessel.rootPart.rigidbody.position - thisVessel.mainBody.position).normalized;
velocity = thisVessel.obt_velocity;
vertSpeed2 = Vector3d.Dot(velocity, vertical); // worst offset yet, +0.1m/s
vertSpeed3 = Vector3d.Dot(velocity, lastVertical); // same as vessel.verticalSpeed

I wonder if this is all down to a constant altitude not being a straight line?

Edited by Crzyrndm
Link to comment
Share on other sites

Well, I know where Squad's number came from now. vertSpeed3 exactly matches that of vessel.verticalSpeed (calculating the up vector through the root part, offset by one frame). Neither calculation meets the requirement of zero vertical speed with a constant altitude.

lastVertical = vertical;
vertical = (thisVessel.rootPart.rigidbody.position - thisVessel.mainBody.position).normalized;
velocity = thisVessel.obt_velocity;
vertSpeed2 = Vector3d.Dot(velocity, vertical); // worst offset yet, +0.1m/s
vertSpeed3 = Vector3d.Dot(velocity, lastVertical); // same as vessel.verticalSpeed

I wonder if this is all down to a constant altitude not being a straight line?

First off, you used vessel.orbital_velocity, which will give the same result. you need the velocity and vertical having the same origin, which is a part. Use the velocity I wrote above and it should work correctly. And yes, vertical speed being zero is about having zero altitude climb, and since Kerbin is round, that means going in a circle arc, not a straight line.

Link to comment
Share on other sites

Improved by using the part velocity (herp derp), still offset.

I realise that zero vertical speed == a circular path in KSP. My comment was aimed at whether the fact it is a circular path is throwing off whatever calculation is used for rigidbody.velocity (or possibly something to do with Krackensbane). For example, if the direction is determined from the last position to the current position, that would be rotated slightly upwards. That would make the correct upVec exactly halfway between the current and the previous one.

EDIT

Initial testing is giving very good indications that the ^^ was exactly the issue.

lastUp = vertical;
vertical = (thisVessel.rootPart.transform.position - thisVessel.mainBody.position).normalized;
velocity = thisVessel.rootPart.Rigidbody.velocity + Krakensbane.GetFrameVelocity();
vertSpeed = Vector3d.Dot((vertical + lastUp) / 2, velocity); // VS calculated from upvec bisecting current and last upVec

EDIT2

Unless any other suggestions come up, I'm going to call this solved. The ^^ calculation matches the changes in altitude with no notable offset (9um/s over 3500 samples), and Squad's calculation was already identified as this

lastVertical = vertical;
vertical = (thisVessel.rootPart.rigidbody.position - thisVessel.mainBody.position).normalized;
vertSpeed = Vector3d.Dot(vessel.obt_velocity, lastVertical);

Edited by Crzyrndm
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...