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