Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e56cb2619785
Choose a base ref
...
head repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5c0e5b26126a
Choose a head ref
  • 7 commits
  • 3 files changed
  • 1 contributor

Commits on May 7, 2020

  1. Copy the full SHA
    8802ae7 View commit details
  2. clean things up a bit

    eggrobin committed May 7, 2020
    Copy the full SHA
    19ccc3f View commit details

Commits on May 8, 2020

  1. after pleroy’s review

    eggrobin committed May 8, 2020
    Copy the full SHA
    0f1809d View commit details
  2. tolerances and lint

    eggrobin committed May 8, 2020
    Copy the full SHA
    cf31709 View commit details
  3. missed one

    eggrobin committed May 8, 2020
    Copy the full SHA
    45c29a1 View commit details
  4. ...

    eggrobin committed May 8, 2020
    Copy the full SHA
    24fdcc8 View commit details
  5. Merge pull request #2561 from eggrobin/bring-back-the-toggle

    A smoother correction
    eggrobin authored May 8, 2020
    Copy the full SHA
    5c0e5b2 View commit details
Showing with 181 additions and 145 deletions.
  1. +48 −24 ksp_plugin/pile_up.cpp
  2. +3 −3 ksp_plugin_adapter/main_window.cs
  3. +130 −118 ksp_plugin_test/pile_up_test.cpp
