Skip to content

Commit

Permalink
fixup! core: implement etcs braking simulator
Browse files Browse the repository at this point in the history
Signed-off-by: Erashin <[email protected]>
  • Loading branch information
Erashin committed Jan 14, 2025
1 parent b8d98cc commit 5997a2e
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public interface PhysicsPath {
/** The average slope on a given range, in m/km */
double getAverageGrade(double begin, double end);

/** The lowest slope on a given range, in m/km*/
/** The lowest slope on a given range, in m/km */
double getMinGrade(double begin, double end);
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ static double getMaxEffort(double speed, TractiveEffortPoint[] tractiveEffortCur
/**
* The gradient acceleration of the rolling stock taking its rotating mass into account, in m/s².
* Grade is in m/km.
* */
* mRotating (Max or Min) is in %, as seen in ERA braking curves simulation tool v5.1.
*/
static double getGradientAcceleration(double grade) {
var mRotating = grade >= 0 ? mRotatingMax : mRotatingMin;
return -GRAVITY_ACCELERATION * grade / (1000.0 + 10.0 * mRotating);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,13 @@ private double getDeceleration(double speed, double position) {
var grade = getMinGrade(rollingStock, path, position);
var gradientAcceleration = getGradientAcceleration(grade);
return switch (brakingType) {
// See Subset referenced in RJSEtcsBrakeParams: §3.13.6.2.1.3.
case ETCS_EBD -> -rollingStock.getRJSEtcsBrakeParams().getSafeBrakingAcceleration(speed)
+ gradientAcceleration;
// See Subset referenced in RJSEtcsBrakeParams: §3.13.6.3.1.3.
case ETCS_SBD -> -rollingStock.getRJSEtcsBrakeParams().getServiceBrakingAcceleration(speed)
+ gradientAcceleration;
// See Subset referenced in RJSEtcsBrakeParams: §3.13.6.4.3.
case ETCS_GUI -> -rollingStock.getRJSEtcsBrakeParams().getNormalServiceBrakingAcceleration(speed)
+ gradientAcceleration
+ rollingStock.getRJSEtcsBrakeParams().getGradientAccelerationCorrection(grade, speed);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package fr.sncf.osrd.envelope_sim.etcs

/** See Subset referenced in ETCSBrakingSimulator: table in Appendix A.3.1. */
const val tDriver = 4.0 // s
const val mRotatingMax = 15.0 // %
const val mRotatingMin = 2.0 // %
Original file line number Diff line number Diff line change
Expand Up @@ -129,37 +129,46 @@ private fun computeBrakingCurve(
return brakingCurve
}

/** Compute Indication curve: EBI/SBD -> SBI -> PS -> IND */
/**
* Compute Indication curve: EBI/SBD -> SBI -> PS -> IND. See Subset referenced in
* ETCSBrakingSimulator: figures 45 and 46.
*/
private fun computeIndicationBrakingCurveFromRef(
context: EnvelopeSimContext,
refCurve: EnvelopePart,
refBrakingCurve: EnvelopePart,
refBrakingCurveType: BrakingCurveType,
guiCurve: EnvelopePart,
beginPos: Double
): EnvelopePart {
assert(
refBrakingCurveType == BrakingCurveType.EBI || refBrakingCurveType == BrakingCurveType.SBD
)
assert(refCurve.endPos > beginPos)
assert(refBrakingCurve.endPos > beginPos)
val rollingStock = context.rollingStock
val tBs =
if (refBrakingCurveType == BrakingCurveType.EBI) rollingStock.rjsEtcsBrakeParams.tBs2
else rollingStock.rjsEtcsBrakeParams.tBs1
when (refBrakingCurveType) {
BrakingCurveType.EBI -> rollingStock.rjsEtcsBrakeParams.tBs2
BrakingCurveType.SBD -> rollingStock.rjsEtcsBrakeParams.tBs1
else ->
throw IllegalArgumentException(
"Expected EBI or SBD reference braking curve type, found: $refBrakingCurveType"
)
}

val pos = refCurve.clonePositions()
val speeds = refCurve.cloneSpeeds()
val reversedNewPos = ArrayList<Double>()
val reversedNewSpeeds = ArrayList<Double>()
for (i in refCurve.pointCount() - 1 downTo 0) {
val speed = speeds[i]
val sbiPosition = getSbiPosition(pos[i], speed, tBs)
val permittedSpeedPosition =
getPermittedSpeedPosition(sbiPosition, speed, guiCurve.interpolatePosition(speed))
val indicationPosition = getIndicationPosition(permittedSpeedPosition, speed, tBs)
for (i in refBrakingCurve.pointCount() - 1 downTo 0) {
val speed = refBrakingCurve.getPointSpeed(i)
val sbiPosition = getSbiPosition(refBrakingCurve.getPointPos(i), speed, tBs)
val permittedSpeedPosition = getPermittedSpeedPosition(sbiPosition, speed)
val adjustedPermittedSpeedPosition =
getAdjustedPermittedSpeedPosition(
permittedSpeedPosition,
guiCurve.interpolatePosition(speed)
)
val indicationPosition = getIndicationPosition(adjustedPermittedSpeedPosition, speed, tBs)
if (indicationPosition >= beginPos) {
reversedNewPos.add(indicationPosition)
reversedNewSpeeds.add(speed)
} else if (i != refCurve.pointCount() - 1 && reversedNewPos[i + 1] > beginPos) {
} else if (i != refBrakingCurve.pointCount() - 1 && reversedNewPos[i + 1] > beginPos) {
// Interpolate to begin position if reaching a position before it
val prevPos = reversedNewPos[i + 1]
val prevSpeed = reversedNewSpeeds[i + 1]
val speedAtBeginPos =
Expand Down Expand Up @@ -215,21 +224,28 @@ private fun keepBrakingCurveUnderOverlay(
return partBuilder.build()
}

/** See Subset referenced in ETCSBrakingSimulator: §3.13.9.3.3.1 and §3.13.9.3.3.2. */
fun getSbiPosition(ebiOrSbdPosition: Double, speed: Double, tbs: Double): Double {
return getPreviousPosition(ebiOrSbdPosition, speed, tbs)
}

fun getPermittedSpeedPosition(
sbiPosition: Double,
speed: Double,
/** See Subset referenced in ETCSBrakingSimulator: §3.13.9.3.5.1. */
fun getPermittedSpeedPosition(sbiPosition: Double, speed: Double): Double {
return getPreviousPosition(sbiPosition, speed, tDriver)
}

/** See Subset referenced in ETCSBrakingSimulator: §3.13.9.3.5.4. */
fun getAdjustedPermittedSpeedPosition(
permittedSpeedPosition: Double,
guiPosition: Double = Double.POSITIVE_INFINITY
): Double {
return min(getPreviousPosition(sbiPosition, speed, tDriver), guiPosition)
return min(permittedSpeedPosition, guiPosition)
}

fun getIndicationPosition(psPosition: Double, speed: Double, tBs: Double): Double {
/** See Subset referenced in ETCSBrakingSimulator: §3.13.9.3.6.1 and §3.13.9.3.6.2. */
fun getIndicationPosition(permittedSpeedPosition: Double, speed: Double, tBs: Double): Double {
val tIndication = max((0.8 * tBs), 5.0) + tDriver
return getPreviousPosition(psPosition, speed, tIndication)
return getPreviousPosition(permittedSpeedPosition, speed, tIndication)
}

private fun getPreviousPosition(position: Double, speed: Double, elapsedTime: Double): Double {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import fr.sncf.osrd.sim_infra.api.Path
import fr.sncf.osrd.sim_infra.api.TravelledPath
import fr.sncf.osrd.utils.units.Offset

/**
* In charge of computing and adding the ETCS braking curves. Formulas are found in `SUBSET-026-3
* v400.pdf` from the file at
* https://www.era.europa.eu/system/files/2023-09/index004_-_SUBSET-026_v400.zip
*/
interface ETCSBrakingSimulator {
val context: EnvelopeSimContext

Expand Down Expand Up @@ -55,6 +60,7 @@ class ETCSBrakingSimulatorImpl(override val context: EnvelopeSimContext) : ETCSB
endsOfAuthority: Collection<EndOfAuthority>
): Envelope {
if (endsOfAuthority.isEmpty()) return envelope
// TODO: compute curve at SvL and intersect
return addBrakingCurvesAtEOAs(envelope, context, endsOfAuthority)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.google.common.collect.Range;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import fr.sncf.osrd.railjson.schema.rollingstock.RJSEtcsBrakeParams;

import java.util.ArrayList;

@SuppressFBWarnings({"URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
*/
public class RJSEtcsBrakeParams {

/** National Default Value: Available Adhesion */
private final double mNvavadh = 0.0;
/** National Default Value: Available Adhesion. Found in Subset Appendix A.3.2 table. */
private static final double mNvavadh = 0.0;

/** National Default Value: Emergency Brake Confidence Level in % */
private final double mNvebcl = 1 - 1E-9;
/** National Default Value: Emergency Brake Confidence Level ratio. Found in Subset Appendix A.3.2 table. */
private static final double mNvebcl = 1 - 1E-9;

// A_brake_emergency: the emergency deceleration curve (values > 0 m/s²)
@Json(name = "gamma_emergency")
Expand Down Expand Up @@ -66,6 +66,7 @@ public class RJSEtcsBrakeParams {
@Json(name = "t_be")
public double tBe;

/** See Subset §3.13.6.2.1.4. */
public double getSafeBrakingAcceleration(double speed) {
var aBrakeEmergency = getEmergencyBrakingDeceleration(speed);
var kDry = getRollingStockCorrectionFactorDry(speed);
Expand All @@ -77,10 +78,15 @@ private double getEmergencyBrakingDeceleration(double speed) {
return gammaEmergency.getValue(speed);
}

/**
* Corresponds to the level of confidence on the emergency brake deceleration on dry tracks, with mNvebcl
* depending on the country. See Subset, §3.13.6.2.1.7.
*/
private double getRollingStockCorrectionFactorDry(double speed) {
return kDry.getValue(speed) * mNvebcl;
}

/** Corresponds to the level of confidence on the emergency brake deceleration on wet tracks. */
private double getRollingStockCorrectionFactorWet(double speed) {
return kWet.getValue(speed);
}
Expand All @@ -93,6 +99,10 @@ public double getNormalServiceBrakingAcceleration(double speed) {
return gammaNormalService.getValue(speed);
}

/**
* Gradient acceleration correction using on-board correction factors kN+ and kN-.
* See Subset, §3.13.6.4.2 and §3.13.6.4.3.
*/
public double getGradientAccelerationCorrection(double grade, double speed) {
var k = grade >= 0 ? kNPos.getValue(speed) : kNNeg.getValue(speed);
return -k * grade / 1000;
Expand Down

0 comments on commit 5997a2e

Please sign in to comment.