16
0
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:
tmj-fstate
2019-06-14 21:30:30 +02:00
parent bc0267dca6
commit b75a4d6075
4 changed files with 162 additions and 39 deletions

View File

@@ -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 );
} }
} }

View File

@@ -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
{ {

View File

@@ -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

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 19 #define VERSION_MAJOR 19
#define VERSION_MINOR 610 #define VERSION_MINOR 614
#define VERSION_REVISION 0 #define VERSION_REVISION 0