CogniPilot

MODELICA LIBRARY · ENGINEERING REFERENCE

Tests/LieGroupsTests.mo

Download original .moGitHub source

Documentation: Tests.LieGroupsTests

within Tests;
model LieGroupsTests "Core group identities, charts, Jacobians, and edge cases"
  constant Real tolerance = 1.0e-8;
  constant Real vectorTolerance = 5.0e-8;
  constant Real pi = 3.1415926535897932384626433832795;
  constant Real rotationVector[3] = {0.12, -0.08, 0.05};
  constant Real nearZeroVector[3] = {1.0e-12, -2.0e-12, 3.0e-12};
  constant Real se2Algebra[3] = {0.4, -0.2, 0.3};
  constant Real se3Algebra[6] = {0.4, -0.2, 0.3, 0.08, -0.04, 0.06};
  constant Real se23Algebra[9] = {
    0.3, -0.1, 0.2, -0.05, 0.08, 0.12, 0.06, -0.03, 0.04};
  constant Real euler[3] = {0.4, -0.3, 0.2};
  Real so2Identity;
  Real rotated2[2];
  Real se2Element[3];
  Real se2RoundTrip[3];
  Real se2Identity[3];
  Real quaternion[4];
  Real quaternionIdentity[4];
  Real rotationRoundTrip[3];
  Real nearZeroRoundTrip[3];
  Real R[3, 3];
  Real quaternionFromR[4];
  Real leftJacobian[3, 3];
  Real inverseLeftJacobian[3, 3];
  Real rightJacobian[3, 3];
  Real expectedRightJacobian[3, 3];
  Real mrp[3];
  Real mrpRoundTrip[3];
  Real eulerRoundTrip[3];
  Real se3Element[7];
  Real se3RoundTrip[6];
  Real se3Identity[7];
  Real se3AdjointIdentity[6, 6];
  Real se23Element[10];
  Real se23RoundTrip[9];
  Real se23Identity[10];
  Real se23AdjointIdentity[9, 9];
  Real mixed[10];
  Real saturated[3];
