From a9365e7845a316c4e20f12050c32e282df5f3892 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 4 Jun 2019 18:41:47 +0200 Subject: [PATCH 01/13] timetable ui panel enhancement, door cab control logic fix, load visualization model loading error logging tweak --- DynObj.cpp | 29 +++++++++++++++++------------ MdlMngr.cpp | 6 ++++-- MdlMngr.h | 2 +- Train.cpp | 11 ++--------- driveruipanels.cpp | 20 +++++++++++--------- mtable.cpp | 1 + 6 files changed, 36 insertions(+), 33 deletions(-) diff --git a/DynObj.cpp b/DynObj.cpp index 6f2f3eaf..4057086d 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -5769,23 +5769,28 @@ TDynamicObject::LoadMMediaFile_mdload( std::string const &Name ) const { TModel3d *loadmodel { nullptr }; // check if we don't have model override for this load type - auto const lookup { LoadModelOverrides.find( Name ) }; - if( lookup != LoadModelOverrides.end() ) { - loadmodel = TModelsManager::GetModel( asBaseDir + lookup->second, true ); - // if the override was succesfully loaded call it a day - if( loadmodel != nullptr ) { return loadmodel; } + { + auto const lookup { LoadModelOverrides.find( Name ) }; + if( lookup != LoadModelOverrides.end() ) { + loadmodel = TModelsManager::GetModel( asBaseDir + lookup->second, true ); + // if the override was succesfully loaded call it a day + if( loadmodel != nullptr ) { return loadmodel; } + } } // regular routine if there's no override or it couldn't be loaded // try first specialized version of the load model, vehiclename_loadname - auto const specializedloadfilename { asBaseDir + MoverParameters->TypeName + "_" + Name }; - if( ( true == FileExists( specializedloadfilename + ".e3d" ) ) - || ( true == FileExists( specializedloadfilename + ".t3d" ) ) ) { - loadmodel = TModelsManager::GetModel( specializedloadfilename, true ); + { + auto const specializedloadfilename { asBaseDir + MoverParameters->TypeName + "_" + Name }; + loadmodel = TModelsManager::GetModel( specializedloadfilename, true, false ); + if( loadmodel != nullptr ) { return loadmodel; } } - if( loadmodel == nullptr ) { - // if this fails, try generic load model - loadmodel = TModelsManager::GetModel( asBaseDir + Name, true ); + // try generic version of the load model next, loadname + { + auto const genericloadfilename { asBaseDir + Name }; + loadmodel = TModelsManager::GetModel( genericloadfilename, true, false ); + if( loadmodel != nullptr ) { return loadmodel; } } + // if we're still here, give up return loadmodel; } diff --git a/MdlMngr.cpp b/MdlMngr.cpp index 015de0ee..f71b2921 100644 --- a/MdlMngr.cpp +++ b/MdlMngr.cpp @@ -57,7 +57,7 @@ TModelsManager::LoadModel(std::string const &Name, bool dynamic) { } TModel3d * -TModelsManager::GetModel(std::string const &Name, bool const Dynamic) +TModelsManager::GetModel(std::string const &Name, bool const Dynamic, bool const Logerrors ) { // model może być we wpisie "node...model" albo "node...dynamic", a także być dodatkowym w dynamic // (kabina, wnętrze, ładunek) // dla "node...dynamic" mamy podaną ścieżkę w "\dynamic\" i musi być co najmniej 1 poziom, zwkle @@ -107,7 +107,9 @@ TModelsManager::GetModel(std::string const &Name, bool const Dynamic) } else { // there's nothing matching in the databank nor on the disk, report failure... - ErrorLog( "Bad file: failed do locate 3d model file \"" + filename + "\"", logtype::file ); + if( Logerrors ) { + ErrorLog( "Bad file: failed do locate 3d model file \"" + filename + "\"", logtype::file ); + } // ...and link it with the error model slot m_modelsmap.emplace( filename, null_handle ); } diff --git a/MdlMngr.h b/MdlMngr.h index b70eb30d..196da420 100644 --- a/MdlMngr.h +++ b/MdlMngr.h @@ -22,7 +22,7 @@ private: class TModelsManager { public: // McZapkie: dodalem sciezke, notabene Path!=Patch :) - static TModel3d *GetModel( std::string const &Name, bool dynamic = false ); + static TModel3d *GetModel( std::string const &Name, bool const dynamic = false, bool const Logerrors = true ); private: // types: diff --git a/Train.cpp b/Train.cpp index 1870279e..f171ccec 100644 --- a/Train.cpp +++ b/Train.cpp @@ -4719,13 +4719,10 @@ void TTrain::OnCommand_doorcloseall( TTrain *Train, command_data const &Command if( Command.action == GLFW_PRESS ) { if( Train->mvOccupied->Doors.has_autowarning ) { - // automatic departure signal delays actual door closing until the button is released Train->mvOccupied->signal_departure( true ); } - else { - Train->mvOccupied->OperateDoors( side::right, false ); - Train->mvOccupied->OperateDoors( side::left, false ); - } + Train->mvOccupied->OperateDoors( side::right, false ); + Train->mvOccupied->OperateDoors( side::left, false ); // visual feedback Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch ); Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -4735,11 +4732,7 @@ void TTrain::OnCommand_doorcloseall( TTrain *Train, command_data const &Command else if( Command.action == GLFW_RELEASE ) { // release the button if( Train->mvOccupied->Doors.has_autowarning ) { - // automatic departure signal delays actual door closing until the button is released Train->mvOccupied->signal_departure( false ); - // now we can actually close the door - Train->mvOccupied->OperateDoors( side::right, false ); - Train->mvOccupied->OperateDoors( side::left, false ); } // visual feedback if( Train->ggDoorAllOffButton.SubModel ) diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 6a482e81..ff93e88e 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -377,24 +377,26 @@ timetable_panel::update() { candeparture ? readycolor : // czas minął i odjazd był, to nazwa stacji będzie na zielono isatpassengerstop ? waitcolor : Global.UITextColor ) }; + auto const trackcount{ ( tableline->TrackNo == 1 ? u8" ┃ " : u8" ║ " ) }; m_tablelines.emplace_back( - ( u8"│ " + vmax + u8" │ " + station + u8" │ " + arrival + u8" │ " + traveltime + u8" │" ), + ( u8"│ " + vmax + u8" │ " + station + trackcount + arrival + u8" │ " + traveltime + u8" │" ), linecolor ); m_tablelines.emplace_back( - ( u8"│ │ " + location + tableline->StationWare + u8" │ " + departure + u8" │ │" ), + ( u8"│ │ " + location + tableline->StationWare + trackcount + departure + u8" │ │" ), linecolor ); // divider/footer if( i < table->StationCount ) { auto const *nexttableline { tableline + 1 }; - if( tableline->vmax == nexttableline->vmax ) { - m_tablelines.emplace_back( u8"│ ├────────────────────────────────────┼─────────┼─────┤", Global.UITextColor ); - } - else { - m_tablelines.emplace_back( u8"├─────┼────────────────────────────────────┼─────────┼─────┤", Global.UITextColor ); - } + std::string const vmaxnext{ ( tableline->vmax == nexttableline->vmax ? u8"│ ├" : u8"├─────┼" ) }; + auto const trackcountnext{ ( nexttableline->TrackNo == 1 ? u8"╂" : u8"╫" ) }; + m_tablelines.emplace_back( + vmaxnext + u8"────────────────────────────────────" + trackcountnext + u8"─────────┼─────┤", + Global.UITextColor ); } else { - m_tablelines.emplace_back( u8"└─────┴────────────────────────────────────┴─────────┴─────┘", Global.UITextColor ); + m_tablelines.emplace_back( + u8"└─────┴────────────────────────────────────┴─────────┴─────┘", + Global.UITextColor ); } } } diff --git a/mtable.cpp b/mtable.cpp index 957a4f8d..b1749f87 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -549,6 +549,7 @@ void TTrainParameters::serialize( dictionary_source *Output ) const { Output->insert( ( stationlabel + "am" ), timetableline.Am ); Output->insert( ( stationlabel + "dh" ), timetableline.Dh ); Output->insert( ( stationlabel + "dm" ), timetableline.Dm ); + Output->insert( ( stationlabel + "tracks" ), timetableline.TrackNo ); } } } From 32f95bcc3f05fbdb5aff12d1ca86afbd07cf9a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Mon, 27 May 2019 18:52:04 +0200 Subject: [PATCH 02/13] EIMIC for DieselEngine --- Driver.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++ Driver.h | 2 ++ DynObj.cpp | 9 ++++++- McZapkie/Mover.cpp | 59 +++++++++++++++++++++++++++++++++---------- driveruipanels.cpp | 4 ++- 5 files changed, 122 insertions(+), 15 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 46369124..dec7cc3b 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3131,6 +3131,14 @@ bool TController::IncSpeed() { // dla 2Ls150 można zmienić tryb pracy, jeśli jest w liniowym i nie daje rady (wymaga zerowania kierunku) // mvControlling->ShuntMode=(OrderList[OrderPos]&Shunt)||(fMass>224000.0); } + if (mvControlling->EIMCtrlType > 0) { + if (true == Ready) + { + DizelPercentage = (mvControlling->Vel > mvControlling->dizel_minVelfullengage ? 100 : 1); + } + break; + } + else if( true == Ready ) { if( ( mvControlling->Vel > mvControlling->dizel_minVelfullengage ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Mn > 0 ) ) { @@ -3193,6 +3201,12 @@ bool TController::DecSpeed(bool force) mvControlling->DecMainCtrl(3 + 3 * floor(0.5 + fabs(AccDesired))); break; case TEngineType::DieselEngine: + if (mvControlling->EIMCtrlType > 0) + { + DizelPercentage = 0; + break; + } + if ((mvControlling->Vel > mvControlling->dizel_minVelfullengage)) { if (mvControlling->RList[mvControlling->MainCtrlPos].Mn > 0) @@ -3516,6 +3530,37 @@ void TController::SetTimeControllers() } } //5. Check Main Controller in Dizels + //5.1. Digital controller in DMUs with hydro + if ((mvControlling->EngineType == TEngineType::DieselEngine) && (mvControlling->EIMCtrlType == 3)) + { + DizelPercentage_Speed = DizelPercentage; + double Factor = 10 * (mvControlling->Vmax) / (mvControlling->Vmax + 3*mvControlling->Vel); + double DesiredPercentage = (VelDesired > mvControlling->Vel ? (VelDesired - mvControlling->Vel) / Factor : 0); + DesiredPercentage = clamp(DesiredPercentage, 0.0, 1.0); + if (VelDesired < 0.5 * mvControlling->Vmax && VelDesired - mvControlling->Vel < 10) + DesiredPercentage = std::min(DesiredPercentage, 0.75); + if (VelDesired < mvControlling->hydro_TC_LockupSpeed) DizelPercentage = std::min(DizelPercentage,1); + int DizelActualPercentage = 100.4 * mvControlling->eimic_real; + int PosInc = mvControlling->MainCtrlPosNo; + int PosDec = 0; + for(int i=PosInc;i>=0;i--) + if ((mvControlling->UniCtrlList[i].SetCtrlVal <= 0) && (mvControlling->UniCtrlList[i].SpeedDown > 0.01)) + { + PosDec = i; + break; + } + DizelPercentage_Speed = round(double(DizelPercentage*DesiredPercentage)); + if (VelDesired < mvControlling->hydro_TC_LockupSpeed) DizelPercentage = std::min(DizelPercentage_Speed, 1); + if (abs(DizelPercentage_Speed - DizelActualPercentage)>(DizelPercentage>1?3:0)) + { + if (((DizelPercentage_Speed == 0 && DizelActualPercentage > 10) || (DizelActualPercentage - DizelPercentage_Speed > 50)) && PosDec > 0) PosDec -= 1; //pozycję wczesniej powinno byc szybkie zejscie, jeśli trzeba + int DesiredPos = (DizelPercentage_Speed > DizelActualPercentage ? PosInc : PosDec); + while (mvControlling->MainCtrlPos > DesiredPos) mvControlling->DecMainCtrl(1); + while (mvControlling->MainCtrlPos < DesiredPos) mvControlling->IncMainCtrl(1); + } + } + else + //5.2. Analog direct controller if ((mvControlling->EngineType == TEngineType::DieselEngine)&&(mvControlling->Vmax>30)) { int MaxPos = mvControlling->MainCtrlPosNo; @@ -3575,6 +3620,24 @@ void TController::CheckTimeControllers() mvOccupied->ScndCtrlPos = 2; } } + + //5. Check Main Controller in Dizels + //5.1. Digital controller in DMUs with hydro + if ((mvControlling->EngineType == TEngineType::DieselEngine) && (mvControlling->EIMCtrlType == 3)) + { + int DizelActualPercentage = 100.4 * mvControlling->eimic_real; + int NeutralPos = mvControlling->MainCtrlPosNo - 1; //przedostatnia powinna wstrzymywać - hipoteza robocza + for (int i = mvControlling->MainCtrlPosNo; i >= 0; i--) + if ((mvControlling->UniCtrlList[i].SetCtrlVal <= 0) && (mvControlling->UniCtrlList[i].SpeedDown < 0.01)) //niby zero, ale nie zmniejsza procentów + { + NeutralPos = i; + break; + } + if ((DizelActualPercentage >= DizelPercentage_Speed) && (mvControlling->MainCtrlPos > NeutralPos)) + while (mvControlling->MainCtrlPos > NeutralPos) mvControlling->DecMainCtrl(1); + if ((DizelActualPercentage <= DizelPercentage_Speed) && (mvControlling->MainCtrlPos < NeutralPos)) + while (mvControlling->MainCtrlPos < NeutralPos) mvControlling->IncMainCtrl(1); + } }; // otwieranie/zamykanie drzwi w składzie albo (tylko AI) EZT diff --git a/Driver.h b/Driver.h index 96067b79..85177dbe 100644 --- a/Driver.h +++ b/Driver.h @@ -256,6 +256,8 @@ public: int iOverheadZero = 0; // suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z podniesionymi pantografami int iOverheadDown = 0; // suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z podniesionymi pantografami double BrakeCtrlPosition = 0.0; // intermediate position of main brake controller + int DizelPercentage = 0; // oczekiwane procenty jazdy/hamowania szynobusem + int DizelPercentage_Speed = 0; // oczekiwane procenty jazdy/hamowania szynobusem w związku z osiąganiem VelDesired private: bool Psyche = false; int HelperState = 0; //stan pomocnika maszynisty diff --git a/DynObj.cpp b/DynObj.cpp index 4057086d..9d346ae3 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2758,7 +2758,14 @@ bool TDynamicObject::Update(double dt, double dt1) if (Mechanik) { // Ra 2F3F: do Driver.cpp to przenieść? MoverParameters->EqvtPipePress = GetEPP(); // srednie cisnienie w PG - if( ( Mechanik->Primary() ) + if ((Mechanik->Primary()) + && (MoverParameters->EngineType == TEngineType::DieselEngine) + && (MoverParameters->EIMCtrlType > 0)) { + MoverParameters->CheckEIMIC(dt1); + MoverParameters->eimic_real = MoverParameters->eimic; + MoverParameters->SendCtrlToNext("EIMIC", MoverParameters->eimic, MoverParameters->CabNo); + } + if( ( Mechanik->Primary() ) && ( MoverParameters->EngineType == TEngineType::ElectricInductionMotor ) ) { // jesli glowny i z asynchronami, to niech steruje hamulcem i napedem lacznie dla calego pociagu/ezt auto const kier = (DirectionGet() * MoverParameters->ActiveCab > 0); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index fb83ef35..624bf0db 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -4567,7 +4567,7 @@ double TMoverParameters::TractionForce( double dt ) { EnginePower = ( 2 * dizel_Mstand + dmoment ) * enrot * ( 2.0 * M_PI / 1000.0 ); if( MainCtrlPowerPos() > 1 ) { // dodatkowe opory z powodu sprezarki} - dmoment -= dizel_Mstand * ( 0.2 * enrot / dizel_nmax ); +// dmoment -= dizel_Mstand * ( 0.2 * enrot / dizel_nmax ); //yB: skąd to w ogóle się bierze?! } break; } @@ -6114,9 +6114,20 @@ void TMoverParameters::CheckEIMIC(double dt) } break; case 3: - eimic -= clamp(-UniCtrlList[MainCtrlPos].SetCtrlVal + eimic, 0.0, dt * UniCtrlList[MainCtrlPos].SpeedDown); //odejmuj do X - eimic += clamp(UniCtrlList[MainCtrlPos].SetCtrlVal - eimic, 0.0, dt * UniCtrlList[MainCtrlPos].SpeedUp); //dodawaj do X - eimic = clamp(eimic, UniCtrlList[MainCtrlPos].MinCtrlVal, UniCtrlList[MainCtrlPos].MaxCtrlVal); + if ((MainCtrlActualPos != MainCtrlPos) || (LastRelayTime>InitialCtrlDelay)) + { + eimic -= clamp(-UniCtrlList[MainCtrlPos].SetCtrlVal + eimic, 0.0, (MainCtrlActualPos == MainCtrlPos ? dt * UniCtrlList[MainCtrlPos].SpeedDown : sign(UniCtrlList[MainCtrlPos].SpeedDown) * 0.01)); //odejmuj do X + eimic += clamp(UniCtrlList[MainCtrlPos].SetCtrlVal - eimic, 0.0, (MainCtrlActualPos == MainCtrlPos ? dt * UniCtrlList[MainCtrlPos].SpeedUp : sign(UniCtrlList[MainCtrlPos].SpeedUp) * 0.01)); //dodawaj do X + eimic = clamp(eimic, UniCtrlList[MainCtrlPos].MinCtrlVal, UniCtrlList[MainCtrlPos].MaxCtrlVal); + } + if (MainCtrlActualPos == MainCtrlPos) + LastRelayTime += dt; + else + { + LastRelayTime = 0; + MainCtrlActualPos = MainCtrlPos; + } + //BrakeLevelSet(UniCtrlList[MainCtrlPos].mode); } auto const eimicpowerenabled { ( ( true == Mains ) || ( Power == 0.0 ) ) @@ -6239,6 +6250,17 @@ bool TMoverParameters::dizel_AutoGearCheck(void) if (Mains) { + if (EIMCtrlType > 0) //sterowanie komputerowe + { + if (dizel_automaticgearstatus == 0) + if ((hydro_TC && hydro_TC_Fill > 0.01 )||( eimic_real > 0.0 )) + dizel_EngageSwitch(1.0); + else + dizel_EngageSwitch(0.0); + else + dizel_EngageSwitch(0.0); + } + else if (dizel_automaticgearstatus == 0) // ustaw cisnienie w silowniku sprzegla} switch (RList[MainCtrlPos].Mn) { @@ -6385,6 +6407,7 @@ bool TMoverParameters::dizel_Update(double dt) { double TMoverParameters::dizel_fillcheck(int mcp) { auto realfill { 0.0 }; + auto reg_factor { 0.98 }; if( ( true == Mains ) && ( MainCtrlPosNo > 0 ) @@ -6399,11 +6422,20 @@ double TMoverParameters::dizel_fillcheck(int mcp) } else { // napelnienie zalezne od MainCtrlPos - realfill = RList[ mcp ].R; + if (EIMCtrlType > 0) + { + realfill = std::max(0.0, eimic_real); + reg_factor = 1.0; + } + else + realfill = RList[mcp].R; } if (dizel_nmax_cutoff > 0) { auto nreg { 0.0 }; + if (EIMCtrlType > 0) + nreg = (eimic_real > 0 ? dizel_nmax : dizel_nmin); + else switch (RList[MainCtrlPos].Mn) { case 0: @@ -6442,7 +6474,7 @@ double TMoverParameters::dizel_fillcheck(int mcp) realfill = 0; if (enrot < nreg) //pod predkoscia regulatora dawka zadana realfill = realfill; - if ((enrot < dizel_nmin * 0.98)&&(RList[mcp].R>0.001)) //jesli ponizej biegu jalowego i niezerowa dawka, to dawaj pelna + if ((enrot < dizel_nmin * reg_factor)&&(RList[mcp].R>0.001)) //jesli ponizej biegu jalowego i niezerowa dawka, to dawaj pelna realfill = 1; } } @@ -6485,10 +6517,11 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) if (hydro_TC) //jesli przetwornik momentu { //napelnianie przetwornika - if ((MainCtrlPowerPos() > 0) && (Mains) && (enrot>dizel_nmin*0.9)) + bool IsPower = (EIMCtrlType > 0 ? eimic_real > 0 : MainCtrlPowerPos() > 0); + if ((IsPower) && (Mains) && (enrot>dizel_nmin*0.9)) hydro_TC_Fill += hydro_TC_FillRateInc * dt; //oproznianie przetwornika - if (((IsMainCtrlNoPowerPos()) && (Vel<3)) + if (((!IsPower) && (Vel<3)) || (!Mains) || (enrot hydro_TC_LockupSpeed) && (Mains) && (enrot > 0.9 * dizel_nmin) && (MainCtrlPowerPos() > 0)) + if ((Vel > hydro_TC_LockupSpeed) && (Mains) && (enrot > 0.9 * dizel_nmin) && (IsPower)) hydro_TC_LockupRate += hydro_TC_FillRateInc*dt; //luzowanie sprzegla blokujacego - if ((Vel < (MainCtrlPowerPos() > 0 ? hydro_TC_LockupSpeed : hydro_TC_UnlockSpeed)) || (!Mains) || (enrot < 0.8 * dizel_nmin)) + if ((Vel < (IsPower ? hydro_TC_LockupSpeed : hydro_TC_UnlockSpeed)) || (!Mains) || (enrot < 0.8 * dizel_nmin)) hydro_TC_LockupRate -= hydro_TC_FillRateDec*dt; //obcinanie zakresu hydro_TC_LockupRate = clamp(hydro_TC_LockupRate, 0.0, 1.0); @@ -7860,7 +7893,7 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) startRLIST = false; continue; } - if (issection("END-RL", inputline)) { + if (issection("END-UCL", inputline)) { startBPT = false; startUCLIST = false; continue; @@ -8073,7 +8106,7 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) startBPT = false; fizlines.emplace("UCList", inputline); startUCLIST = true; LISTLINE = 0; - LoadFIZ_RList(inputline); + LoadFIZ_UCList(inputline); continue; } @@ -8127,7 +8160,7 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) continue; } if (true == startUCLIST) { - readRList(inputline); + readUCList(inputline); continue; } if( true == startDLIST ) { diff --git a/driveruipanels.cpp b/driveruipanels.cpp index ff93e88e..a748ec80 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -884,7 +884,9 @@ debug_panel::update_section_ai( std::vector &Output ) { + "\n brake threshold: " + to_string( mechanik.fAccThreshold, 2 ) + ", delays: " + to_string( mechanik.fBrake_a0[ 0 ], 2 ) + "+" + to_string( mechanik.fBrake_a1[ 0 ], 2 ) - + "\n virtual brake position: " + to_string(mechanik.BrakeCtrlPosition, 2); + + "\n virtual brake position: " + to_string(mechanik.BrakeCtrlPosition, 2) + + "\n desired diesel percentage: " + to_string(mechanik.DizelPercentage, 0) + + "/" + to_string(mechanik.DizelPercentage_Speed, 0); Output.emplace_back( textline, Global.UITextColor ); From 0db6f588c47d765ecb17e310627de4ec12a09543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Mon, 27 May 2019 18:57:04 +0200 Subject: [PATCH 03/13] Fixed turbo for non DieselEngine vehicles --- DynObj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DynObj.cpp b/DynObj.cpp index 9d346ae3..2dc302c9 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -6638,7 +6638,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub // youBy - przenioslem, bo diesel tez moze miec turbo if( Vehicle.TurboTest > 0 ) { // udawanie turbo: - auto const pitch_diesel { Vehicle.EngineType == TEngineType::DieselEngine ? Vehicle.enrot / Vehicle.dizel_nmax : 0 }; + auto const pitch_diesel { Vehicle.EngineType == TEngineType::DieselEngine ? Vehicle.enrot / Vehicle.dizel_nmax : 1 }; auto const goalpitch { std::max( 0.025, ( engine_volume * pitch_diesel + engine_turbo.m_frequencyoffset ) * engine_turbo.m_frequencyfactor ) }; auto const goalvolume { ( ( ( Vehicle.MainCtrlPos >= Vehicle.TurboTest ) && ( Vehicle.enrot > 0.1 ) ) ? From b1d9c9db46edc1ce103674390ef12506ab2c98b2 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 5 Jun 2019 02:51:44 +0200 Subject: [PATCH 04/13] build 190604. vehicle device startup ai logic tweaks --- Driver.cpp | 29 +++++++++++++++++++++-------- version.h | 2 +- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index dec7cc3b..6604fa24 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2133,7 +2133,10 @@ bool TController::CheckVehicles(TOrders user) // NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly p->MoverParameters->BatterySwitch( true ); } - // enable heating and converter in carriages with can be heated + } + // enable heating and converter in carriages with can be heated + // NOTE: don't touch the controlled vehicle, let the user/ai handle it explicitly + if( p->MoverParameters != mvControlling ) { if( p->MoverParameters->HeatingPower > 0 ) { p->MoverParameters->HeatingAllow = true; p->MoverParameters->ConverterSwitch( true, range_t::local ); @@ -2529,14 +2532,14 @@ bool TController::PrepareEngine() } else { OK = ( OrderDirectionChange( iDirection, mvOccupied ) == -1 ); - mvOccupied->ConverterSwitch( true ); + mvControlling->ConverterSwitch( true ); // w EN57 sprężarka w ra jest zasilana z silnikowego - mvOccupied->CompressorSwitch( true ); + mvControlling->CompressorSwitch( true ); // enable motor blowers - mvOccupied->MotorBlowersSwitchOff( false, end::front ); - mvOccupied->MotorBlowersSwitch( true, end::front ); - mvOccupied->MotorBlowersSwitchOff( false, end::rear ); - mvOccupied->MotorBlowersSwitch( true, end::rear ); + mvControlling->MotorBlowersSwitchOff( false, end::front ); + mvControlling->MotorBlowersSwitch( true, end::front ); + mvControlling->MotorBlowersSwitchOff( false, end::rear ); + mvControlling->MotorBlowersSwitch( true, end::rear ); // enable train brake if it's off if( mvOccupied->fBrakeCtrlPos == mvOccupied->Handle->GetPos( bh_NP ) ) { mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_RP ) ); @@ -2550,6 +2553,14 @@ bool TController::PrepareEngine() if( lookup != brakepositions.end() ) { BrakeLevelSet( lookup->second ); // GBH } + // enable train heating + // HACK: to account for su-45/-46 shortcomings diesel-powered engines only activate heating in cold conditions + // TODO: take instead into account presence of converters in attached cars, once said presence is possible to specify + mvControlling->HeatingAllow = ( + ( ( mvControlling->EngineType == TEngineType::DieselElectric ) + || ( mvControlling->EngineType == TEngineType::DieselEngine ) ) ? + ( Global.AirTemperature < 10 ) : + true ); } } else @@ -2632,7 +2643,9 @@ bool TController::ReleaseEngine() { mvOccupied->OperateDoors( side::left, false ); if( true == mvControlling->Mains ) { - mvControlling->CompressorSwitch( false ); + // heating + mvControlling->HeatingAllow = false; + // devices mvControlling->ConverterSwitch( false ); // line breaker/engine OK = mvControlling->MainSwitch( false ); diff --git a/version.h b/version.h index 5424911c..41fe7b9d 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 522 +#define VERSION_MINOR 604 #define VERSION_REVISION 0 From 4ca55d7b2b5a7308176a9e6f26871836d22d47f3 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 6 Jun 2019 16:01:41 +0200 Subject: [PATCH 05/13] power grid debug panel --- Traction.cpp | 2 +- TractionPower.h | 2 ++ driveruipanels.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++++++ driveruipanels.h | 2 ++ utilities.cpp | 1 + utilities.h | 1 + 6 files changed, 54 insertions(+), 1 deletion(-) diff --git a/Traction.cpp b/Traction.cpp index 70a4f55f..d0169b95 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -528,7 +528,7 @@ glm::vec3 TTraction::wire_color() const { glm::vec3 color; - if( false == DebugModeFlag ) { + if( false == DebugTractionFlag ) { switch( Material ) { // Ra: kolory podzieliłem przez 2, bo po zmianie ambient za jasne były // trzeba uwzględnić kierunek świecenia Słońca - tylko ze Słońcem widać kolor case 1: { diff --git a/TractionPower.h b/TractionPower.h index f19a087f..171f2879 100644 --- a/TractionPower.h +++ b/TractionPower.h @@ -15,6 +15,8 @@ http://mozilla.org/MPL/2.0/. class TTractionPowerSource : public scene::basic_node { + friend class debug_panel; + public: // constructor TTractionPowerSource( scene::node_data const &Nodedata ); diff --git a/driveruipanels.cpp b/driveruipanels.cpp index a748ec80..ecec98d7 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/. #include "simulationtime.h" #include "Timer.h" #include "Event.h" +#include "TractionPower.h" #include "Camera.h" #include "mtable.h" #include "Train.h" @@ -476,6 +477,7 @@ debug_panel::update() { m_scantablelines.clear(); m_scenariolines.clear(); m_eventqueuelines.clear(); + m_powergridlines.clear(); m_cameralines.clear(); m_rendererlines.clear(); @@ -485,6 +487,7 @@ debug_panel::update() { update_section_scantable( m_scantablelines ); update_section_scenario( m_scenariolines ); update_section_eventqueue( m_eventqueuelines ); + update_section_powergrid( m_powergridlines ); update_section_camera( m_cameralines ); update_section_renderer( m_rendererlines ); } @@ -526,6 +529,10 @@ debug_panel::render() { // event queue filter ImGui::Checkbox( "By This Vehicle Only", &m_eventqueueactivevehicleonly ); } + if( true == render_section( "Power Grid", m_powergridlines ) ) { + // traction state debug + ImGui::Checkbox( "Debug Traction", &DebugTractionFlag ); + } render_section( "Camera", m_cameralines ); render_section( "Gfx Renderer", m_rendererlines ); // toggles @@ -984,6 +991,46 @@ debug_panel::update_section_eventqueue( std::vector &Output ) { } } +void +debug_panel::update_section_powergrid( std::vector &Output ) { + + auto const lowpowercolor { glm::vec4( 164.0f / 255.0f, 132.0f / 255.0f, 84.0f / 255.0f, 1.f ) }; + auto const nopowercolor { glm::vec4( 164.0f / 255.0f, 84.0f / 255.0f, 84.0f / 255.0f, 1.f ) }; + + Output.emplace_back( "Name: Output: Timeout:", Global.UITextColor ); + + std::string textline; + + for( auto const *powerstation : simulation::Powergrid.sequence() ) { + + if( true == powerstation->bSection ) { continue; } + + auto const name { ( + powerstation->m_name.empty() ? + "(unnamed)" : + powerstation->m_name ) + + " " }; + + textline = + name.substr( 0, 20 ) + + " " + to_string( powerstation->OutputVoltage, 0, 5 ) + + " " + to_string( powerstation->FuseTimer, 1, 12 ) + + ( powerstation->FuseCounter == 0 ? + "" : + " (x" + to_string( powerstation->FuseCounter ) + ")" ); + + Output.emplace_back( + textline, + ( ( powerstation->FastFuse || powerstation->SlowFuse ) ? nopowercolor : + powerstation->OutputVoltage < ( 0.8 * powerstation->NominalVoltage ) ? lowpowercolor : + Global.UITextColor ) ); + } + + if( Output.size() == 1 ) { + Output.front().data = "(no power stations)"; + } +} + void debug_panel::update_section_camera( std::vector &Output ) { diff --git a/driveruipanels.h b/driveruipanels.h index 7c075562..ddd4eff2 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -87,6 +87,7 @@ private: void update_section_scantable( std::vector &Output ); void update_section_scenario( std::vector &Output ); void update_section_eventqueue( std::vector &Output ); + void update_section_powergrid( std::vector &Output ); void update_section_camera( std::vector &Output ); void update_section_renderer( std::vector &Output ); // section update helpers @@ -105,6 +106,7 @@ private: m_cameralines, m_scenariolines, m_eventqueuelines, + m_powergridlines, m_rendererlines; int tprev { 0 }; // poprzedni czas double VelPrev { 0.0 }; // poprzednia prędkość diff --git a/utilities.cpp b/utilities.cpp index 4c9953b1..5393d28e 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -31,6 +31,7 @@ bool DebugModeFlag = false; bool FreeFlyModeFlag = false; bool EditorModeFlag = false; bool DebugCameraFlag = false; +bool DebugTractionFlag = false; double Max0R(double x1, double x2) { diff --git a/utilities.h b/utilities.h index 1c930f7a..85734f37 100644 --- a/utilities.h +++ b/utilities.h @@ -38,6 +38,7 @@ extern bool DebugModeFlag; extern bool FreeFlyModeFlag; extern bool EditorModeFlag; extern bool DebugCameraFlag; +extern bool DebugTractionFlag; /*funkcje matematyczne*/ double Max0R(double x1, double x2); From 32ca2b76ff2e5e20ef083afd5c4b6262c6069edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Thu, 6 Jun 2019 08:55:37 +0200 Subject: [PATCH 06/13] Working retarder for DieselEngine --- McZapkie/MOVER.h | 1 + McZapkie/Mover.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ driveruipanels.cpp | 6 +++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index a286f238..8bfb28d4 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -1544,6 +1544,7 @@ public: bool dizel_AutoGearCheck(void); double dizel_fillcheck(int mcp); double dizel_Momentum(double dizel_fill, double n, double dt); + double dizel_MomentumRetarder(double n, double dt); // moment hamowania retardera void dizel_HeatSet( float const Value ); void dizel_Heat( double const dt ); bool dizel_StartupCheck(); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 624bf0db..f10bf5e2 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -4750,6 +4750,8 @@ double TMoverParameters::TractionForce( double dt ) { { Mm = dmoment; //bylo * dizel_engage Mw = Mm * dtrans; // dmoment i dtrans policzone przy okazji enginerotation + if ((hydro_R) && (hydro_R_Placement == 0)) + Mw -= dizel_MomentumRetarder(nrot * Transmision.Ratio, dt) * Transmision.Ratio; Fw = Mw * 2.0 / WheelDiameter / NPoweredAxles; Ft = Fw * NPoweredAxles; // sila trakcyjna Ft = Ft * DirAbsolute; // ActiveDir*CabNo; @@ -6500,6 +6502,8 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) if( enrot > 0 ) { Moment = ( dizel_Mmax - ( dizel_Mmax - dizel_Mnmax ) * square( ( enrot - dizel_nMmax ) / ( dizel_nMmax - dizel_nmax ) ) ) * dizel_fill - dizel_Mstand; + if ((hydro_R) && (hydro_R_Placement == 2)) + Moment -= dizel_MomentumRetarder(enrot, dt); } else { Moment = -dizel_Mstand; @@ -6619,6 +6623,8 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) double enrot_max = enrot + (Min0R(TorqueC, TorqueL + abs(hydro_TC_TorqueIn)) + Moment) / dizel_AIM * dt; enrot = clamp(n,enrot_min,enrot_max); } + if ((hydro_R) && (hydro_R_Placement == 1)) + gearMoment -= dizel_MomentumRetarder(hydro_TC_nOut, dt); if( ( enrot <= 0 ) && ( false == dizel_spinup ) ) { @@ -6631,6 +6637,40 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) return gearMoment; } +double TMoverParameters::dizel_MomentumRetarder(double n, double dt) +{ + double RetarderRequest = (Mains ? std::max(0.0, -eimic_real) : 0); + if (Vel < hydro_R_MinVel) + RetarderRequest = 0; + if ((hydro_R_Placement == 2) && (enrot < dizel_nmin)) + { + RetarderRequest = 0; + } + + hydro_R_n = n * 60; + + if (hydro_R_Fill < RetarderRequest) //gdy zadane hamowanie + { + hydro_R_Fill = std::min(hydro_R_Fill + hydro_R_FillRateInc*dt, RetarderRequest); + } + else + { + hydro_R_Fill = std::max(hydro_R_Fill - hydro_R_FillRateDec*dt, RetarderRequest); + } + + double Moment = hydro_R_MaxTorque; + double pwr = Moment * n * M_PI * 2 * 0.001; + if (pwr > hydro_R_MaxPower) + Moment = Moment * hydro_R_MaxPower / pwr; + double moment_in = n*n*hydro_R_TorqueInIn; + Moment = std::min(moment_in, Moment * hydro_R_Fill); + + hydro_R_Torque = Moment; + + return Moment; + +} + // sets component temperatures to specified value void TMoverParameters::dizel_HeatSet( float const Value ) { diff --git a/driveruipanels.cpp b/driveruipanels.cpp index ecec98d7..6ba9018e 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -806,7 +806,11 @@ debug_panel::update_section_engine( std::vector &Output ) { { "hTCTI: ", mover.hydro_TC_TorqueIn }, { "hTCTO: ", mover.hydro_TC_TorqueOut }, { "hTCfl: ", mover.hydro_TC_Fill }, - { "hTCLR: ", mover.hydro_TC_LockupRate } }; + { "hRtFl: ", mover.hydro_R_Fill } , + { " hRtn: ", mover.hydro_R_n } , + { "hRtTq: ", mover.hydro_R_Torque } + + }; for( auto const ¶meter : hydrovalues ) { parameterstext += "\n" + parameter.first + to_string( parameter.second, 2, 9 ); } From 85d810b330ebd36283b5b93bfd4397b5aee7b513 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Thu, 13 Jun 2019 01:38:20 +0200 Subject: [PATCH 07/13] configurable pantograph compressor valve type, power coupler state calculation fixes, vehicle heating system enhancements, fiz file parser enhancement, debug ui panel enhancements, delayed door closing cab switch type --- Driver.cpp | 2 +- DynObj.cpp | 5 +- Gauge.cpp | 1 + Gauge.h | 3 +- McZapkie/MOVER.h | 7 +- McZapkie/Mover.cpp | 219 +++++++++++++++++++++++++-------------------- Train.cpp | 13 ++- driveruipanels.cpp | 9 +- translation.cpp | 4 +- version.h | 2 +- 10 files changed, 152 insertions(+), 113 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 6604fa24..ca721562 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2459,7 +2459,7 @@ bool TController::PrepareEngine() mvOccupied->PantRear( true ); if (mvControlling->PantPress < 4.2) { // załączenie małej sprężarki - if( mvControlling->TrainType != dt_EZT ) { + if( false == mvControlling->PantAutoValve ) { // odłączenie zbiornika głównego, bo z nim nie da rady napompować mvControlling->bPantKurek3 = false; } diff --git a/DynObj.cpp b/DynObj.cpp index 2dc302c9..d77bb599 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2702,10 +2702,11 @@ bool TDynamicObject::Update(double dt, double dt1) if (v == 0.0) { v = MoverParameters->PantFrontVolt; if( v == 0.0 ) { - if( MoverParameters->TrainType & ( dt_EZT | dt_ET40 | dt_ET41 | dt_ET42 ) ) { +// if( MoverParameters->TrainType & ( dt_EZT | dt_ET40 | dt_ET41 | dt_ET42 ) ) { // dwuczłony mogą mieć sprzęg WN + // NOTE: condition disabled, other vehicles types can have power cables as well v = MoverParameters->GetTrainsetVoltage(); // ostatnia szansa - } +// } } } if (v != 0.0) diff --git a/Gauge.cpp b/Gauge.cpp index 0ee74581..c135e18f 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -183,6 +183,7 @@ TGauge::Load_mapping( cParser &Input ) { m_type = ( gaugetype == "impulse" ? TGaugeType::push : gaugetype == "return" ? TGaugeType::push : + gaugetype == "delayed" ? TGaugeType::push_delayed : TGaugeType::toggle ); // default } else if( key == "soundinc:" ) { diff --git a/Gauge.h b/Gauge.h index 0a84d5d9..6d36b67c 100644 --- a/Gauge.h +++ b/Gauge.h @@ -23,7 +23,8 @@ enum class TGaugeAnimation { enum class TGaugeType { toggle, - push + push, + push_delayed }; // animowany wskaźnik, mogący przyjmować wiele stanów pośrednich diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 8bfb28d4..6968475b 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -618,7 +618,8 @@ enum class TCouplerType { NoCoupler, Articulated, Bare, Chain, Screw, Automatic struct power_coupling { double current{ 0.0 }; double voltage{ 0.0 }; - bool local{ false }; // whether the power comes from external or onboard source + bool is_local{ false }; // whether the power comes from external or onboard source + bool is_live{ false }; // whether the coupling with next vehicle is live }; struct TCoupling { @@ -1369,6 +1370,7 @@ public: double fBrakeCtrlPos = -2.0; // płynna nastawa hamulca zespolonego bool bPantKurek3 = true; // kurek trójdrogowy (pantografu): true=połączenie z ZG, false=połączenie z małą sprężarką // domyślnie zbiornik pantografu połączony jest ze zbiornikiem głównym + bool PantAutoValve { false }; // type of installed pantograph compressor valve int iProblem = 0; // flagi problemów z taborem, aby AI nie musiało porównywać; 0=może jechać int iLights[2]; // bity zapalonych świateł tutaj, żeby dało się liczyć pobór prądu @@ -1502,7 +1504,8 @@ public: bool CompressorSwitch( bool State, range_t const Notify = range_t::consist );/*! wl/wyl sprezarki*/ /*-funkcje typowe dla lokomotywy elektrycznej*/ - void ConverterCheck( double const Timestep ); // przetwornica + void PowerCouplersCheck( double const Deltatime ); + void ConverterCheck( double const Timestep ); // przetwornica void HeatingCheck( double const Timestep ); void WaterPumpCheck( double const Timestep ); void WaterHeaterCheck( double const Timestep ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index f10bf5e2..44ea1490 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -673,7 +673,7 @@ void TMoverParameters::UpdatePantVolume(double dt) // Ra 2014-07: kurek trójdrogowy łączy spr.pom. z pantografami i wyłącznikiem ciśnieniowym WS // Ra 2014-07: zbiornika rozrządu nie pompuje się tu, tylko pantografy; potem można zamknąć // WS i odpalić resztę - if ((TrainType == dt_EZT) ? + if (PantAutoValve ? (PantPress < ScndPipePress) : bPantKurek3) // kurek zamyka połączenie z ZG { // zbiornik pantografu połączony ze zbiornikiem głównym - małą sprężarką się tego nie napompuje @@ -1070,85 +1070,6 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap const double Vepsilon = 1e-5; const double Aepsilon = 1e-3; // ASBSpeed=0.8; - // T_MoverParameters::ComputeMovement(dt, dt1, Shape, Track, ElectricTraction, NewLoc, NewRot); - // // najpierw kawalek z funkcji w pliku mover.pas - TotalCurrent = 0; - double hvc = - std::max( - std::max( - PantFrontVolt, - PantRearVolt ), - ElectricTraction.TractionVoltage * 0.9 ); - - for( int side = 0; side < 2; ++side ) { - // przekazywanie napiec - auto const oppositeside { ( side == end::front ? end::rear : end::front ) }; - auto const liveconnection{ - ( Couplers[ side ].CouplingFlag & ctrain_power ) - || ( ( Couplers[ side ].CouplingFlag & ctrain_heating ) - && ( Couplers[ side ].Connected->Heating ) ) }; - - if( liveconnection ) { - auto const &connectedcoupler = Couplers[ side ].Connected->Couplers[ Couplers[ side ].ConnectedNr ]; - Couplers[ oppositeside ].power_high.voltage = - std::max( - std::abs( hvc ), - connectedcoupler.power_high.voltage - Couplers[ side ].power_high.current * 0.02 ); - } - else { - Couplers[ oppositeside ].power_high.voltage = std::abs( hvc ) - Couplers[ side ].power_high.current * 0.02; - } - } - - hvc = Couplers[ end::front ].power_high.voltage + Couplers[ end::rear ].power_high.voltage; - - if( std::abs( PantFrontVolt ) + std::abs( PantRearVolt ) < 1.0 ) { - // bez napiecia... - if( hvc != 0.0 ) { - // ...ale jest cos na sprzegach: - // przekazywanie pradow - for( int side = 0; side < 2; ++side ) { - - Couplers[ side ].power_high.local = false; // power, if any, will be from external source - - if( ( Couplers[ side ].CouplingFlag & ctrain_power ) - || ( ( Couplers[ side ].CouplingFlag & ctrain_heating ) - && ( Couplers[ side ].Connected->Heating ) ) ) { - auto const &connectedcoupler = - Couplers[ side ].Connected->Couplers[ - ( Couplers[ side ].ConnectedNr == end::front ? - end::rear : - end::front ) ]; - Couplers[ side ].power_high.current = - connectedcoupler.power_high.current - + Itot * Couplers[ side ].power_high.voltage / hvc; // obciążenie rozkladane stosownie do napiec - } - else { - Couplers[ side ].power_high.current = Itot * Couplers[ side ].power_high.voltage / hvc; - } - } - } - } - else - { - for( int side = 0; side < 2; ++side ) { - - Couplers[ side ].power_high.local = true; // power is coming from local pantographs - - if( ( Couplers[ side ].CouplingFlag & ctrain_power ) - || ( ( Couplers[ side ].CouplingFlag & ctrain_heating ) - && ( Couplers[ side ].Connected->Heating ) ) ) { - auto const &connectedcoupler = - Couplers[ side ].Connected->Couplers[ - ( Couplers[ side ].ConnectedNr == end::front ? - end::rear : - end::front ) ]; - TotalCurrent += connectedcoupler.power_high.current; - Couplers[ side ].power_high.current = 0.0; - } - } - } - if (!TestFlag(DamageFlag, dtrain_out)) { // Ra: to przepisywanie tu jest bez sensu RunningShape = Shape; @@ -1399,6 +1320,10 @@ void TMoverParameters::compute_movement_( double const Deltatime ) { SetFlag( SoundFlag, sound::relay ); } } + + // TODO: gather and move current calculations to dedicated method + TotalCurrent = 0; + // traction motors MotorBlowersCheck( Deltatime ); // uklady hamulcowe: @@ -1436,6 +1361,81 @@ void TMoverParameters::compute_movement_( double const Deltatime ) { BrakeSlippingTimer += Deltatime; // automatic doors update_doors( Deltatime ); + + PowerCouplersCheck( Deltatime ); +} + +void TMoverParameters::PowerCouplersCheck( double const Deltatime ) { + + // TODO: add support for other power sources + auto const localpowersource { ( std::abs( PantFrontVolt ) + std::abs( PantRearVolt ) > 1.0 ) }; + + auto hvc = std::max( PantFrontVolt, PantRearVolt ); + + // przekazywanie napiec + for( auto side = 0; side < 2; ++side ) { + + auto &coupler { Couplers[ side ] }; + // NOTE: in the loop we actually update the state of the coupler on the opposite end of the vehicle + auto &oppositecoupler { Couplers[ ( side == end::front ? end::rear : end::front ) ] }; + auto const oppositehighvoltagecoupling { ( oppositecoupler.CouplingFlag & coupling::highvoltage ) != 0 }; + auto const oppositeheatingcoupling { ( oppositecoupler.CouplingFlag & coupling::heating ) != 0 }; + + // start with base voltage + oppositecoupler.power_high.voltage = std::abs( hvc ); + oppositecoupler.power_high.is_live = false; + oppositecoupler.power_high.is_local = localpowersource; // indicate power source + // draw from external source + if( coupler.Connected != nullptr ) { + auto const &connectedcoupler { coupler.Connected->Couplers[ coupler.ConnectedNr ] }; + auto const connectedvoltage { ( + connectedcoupler.power_high.is_live ? + connectedcoupler.power_high.voltage : + 0.0 ) }; + oppositecoupler.power_high.voltage = std::max( + oppositecoupler.power_high.voltage, + connectedvoltage - coupler.power_high.current * 0.02 ); + oppositecoupler.power_high.is_live = + ( connectedvoltage > 0.1 ) + && ( oppositehighvoltagecoupling || oppositeheatingcoupling ); + } + // draw from local source + if( localpowersource ) { + auto const localvoltage { std::abs( hvc ) }; + oppositecoupler.power_high.voltage = std::max( + oppositecoupler.power_high.voltage, + localvoltage - coupler.power_high.current * 0.02 ); + oppositecoupler.power_high.is_live |= + ( localvoltage > 0.1 ) + && ( oppositehighvoltagecoupling || ( oppositeheatingcoupling && localpowersource && Heating ) ); + } + } + + // przekazywanie pradow + hvc = Couplers[ end::front ].power_high.voltage + Couplers[ end::rear ].power_high.voltage; + + for( auto side = 0; side < 2; ++side ) { + + auto &coupler { Couplers[ side ] }; + auto const &connectedothercoupler { coupler.Connected->Couplers[ ( coupler.ConnectedNr == end::front ? end::rear : end::front ) ] }; + + coupler.power_high.current = 0.0; + if( false == localpowersource ) { + // bez napiecia... + if( hvc != 0.0 ) { + // ...ale jest cos na sprzegach: + coupler.power_high.current = ( Itot + TotalCurrent ) * coupler.power_high.voltage / hvc; // obciążenie rozkladane stosownie do napiec + if( true == coupler.power_high.is_live ) { + coupler.power_high.current += connectedothercoupler.power_high.current; + } + } + } + else { + if( true == coupler.power_high.is_live ) { + TotalCurrent += connectedothercoupler.power_high.current; + } + } + } } double TMoverParameters::ShowEngineRotation(int VehN) @@ -1492,12 +1492,24 @@ void TMoverParameters::ConverterCheck( double const Timestep ) { // heating system status check void TMoverParameters::HeatingCheck( double const Timestep ) { - Heating = ( - ( true == HeatingAllow ) + auto const heatingpowerthreshold { 0.1 }; + + auto const voltage { ( // powered vehicles are generally required to activate their power source to provide heating // passive vehicles get a pass in this regard - && ( ( Power < 0.1 ) - || ( true == Mains ) ) ); + Power < 0.1 ? + GetTrainsetVoltage() : + ( true == Mains ? + Voltage : + GetTrainsetVoltage() ) ) }; + + Heating = ( + ( true == HeatingAllow ) + && ( std::abs( voltage ) > heatingpowerthreshold ) ); + + if( Heating ) { + TotalCurrent += 1000 * HeatingPower / voltage; // heater power cost presumably specified in kilowatts + } } // water pump status check @@ -3882,7 +3894,6 @@ void TMoverParameters::ComputeConstans(void) double BearingF, RollF, HideModifier; double Curvature; // Ra 2014-07: odwrotność promienia - TotalCurrent = 0; // Ra 2014-04: tu zerowanie, aby EZT mogło pobierać prąd innemu członowi TotalMass = ComputeMass(); TotalMassxg = TotalMass * g; // TotalMass*g BearingF = 2.0 * (DamageFlag && dtrain_bearing); @@ -4021,9 +4032,10 @@ void TMoverParameters::ComputeTotalForce(double dt) { else Voltage = RunningTraction.TractionVoltage * DirAbsolute; // ActiveDir*CabNo; } // bo nie dzialalo + // TODO: clean up this elseif to match changes in power coupling code else if( ( EngineType == TEngineType::ElectricInductionMotor ) || ( ( ( Couplers[ end::front ].CouplingFlag & ctrain_power ) == ctrain_power ) - || ( ( Couplers[ end::rear ].CouplingFlag & ctrain_power ) == ctrain_power ) ) ) { + || ( ( Couplers[ end::rear ].CouplingFlag & ctrain_power ) == ctrain_power ) ) ) { // potem ulepszyc! pantogtrafy! Voltage = std::max( @@ -4413,7 +4425,7 @@ double TMoverParameters::TractionForce( double dt ) { tmp = DElist[ MainCtrlPos ].RPM / 60.0; - if( ( true == Heating ) + if( ( true == HeatingAllow ) && ( HeatingPower > 0 ) && ( EngineHeatingRPM > 0 ) ) { // bump engine revolutions up if needed, when heating is on @@ -5292,12 +5304,12 @@ double TMoverParameters::TractionForce( double dt ) { Im = eimv[eimv_If]; if ((eimv[eimv_Ipoj] >= 0)) Vadd *= (1.0 - 2.0 * dt); - else if ((Voltage < EnginePowerSource.CollectorParameters.MaxV)) + else if ((std::abs(Voltage) < EnginePowerSource.CollectorParameters.MaxV)) Vadd *= (1.0 - dt); else Vadd = Max0R( Vadd * (1.0 - 0.2 * dt), - 0.007 * (Voltage - (EnginePowerSource.CollectorParameters.MaxV - 100))); + 0.007 * (std::abs(Voltage) - (EnginePowerSource.CollectorParameters.MaxV - 100))); Itot = eimv[eimv_Ipoj] * (0.01 + Min0R(0.99, 0.99 - Vadd)); EnginePower = abs(eimv[eimv_Ic] * eimv[eimv_U] * NPoweredAxles) / 1000; @@ -7439,15 +7451,11 @@ double TMoverParameters::GetTrainsetVoltage(void) {//ABu: funkcja zwracajaca napiecie dla calego skladu, przydatna dla EZT return std::max( ( ( ( Couplers[end::front].Connected ) - && ( ( Couplers[ end::front ].CouplingFlag & ctrain_power ) - || ( ( Couplers[ end::front ].CouplingFlag & ctrain_heating ) - && ( Couplers[ end::front ].Connected->Heating ) ) ) ) ? + && ( Couplers[ end::front ].Connected->Couplers[ Couplers[ end::front ].ConnectedNr ].power_high.is_live ) ) ? Couplers[end::front].Connected->Couplers[ Couplers[end::front].ConnectedNr ].power_high.voltage : 0.0 ), ( ( ( Couplers[end::rear].Connected ) - && ( ( Couplers[ end::rear ].CouplingFlag & ctrain_power ) - || ( ( Couplers[ end::rear ].CouplingFlag & ctrain_heating ) - && ( Couplers[ end::rear ].Connected->Heating ) ) ) ) ? + && ( Couplers[ end::rear ].Connected->Couplers[ Couplers[ end::rear ].ConnectedNr ].power_high.is_live ) ) ? Couplers[ end::rear ].Connected->Couplers[ Couplers[ end::rear ].ConnectedNr ].power_high.voltage : 0.0 ) ); } @@ -7889,13 +7897,19 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) std::string file = chkpath + TypeName + ".fiz"; WriteLog("LOAD FIZ FROM " + file); - +/* std::ifstream in(file); if (!in.is_open()) { WriteLog("E8 - FIZ FILE NOT EXIST."); return false; } +*/ + cParser fizparser( file, cParser::buffer_FILE ); + if( false == fizparser.ok() ) { + WriteLog( "E8 - FIZ FILE NOT EXIST." ); + return false; + } ConversionError = 0; @@ -7903,8 +7917,13 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ std::unordered_map fizlines; std::string inputline; +/* while (std::getline(in, inputline)) - { +*/ + while( fizparser.ok() ) { + + inputline = fizparser.getToken( false, "\n" ); + bool comment = ( ( inputline.find('#') != std::string::npos ) || ( inputline.compare( 0, 2, "//" ) == 0 ) ); if( true == comment ) { @@ -8220,8 +8239,9 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) continue; } } // while line +/* in.close(); - +*/ // Operacje na zebranych parametrach - przypisywanie do wlasciwych zmiennych i ustawianie // zaleznosci @@ -8869,6 +8889,9 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { lookup->second : start_t::manual; } + // pantograph compressor valve + PantAutoValve = ( TrainType == dt_EZT ); // legacy code behaviour, automatic valve was initially installed in all EMUs + extract_value( PantAutoValve, "PantAutoValve", line, "" ); // fuel pump { auto lookup = starts.find( extract_value( "FuelStart", line ) ); diff --git a/Train.cpp b/Train.cpp index f171ccec..b750a4dd 100644 --- a/Train.cpp +++ b/Train.cpp @@ -4721,8 +4721,11 @@ void TTrain::OnCommand_doorcloseall( TTrain *Train, command_data const &Command if( Train->mvOccupied->Doors.has_autowarning ) { Train->mvOccupied->signal_departure( true ); } - Train->mvOccupied->OperateDoors( side::right, false ); - Train->mvOccupied->OperateDoors( side::left, false ); + if( Train->ggDoorAllOffButton.type() != TGaugeType::push_delayed ) { + // delays the action until the button is released + Train->mvOccupied->OperateDoors( side::right, false ); + Train->mvOccupied->OperateDoors( side::left, false ); + } // visual feedback Train->ggDoorLeftButton.UpdateValue( 0.0, Train->dsbSwitch ); Train->ggDoorRightButton.UpdateValue( 0.0, Train->dsbSwitch ); @@ -4730,10 +4733,14 @@ void TTrain::OnCommand_doorcloseall( TTrain *Train, command_data const &Command Train->ggDoorAllOffButton.UpdateValue( 1.0, Train->dsbSwitch ); } else if( Command.action == GLFW_RELEASE ) { - // release the button if( Train->mvOccupied->Doors.has_autowarning ) { Train->mvOccupied->signal_departure( false ); } + if( Train->ggDoorAllOffButton.type() == TGaugeType::push_delayed ) { + // now we can actually close the door + Train->mvOccupied->OperateDoors( side::right, false ); + Train->mvOccupied->OperateDoors( side::left, false ); + } // visual feedback if( Train->ggDoorAllOffButton.SubModel ) Train->ggDoorAllOffButton.UpdateValue( 0.0 ); diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 6ba9018e..56335eb9 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -589,14 +589,17 @@ debug_panel::update_section_vehicle( std::vector &Output ) { ( mover.ConvOvldFlag ? '!' : '.' ), ( mover.CompressorFlag ? 'C' : ( false == mover.CompressorAllowLocal ? '-' : ( ( mover.CompressorAllow || mover.CompressorStart == start_t::automatic ) ? 'c' : '.' ) ) ), ( mover.CompressorGovernorLock ? '!' : '.' ), + ( mover.Heating ? 'H' : ( mover.HeatingAllow ? 'h' : '.' ) ), std::string( isplayervehicle ? locale::strings[ locale::string::debug_vehicle_radio ] + ( mover.Radio ? std::to_string( m_input.train->RadioChannel() ) : "-" ) : "" ).c_str(), std::string( isdieselenginepowered ? locale::strings[ locale::string::debug_vehicle_oilpressure ] + to_string( mover.OilPump.pressure, 2 ) : "" ).c_str(), // power transfers mover.Couplers[ end::front ].power_high.voltage, mover.Couplers[ end::front ].power_high.current, - std::string( mover.Couplers[ end::front ].power_high.local ? "" : "-" ).c_str(), - std::string( vehicle.DirectionGet() ? ":<<:" : ":>>:" ).c_str(), - std::string( mover.Couplers[ end::rear ].power_high.local ? "" : "-" ).c_str(), + std::string( mover.Couplers[ end::front ].power_high.is_local ? "" : "-" ).c_str(), + std::string( vehicle.DirectionGet() ? ":<<" : ":>>" ).c_str(), + mover.Voltage, + std::string( vehicle.DirectionGet() ? "<<:" : ">>:" ).c_str(), + std::string( mover.Couplers[ end::rear ].power_high.is_local ? "" : "-" ).c_str(), mover.Couplers[ end::rear ].power_high.voltage, mover.Couplers[ end::rear ].power_high.current ); diff --git a/translation.cpp b/translation.cpp index fe0df205..631b79a4 100644 --- a/translation.cpp +++ b/translation.cpp @@ -70,7 +70,7 @@ init() { "Name: %s%s\nLoad: %.0f %s\nStatus: %s%s\nCouplers:\n front: %s\n rear: %s", ", owned by: ", "none", - "Devices: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nPower transfers: %.0f@%.0f%s%s%s%.0f@%.0f", + "Devices: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nPower transfers: %.0f@%.0f%s%s[%.0f]%s%s%.0f@%.0f", " radio: ", " oil pressure: ", "Controllers:\n master: %d(%d), secondary: %s\nEngine output: %.1f, current: %.0f\nRevolutions:\n engine: %.0f, motors: %.0f\n engine fans: %.0f, motor fans: %.0f+%.0f, cooling fans: %.0f+%.0f", @@ -236,7 +236,7 @@ init() { "Nazwa: %s%s\nLadunek: %.0f %s\nStatus: %s%s\nSprzegi:\n przedni: %s\n tylny: %s", ", wlasciciel: ", "wolny", - "Urzadzenia: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nTransfer pradow: %.0f@%.0f%s%s%s%.0f@%.0f", + "Urzadzenia: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%s%s\nTransfer pradow: %.0f@%.0f%s%s[%.0f]%s%s%.0f@%.0f", " radio: ", " cisn.oleju: ", "Nastawniki:\n glowny: %d(%d), dodatkowy: %s\nMoc silnika: %.1f, prad silnika: %.0f\nObroty:\n silnik: %.0f, motory: %.0f\n went.silnika: %.0f, went.motorow: %.0f+%.0f, went.chlodnicy: %.0f+%.0f", diff --git a/version.h b/version.h index 41fe7b9d..2e2b2dc7 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 604 +#define VERSION_MINOR 610 #define VERSION_REVISION 0 From bc0267dca637c8416863346fb44b6f1221c7c2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Mon, 10 Jun 2019 19:44:23 +0200 Subject: [PATCH 08/13] UniversalControl is connected with BrakeCtrl --- Driver.cpp | 11 +++++++---- McZapkie/Mover.cpp | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index ca721562..edc3d75e 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3646,10 +3646,13 @@ void TController::CheckTimeControllers() NeutralPos = i; break; } - if ((DizelActualPercentage >= DizelPercentage_Speed) && (mvControlling->MainCtrlPos > NeutralPos)) - while (mvControlling->MainCtrlPos > NeutralPos) mvControlling->DecMainCtrl(1); - if ((DizelActualPercentage <= DizelPercentage_Speed) && (mvControlling->MainCtrlPos < NeutralPos)) - while (mvControlling->MainCtrlPos < NeutralPos) mvControlling->IncMainCtrl(1); + if (BrakeCtrlPosition < 0.1) //jesli nie hamuje + { + if ((DizelActualPercentage >= DizelPercentage_Speed) && (mvControlling->MainCtrlPos > NeutralPos)) + while (mvControlling->MainCtrlPos > NeutralPos) mvControlling->DecMainCtrl(1); + if ((DizelActualPercentage <= DizelPercentage_Speed) && (mvControlling->MainCtrlPos < NeutralPos)) + while (mvControlling->MainCtrlPos < NeutralPos) mvControlling->IncMainCtrl(1); + } } }; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 44ea1490..37d2f789 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -6128,6 +6128,19 @@ void TMoverParameters::CheckEIMIC(double dt) } break; case 3: + + if ((UniCtrlList[MainCtrlPos].mode != BrakeCtrlPos) && (MainCtrlActualPos == MainCtrlPos)) //nie było ruszane nastawnikiem tylko hamulcem + { + if (BrakeCtrlPos < UniCtrlList[MainCtrlPosNo].mode) + BrakeLevelSet(UniCtrlList[MainCtrlPosNo].mode); //przytnij z dołu + if (BrakeCtrlPos > UniCtrlList[0].mode) + BrakeLevelSet(UniCtrlList[0].mode); //przytnij z góry + while (BrakeCtrlPos > UniCtrlList[MainCtrlPos].mode) DecMainCtrl(1); //znajdź najbliższą pozycję + while (BrakeCtrlPos < UniCtrlList[MainCtrlPos].mode) IncMainCtrl(1); //znajdź najbliższą pozycję + } + else //było ruszane nastawnikiem + BrakeLevelSet(UniCtrlList[MainCtrlPos].mode); + if ((MainCtrlActualPos != MainCtrlPos) || (LastRelayTime>InitialCtrlDelay)) { eimic -= clamp(-UniCtrlList[MainCtrlPos].SetCtrlVal + eimic, 0.0, (MainCtrlActualPos == MainCtrlPos ? dt * UniCtrlList[MainCtrlPos].SpeedDown : sign(UniCtrlList[MainCtrlPos].SpeedDown) * 0.01)); //odejmuj do X @@ -6141,7 +6154,7 @@ void TMoverParameters::CheckEIMIC(double dt) LastRelayTime = 0; MainCtrlActualPos = MainCtrlPos; } - //BrakeLevelSet(UniCtrlList[MainCtrlPos].mode); + } auto const eimicpowerenabled { ( ( true == Mains ) || ( Power == 0.0 ) ) From b75a4d6075cd82b2f039c01053d61fb1a86a58c0 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Fri, 14 Jun 2019 21:30:30 +0200 Subject: [PATCH 09/13] build 190614. basic heating subsystem generator implementation --- Driver.cpp | 3 +- McZapkie/MOVER.h | 37 ++++++++--- McZapkie/Mover.cpp | 159 +++++++++++++++++++++++++++++++++++++-------- version.h | 2 +- 4 files changed, 162 insertions(+), 39 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index edc3d75e..9ebc49e5 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -5406,7 +5406,8 @@ TController::UpdateSituation(double dt) { exchangetime = std::max( exchangetime, vehicle->LoadExchangeTime() ); vehicle = vehicle->Next(); } - if( exchangetime > 0 ) { + if( ( exchangetime > 0 ) + || ( mvOccupied->Vel > 2.0 ) ) { // HACK: force timer reset if the load exchange is cancelled due to departure WaitingSet( exchangetime ); } } diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 6968475b..411d1fd6 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -387,7 +387,7 @@ struct TBrakePressure typedef std::map TBrakePressureTable; /*typy napedow*/ -enum class TEngineType { None, Dumb, WheelsDriven, ElectricSeriesMotor, ElectricInductionMotor, DieselEngine, SteamEngine, DieselElectric }; +enum class TEngineType { None, Dumb, WheelsDriven, ElectricSeriesMotor, ElectricInductionMotor, DieselEngine, SteamEngine, DieselElectric, Main }; /*postac dostarczanej energii*/ enum class TPowerType { NoPower, BioPower, MechPower, ElectricPower, SteamPower }; /*rodzaj paliwa*/ @@ -440,10 +440,22 @@ struct TCurrentCollector { //} }; /*typy źródeł mocy*/ -enum class TPowerSource { NotDefined, InternalSource, Transducer, Generator, Accumulator, CurrentCollector, PowerCable, Heater }; +enum class TPowerSource { NotDefined, InternalSource, Transducer, Generator, Accumulator, CurrentCollector, PowerCable, Heater, Main }; +struct engine_generator { + // ld inputs + double *engine_revolutions; // revs per second of the prime mover + // config + double revolutions_min; // min working revolutions rate, in revs per second + double revolutions_max; // max working revolutions rate, in revs per second + double voltage_min; // voltage generated at min working revolutions + double voltage_max; // voltage generated at max working revolutions + // ld outputs + double revolutions; + double voltage; +}; -struct _mover__1 +struct TAccumulator { double MaxCapacity; TPowerSource RechargeSource; @@ -453,7 +465,7 @@ struct _mover__1 //} }; -struct _mover__2 +struct TPowerCable { TPowerType PowerTrans; double SteamPressure; @@ -463,12 +475,17 @@ struct _mover__2 //} }; -struct _mover__3 +struct THeater { TGrateType Grate; TBoilerType Boiler; }; +struct TTransducer { + // ld inputs + double InputVoltage; +}; + /*parametry źródeł mocy*/ struct TPowerParameters { @@ -480,11 +497,11 @@ struct TPowerParameters { struct { - _mover__3 RHeater; + THeater RHeater; }; struct { - _mover__2 RPowerCable; + TPowerCable RPowerCable; }; struct { @@ -492,15 +509,15 @@ struct TPowerParameters }; struct { - _mover__1 RAccumulator; + TAccumulator RAccumulator; }; struct { - TEngineType GeneratorEngine; + engine_generator EngineGenerator; }; struct { - double InputVoltage; + TTransducer Transducer; }; struct { diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 37d2f789..5fed76a8 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1366,12 +1366,46 @@ void TMoverParameters::compute_movement_( double const Deltatime ) { } void TMoverParameters::PowerCouplersCheck( double const Deltatime ) { - // TODO: add support for other power sources + auto localvoltage { 0.0 }; + // heating power sources + if( Heating ) { + switch( HeatingPowerSource.SourceType ) { + case TPowerSource::Generator: { + localvoltage = HeatingPowerSource.EngineGenerator.voltage - TotalCurrent * 0.02; + break; + } + case TPowerSource::Main: { + localvoltage = ( true == Mains ? Voltage : 0.0 ); + break; + } + default: { + break; + } + } + } + // high voltage power sources + switch( EnginePowerSource.SourceType ) { + case TPowerSource::CurrentCollector: { + localvoltage = + std::max( + localvoltage, + std::max( + PantFrontVolt, + PantRearVolt ) ); + break; + } + default: { + break; + } + } + + auto const abslocalvoltage { std::abs( localvoltage ) }; + auto const localpowersource { ( abslocalvoltage > 1.0 ) }; +/* auto const localpowersource { ( std::abs( PantFrontVolt ) + std::abs( PantRearVolt ) > 1.0 ) }; - auto hvc = std::max( PantFrontVolt, PantRearVolt ); - +*/ // przekazywanie napiec for( auto side = 0; side < 2; ++side ) { @@ -1382,7 +1416,7 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) { auto const oppositeheatingcoupling { ( oppositecoupler.CouplingFlag & coupling::heating ) != 0 }; // start with base voltage - oppositecoupler.power_high.voltage = std::abs( hvc ); + oppositecoupler.power_high.voltage = abslocalvoltage; oppositecoupler.power_high.is_live = false; oppositecoupler.power_high.is_local = localpowersource; // indicate power source // draw from external source @@ -1401,18 +1435,17 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) { } // draw from local source if( localpowersource ) { - auto const localvoltage { std::abs( hvc ) }; oppositecoupler.power_high.voltage = std::max( oppositecoupler.power_high.voltage, - localvoltage - coupler.power_high.current * 0.02 ); + abslocalvoltage - coupler.power_high.current * 0.02 ); oppositecoupler.power_high.is_live |= - ( localvoltage > 0.1 ) + ( abslocalvoltage > 0.1 ) && ( oppositehighvoltagecoupling || ( oppositeheatingcoupling && localpowersource && Heating ) ); } } // przekazywanie pradow - hvc = Couplers[ end::front ].power_high.voltage + Couplers[ end::rear ].power_high.voltage; + auto couplervoltage { Couplers[ end::front ].power_high.voltage + Couplers[ end::rear ].power_high.voltage }; for( auto side = 0; side < 2; ++side ) { @@ -1422,9 +1455,9 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) { coupler.power_high.current = 0.0; if( false == localpowersource ) { // bez napiecia... - if( hvc != 0.0 ) { + if( couplervoltage != 0.0 ) { // ...ale jest cos na sprzegach: - coupler.power_high.current = ( Itot + TotalCurrent ) * coupler.power_high.voltage / hvc; // obciążenie rozkladane stosownie do napiec + coupler.power_high.current = ( Itot + TotalCurrent ) * coupler.power_high.voltage / couplervoltage; // obciążenie rozkladane stosownie do napiec if( true == coupler.power_high.is_live ) { coupler.power_high.current += connectedothercoupler.power_high.current; } @@ -1492,20 +1525,64 @@ void TMoverParameters::ConverterCheck( double const Timestep ) { // heating system status check void TMoverParameters::HeatingCheck( double const Timestep ) { + // update heating devices + // TBD, TODO: move this to a separate method? + switch( HeatingPowerSource.SourceType ) { + case TPowerSource::Generator: { + if( ( HeatingPowerSource.EngineGenerator.engine_revolutions != nullptr ) + && ( HeatingPowerSource.EngineGenerator.revolutions_max > 0 ) ) { + + auto &generator { HeatingPowerSource.EngineGenerator }; + // TBD, TODO: engine-generator transmission + generator.revolutions = *(generator.engine_revolutions); + + auto const absrevolutions { std::abs( generator.revolutions ) }; + generator.voltage = ( + absrevolutions < generator.revolutions_min ? generator.voltage_min * absrevolutions / generator.revolutions_min : +// absrevolutions > generator.revolutions_max ? generator.voltage_max * absrevolutions / generator.revolutions_max : + interpolate( + generator.voltage_min, generator.voltage_max, + clamp( + ( absrevolutions - generator.revolutions_min ) / ( generator.revolutions_max - generator.revolutions_min ), + 0.0, 1.0 ) ) ) + * sign( generator.revolutions ); + } + break; + } + default: { + break; + } + } + + // quick check first to avoid unnecessary calls... + if( false == HeatingAllow ) { + Heating = false; + return; + } + // ...detailed check if we're still here auto const heatingpowerthreshold { 0.1 }; + // start with external power sources + auto voltage { GetTrainsetVoltage() }; + // then try internal ones + auto localvoltage { 0.0 }; + switch( HeatingPowerSource.SourceType ) { + case TPowerSource::Generator: { + localvoltage = HeatingPowerSource.EngineGenerator.voltage; + break; + } + case TPowerSource::Main: { + localvoltage = ( true == Mains ? Voltage : 0.0 ); + break; + } + default: { + break; + } + } + if( std::abs( localvoltage ) > std::abs( voltage ) ) { + voltage = localvoltage; + } - auto const voltage { ( - // powered vehicles are generally required to activate their power source to provide heating - // passive vehicles get a pass in this regard - Power < 0.1 ? - GetTrainsetVoltage() : - ( true == Mains ? - Voltage : - GetTrainsetVoltage() ) ) }; - - Heating = ( - ( true == HeatingAllow ) - && ( std::abs( voltage ) > heatingpowerthreshold ) ); + Heating = ( std::abs( voltage ) > heatingpowerthreshold ); if( Heating ) { TotalCurrent += 1000 * HeatingPower / voltage; // heater power cost presumably specified in kilowatts @@ -9003,12 +9080,13 @@ void TMoverParameters::LoadFIZ_Power( std::string const &Line ) { EnginePowerSource.SourceType = LoadFIZ_SourceDecode( extract_value( "EnginePower", Line ) ); LoadFIZ_PowerParamsDecode( EnginePowerSource, "", Line ); - +/* if( ( EnginePowerSource.SourceType == TPowerSource::Generator ) && ( EnginePowerSource.GeneratorEngine == TEngineType::WheelsDriven ) ) { // perpetuum mobile? ConversionError = 666; } +*/ if( Power == 0.0 ) { //jeśli nie ma mocy, np. rozrządcze EZT EnginePowerSource.SourceType = TPowerSource::NotDefined; @@ -9331,12 +9409,31 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet } case TPowerSource::Transducer: { - extract_value( Powerparameters.InputVoltage, Prefix + "TransducerInputV", Line, "" ); + extract_value( Powerparameters.Transducer.InputVoltage, Prefix + "TransducerInputV", Line, "" ); break; } case TPowerSource::Generator: { + // prime mover for the generator + auto &generatorparameters { Powerparameters.EngineGenerator }; - Powerparameters.GeneratorEngine = LoadFIZ_EngineDecode( extract_value( Prefix + "GeneratorEngine", Line ) ); + auto const enginetype { LoadFIZ_EngineDecode( extract_value( Prefix + "GeneratorEngine", Line ) ) }; + if( enginetype == TEngineType::Main ) { + generatorparameters.engine_revolutions = &enrot; + } + else { + // TODO: for engine types other than Main create requested engine object and link to its revolutions + generatorparameters.engine_revolutions = nullptr; + generatorparameters.revolutions = 0; + generatorparameters.voltage = 0; + } + // config + extract_value( generatorparameters.voltage_min, Prefix + "GeneratorMinVoltage", Line, "0" ); + extract_value( generatorparameters.voltage_max, Prefix + "GeneratorMaxVoltage", Line, "0" ); + // NOTE: for consistency the fiz file specifies revolutions per minute + extract_value( generatorparameters.revolutions_min, Prefix + "GeneratorMinRPM", Line, "0" ); + extract_value( generatorparameters.revolutions_max, Prefix + "GeneratorMaxRPM", Line, "0" ); + generatorparameters.revolutions_min /= 60; + generatorparameters.revolutions_max /= 60; break; } case TPowerSource::Accumulator: { @@ -9422,7 +9519,8 @@ TPowerSource TMoverParameters::LoadFIZ_SourceDecode( std::string const &Source ) { "CurrentCollector", TPowerSource::CurrentCollector }, { "PowerCable", TPowerSource::PowerCable }, { "Heater", TPowerSource::Heater }, - { "Internal", TPowerSource::InternalSource } + { "Internal", TPowerSource::InternalSource }, + { "Main", TPowerSource::Main } }; auto lookup = powersources.find( Source ); return @@ -9441,7 +9539,8 @@ TEngineType TMoverParameters::LoadFIZ_EngineDecode( std::string const &Engine ) { "Dumb", TEngineType::Dumb }, { "DieselElectric", TEngineType::DieselElectric }, { "DumbDE", TEngineType::DieselElectric }, - { "ElectricInductionMotor", TEngineType::ElectricInductionMotor } + { "ElectricInductionMotor", TEngineType::ElectricInductionMotor }, + { "Main", TEngineType::Main } }; auto lookup = enginetypes.find( Engine ); return @@ -9659,6 +9758,12 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) if( LightsPosNo > 0 ) LightsPos = LightsDefPos; + // NOTE: legacy compatibility behaviour for vehicles without defined heating power source + if( ( EnginePowerSource.SourceType == TPowerSource::CurrentCollector ) + && ( HeatingPowerSource.SourceType == TPowerSource::NotDefined ) ) { + HeatingPowerSource.SourceType = TPowerSource::Main; + } + // checking ready flag // to dac potem do init if( ReadyFlag ) // gotowy do drogi diff --git a/version.h b/version.h index 2e2b2dc7..ee544018 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 610 +#define VERSION_MINOR 614 #define VERSION_REVISION 0 From 6ba274befc7456ade4f8c88f23a0ae9aa4a4b7bc Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sat, 15 Jun 2019 18:46:59 +0200 Subject: [PATCH 10/13] basic heating power cable implementation, door permit preset logic tweaks, timetable ui panel tweaks --- McZapkie/Mover.cpp | 25 ++++++++++++++++--------- Train.cpp | 11 ++++++++++- driveruilayer.cpp | 2 +- driveruipanels.cpp | 9 ++++----- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 5fed76a8..df79b80d 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1562,25 +1562,27 @@ void TMoverParameters::HeatingCheck( double const Timestep ) { // ...detailed check if we're still here auto const heatingpowerthreshold { 0.1 }; // start with external power sources - auto voltage { GetTrainsetVoltage() }; + auto voltage { 0.0 }; // then try internal ones - auto localvoltage { 0.0 }; switch( HeatingPowerSource.SourceType ) { case TPowerSource::Generator: { - localvoltage = HeatingPowerSource.EngineGenerator.voltage; + voltage = HeatingPowerSource.EngineGenerator.voltage; + break; + } + case TPowerSource::PowerCable: { + if( HeatingPowerSource.PowerType == TPowerType::ElectricPower ) { + voltage = GetTrainsetVoltage(); + } break; } case TPowerSource::Main: { - localvoltage = ( true == Mains ? Voltage : 0.0 ); + voltage = ( true == Mains ? Voltage : 0.0 ); break; } default: { break; } } - if( std::abs( localvoltage ) > std::abs( voltage ) ) { - voltage = localvoltage; - } Heating = ( std::abs( voltage ) > heatingpowerthreshold ); @@ -7082,8 +7084,8 @@ bool TMoverParameters::ChangeDoorPermitPreset( int const Change, range_t const N Doors.permit_preset = clamp( Doors.permit_preset + Change, 0, Doors.permit_presets.size() - 1 ); auto const doors { Doors.permit_presets[ Doors.permit_preset ] }; - auto const permitleft = doors & 1; - auto const permitright = doors & 2; + auto const permitleft { ( ( doors & 1 ) != 0 ) }; + auto const permitright { ( ( doors & 2 ) != 0 ) }; PermitDoors( ( CabNo > 0 ? side::left : side::right ), permitleft, Notify ); PermitDoors( ( CabNo > 0 ? side::right : side::left ), permitright, Notify ); @@ -9763,6 +9765,11 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) && ( HeatingPowerSource.SourceType == TPowerSource::NotDefined ) ) { HeatingPowerSource.SourceType = TPowerSource::Main; } + if( ( HeatingPowerSource.SourceType == TPowerSource::NotDefined ) + && ( HeatingPower > 0 ) ) { + HeatingPowerSource.SourceType = TPowerSource::PowerCable; + HeatingPowerSource.PowerType = TPowerType::ElectricPower; + } // checking ready flag // to dac potem do init diff --git a/Train.cpp b/Train.cpp index b750a4dd..caafa3d6 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5037,6 +5037,10 @@ void TTrain::OnCommand_cabchangeforward( TTrain *Train, command_data const &Comm 1 ); } } + // HACK: match consist door permit state with the preset in the active cab + if( Train->ggDoorPermitPresetButton.SubModel != nullptr ) { + Train->mvOccupied->ChangeDoorPermitPreset( 0 ); + } } } @@ -5053,6 +5057,10 @@ void TTrain::OnCommand_cabchangebackward( TTrain *Train, command_data const &Com 1 ); } } + // HACK: match consist door permit state with the preset in the active cab + if( Train->ggDoorPermitPresetButton.SubModel != nullptr ) { + Train->mvOccupied->ChangeDoorPermitPreset( 0 ); + } } } @@ -7656,7 +7664,7 @@ void TTrain::set_cab_controls( int const Cab ) { TimetableLightActive ? 1.f : 0.f ) ); - // doors + // doors permits if( ggDoorLeftPermitButton.type() != TGaugeType::push ) { ggDoorLeftPermitButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::left : side::right ) ].open_permit ? 1.f : 0.f ); } @@ -7664,6 +7672,7 @@ void TTrain::set_cab_controls( int const Cab ) { ggDoorRightPermitButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::right : side::left ) ].open_permit ? 1.f : 0.f ); } ggDoorPermitPresetButton.PutValue( mvOccupied->Doors.permit_preset ); + // door controls ggDoorLeftButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::left : side::right ) ].is_closed ? 0.f : 1.f ); ggDoorRightButton.PutValue( mvOccupied->Doors.instances[ ( mvOccupied->ActiveCab == 1 ? side::right : side::left ) ].is_closed ? 0.f : 1.f ); // door lock diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 2f5f138e..1a3ecad7 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -35,7 +35,7 @@ driver_ui::driver_ui() { m_scenariopanel.size_max = { Global.iWindowWidth * 0.95, Global.iWindowHeight * 0.95 }; m_timetablepanel.title = locale::strings[ locale::string::driver_timetable_header ]; - m_timetablepanel.size_min = { 435, 110 }; + m_timetablepanel.size_min = { 435, 70 }; m_timetablepanel.size_max = { 435, Global.iWindowHeight * 0.95 }; m_transcriptspanel.title = locale::strings[ locale::string::driver_transcripts_header ]; diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 56335eb9..7acfad6f 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -266,23 +266,23 @@ timetable_panel::update() { auto const *table = owner->TrainTimetable(); if( table == nullptr ) { return; } - { // destination + // destination + { auto textline = Bezogonkow( owner->Relation(), true ); if( false == textline.empty() ) { textline += " (" + Bezogonkow( owner->TrainName(), true ) + ")"; } - text_lines.emplace_back( textline, Global.UITextColor ); } - { // next station + if( false == is_expanded ) { + // next station auto const nextstation = owner->NextStop(); if( false == nextstation.empty() ) { // jeśli jest podana relacja, to dodajemy punkt następnego zatrzymania auto textline = " -> " + nextstation; text_lines.emplace_back( textline, Global.UITextColor ); - text_lines.emplace_back( "", Global.UITextColor ); } } @@ -310,7 +310,6 @@ timetable_panel::update() { static_cast( consistlength ) ); text_lines.emplace_back( m_buffer.data(), Global.UITextColor ); - text_lines.emplace_back( "", Global.UITextColor ); } if( 0 == table->StationCount ) { From 66fc5ad83596bf3ed92fd2a727dfa3e6c2eff275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Sat, 15 Jun 2019 12:04:56 +0200 Subject: [PATCH 11/13] Small fix for AI driving hydrodynamic transmission with high lockup speed --- Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Driver.cpp b/Driver.cpp index 9ebc49e5..1d318d0d 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3563,7 +3563,7 @@ void TController::SetTimeControllers() break; } DizelPercentage_Speed = round(double(DizelPercentage*DesiredPercentage)); - if (VelDesired < mvControlling->hydro_TC_LockupSpeed) DizelPercentage = std::min(DizelPercentage_Speed, 1); + if (VelDesired < std::min(mvControlling->hydro_TC_LockupSpeed,mvControlling->Vmax/5)) DizelPercentage = std::min(DizelPercentage_Speed, 1); if (abs(DizelPercentage_Speed - DizelActualPercentage)>(DizelPercentage>1?3:0)) { if (((DizelPercentage_Speed == 0 && DizelActualPercentage > 10) || (DizelActualPercentage - DizelPercentage_Speed > 50)) && PosDec > 0) PosDec -= 1; //pozycję wczesniej powinno byc szybkie zejscie, jeśli trzeba From a8511c89b3add803dc2bd589934c19b005dcf9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Sat, 15 Jun 2019 17:22:45 +0200 Subject: [PATCH 12/13] Fix for fix --- Driver.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 1d318d0d..63e39402 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3552,7 +3552,6 @@ void TController::SetTimeControllers() DesiredPercentage = clamp(DesiredPercentage, 0.0, 1.0); if (VelDesired < 0.5 * mvControlling->Vmax && VelDesired - mvControlling->Vel < 10) DesiredPercentage = std::min(DesiredPercentage, 0.75); - if (VelDesired < mvControlling->hydro_TC_LockupSpeed) DizelPercentage = std::min(DizelPercentage,1); int DizelActualPercentage = 100.4 * mvControlling->eimic_real; int PosInc = mvControlling->MainCtrlPosNo; int PosDec = 0; @@ -3563,7 +3562,7 @@ void TController::SetTimeControllers() break; } DizelPercentage_Speed = round(double(DizelPercentage*DesiredPercentage)); - if (VelDesired < std::min(mvControlling->hydro_TC_LockupSpeed,mvControlling->Vmax/5)) DizelPercentage = std::min(DizelPercentage_Speed, 1); + if (VelDesired < std::min(mvControlling->hydro_TC_LockupSpeed,mvControlling->Vmax / 5)) DizelPercentage = std::min(DizelPercentage_Speed, 1); if (abs(DizelPercentage_Speed - DizelActualPercentage)>(DizelPercentage>1?3:0)) { if (((DizelPercentage_Speed == 0 && DizelActualPercentage > 10) || (DizelActualPercentage - DizelPercentage_Speed > 50)) && PosDec > 0) PosDec -= 1; //pozycję wczesniej powinno byc szybkie zejscie, jeśli trzeba From 49e34fa3d83b1b0499a072e74e7c49125979e396 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Sun, 16 Jun 2019 00:40:04 +0200 Subject: [PATCH 13/13] minor ai logic fixes --- Driver.cpp | 74 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 23 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 63e39402..a306dfba 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3546,29 +3546,56 @@ void TController::SetTimeControllers() //5.1. Digital controller in DMUs with hydro if ((mvControlling->EngineType == TEngineType::DieselEngine) && (mvControlling->EIMCtrlType == 3)) { - DizelPercentage_Speed = DizelPercentage; - double Factor = 10 * (mvControlling->Vmax) / (mvControlling->Vmax + 3*mvControlling->Vel); - double DesiredPercentage = (VelDesired > mvControlling->Vel ? (VelDesired - mvControlling->Vel) / Factor : 0); - DesiredPercentage = clamp(DesiredPercentage, 0.0, 1.0); - if (VelDesired < 0.5 * mvControlling->Vmax && VelDesired - mvControlling->Vel < 10) - DesiredPercentage = std::min(DesiredPercentage, 0.75); - int DizelActualPercentage = 100.4 * mvControlling->eimic_real; - int PosInc = mvControlling->MainCtrlPosNo; - int PosDec = 0; - for(int i=PosInc;i>=0;i--) - if ((mvControlling->UniCtrlList[i].SetCtrlVal <= 0) && (mvControlling->UniCtrlList[i].SpeedDown > 0.01)) - { - PosDec = i; - break; - } - DizelPercentage_Speed = round(double(DizelPercentage*DesiredPercentage)); - if (VelDesired < std::min(mvControlling->hydro_TC_LockupSpeed,mvControlling->Vmax / 5)) DizelPercentage = std::min(DizelPercentage_Speed, 1); - if (abs(DizelPercentage_Speed - DizelActualPercentage)>(DizelPercentage>1?3:0)) - { - if (((DizelPercentage_Speed == 0 && DizelActualPercentage > 10) || (DizelActualPercentage - DizelPercentage_Speed > 50)) && PosDec > 0) PosDec -= 1; //pozycję wczesniej powinno byc szybkie zejscie, jeśli trzeba - int DesiredPos = (DizelPercentage_Speed > DizelActualPercentage ? PosInc : PosDec); - while (mvControlling->MainCtrlPos > DesiredPos) mvControlling->DecMainCtrl(1); - while (mvControlling->MainCtrlPos < DesiredPos) mvControlling->IncMainCtrl(1); + if( mvControlling->Vel > 10 ) { + + DizelPercentage_Speed = DizelPercentage; + auto const Factor{ 10 * ( mvControlling->Vmax ) / ( mvControlling->Vmax + 3 * mvControlling->Vel ) }; + auto DesiredPercentage{ clamp( + ( VelDesired > mvControlling->Vel ? + ( VelDesired - mvControlling->Vel ) / Factor : + 0 ), + 0.0, 1.0 ) }; + if( ( VelDesired < 0.5 * mvControlling->Vmax ) + && ( VelDesired - mvControlling->Vel < 10 ) ) { + DesiredPercentage = std::min( DesiredPercentage, 0.75 ); + } + DizelPercentage_Speed = std::round( DesiredPercentage * DizelPercentage ); + if( VelDesired < std::min( mvControlling->hydro_TC_LockupSpeed, mvControlling->Vmax / 5 ) ) { + DizelPercentage = std::min( DizelPercentage_Speed, 1 ); + } + } + else { + // HACK: workaround for the default mode breaking at low speeds + DizelPercentage = DizelPercentage_Speed = ( AccDesired > 0.0 ? 100 : 0 ); + } + + auto const DizelActualPercentage { 100.4 * mvControlling->eimic_real }; + + auto const PosInc { mvControlling->MainCtrlPosNo }; + auto PosDec { 0 }; + for( int i = PosInc; i >= 0; --i ) { + if( ( mvControlling->UniCtrlList[ i ].SetCtrlVal <= 0 ) + && ( mvControlling->UniCtrlList[ i ].SpeedDown > 0.01 ) ) { + PosDec = i; + break; + } + } + + if( std::abs( DizelPercentage_Speed - DizelActualPercentage ) > ( DizelPercentage > 1 ? 3 : 0 ) ) { + + if( ( PosDec > 0 ) + && ( ( DizelActualPercentage - DizelPercentage_Speed > 50 ) + || ( ( DizelPercentage_Speed == 0 ) + && ( DizelActualPercentage > 10 ) ) ) ) { + //pozycję wczesniej powinno byc szybkie zejscie, jeśli trzeba + PosDec -= 1; + } + auto const DesiredPos { ( + DizelPercentage_Speed > DizelActualPercentage ? + PosInc : + PosDec ) }; + while( mvControlling->MainCtrlPos > DesiredPos ) { mvControlling->DecMainCtrl( 1 ); } + while( mvControlling->MainCtrlPos < DesiredPos ) { mvControlling->IncMainCtrl( 1 ); } } } else @@ -5158,6 +5185,7 @@ TController::UpdateSituation(double dt) { // za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach // powino zostać wyłączone) // WriteLog("Zahamowanie składu"); + AccDesired = std::min( AccDesired, -0.9 ); // HACK: make sure the ai doesn't try to release the brakes to accelerate if( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) { mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EPB ) ); }