Skip to content

core: stdcm: fix post-processing mismatch #12588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 24, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class EngineeringAllowanceManager(
// We still try to roughly guess the maximum length over which to add the time
var distance = 0.meters
for (segment in segments) {
if (segment.maxAddedDelay <= requiredAdditionalTime) break
distance += segment.length
if (distance > 10_000.meters) return distance
}
return Distance.max(solution.distance, distance)
}
Expand Down Expand Up @@ -209,21 +209,34 @@ class EngineeringAllowanceManager(
constDeceleration: Double
): Sequence<ConstDecelerationData> = sequence {
var endSpeed = decelerationEndSpeed
var intersection = false
for (segment in prevSegments) {
val pureDecelerationSim =
runSimplifiedSimulation(
-constDeceleration,
endSpeed,
segment.length.meters,
)
var simTravelTime = pureDecelerationSim.newDuration
if (pureDecelerationSim.newBeginSpeed > segment.beginSpeed) {
// Intersection with base sim. We could try to guess the exact added time,
// but ignoring this segment is generally good enough.
break
// Intersection with base sim. We estimate the new time with a basic speed plateau +
// const deceleration, return this segment, and exit the loop.
if (segment.beginSpeed < endSpeed || segment.beginSpeed <= 0.0)
break // Can't run the simplified sim, there's an acceleration
val newTime =
simplifiedSpeedPlateauThenDeceleration(
constDeceleration,
segment.beginSpeed,
endSpeed,
segment.length.meters
)
intersection = true
simTravelTime = newTime
}
val newTravelTime =
scaleAllowanceTime(graph, pureDecelerationSim.newDuration, segment.length)
val addedTimeOnSegment = positive(newTravelTime - segment.travelTime)

var newTravelTime = scaleAllowanceTime(graph, simTravelTime, segment.length)
newTravelTime = max(newTravelTime, segment.travelTime)
val addedTimeOnSegment = newTravelTime - segment.travelTime

yield(
ConstDecelerationData(
Expand All @@ -232,6 +245,7 @@ class EngineeringAllowanceManager(
addedTimeOnSegment,
)
)
if (intersection) break
endSpeed = pureDecelerationSim.newBeginSpeed
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import fr.sncf.osrd.envelope.EnvelopeTimeInterpolate.EnvelopePoint
import fr.sncf.osrd.stdcm.graph.STDCMGraph
import fr.sncf.osrd.utils.units.Distance
import kotlin.math.abs
import kotlin.math.pow
import kotlin.math.sqrt

/** Run a very simplified simulation with a constant acceleration value. */
Expand All @@ -26,6 +27,28 @@ fun runSimplifiedSimulation(
)
}

/**
* Similar function as above, computes a simplified simulation using basic kinetic equations. Here
* we compute the travel time over some known distance, with first a speed plateau and then a
* deceleration. The exact transition isn't known, but we know the start/end speed and acceleration.
*/
fun simplifiedSpeedPlateauThenDeceleration(
acceleration: Double,
initialSpeed: Double,
finalSpeed: Double,
distance: Double
): Double {
require(initialSpeed > 0.0)
require(finalSpeed >= 0.0)
require(initialSpeed > finalSpeed)
require(distance > 0.0)

val constSpeedTime = distance / initialSpeed
val addedDecelerationTime =
(initialSpeed - finalSpeed).pow(2.0) / abs(2.0 * acceleration * initialSpeed)
return constSpeedTime + addedDecelerationTime
}

/**
* Iterates (time, speed, position) points over a given envelope (backwards). Points are placed
* exactly $distance apart, last point may be closer. Much faster than repeated `interpolate` calls.
Expand Down