equation
  so2Identity = LieGroups.SO2.product(0.7, LieGroups.SO2.inverse(0.7));
  rotated2 = LieGroups.SO2.rotate(0.5 * pi, {1.0, 0.0});
  se2Element = LieGroups.SE2.exp_map(se2Algebra);
  se2RoundTrip = LieGroups.SE2.log_map(se2Element);
  se2Identity = LieGroups.SE2.product(se2Element, LieGroups.SE2.inverse(se2Element));

  quaternion = LieGroups.SO3.Quat.exp_map(rotationVector);
  quaternionIdentity = LieGroups.SO3.Quat.product(
    quaternion,
    LieGroups.SO3.Quat.inverse(quaternion));
  rotationRoundTrip = LieGroups.SO3.Quat.log_map(quaternion);
  nearZeroRoundTrip = LieGroups.SO3.Quat.log_map(
    LieGroups.SO3.Quat.exp_map(nearZeroVector));
  R = LieGroups.SO3.Quat.to_DCM(quaternion);
  quaternionFromR = LieGroups.SO3.Quat.from_DCM(R);
  leftJacobian = LieGroups.SO3.Quat.left_jacobian(rotationVector);
  inverseLeftJacobian = LieGroups.SO3.Quat.left_jacobian_inv(rotationVector);
  rightJacobian = LieGroups.SO3.Quat.right_jacobian(rotationVector);
  expectedRightJacobian = LieGroups.SO3.Quat.left_jacobian(-rotationVector);

  mrp = LieGroups.SO3.Mrp.exp_map(rotationVector);
  mrpRoundTrip = LieGroups.SO3.Mrp.log_map(mrp);
  eulerRoundTrip = LieGroups.SO3.EulerB321.from_Quat(
    LieGroups.SO3.EulerB321.to_Quat(euler));

  se3Element = LieGroups.SE3.Quat.exp_map(se3Algebra);
  se3RoundTrip = LieGroups.SE3.Quat.log_map(se3Element);
  se3Identity = LieGroups.SE3.Quat.product(
    se3Element,
    LieGroups.SE3.Quat.inverse(se3Element));
  se3AdjointIdentity = LieGroups.SE3.Quat.adjoint(se3Element)
    * LieGroups.SE3.Quat.adjoint(LieGroups.SE3.Quat.inverse(se3Element));

  se23Element = LieGroups.SE23.Quat.exp_map(se23Algebra);
  se23RoundTrip = LieGroups.SE23.Quat.log_map(se23Element);
  se23Identity = LieGroups.SE23.Quat.product(
    se23Element,
    LieGroups.SE23.Quat.inverse(se23Element));
  se23AdjointIdentity = LieGroups.SE23.Quat.adjoint(se23Element)
    * LieGroups.SE23.Quat.adjoint(LieGroups.SE23.Quat.inverse(se23Element));
  mixed = LieGroups.SE23.Quat.exp_mixed(
    {1.0, 2.0, -0.5, 0.2, -0.1, 0.3, 1.0, 0.0, 0.0, 0.0},
    zeros(9),
    zeros(9),
    [0.0, 0.25; 0.0, 0.0]);
  saturated = LieGroups.Util.saturate3(
    {-2.0, 0.5, 3.0},
    {-1.0, -1.0, -1.0},
    {1.0, 1.0, 2.0});

  assert(abs(so2Identity) < tolerance, "SO(2) inverse identity failed");
  assert(Tests.Assertions.maxAbsVector(rotated2 - {0.0, 1.0}) < tolerance,
    "SO(2) quarter-turn rotation failed");
  assert(Tests.Assertions.maxAbsVector(se2RoundTrip - se2Algebra) < vectorTolerance,
    "SE(2) logarithm/exponential round trip failed");
  assert(Tests.Assertions.maxAbsVector(se2Identity) < tolerance,
    "SE(2) inverse identity failed");
  assert(abs(quaternionIdentity[1] - 1.0) < tolerance and
         Tests.Assertions.maxAbsVector(quaternionIdentity[2:4]) < tolerance,
    "Quaternion inverse identity failed");
  assert(Tests.Assertions.maxAbsVector(rotationRoundTrip - rotationVector) < vectorTolerance,
    "SO(3) logarithm/exponential round trip failed");
  assert(Tests.Assertions.maxAbsVector(nearZeroRoundTrip - nearZeroVector) < 1.0e-15,
    "SO(3) near-zero series failed");
  assert(Tests.Assertions.maxAbsMatrix(transpose(R) * R - identity(3)) < tolerance,
    "Quaternion DCM is not orthogonal");
  assert(abs(abs(quaternion * quaternionFromR) - 1.0) < tolerance,
    "DCM/quaternion round trip failed up to quaternion sign");
  assert(Tests.Assertions.maxAbsMatrix(leftJacobian * inverseLeftJacobian - identity(3)) < tolerance,
    "SO(3) left Jacobian inverse failed");
  assert(Tests.Assertions.maxAbsMatrix(rightJacobian - expectedRightJacobian) < tolerance,
    "SO(3) right/left Jacobian relation failed");
  assert(Tests.Assertions.maxAbsVector(mrpRoundTrip - rotationVector) < vectorTolerance,
    "MRP logarithm/exponential round trip failed");
  assert(Tests.Assertions.maxAbsVector(eulerRoundTrip - euler) < vectorTolerance,
    "Euler B321/quaternion round trip failed");
  assert(Tests.Assertions.maxAbsVector(se3RoundTrip - se3Algebra) < vectorTolerance,
    "SE(3) logarithm/exponential round trip failed");
  assert(Tests.Assertions.maxAbsVector(se3Identity - {0, 0, 0, 1, 0, 0, 0}) < tolerance,
    "SE(3) inverse identity failed");
  assert(Tests.Assertions.maxAbsMatrix(se3AdjointIdentity - identity(6)) < vectorTolerance,
    "SE(3) adjoint inverse identity failed");
  assert(Tests.Assertions.maxAbsVector(se23RoundTrip - se23Algebra) < vectorTolerance,
    "SE_2(3) logarithm/exponential round trip failed");
  assert(Tests.Assertions.maxAbsVector(se23Identity - {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}) < tolerance,
    "SE_2(3) inverse identity failed");
  assert(Tests.Assertions.maxAbsMatrix(se23AdjointIdentity - identity(9)) < vectorTolerance,
    "SE_2(3) adjoint inverse identity failed");
  assert(Tests.Assertions.maxAbsVector(mixed[1:3] - {1.05, 1.975, -0.425}) < tolerance,
    "SE_2(3) mixed exponential coupling failed");
  assert(Tests.Assertions.maxAbsVector(saturated - {-1.0, 0.5, 2.0}) < tolerance,
    "Vector saturation failed");
  assert(abs(LieGroups.Util.angle_wrap(3.0 * pi) + pi) < tolerance,
    "Angle wrapping failed");
end LieGroupsTests;