fix: refine EM stopping speed limits
This commit is contained in:
@@ -11,6 +11,8 @@ internal static class LongitudinalModelChecks
|
||||
public static void Run()
|
||||
{
|
||||
VerifiesFinitePathSIndexedSpeedEnvelope();
|
||||
VerifiesStoppingEnvelopeIsRefinedOnActualPathS();
|
||||
VerifiesStoppingEnvelopeUsesDiscreteTimeTailStations();
|
||||
VerifiesStoppingPrecheckBeforeQpAssembly();
|
||||
VerifiesReferenceHorizonSelectionKeepsTheCurrentSegmentBoundary();
|
||||
VerifiesTimeKnotLayoutDynamicsObjectiveAndHardConstraints();
|
||||
@@ -58,11 +60,72 @@ internal static class LongitudinalModelChecks
|
||||
"stopping speed limit");
|
||||
Verification.NearlyEqual(Math.Sqrt(0.20d / 20d), envelope.MaximumSpeedAt(4d),
|
||||
"combined limit chooses the finite minimum");
|
||||
Verification.NearlyEqual((envelope.MaximumSpeedAt(0d) + envelope.MaximumSpeedAt(2d)) / 2d,
|
||||
envelope.MaximumSpeedAt(1d), "speed envelope interpolates by PathS rather than ReferenceS");
|
||||
double interpolationQueryPathS = 1.013d;
|
||||
int upperStation = 1;
|
||||
while (envelope.PathS[upperStation] < interpolationQueryPathS)
|
||||
upperStation++;
|
||||
double lowerPathS = envelope.PathS[upperStation - 1];
|
||||
double upperPathS = envelope.PathS[upperStation];
|
||||
double fraction = (interpolationQueryPathS - lowerPathS) / (upperPathS - lowerPathS);
|
||||
double expectedInterpolatedSpeed = envelope.MaximumSpeedMetersPerSecond[upperStation - 1] +
|
||||
(envelope.MaximumSpeedMetersPerSecond[upperStation] - envelope.MaximumSpeedMetersPerSecond[upperStation - 1]) *
|
||||
fraction;
|
||||
Verification.NearlyEqual(expectedInterpolatedSpeed, envelope.MaximumSpeedAt(interpolationQueryPathS),
|
||||
"speed envelope interpolates by PathS rather than ReferenceS");
|
||||
Verification.NearlyEqual(0d, envelope.MaximumSpeedAt(5d), "terminal speed is exactly zero");
|
||||
}
|
||||
|
||||
private static void VerifiesStoppingEnvelopeIsRefinedOnActualPathS()
|
||||
{
|
||||
EmPlannerConfiguration configuration = EmPlannerConfiguration.CreateDefault();
|
||||
configuration.Longitudinal.MaximumForwardSpeedMetersPerSecond = 1d;
|
||||
configuration.Longitudinal.MaximumReverseSpeedMetersPerSecond = 1d;
|
||||
LateralPath path = CreatePath(new[]
|
||||
{
|
||||
new PathFixture(0d, 0d, 0d, 0d),
|
||||
new PathFixture(100d, 2d, 0d, 0d),
|
||||
});
|
||||
var input = new LongitudinalPlanningInput(path, TravelDirection.Forward, 0d, 0d,
|
||||
EmTerminalType.Goal, configuration, Array.Empty<double>(), Array.Empty<double>());
|
||||
|
||||
EmPlanningStatus status = new PathSpeedLimitBuilder().Build(input, out PathSpeedLimit envelope,
|
||||
out string failureReason);
|
||||
Verification.Equal(EmPlanningStatus.Success, status, "refined stopping envelope status: " + failureReason);
|
||||
Verification.True(envelope.PathS.Count > path.Points.Count, "stopping envelope inserts actual-PathS refinement stations");
|
||||
Verification.NearlyEqual(Math.Sqrt(2d * 0.30d * (2d - 1.5d)), envelope.MaximumSpeedAt(1.5d),
|
||||
"refined stopping envelope avoids a sparse terminal chord");
|
||||
}
|
||||
|
||||
private static void VerifiesStoppingEnvelopeUsesDiscreteTimeTailStations()
|
||||
{
|
||||
EmPlannerConfiguration configuration = EmPlannerConfiguration.CreateDefault();
|
||||
configuration.Longitudinal.MaximumForwardSpeedMetersPerSecond = 1d;
|
||||
configuration.Longitudinal.MaximumReverseSpeedMetersPerSecond = 1d;
|
||||
LateralPath path = CreatePath(new[]
|
||||
{
|
||||
new PathFixture(0d, 0d, 0d, 0d),
|
||||
new PathFixture(100d, 2d, 0d, 0d),
|
||||
});
|
||||
var input = new LongitudinalPlanningInput(path, TravelDirection.Forward, 0d, 0d,
|
||||
EmTerminalType.Goal, configuration, Array.Empty<double>(), Array.Empty<double>());
|
||||
|
||||
EmPlanningStatus status = new PathSpeedLimitBuilder().Build(input, out PathSpeedLimit envelope,
|
||||
out string failureReason);
|
||||
Verification.Equal(EmPlanningStatus.Success, status, "discrete stopping-tail status: " + failureReason);
|
||||
double timeStep = configuration.Scheduling.OutputTimeStepSeconds;
|
||||
double deceleration = configuration.Longitudinal.MaximumDecelerationMetersPerSecondSquared;
|
||||
double firstTailDistance = 0.5d * deceleration * timeStep * timeStep;
|
||||
double firstTailPathS = input.TerminalPathS - firstTailDistance;
|
||||
Verification.NearlyEqual(deceleration * timeStep, envelope.StoppingLimitAt(firstTailPathS),
|
||||
"first stopping-tail station matches one discrete deceleration time step");
|
||||
double jerk = configuration.Longitudinal.MaximumJerkMetersPerSecondCubed;
|
||||
double firstJerkTailDistance = jerk * timeStep * timeStep * timeStep / 6d;
|
||||
double firstJerkTailPathS = input.TerminalPathS - firstJerkTailDistance;
|
||||
Verification.NearlyEqual(Math.Sqrt(2d * deceleration * firstJerkTailDistance),
|
||||
envelope.StoppingLimitAt(firstJerkTailPathS),
|
||||
"first stopping-tail station matches one discrete jerk-release time step");
|
||||
}
|
||||
|
||||
private static void VerifiesStoppingPrecheckBeforeQpAssembly()
|
||||
{
|
||||
EmPlannerConfiguration configuration = EmPlannerConfiguration.CreateDefault();
|
||||
|
||||
Reference in New Issue
Block a user