mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 15:09:19 +02:00
build 190614. basic heating subsystem generator implementation
This commit is contained in:
@@ -5406,7 +5406,8 @@ TController::UpdateSituation(double dt) {
|
|||||||
exchangetime = std::max( exchangetime, vehicle->LoadExchangeTime() );
|
exchangetime = std::max( exchangetime, vehicle->LoadExchangeTime() );
|
||||||
vehicle = vehicle->Next();
|
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 );
|
WaitingSet( exchangetime );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,7 +387,7 @@ struct TBrakePressure
|
|||||||
typedef std::map<int,TBrakePressure> TBrakePressureTable;
|
typedef std::map<int,TBrakePressure> TBrakePressureTable;
|
||||||
|
|
||||||
/*typy napedow*/
|
/*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*/
|
/*postac dostarczanej energii*/
|
||||||
enum class TPowerType { NoPower, BioPower, MechPower, ElectricPower, SteamPower };
|
enum class TPowerType { NoPower, BioPower, MechPower, ElectricPower, SteamPower };
|
||||||
/*rodzaj paliwa*/
|
/*rodzaj paliwa*/
|
||||||
@@ -440,10 +440,22 @@ struct TCurrentCollector {
|
|||||||
//}
|
//}
|
||||||
};
|
};
|
||||||
/*typy źródeł mocy*/
|
/*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;
|
double MaxCapacity;
|
||||||
TPowerSource RechargeSource;
|
TPowerSource RechargeSource;
|
||||||
@@ -453,7 +465,7 @@ struct _mover__1
|
|||||||
//}
|
//}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _mover__2
|
struct TPowerCable
|
||||||
{
|
{
|
||||||
TPowerType PowerTrans;
|
TPowerType PowerTrans;
|
||||||
double SteamPressure;
|
double SteamPressure;
|
||||||
@@ -463,12 +475,17 @@ struct _mover__2
|
|||||||
//}
|
//}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _mover__3
|
struct THeater
|
||||||
{
|
{
|
||||||
TGrateType Grate;
|
TGrateType Grate;
|
||||||
TBoilerType Boiler;
|
TBoilerType Boiler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TTransducer {
|
||||||
|
// ld inputs
|
||||||
|
double InputVoltage;
|
||||||
|
};
|
||||||
|
|
||||||
/*parametry źródeł mocy*/
|
/*parametry źródeł mocy*/
|
||||||
struct TPowerParameters
|
struct TPowerParameters
|
||||||
{
|
{
|
||||||
@@ -480,11 +497,11 @@ struct TPowerParameters
|
|||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
_mover__3 RHeater;
|
THeater RHeater;
|
||||||
};
|
};
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
_mover__2 RPowerCable;
|
TPowerCable RPowerCable;
|
||||||
};
|
};
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@@ -492,15 +509,15 @@ struct TPowerParameters
|
|||||||
};
|
};
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
_mover__1 RAccumulator;
|
TAccumulator RAccumulator;
|
||||||
};
|
};
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
TEngineType GeneratorEngine;
|
engine_generator EngineGenerator;
|
||||||
};
|
};
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
double InputVoltage;
|
TTransducer Transducer;
|
||||||
};
|
};
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1366,12 +1366,46 @@ void TMoverParameters::compute_movement_( double const Deltatime ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
|
void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
|
||||||
|
|
||||||
// TODO: add support for other power sources
|
// 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 const localpowersource { ( std::abs( PantFrontVolt ) + std::abs( PantRearVolt ) > 1.0 ) };
|
||||||
|
|
||||||
auto hvc = std::max( PantFrontVolt, PantRearVolt );
|
auto hvc = std::max( PantFrontVolt, PantRearVolt );
|
||||||
|
*/
|
||||||
// przekazywanie napiec
|
// przekazywanie napiec
|
||||||
for( auto side = 0; side < 2; ++side ) {
|
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 };
|
auto const oppositeheatingcoupling { ( oppositecoupler.CouplingFlag & coupling::heating ) != 0 };
|
||||||
|
|
||||||
// start with base voltage
|
// 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_live = false;
|
||||||
oppositecoupler.power_high.is_local = localpowersource; // indicate power source
|
oppositecoupler.power_high.is_local = localpowersource; // indicate power source
|
||||||
// draw from external source
|
// draw from external source
|
||||||
@@ -1401,18 +1435,17 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
|
|||||||
}
|
}
|
||||||
// draw from local source
|
// draw from local source
|
||||||
if( localpowersource ) {
|
if( localpowersource ) {
|
||||||
auto const localvoltage { std::abs( hvc ) };
|
|
||||||
oppositecoupler.power_high.voltage = std::max(
|
oppositecoupler.power_high.voltage = std::max(
|
||||||
oppositecoupler.power_high.voltage,
|
oppositecoupler.power_high.voltage,
|
||||||
localvoltage - coupler.power_high.current * 0.02 );
|
abslocalvoltage - coupler.power_high.current * 0.02 );
|
||||||
oppositecoupler.power_high.is_live |=
|
oppositecoupler.power_high.is_live |=
|
||||||
( localvoltage > 0.1 )
|
( abslocalvoltage > 0.1 )
|
||||||
&& ( oppositehighvoltagecoupling || ( oppositeheatingcoupling && localpowersource && Heating ) );
|
&& ( oppositehighvoltagecoupling || ( oppositeheatingcoupling && localpowersource && Heating ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// przekazywanie pradow
|
// 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 ) {
|
for( auto side = 0; side < 2; ++side ) {
|
||||||
|
|
||||||
@@ -1422,9 +1455,9 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime ) {
|
|||||||
coupler.power_high.current = 0.0;
|
coupler.power_high.current = 0.0;
|
||||||
if( false == localpowersource ) {
|
if( false == localpowersource ) {
|
||||||
// bez napiecia...
|
// bez napiecia...
|
||||||
if( hvc != 0.0 ) {
|
if( couplervoltage != 0.0 ) {
|
||||||
// ...ale jest cos na sprzegach:
|
// ...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 ) {
|
if( true == coupler.power_high.is_live ) {
|
||||||
coupler.power_high.current += connectedothercoupler.power_high.current;
|
coupler.power_high.current += connectedothercoupler.power_high.current;
|
||||||
}
|
}
|
||||||
@@ -1492,20 +1525,64 @@ void TMoverParameters::ConverterCheck( double const Timestep ) {
|
|||||||
// heating system status check
|
// heating system status check
|
||||||
void TMoverParameters::HeatingCheck( double const Timestep ) {
|
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 };
|
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 { (
|
Heating = ( std::abs( voltage ) > heatingpowerthreshold );
|
||||||
// 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 ) );
|
|
||||||
|
|
||||||
if( Heating ) {
|
if( Heating ) {
|
||||||
TotalCurrent += 1000 * HeatingPower / voltage; // heater power cost presumably specified in kilowatts
|
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 ) );
|
EnginePowerSource.SourceType = LoadFIZ_SourceDecode( extract_value( "EnginePower", Line ) );
|
||||||
LoadFIZ_PowerParamsDecode( EnginePowerSource, "", Line );
|
LoadFIZ_PowerParamsDecode( EnginePowerSource, "", Line );
|
||||||
|
/*
|
||||||
if( ( EnginePowerSource.SourceType == TPowerSource::Generator )
|
if( ( EnginePowerSource.SourceType == TPowerSource::Generator )
|
||||||
&& ( EnginePowerSource.GeneratorEngine == TEngineType::WheelsDriven ) ) {
|
&& ( EnginePowerSource.GeneratorEngine == TEngineType::WheelsDriven ) ) {
|
||||||
// perpetuum mobile?
|
// perpetuum mobile?
|
||||||
ConversionError = 666;
|
ConversionError = 666;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if( Power == 0.0 ) {
|
if( Power == 0.0 ) {
|
||||||
//jeśli nie ma mocy, np. rozrządcze EZT
|
//jeśli nie ma mocy, np. rozrządcze EZT
|
||||||
EnginePowerSource.SourceType = TPowerSource::NotDefined;
|
EnginePowerSource.SourceType = TPowerSource::NotDefined;
|
||||||
@@ -9331,12 +9409,31 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet
|
|||||||
}
|
}
|
||||||
case TPowerSource::Transducer: {
|
case TPowerSource::Transducer: {
|
||||||
|
|
||||||
extract_value( Powerparameters.InputVoltage, Prefix + "TransducerInputV", Line, "" );
|
extract_value( Powerparameters.Transducer.InputVoltage, Prefix + "TransducerInputV", Line, "" );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TPowerSource::Generator: {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case TPowerSource::Accumulator: {
|
case TPowerSource::Accumulator: {
|
||||||
@@ -9422,7 +9519,8 @@ TPowerSource TMoverParameters::LoadFIZ_SourceDecode( std::string const &Source )
|
|||||||
{ "CurrentCollector", TPowerSource::CurrentCollector },
|
{ "CurrentCollector", TPowerSource::CurrentCollector },
|
||||||
{ "PowerCable", TPowerSource::PowerCable },
|
{ "PowerCable", TPowerSource::PowerCable },
|
||||||
{ "Heater", TPowerSource::Heater },
|
{ "Heater", TPowerSource::Heater },
|
||||||
{ "Internal", TPowerSource::InternalSource }
|
{ "Internal", TPowerSource::InternalSource },
|
||||||
|
{ "Main", TPowerSource::Main }
|
||||||
};
|
};
|
||||||
auto lookup = powersources.find( Source );
|
auto lookup = powersources.find( Source );
|
||||||
return
|
return
|
||||||
@@ -9441,7 +9539,8 @@ TEngineType TMoverParameters::LoadFIZ_EngineDecode( std::string const &Engine )
|
|||||||
{ "Dumb", TEngineType::Dumb },
|
{ "Dumb", TEngineType::Dumb },
|
||||||
{ "DieselElectric", TEngineType::DieselElectric },
|
{ "DieselElectric", TEngineType::DieselElectric },
|
||||||
{ "DumbDE", TEngineType::DieselElectric },
|
{ "DumbDE", TEngineType::DieselElectric },
|
||||||
{ "ElectricInductionMotor", TEngineType::ElectricInductionMotor }
|
{ "ElectricInductionMotor", TEngineType::ElectricInductionMotor },
|
||||||
|
{ "Main", TEngineType::Main }
|
||||||
};
|
};
|
||||||
auto lookup = enginetypes.find( Engine );
|
auto lookup = enginetypes.find( Engine );
|
||||||
return
|
return
|
||||||
@@ -9659,6 +9758,12 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir)
|
|||||||
if( LightsPosNo > 0 )
|
if( LightsPosNo > 0 )
|
||||||
LightsPos = LightsDefPos;
|
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
|
// checking ready flag
|
||||||
// to dac potem do init
|
// to dac potem do init
|
||||||
if( ReadyFlag ) // gotowy do drogi
|
if( ReadyFlag ) // gotowy do drogi
|
||||||
|
|||||||
Reference in New Issue
Block a user