72 changes: 48 additions & 24 deletions ksp_plugin/pile_up.cpp
Original file line number Diff line number Diff line change
@@ -46,6 +46,8 @@ using quantities::AngularFrequency;
using quantities::AngularMomentum;
using quantities::Inverse;
using quantities::ParseQuantity;
using quantities::Sqrt;
using quantities::Tanh;
using quantities::Time;
using quantities::si::Kilogram;
using quantities::si::Metre;
@@ -499,24 +501,20 @@ void PileUp::DeformPileUpIfNeeded(Instant const& t) {
// This amounts to trusting the direction of the angular momentum with respect
// to the vessel as given to us by the game.
// However, mapping L̂_apparent to L̂_actual is essentially singular when either
// is 0. We remedy to that by only performing an attitude correction if its
// angle would be less than ω Δt, where ω is the smaller of the two equivalent
// angular frequencies |L_actual / I| and |L_apparent / I|.
// is 0. We remedy to that by only performing the full attitude correction if
// its angle would be much less than ω Δt, where ω is the geometric mean of
// the two equivalent angular frequencies |L_actual / I| and |L_apparent / I|.
// As a result, as either L tends towards 0, so does the largest attitude
// correction that we allow.
// If the attitude correction would exceed this threshold, we leave the
// attitude unchanged, and the correction in angular momentum is effected
// solely by a change in angular velocity.

// The correction is computed via an intermediate frame.
// In the |EquivalentRigidPileUp| reference frame, a rigid body with the same
// inertia and angular momentum as the pile up would be immobile.
// If no attitude correction is performed, the axes of
// |EquivalentRigidPileUp|, |ApparentPileUp|, and |NonRotatingPileUp| are
// identical.
// If an attitude correction is performed, the y axis of
// |EquivalentRigidPileUp| is the direction of the angular momentum, and the x
// axis is the correction axis.
// If an attitude correction is performed, the correction occurs between
// |ApparentPileUp| and |EquivalentRigidPileUp|.
// NOTE(egg): while the correction axis is essentially singular at
// L_apparent = L_actual, the correction itself is only removably singular (as
// the angle goes to 0). Since the computation ensured that
@@ -578,20 +576,41 @@ void PileUp::DeformPileUpIfNeeded(Instant const& t) {
// α is the angle of the tentative attitude correction.
Angle const α =
2 * quantities::ArcTan(q.imaginary_part().Norm(), q.real_part());
// The geometric mean of the norms of the equivalent angular velocities; this
// is zero when either one is zero, and thus it is zero when either angular
// momentum is zero.
AngularFrequency const ω =
std::min(apparent_equivalent_angular_velocity.Norm(),
actual_equivalent_angular_velocity.Norm());
thresholding ? std::min(apparent_equivalent_angular_velocity.Norm(),
actual_equivalent_angular_velocity.Norm())
: Sqrt(apparent_equivalent_angular_velocity.Norm() *
actual_equivalent_angular_velocity.Norm());
Time const Δt = t - psychohistory_->back().time;
if (thresholding && α > ω * Δt) {
// The attitude correction is too large. Preserve attitude.
apparent_pile_up_equivalent_rotation =
Rotation<ApparentPileUp, EquivalentRigidPileUp>::Identity();
actual_pile_up_equivalent_rotation =
Rotation<NonRotatingPileUp, EquivalentRigidPileUp>::Identity();
actual_equivalent_angular_velocity =
angular_momentum_ /
Identity<ApparentPileUp, NonRotatingPileUp>()(inertia_tensor);
// This correction angle is bounded by ω Δt (correct at most as fast as the
// ship is turning) and by α (correct at most what is needed).
// This in particular eliminates the neighbourhood of the singularity where L
// is small (and thus ω is small), by using α itself as a scale-free
// definition of “small”.
Angle const β = thresholding ? (α > ω * Δt ? Angle{} : α)
: Tanh(ω * Δt / α * Radian) * α;
auto attitude_correction =
Rotation<ApparentPileUp, EquivalentRigidPileUp>::Identity();
if (!trivial_rotations) {
// An active rotation of angle β around apparent_correction_axis maps
// L̂_apparent to its corrected direction.
// TODO(egg): The definitions might be more readable if
// |EquivalentRigidPileUp| were defined as in Fubini, with its y axis being
// L̂_apparent in |ApparentPileUp| and
// Identity<ApparentPileUp, NonRotatingPileUp>()(
// Rotation<ApparentPileUp, ApparentPileUp>(β)(L̂_apparent));
// in |NonRotatingPileUp|. On the other hand, this would make the
// computations even more convoluted.
attitude_correction =
Rotation<ApparentPileUp, EquivalentRigidPileUp>::Identity() *
Rotation<ApparentPileUp, ApparentPileUp>(β, apparent_correction_axis);
}
actual_equivalent_angular_velocity =
angular_momentum_ / Identity<EquivalentRigidPileUp, NonRotatingPileUp>()(
attitude_correction(inertia_tensor));

bool const correcting_orientation =
apparent_pile_up_equivalent_rotation.quaternion() != Quaternion(1) ||
@@ -602,7 +621,7 @@ void PileUp::DeformPileUpIfNeeded(Instant const& t) {
RigidTransformation<ApparentPileUp, EquivalentRigidPileUp>(
ApparentPileUp::origin,
EquivalentRigidPileUp::origin,
apparent_pile_up_equivalent_rotation.Forget<OrthogonalMap>()),
attitude_correction.Forget<OrthogonalMap>()),
correct_angular_velocity ? apparent_equivalent_angular_velocity
: ApparentPileUp::nonrotating,
ApparentPileUp::unmoving);
@@ -611,7 +630,8 @@ void PileUp::DeformPileUpIfNeeded(Instant const& t) {
RigidTransformation<NonRotatingPileUp, EquivalentRigidPileUp>(
NonRotatingPileUp::origin,
EquivalentRigidPileUp::origin,
actual_pile_up_equivalent_rotation.Forget<OrthogonalMap>()),
OrthogonalMap<NonRotatingPileUp,
EquivalentRigidPileUp>::Identity()),
correct_angular_velocity ? actual_equivalent_angular_velocity
: NonRotatingPileUp::nonrotating,
NonRotatingPileUp::unmoving);
@@ -649,6 +669,9 @@ void PileUp::DeformPileUpIfNeeded(Instant const& t) {
quantities::si::Degree
<< u8"°\n"
<< u8"α: " << α / quantities::si::Degree << u8"°\n"
<< u8"ωΔt: " << ω * Δt / quantities::si::Degree << u8"°\n"
<< u8"β: " << β / quantities::si::Degree << u8"°\n"
<< u8"ω: " << ω / (2 * π * Radian / quantities::si::Minute) << " rpm\n"
<< u8"|ωap|: "
<< apparent_equivalent_angular_velocity.Norm() /
(2 * π * Radian / quantities::si::Minute)
@@ -657,7 +680,8 @@ void PileUp::DeformPileUpIfNeeded(Instant const& t) {
<< actual_equivalent_angular_velocity.Norm() /
(2 * π * Radian / quantities::si::Minute)
<< " rpm\n"
<< (correcting_orientation ? "CORRECTING ORIENTATION" : u8"");
<< u8"Δt: " << Δt / quantities::si::Milli(quantities::si::Second)
<< u8"ms\n";
trace = s.str();

MakeEulerSolver(Identity<ApparentPileUp, NonRotatingPileUp>()(inertia_tensor),
@@ -788,7 +812,7 @@ PileUpFuture::PileUpFuture(not_null<PileUp const*> const pile_up,

bool PileUp::correct_orientation = true;
bool PileUp::correct_angular_velocity = true;
bool PileUp::thresholding = true;
bool PileUp::thresholding = false;

} // namespace internal_pile_up
} // namespace ksp_plugin
6 changes: 3 additions & 3 deletions ksp_plugin_adapter/main_window.cs
Original file line number Diff line number Diff line change
@@ -247,7 +247,7 @@ private void RenderKSPFeatures() {
"Correct angular velocity");
thresholding = UnityEngine.GUILayout.Toggle(
thresholding,
"Only correct orientation slower than ω");
"Fubini orientation correction");
Interface.SetAngularMomentumConservation(
correct_orientation, correct_angular_velocity, thresholding);
string trace = null;
@@ -517,8 +517,8 @@ private void RenderToggleableSection(string name,
// behaviour.
private static bool correct_orientation = true;
private static bool correct_angular_velocity = true;
private static bool thresholding = true;
private static readonly bool show_2519_debugging_ui = false;
private static bool thresholding = false;
private static readonly bool show_2519_debugging_ui = true;

private static readonly double[] prediction_length_tolerances_ =
{1e-3, 1e-2, 1e0, 1e1, 1e2, 1e3, 1e4};
Loading