build 191115. vehicle voltage circuits logic fixes, ai train manager logic tweak

This commit is contained in:
tmj-fstate
2019-11-16 21:09:52 +01:00
parent ff0f14ab1a
commit 14ab3fd3d7
7 changed files with 133 additions and 58 deletions

View File

@@ -2156,12 +2156,26 @@ bool TController::CheckVehicles(TOrders user)
int pantmask = 1;
if (iDrivigFlags & movePrimary)
{ // jeśli jest aktywnie prowadzącym pojazd, może zrobić własny porządek
p = pVehicles[0];
// establish ownership and vehicle order
while (p)
{
if (p->MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector)
{ // jeśli pojazd posiada pantograf, to przydzielamy mu maskę, którą będzie informował o jeździe bezprądowej
p->iOverheadMask = pantmask;
pantmask = pantmask << 1; // przesunięcie bitów, max. 32 pojazdy z pantografami w składzie
}
d = p->DirectionSet(d ? 1 : -1); // zwraca położenie następnego (1=zgodny,0=odwrócony - względem czoła składu)
p->ctOwner = this; // dominator oznacza swoje terytorium
p = p->Next(); // pojazd podłączony od tyłu (licząc od czoła)
}
// with the order established the virtual train manager can do their work
p = pVehicles[0];
while (p)
{
if( p != pVehicle ) {
if( ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control ) ) == 0 )
&& ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control ) ) == 0 ) ) {
if( false == p->is_connected( pVehicle, coupling::control ) ) {
// NOTE: don't set battery in controllable vehicles, let the user/ai do it explicitly
// HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi...
p->MoverParameters->BatterySwitch( true );
@@ -2177,15 +2191,9 @@ bool TController::CheckVehicles(TOrders user)
p->DestinationSet(TrainParams.Relation2, TrainParams.TrainName); // relacja docelowa, jeśli nie było
if (AIControllFlag) // jeśli prowadzi komputer
p->RaLightsSet(0, 0); // gasimy światła
if (p->MoverParameters->EnginePowerSource.SourceType == TPowerSource::CurrentCollector)
{ // jeśli pojazd posiada pantograf, to przydzielamy mu maskę, którą będzie informował o jeździe bezprądowej
p->iOverheadMask = pantmask;
pantmask = pantmask << 1; // przesunięcie bitów, max. 32 pojazdy z pantografami w składzie
}
d = p->DirectionSet(d ? 1 : -1); // zwraca położenie następnego (1=zgodny,0=odwrócony - względem czoła składu)
p->ctOwner = this; // dominator oznacza swoje terytorium
p = p->Next(); // pojazd podłączony od tyłu (licząc od czoła)
}
if (AIControllFlag)
{ // jeśli prowadzi komputer
if( true == TestFlag( OrderCurrentGet(), Obey_train ) ) {
@@ -2562,7 +2570,7 @@ bool TController::PrepareEngine()
}
}
if( ( mvControlling->EnginePowerSource.SourceType != TPowerSource::CurrentCollector )
|| ( std::max( mvControlling->GetTrainsetVoltage(), mvControlling->PantographVoltage ) > mvControlling->EnginePowerSource.CollectorParameters.MinV ) ) {
|| ( std::max( mvControlling->GetAnyTrainsetVoltage(), mvControlling->PantographVoltage ) > mvControlling->EnginePowerSource.CollectorParameters.MinV ) ) {
mvControlling->MainSwitch( true );
}
}

View File

