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 9d0af55
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 34 deletions.
1 change: 1 addition & 0 deletions core/envelope-sim/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies {

implementation project(':osrd-reporting')
implementation project(":kt-osrd-sim-infra")
api project(":osrd-railjson")
api project(":kt-osrd-utils")
implementation libs.guava
implementation libs.slf4j
Expand Down
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
5 changes: 3 additions & 2 deletions core/osrd-railjson/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
plugins {
alias(libs.plugins.kotlin.jvm)
id 'java'
id 'jacoco'
}
Expand All @@ -20,8 +21,8 @@ dependencies {
implementation libs.hppc

// JSON parsing
implementation libs.moshi
implementation libs.moshi.adapters
api libs.moshi
api libs.moshi.adapters

implementation libs.guava

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@
*/
public class RJSEtcsBrakeParams {

/** National Default Value: Available Adhesion */
private final double mNvavadh = 0.0;

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

// A_brake_emergency: the emergency deceleration curve (values > 0 m/s²)
@Json(name = "gamma_emergency")
Expand Down Expand Up @@ -66,6 +63,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 +75,16 @@ private double getEmergencyBrakingDeceleration(double speed) {
return gammaEmergency.getValue(speed);
}

/**
* Corresponds to the correction factor of the emergency brake deceleration on dry tracks.
* The confidence level mNvebcl is the confidence level that the corresponding deceleration can be reached,
* but does not impact the calculation of kDry. See Subset §3.13.6.2.1.7.
*/
private double getRollingStockCorrectionFactorDry(double speed) {
return kDry.getValue(speed) * mNvebcl;
return kDry.getValue(speed);
}

/** Corresponds to the correction factor of the emergency brake deceleration on wet tracks. */
private double getRollingStockCorrectionFactorWet(double speed) {
return kWet.getValue(speed);
}
Expand All @@ -93,6 +97,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
1 change: 1 addition & 0 deletions core/src/main/java/fr/sncf/osrd/train/RollingStock.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public double getRollingResistanceDeriv(double speed) {

@Override
public RJSEtcsBrakeParams getRJSEtcsBrakeParams() {
assert etcsBrakeParams != null;
return etcsBrakeParams;
}

Expand Down

0 comments on commit 9d0af55

Please sign in to comment.