mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-12 14:01:02 +01:00
AI braking: smaller steps, earlier, while approaching a stop or a lower speed
Changes to how the AI works the train brake on the way to a lower speed or a stop, so that it uses few, early applications instead of a late deep one: - Approaching a lower speed, the deceleration may fall short of the demand by only half of a step (fBrake_a1) before the brake is applied harder. With a full step the demand crept up meanwhile and a long G train got its next step many seconds too late. - The shortfall is checked every 3 s. If it keeps growing at a handle left alone for longer than the brake takes to respond, the AI adds a small step at once instead of waiting until the margin calls for a deep one. A shortfall that shrinks on its own (brake still filling, blocks gripping harder at lower speed) does not trigger it. - Releasing, a position short of the first one counts as giving the minimum stage of the distributor, not less. - Holding the speed on a descent, the predicted excess speed is taken off over the time the brake takes to respond, not at once, so a slow brake does not get a deep application that then takes as long to release.
This commit is contained in:
@@ -2928,6 +2928,9 @@ bool TController::ReleaseEngine() {
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// defined further down, with the braking demand it is used for
|
||||||
|
static double brake_response_horizon( TMoverParameters const *Vehicle, TBrakeSystem const Brakesystem, double const Acceleration, double const Brakea0 );
|
||||||
|
|
||||||
bool TController::IncBrake()
|
bool TController::IncBrake()
|
||||||
{ // zwiększenie hamowania
|
{ // zwiększenie hamowania
|
||||||
auto OK { false };
|
auto OK { false };
|
||||||
@@ -3040,7 +3043,7 @@ bool TController::IncBrake()
|
|||||||
}
|
}
|
||||||
double deltaAcc = -AccDesired*BrakeAccFactor() - (fBrake_a0[0] + 4.0 * (/*GBH mvOccupied->BrakeCtrlPosR*/BrakeCtrlPosition - 1 - pos_corr)*fBrake_a1[0]);
|
double deltaAcc = -AccDesired*BrakeAccFactor() - (fBrake_a0[0] + 4.0 * (/*GBH mvOccupied->BrakeCtrlPosR*/BrakeCtrlPosition - 1 - pos_corr)*fBrake_a1[0]);
|
||||||
|
|
||||||
if( deltaAcc > fBrake_a1[0])
|
if( deltaAcc > brake_increase_margin() )
|
||||||
{
|
{
|
||||||
if( /*GBH mvOccupied->BrakeCtrlPosR*/BrakeCtrlPosition < 0.1 ) {
|
if( /*GBH mvOccupied->BrakeCtrlPosR*/BrakeCtrlPosition < 0.1 ) {
|
||||||
OK = /*mvOccupied->*/BrakeLevelAdd( BrakingInitialLevel ); //GBH
|
OK = /*mvOccupied->*/BrakeLevelAdd( BrakingInitialLevel ); //GBH
|
||||||
@@ -3069,10 +3072,13 @@ bool TController::IncBrake()
|
|||||||
}
|
}
|
||||||
else if( BrakeCtrlPosition > 0.0
|
else if( BrakeCtrlPosition > 0.0
|
||||||
&& AccDesired < 0.0 // only while braking is asked for, not when called for a train slipping back while starting
|
&& AccDesired < 0.0 // only while braking is asked for, not when called for a train slipping back while starting
|
||||||
&& fBrakeHeldTime > (
|
&& ( fBrakeHeldTime > (
|
||||||
mvOccupied->BrakeDelayFlag > bdelay_G ?
|
mvOccupied->BrakeDelayFlag > bdelay_G ?
|
||||||
mvOccupied->BrakeDelay[ 1 ] :
|
mvOccupied->BrakeDelay[ 1 ] :
|
||||||
mvOccupied->BrakeDelay[ 3 ] ) ) {
|
mvOccupied->BrakeDelay[ 3 ] )
|
||||||
|
// a train falling further behind needs no full fill time to be seen not to get enough
|
||||||
|
|| ( ( fShortfall > 0.02 )
|
||||||
|
&& ( fBrakeHeldTime > brake_response_horizon( mvOccupied, BrakeSystem, 1.0, fBrake_a0[ 0 ] ) ) ) ) ) {
|
||||||
// the table says the present position is enough, but the brake has had its full fill
|
// the table says the present position is enough, but the brake has had its full fill
|
||||||
// time since the handle last moved and the train is still not slowing down as asked:
|
// time since the handle last moved and the train is still not slowing down as asked:
|
||||||
// believe the train rather than the table
|
// believe the train rather than the table
|
||||||
@@ -3194,7 +3200,9 @@ bool TController::DecBrake() {
|
|||||||
if( fBrake_a0[0] != 0.0
|
if( fBrake_a0[0] != 0.0
|
||||||
|| fBrake_a1[0] != 0.0 ) {
|
|| fBrake_a1[0] != 0.0 ) {
|
||||||
auto const pos_diff { ( is_dmu() ? 0.25 : 1.0 ) };
|
auto const pos_diff { ( is_dmu() ? 0.25 : 1.0 ) };
|
||||||
deltaAcc = -AccDesired * BrakeAccFactor() - ( fBrake_a0[ 0 ] + 4 * (/*GBH mvOccupied->BrakeCtrlPosR*/BrakeCtrlPosition - pos_diff )*fBrake_a1[ 0 ] );
|
// a distributor applied at all gives at least its minimum stage, about what the first position does, so
|
||||||
|
// a position short of the first one brakes no weaker than that
|
||||||
|
deltaAcc = -AccDesired * BrakeAccFactor() - ( fBrake_a0[ 0 ] + 4 * std::max( 0.0, BrakeCtrlPosition - pos_diff ) * fBrake_a1[ 0 ] );
|
||||||
}
|
}
|
||||||
if (deltaAcc < 0 && /*GBH mvOccupied->BrakeCtrlPosR*/ BrakeCtrlPosition > 0) {
|
if (deltaAcc < 0 && /*GBH mvOccupied->BrakeCtrlPosR*/ BrakeCtrlPosition > 0) {
|
||||||
OK = /*mvOccupied->*/ BrakeLevelAdd(-0.25);
|
OK = /*mvOccupied->*/ BrakeLevelAdd(-0.25);
|
||||||
@@ -7701,7 +7709,7 @@ TController::adjust_desired_speed_for_target_speed( double const Range ) {
|
|||||||
// train is still speeding up, the prediction above has taken that off already)
|
// train is still speeding up, the prediction above has taken that off already)
|
||||||
auto room { brakingroom };
|
auto room { brakingroom };
|
||||||
if( ( AbsAccS <= 0.0 )
|
if( ( AbsAccS <= 0.0 )
|
||||||
&& ( ( VelNext > 0.0 ) || ( BrakeCtrlPosition <= 0.0 ) ) ) { // for a stop, only while the brake is still to be applied
|
&& ( BrakeCtrlPosition <= 0.0 ) ) { // only while the brake is still to be applied: once it acts, the room it needs to respond is behind
|
||||||
room = std::max(
|
room = std::max(
|
||||||
0.5 * brakingroom,
|
0.5 * brakingroom,
|
||||||
brakingroom - vel / 3.6 * brake_response_horizon( mvOccupied, BrakeSystem, 1.0, fBrake_a0[ 0 ] ) );
|
brakingroom - vel / 3.6 * brake_response_horizon( mvOccupied, BrakeSystem, 1.0, fBrake_a0[ 0 ] ) );
|
||||||
@@ -7830,6 +7838,10 @@ TController::adjust_desired_speed_for_current_speed() {
|
|||||||
BrakeSystem == TBrakeSystem::Pneumatic ?
|
BrakeSystem == TBrakeSystem::Pneumatic ?
|
||||||
std::clamp( fAccGravity * 15.0, 1.0, 3.0 ) :
|
std::clamp( fAccGravity * 15.0, 1.0, 3.0 ) :
|
||||||
std::clamp( fAccGravity * 7.5, 1.0, 1.5 ) ) };
|
std::clamp( fAccGravity * 7.5, 1.0, 1.5 ) ) };
|
||||||
|
// the predicted difference is to be made up over the time the brake takes to respond, not at once: with a
|
||||||
|
// slow brake, a demand sized to remove it at once comes on as a deep application, which then takes as
|
||||||
|
// long to let go, and the train ends up well below the speed it was to hold
|
||||||
|
auto const holdgain { std::min( 0.04, 1.0 / ( 3.6 * std::max( 1.0, horizon ) ) ) };
|
||||||
if( ( speedestimate > VelDesired )
|
if( ( speedestimate > VelDesired )
|
||||||
&& ( VelDesired == 0.0 ) ) {
|
&& ( VelDesired == 0.0 ) ) {
|
||||||
// jesli stoj, to hamuj, ale i tak juz za pozno :)
|
// jesli stoj, to hamuj, ale i tak juz za pozno :)
|
||||||
@@ -7843,7 +7855,7 @@ TController::adjust_desired_speed_for_current_speed() {
|
|||||||
AccDesired = std::min(
|
AccDesired = std::min(
|
||||||
AccDesired, // but don't override decceleration for VelNext
|
AccDesired, // but don't override decceleration for VelNext
|
||||||
std::clamp(
|
std::clamp(
|
||||||
EU07_AI_NOACCELERATION - 0.04 * ( speedestimate - holdspeed ),
|
EU07_AI_NOACCELERATION - holdgain * ( speedestimate - holdspeed ),
|
||||||
-0.05 + fAccThreshold,
|
-0.05 + fAccThreshold,
|
||||||
std::max( EU07_AI_NOACCELERATION, AccPreferred ) ) );
|
std::max( EU07_AI_NOACCELERATION, AccPreferred ) ) );
|
||||||
// HACK: for cargo trains with high braking threshold ensure we cross that threshold
|
// HACK: for cargo trains with high braking threshold ensure we cross that threshold
|
||||||
@@ -8151,6 +8163,20 @@ void TController::increase_tractive_force() {
|
|||||||
cue_action( driver_hint::tractiveforceincrease );
|
cue_action( driver_hint::tractiveforceincrease );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// how far the deceleration may fall short of the demand before the brake is applied harder. approaching a lower
|
||||||
|
// speed, a pneumatic brake given a full step only once that much is missing acts too late: the demand
|
||||||
|
// creeps up meanwhile, and in a long G train the next step takes many seconds to act, so half a step is enough
|
||||||
|
double
|
||||||
|
TController::brake_increase_margin() const {
|
||||||
|
|
||||||
|
if( ( BrakeSystem == TBrakeSystem::Pneumatic )
|
||||||
|
&& ( VelNext > 0.0 )
|
||||||
|
&& ( VelNext < DirectionalVel() ) ) {
|
||||||
|
return 0.5 * fBrake_a1[ 0 ];
|
||||||
|
}
|
||||||
|
return fBrake_a1[ 0 ];
|
||||||
|
}
|
||||||
|
|
||||||
void TController::control_braking_force() {
|
void TController::control_braking_force() {
|
||||||
|
|
||||||
// don't touch the brakes when compressing buffers during coupling/uncoupling
|
// don't touch the brakes when compressing buffers during coupling/uncoupling
|
||||||
@@ -8168,6 +8194,19 @@ void TController::control_braking_force() {
|
|||||||
// resultant the AI asks for, not with the brake-only demand AccDesired holds on a descent
|
// resultant the AI asks for, not with the brake-only demand AccDesired holds on a descent
|
||||||
auto const accdesiredresultant { AccDesired + fAccDesiredGravity };
|
auto const accdesiredresultant { AccDesired + fAccDesiredGravity };
|
||||||
|
|
||||||
|
// every few seconds, note how far the train falls short of the demand and whether that is getting worse: a brake
|
||||||
|
// still filling, or blocks gripping harder as the train slows down, make up a shortfall on their own, but a
|
||||||
|
// shortfall that keeps growing at a constant handle means the train is falling further behind its braking curve
|
||||||
|
if( ElapsedTime - fShortfallTime >= 3.0 ) {
|
||||||
|
auto const shortfall { AbsAccS - accdesiredresultant };
|
||||||
|
iShortfallGrowth = (
|
||||||
|
( ( AccDesired < 0.0 ) && ( shortfall > fShortfall + 0.005 ) ) ?
|
||||||
|
iShortfallGrowth + 1 :
|
||||||
|
0 );
|
||||||
|
fShortfall = shortfall;
|
||||||
|
fShortfallTime = ElapsedTime;
|
||||||
|
}
|
||||||
|
|
||||||
if( is_emu() && !ForcePNBrake ) {
|
if( is_emu() && !ForcePNBrake ) {
|
||||||
// właściwie, to warunek powinien być na działający EP
|
// właściwie, to warunek powinien być na działający EP
|
||||||
// Ra: to dobrze hamuje EP w EZT
|
// Ra: to dobrze hamuje EP w EZT
|
||||||
@@ -8201,7 +8240,7 @@ void TController::control_braking_force() {
|
|||||||
} // type & dt_ezt
|
} // type & dt_ezt
|
||||||
else {
|
else {
|
||||||
// a stara wersja w miarę dobrze działa na składy wagonowe
|
// a stara wersja w miarę dobrze działa na składy wagonowe
|
||||||
if( (accdesiredresultant < fAccGravity - 0.1 && AbsAccS > accdesiredresultant + fBrake_a1[0] // regular braking
|
if( (accdesiredresultant < fAccGravity - 0.1 && AbsAccS > accdesiredresultant + brake_increase_margin() // regular braking
|
||||||
|| fAccGravity < -0.05 && velocity < -0.1) && // also brake if uphill and slipping back
|
|| fAccGravity < -0.05 && velocity < -0.1) && // also brake if uphill and slipping back
|
||||||
(fBrakeTime < 0.0
|
(fBrakeTime < 0.0
|
||||||
// the size of the brake demand decides whether to skip the reaction time, so the brake-only part
|
// the size of the brake demand decides whether to skip the reaction time, so the brake-only part
|
||||||
@@ -8214,6 +8253,18 @@ void TController::control_braking_force() {
|
|||||||
// Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy
|
// Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy
|
||||||
(3.0 + 0.5 * ((mvOccupied->BrakeDelayFlag > bdelay_G ? mvOccupied->BrakeDelay[1] : mvOccupied->BrakeDelay[3]) - 3.0)) * 0.5); // Ra: tymczasowo, bo przeżyna S1
|
(3.0 + 0.5 * ((mvOccupied->BrakeDelayFlag > bdelay_G ? mvOccupied->BrakeDelay[1] : mvOccupied->BrakeDelay[3]) - 3.0)) * 0.5); // Ra: tymczasowo, bo przeżyna S1
|
||||||
}
|
}
|
||||||
|
else if( ( BrakeSystem == TBrakeSystem::Pneumatic )
|
||||||
|
&& ( AccDesired < 0.0 )
|
||||||
|
&& ( BrakeCtrlPosition > 0.0 )
|
||||||
|
&& ( fShortfall > 0.02 )
|
||||||
|
&& ( iShortfallGrowth >= 2 )
|
||||||
|
&& ( fBrakeHeldTime > brake_response_horizon( mvOccupied, BrakeSystem, 1.0, fBrake_a0[ 0 ] ) ) ) {
|
||||||
|
// the train has been falling further behind the demand for a while at a handle left alone for longer than
|
||||||
|
// the brake takes to respond: a small step now, while it still is small, rather than the deep one the
|
||||||
|
// margin above would allow only once the train is far behind
|
||||||
|
cue_action( driver_hint::brakingforceincrease );
|
||||||
|
iShortfallGrowth = 0;
|
||||||
|
}
|
||||||
if ( (accdesiredresultant < fAccGravity - 0.05
|
if ( (accdesiredresultant < fAccGravity - 0.05
|
||||||
|| AccDesired >= EU07_AI_NOACCELERATION) // no braking asked for, yet the train is slowing down more than that
|
|| AccDesired >= EU07_AI_NOACCELERATION) // no braking asked for, yet the train is slowing down more than that
|
||||||
&& accdesiredresultant - fBrake_a1[0] * 0.51 - AbsAccS > 0.05 && OrderCurrentGet() != Disconnect && VelDesired > 0.0 ) {
|
&& accdesiredresultant - fBrake_a1[0] * 0.51 - AbsAccS > 0.05 && OrderCurrentGet() != Disconnect && VelDesired > 0.0 ) {
|
||||||
|
|||||||
@@ -311,6 +311,8 @@ private:
|
|||||||
double DirectionalVel() const {
|
double DirectionalVel() const {
|
||||||
return mvOccupied->Vel * sign( iDirection * mvOccupied->V ); }
|
return mvOccupied->Vel * sign( iDirection * mvOccupied->V ); }
|
||||||
|
|
||||||
|
double brake_increase_margin() const;
|
||||||
|
|
||||||
void update_timers( double const dt );
|
void update_timers( double const dt );
|
||||||
void update_logs( double const dt );
|
void update_logs( double const dt );
|
||||||
void determine_consist_state();
|
void determine_consist_state();
|
||||||
@@ -401,6 +403,9 @@ private:
|
|||||||
double VelDesired = 0.0; // predkość, z jaką ma jechać, wynikająca z analizy tableki; <=VelSignal
|
double VelDesired = 0.0; // predkość, z jaką ma jechać, wynikająca z analizy tableki; <=VelSignal
|
||||||
double fAccDesiredAv = 0.0; // uśrednione przyspieszenie z kolejnych przebłysków świadomości, żeby ograniczyć migotanie
|
double fAccDesiredAv = 0.0; // uśrednione przyspieszenie z kolejnych przebłysków świadomości, żeby ograniczyć migotanie
|
||||||
double fBrakeHeldTime = 0.0; // czas od ostatniego przestawienia kranu hamulca zasadniczego
|
double fBrakeHeldTime = 0.0; // czas od ostatniego przestawienia kranu hamulca zasadniczego
|
||||||
|
double fShortfall = 0.0; // how far the train fell short of the braking demand at the last check [m/s2]
|
||||||
|
double fShortfallTime = 0.0; // when that was checked
|
||||||
|
int iShortfallGrowth = 0; // how many checks in a row the shortfall has grown
|
||||||
double fAccDesiredGravity = 0.0; // część AccDesired odjęta na spadku jako kompensacja pochylenia; AbsAccS zawiera ją już sam
|
double fAccDesiredGravity = 0.0; // część AccDesired odjęta na spadku jako kompensacja pochylenia; AbsAccS zawiera ją już sam
|
||||||
double VelforDriver = -1.0; // prędkość, używana przy zmianie kierunku (ograniczenie przy nieznajmości szlaku?)
|
double VelforDriver = -1.0; // prędkość, używana przy zmianie kierunku (ograniczenie przy nieznajmości szlaku?)
|
||||||
double VelSignal = 0.0; // ograniczenie prędkości z kompilacji znaków i sygnałów // normalnie na początku ma stać, no chyba że jedzie
|
double VelSignal = 0.0; // ograniczenie prędkości z kompilacji znaków i sygnałów // normalnie na początku ma stać, no chyba że jedzie
|
||||||
|
|||||||
Reference in New Issue
Block a user