@@ -2793,7 +2793,7 @@ bool TDynamicObject::Update(double dt, double dt1)
|| MoverParameters->PantRearUp ) {
if( ( MoverParameters->Mains )
&& ( MoverParameters->GetTrainsetVoltage() < 0.1f ) ) {
&& ( MoverParameters->GetAnyTrainsetVoltage() < 0.1f ) ) {
// Ra 15-01: logować tylko, jeśli WS załączony
// yB 16-03: i nie jest to asynchron zasilany z daleka
// Ra 15-01: bezwzględne współrzędne pantografu nie są dostępne,
@@ -6038,30 +6038,60 @@ int TDynamicObject::DirectionSet(int d)
};
// wskaźnik na poprzedni, nawet wirtualny
TDynamicObject * TDynamicObject::PrevAny() {
TDynamicObject * TDynamicObject::PrevAny() const {
return MoverParameters->Neighbours[ iDirection ^ 1 ].vehicle;
}
TDynamicObject * TDynamicObject::Prev() {
TDynamicObject * TDynamicObject::Prev() const {
return ( MoverParameters->Couplers[ iDirection ^ 1 ].CouplingFlag != coupling::faux ?
MoverParameters->Neighbours[ iDirection ^ 1 ].vehicle :
nullptr );// gdy sprzęg wirtualny, to jakby nic nie było
}
TDynamicObject * TDynamicObject::Next() {
TDynamicObject * TDynamicObject::Next() const {
return ( MoverParameters->Couplers[ iDirection ].CouplingFlag != coupling::faux ?
MoverParameters->Neighbours[ iDirection ].vehicle :
nullptr );// gdy sprzęg wirtualny, to jakby nic nie było
}
TDynamicObject * TDynamicObject::PrevC(int C) {
TDynamicObject * TDynamicObject::PrevC(int C) const {
return ( ( MoverParameters->Couplers[ iDirection ^ 1 ].CouplingFlag & C ) == C ?
MoverParameters->Neighbours[ iDirection ^ 1 ].vehicle :
nullptr ); // hide neighbour lacking specified connection type
}
TDynamicObject * TDynamicObject::NextC(int C) {
TDynamicObject * TDynamicObject::NextC(int C) const {
return ( ( MoverParameters->Couplers[ iDirection ].CouplingFlag & C ) == C ?
MoverParameters->Neighbours[ iDirection ].vehicle :
nullptr ); // hide neighbour lacking specified connection type
}
// checks whether there's unbroken connection of specified type to specified vehicle
bool
TDynamicObject::is_connected( TDynamicObject const *Vehicle, coupling const Coupling ) const {
auto *vehicle { this };
if( vehicle == Vehicle ) {
// edge case, vehicle is always "connected" with itself
return true;
}
// check ahead, it's more likely the "owner" using this method is located there
while( ( vehicle = vehicle->PrevC( Coupling ) ) != nullptr ) {
if( vehicle == Vehicle ) {
return true;
}
if( vehicle == this ) {
// edge case, looping consist
return false;
}
}
// start anew in the other direction
vehicle = this;
while( ( vehicle = vehicle->NextC( Coupling ) ) != nullptr ) {
if( vehicle == Vehicle ) {
return true;
}
}
// no lack in either direction, give up
return false;
}
// ustalenie następnego (1) albo poprzedniego (0) w składzie bez względu na prawidłowość iDirection
TDynamicObject *
TDynamicObject::Neighbour(int &dir) {

View File

@@ -484,11 +484,13 @@ private:
public:
int *iLights; // wskaźnik na bity zapalonych świateł (własne albo innego członu)
bool DimHeadlights{ false }; // status of the headlight dimming toggle. NOTE: single toggle for all lights is a simplification. TODO: separate per-light switches
TDynamicObject * PrevAny();
TDynamicObject * Prev();
TDynamicObject * Next();
TDynamicObject * PrevC(int C);
TDynamicObject * NextC(int C);
TDynamicObject * PrevAny() const;
TDynamicObject * Prev() const;
TDynamicObject * Next() const;
TDynamicObject * PrevC(int C) const;
TDynamicObject * NextC(int C) const;
// checks whether there's unbroken connection of specified type to specified vehicle
bool is_connected( TDynamicObject const *Vehicle, coupling const Coupling = coupling::coupler ) const;
void SetdMoveLen(double dMoveLen) {
MoverParameters->dMoveLen = dMoveLen; }
void ResetdMoveLen() {

View File

@@ -1526,7 +1526,8 @@ public:
double ShowEngineRotation(int VehN);
// Q *******************************************************************************************
double GetTrainsetVoltage(void);
double GetTrainsetVoltage( int const Coupling = ( coupling::heating | coupling::highvoltage ) ) const;
double GetAnyTrainsetVoltage() const;
bool switch_physics(bool const State);
double LocalBrakeRatio(void);
double ManualBrakeRatio(void);

View File

@@ -733,7 +733,7 @@ void TMoverParameters::UpdatePantVolume(double dt)
// opuszczenie pantografów przy niskim ciśnieniu
if( TrainType != dt_EZT ) {
// pressure switch safety measure -- open the line breaker, unless there's alternate source of traction voltage
if( GetTrainsetVoltage() < EnginePowerSource.CollectorParameters.MinV ) {
if( GetAnyTrainsetVoltage() < EnginePowerSource.CollectorParameters.MinV ) {
// TODO: check whether line breaker should be open EMU-wide
MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) );
}
@@ -1472,11 +1472,8 @@ void TMoverParameters::MainsCheck( double const Deltatime ) {
// TODO: move other main circuit checks here
if( MainsInitTime == 0.0 ) { return; }
if( MainsInitTime == 0.0 ) { return; }
if( MainsInitTimeCountdown > 0.0 ) {
MainsInitTimeCountdown -= Deltatime;
}
// TBD, TODO: move voltage calculation to separate method and use also in power coupler state calculation?
auto localvoltage { 0.0 };
switch( EnginePowerSource.SourceType ) {
@@ -1491,8 +1488,18 @@ void TMoverParameters::MainsCheck( double const Deltatime ) {
break;
}
}
if( ( localvoltage == 0.0 )
&& ( GetTrainsetVoltage() == 0 ) ) {
auto const maincircuitpowersupply {
( std::abs( localvoltage ) > 0.1 )
|| ( GetAnyTrainsetVoltage() > 0.1 ) };
if( true == maincircuitpowersupply ) {
// all is well
if( MainsInitTimeCountdown > 0.0 ) {
MainsInitTimeCountdown -= Deltatime;
}
}
else {
// no power supply
MainsInitTimeCountdown = MainsInitTime;
}
}
@@ -1507,6 +1514,10 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
localvoltage = HeatingPowerSource.EngineGenerator.voltage - TotalCurrent * 0.02;
break;
}
case TPowerSource::CurrentCollector: {
localvoltage = PantographVoltage;
break;
}
case TPowerSource::Main: {
// HACK: main circuit can be fed through couplers, so we explicitly check pantograph supply here
localvoltage = (
@@ -1641,7 +1652,7 @@ void TMoverParameters::ConverterCheck( double const Timestep ) {
&& ( ConverterAllowLocal )
&& ( false == PantPressLockActive )
&& ( ( Mains )
|| ( GetTrainsetVoltage() > 0 ) ) ) {
|| ( GetAnyTrainsetVoltage() > 0.0 ) ) ) {
// delay timer can be optionally configured, and is set anew whenever converter goes off
if( ConverterStartDelayTimer <= 0.0 ) {
ConverterFlag = true;
@@ -1697,17 +1708,22 @@ void TMoverParameters::HeatingCheck( double const Timestep ) {
}
// ...detailed check if we're still here
auto const heatingpowerthreshold { 0.1 };
// start with external power sources
// start with blank slate
auto voltage { 0.0 };
// then try internal ones
// then try specified power source
switch( HeatingPowerSource.SourceType ) {
case TPowerSource::Generator: {
voltage = HeatingPowerSource.EngineGenerator.voltage;
break;
}
case TPowerSource::CurrentCollector: {
voltage = PantographVoltage;
break;
}
case TPowerSource::PowerCable: {
if( HeatingPowerSource.PowerType == TPowerType::ElectricPower ) {
voltage = GetTrainsetVoltage();
// TBD, TODO: limit input voltage to heating coupling type?
voltage = GetAnyTrainsetVoltage();
}
break;
}
@@ -4501,12 +4517,12 @@ void TMoverParameters::ComputeTotalForce(double dt) {
if( EngineType == TEngineType::ElectricSeriesMotor ) // potem ulepszyc! pantogtrafy!
{ // Ra 2014-03: uwzględnienie kierunku jazdy w napięciu na silnikach, a powinien być zdefiniowany nawrotnik
EngineVoltage =
std::max(
GetTrainsetVoltage(),
( Mains ?
PantographVoltage :
0 ) );
EngineVoltage = (
Mains ?
std::max(
GetAnyTrainsetVoltage(),
PantographVoltage ) :
0.00 );
if( CabNo == 0 ) {
EngineVoltage *= ActiveDir;
}
@@ -4515,10 +4531,12 @@ void TMoverParameters::ComputeTotalForce(double dt) {
}
} // bo nie dzialalo
else {
EngineVoltage =
std::max(
GetTrainsetVoltage(),
PantographVoltage );
EngineVoltage = (
Power > 1.0 ?
std::max(
GetAnyTrainsetVoltage(),
PantographVoltage ) :
0.0 );
}
FTrain = (
@@ -5091,7 +5109,7 @@ double TMoverParameters::TractionForce( double dt ) {
case TEngineType::ElectricSeriesMotor: {
// update the state of voltage relays
auto const voltage { std::max( GetTrainsetVoltage(), PantographVoltage ) };
auto const voltage { std::max( GetAnyTrainsetVoltage(), PantographVoltage ) };
NoVoltRelay =
( EnginePowerSource.SourceType != TPowerSource::CurrentCollector )
|| ( voltage >= EnginePowerSource.CollectorParameters.MinV );
@@ -5110,8 +5128,8 @@ double TMoverParameters::TractionForce( double dt ) {
// TODO: check if we can use instead the code for electricseriesmotor
if( ( Mains ) ) {
// nie wchodzić w funkcję bez potrzeby
if( ( std::max( GetTrainsetVoltage(), PantographVoltage ) < EnginePowerSource.CollectorParameters.MinV )
|| ( std::max( GetTrainsetVoltage(), PantographVoltage ) > EnginePowerSource.CollectorParameters.MaxV + 200 ) ) {
if( ( std::max( GetAnyTrainsetVoltage(), PantographVoltage ) < EnginePowerSource.CollectorParameters.MinV )
|| ( std::max( GetAnyTrainsetVoltage(), PantographVoltage ) > EnginePowerSource.CollectorParameters.MaxV + 200 ) ) {
MainSwitch( false, ( TrainType == dt_EZT ? range_t::unit : range_t::local ) ); // TODO: check whether we need to send this EMU-wide
}
}
@@ -8096,19 +8114,30 @@ std::string TMoverParameters::EngineDescription(int what) const
// Q: 20160709
// Funkcja zwracajaca napiecie dla calego skladu, przydatna dla EZT
// *************************************************************************************************
double TMoverParameters::GetTrainsetVoltage(void)
double TMoverParameters::GetTrainsetVoltage( int const Coupling ) const
{//ABu: funkcja zwracajaca napiecie dla calego skladu, przydatna dla EZT
return std::max(
( ( ( Couplers[end::front].Connected )
&& ( Couplers[ end::front ].Connected->Couplers[ Couplers[ end::front ].ConnectedNr ].power_high.is_live ) ) ?
&& ( Couplers[ end::front ].Connected->Couplers[ Couplers[ end::front ].ConnectedNr ].power_high.is_live )
&& ( ( Couplers[ end::front ].CouplingFlag & Coupling ) != 0 ) ) ?
Couplers[end::front].Connected->Couplers[ Couplers[end::front].ConnectedNr ].power_high.voltage :
0.0 ),
( ( ( Couplers[end::rear].Connected )
&& ( Couplers[ end::rear ].Connected->Couplers[ Couplers[ end::rear ].ConnectedNr ].power_high.is_live ) ) ?
&& ( Couplers[ end::rear ].Connected->Couplers[ Couplers[ end::rear ].ConnectedNr ].power_high.is_live )
&& ( ( Couplers[ end::rear ].CouplingFlag & Coupling ) != 0 ) ) ?
Couplers[ end::rear ].Connected->Couplers[ Couplers[ end::rear ].ConnectedNr ].power_high.voltage :
0.0 ) );
}
double TMoverParameters::GetAnyTrainsetVoltage() const {
return std::max(
GetTrainsetVoltage( coupling::highvoltage ),
( HeatingAllow ?
GetTrainsetVoltage( coupling::heating ) :
0.0 ) );
}
// *************************************************************************************************
// Kasowanie zmiennych pracy fizyki
// *************************************************************************************************
@@ -11278,20 +11307,21 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
}
/*naladunek/rozladunek*/
// TODO: have these commands leverage load exchange system instead
// TODO: CValue1 defines amount to load/unload
else if ( issection( "Load=", Command ) )
{
OK = false; // będzie powtarzane aż się załaduje
if( ( Vel < 0.1 ) // tolerance margin for small vehicle movements in the consist
&& ( MaxLoad > 0 )
&& ( LoadAmount < MaxLoad * ( 1.0 + OverLoadFactor ) )
&& ( Distance( Loc, CommandIn.Location, Dim, Dim ) < 10 ) ) { // ten peron/rampa
&& ( Distance( Loc, CommandIn.Location, Dim, Dim ) < ( CValue2 > 1.0 ? CValue2 : 10.0 ) ) ) { // ten peron/rampa
auto const loadname { ToLower( extract_value( "Load", Command ) ) };
if( LoadAmount == 0.f ) {
AssignLoad( loadname );
}
OK = LoadingDone(
std::min<float>( CValue2, LoadSpeed ),
LoadSpeed,
loadname ); // zmienia LoadStatus
}
else {
@@ -11304,10 +11334,10 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C
OK = false; // będzie powtarzane aż się rozładuje
if( ( Vel < 0.1 ) // tolerance margin for small vehicle movements in the consist
&& ( LoadAmount > 0 ) // czy jest co rozladowac?
&& ( Distance( Loc, CommandIn.Location, Dim, Dim ) < 10 ) ) { // ten peron
&& ( Distance( Loc, CommandIn.Location, Dim, Dim ) < ( CValue2 > 1.0 ? CValue2 : 10.0 ) ) ) { // ten peron
/*mozna to rozladowac*/
OK = LoadingDone(
-1.f * std::min<float>( CValue2, LoadSpeed ),
-1.f * LoadSpeed,
ToLower( extract_value( "UnLoad", Command ) ) );
}
else {

View File

@@ -5701,12 +5701,16 @@ bool TTrain::Update( double const Deltatime )
}
// Ra 2014-09: napięcia i prądy muszą być ustalone najpierw, bo wysyłane są ewentualnie na PoKeys
if ((mvControlled->EngineType != TEngineType::DieselElectric)
&& (mvControlled->EngineType != TEngineType::ElectricInductionMotor)) // Ra 2014-09: czy taki rozdzia? ma sens?
fHVoltage = std::max( mvControlled->PantographVoltage, mvControlled->GetTrainsetVoltage() ); // Winger czy to nie jest zle?
if( ( mvControlled->EngineType != TEngineType::DieselElectric )
&& ( mvControlled->EngineType != TEngineType::ElectricInductionMotor ) ) { // Ra 2014-09: czy taki rozdzia? ma sens?
fHVoltage = std::max(
mvControlled->PantographVoltage,
mvControlled->GetAnyTrainsetVoltage() ); // Winger czy to nie jest zle?
}
// *mvControlled->Mains);
else
else {
fHVoltage = mvControlled->EngineVoltage;
}
if (ShowNextCurrent)
{ // jeśli pokazywać drugi człon
if (mvSecond)

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 19
#define VERSION_MINOR 1111
#define VERSION_MINOR 1115
#define VERSION_REVISION 0