mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-14 14:33:16 +01:00
Merge pull request #273 from MaSzyna-EU07/feat/6dg-power-demand-5pct-steps
6Dg: power demand in 5% steps (eu07/maszyna#412)
This commit is contained in:
@@ -1774,6 +1774,10 @@ class TMoverParameters
|
||||
bool UniCtrlIntegratedBrakeCtrl = false; /*zintegrowany nastawnik JH obsluguje hamowanie*/
|
||||
bool UniCtrlIntegratedLocalBrakeCtrl = false; /*zintegrowany nastawnik JH obsluguje hamowanie hamulcem pomocniczym*/
|
||||
int UniCtrlNoPowerPos{0}; // cached highesr position not generating traction force
|
||||
// UCList CtrlValStep: the universal controller (EIMCtrlType 3) changes its setting in steps of this size (e.g. 0.05 for the
|
||||
// 5% steps of the 6Dg), one at once when moved to a raising or lowering position, then one each time its SpeedUp / SpeedDown
|
||||
// covers a step; 0 (the default) changes it continuously
|
||||
double UniCtrlValStep{0.0};
|
||||
std::pair<std::string, std::array<int, 2>> PantsPreset{"0132", {0, 0}}; // pantograph preset switches; .first holds possible setups as chars, .second holds currently selected preset in each cab
|
||||
|
||||
/*-sekcja parametrow dla lokomotywy elektrycznej*/
|
||||
@@ -2250,6 +2254,7 @@ class TMoverParameters
|
||||
double eimic = 0; /*aktualna pozycja zintegrowanego sterowania jazda i hamowaniem*/
|
||||
double eimic_analog = 0; /*pozycja zadajnika analogowa*/
|
||||
double eimic_real = 0; /*faktycznie uzywana pozycja zintegrowanego sterowania jazda i hamowaniem*/
|
||||
double eimic_step_progress{0.0}; // the part of the next UniCtrlValStep the controller has covered so far
|
||||
double eim_localbrake = 0; /*nastawa hamowania dodatkowego pneumatycznego lokomotywy*/
|
||||
int EIMCtrlType = 0; /*rodzaj wariantu zadajnika jazdy*/
|
||||
bool SpeedCtrlTypeTime = false; /*czy tempomat sterowany czasowo*/
|
||||
|
||||
@@ -7409,6 +7409,60 @@ bool TMoverParameters::DropAllPantographs(bool const State, range_t const Notify
|
||||
return State != initialstate;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// the setting of the universal controller one UniCtrlValStep further from Value towards Limit, never past it
|
||||
double next_uc_step(double const Value, double const Limit, double const Step)
|
||||
{
|
||||
constexpr double epsilon{1e-6};
|
||||
if (Limit > Value)
|
||||
{
|
||||
return std::min((std::floor(Value / Step + epsilon) + 1.0) * Step, Limit);
|
||||
}
|
||||
return std::max((std::ceil(Value / Step - epsilon) - 1.0) * Step, Limit);
|
||||
}
|
||||
|
||||
// the universal controller with UniCtrlValStep: the setting the continuous ramp got to (Ramped) turned into whole steps.
|
||||
// a move of the controller onto a position which changes the setting makes one step at once, the ramp then one step each
|
||||
// time it covers a step's length; the steps stop at the position's set value (or its bound, past which the ramp doesn't go)
|
||||
double stepped_uc_value(double const Current, double const Ramped, TUniversalCtrl const &Position, double const Step, bool const Moved, double &Progress)
|
||||
{
|
||||
if (Moved)
|
||||
{
|
||||
Progress = 0.0;
|
||||
}
|
||||
double const delta{Ramped - Current};
|
||||
if (std::abs(delta) < 1e-9)
|
||||
{
|
||||
Progress = 0.0;
|
||||
return Ramped;
|
||||
}
|
||||
double limit{0.0};
|
||||
if (delta > 0.0)
|
||||
{
|
||||
limit = Position.SetCtrlVal > Current ? Position.SetCtrlVal : Position.MaxCtrlVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
limit = Position.SetCtrlVal < Current ? Position.SetCtrlVal : Position.MinCtrlVal;
|
||||
}
|
||||
Progress = Moved ? Step : Progress + std::abs(delta);
|
||||
double value{Current};
|
||||
bool reached{std::abs(value - limit) < 1e-9};
|
||||
while (!reached && Progress >= Step - 1e-9)
|
||||
{
|
||||
value = next_uc_step(value, limit, Step);
|
||||
Progress -= Step;
|
||||
reached = std::abs(value - limit) < 1e-9;
|
||||
}
|
||||
if (reached)
|
||||
{
|
||||
Progress = 0.0;
|
||||
}
|
||||
return safe_clamp(value, Position.MinCtrlVal, Position.MaxCtrlVal);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TMoverParameters::CheckEIMIC(double dt)
|
||||
{
|
||||
double offset = EIMCtrlAdditionalZeros ? 1.0 : 0.0;
|
||||
@@ -7533,11 +7587,14 @@ void TMoverParameters::CheckEIMIC(double dt)
|
||||
|
||||
if (MainCtrlActualPos != MainCtrlPos || LastRelayTime > InitialCtrlDelay)
|
||||
{
|
||||
eimic -= safe_clamp(-UniCtrlList[MainCtrlPos].SetCtrlVal + eimic, 0.0,
|
||||
MainCtrlActualPos == MainCtrlPos ? dt * UniCtrlList[MainCtrlPos].SpeedDown : sign(UniCtrlList[MainCtrlPos].SpeedDown) * 0.01); // odejmuj do X
|
||||
eimic += safe_clamp(UniCtrlList[MainCtrlPos].SetCtrlVal - eimic, 0.0,
|
||||
MainCtrlActualPos == MainCtrlPos ? dt * UniCtrlList[MainCtrlPos].SpeedUp : sign(UniCtrlList[MainCtrlPos].SpeedUp) * 0.01); // dodawaj do X
|
||||
eimic = safe_clamp(eimic, UniCtrlList[MainCtrlPos].MinCtrlVal, UniCtrlList[MainCtrlPos].MaxCtrlVal);
|
||||
auto const &position{UniCtrlList[MainCtrlPos]};
|
||||
double ramped{eimic};
|
||||
ramped -= safe_clamp(-position.SetCtrlVal + ramped, 0.0,
|
||||
MainCtrlActualPos == MainCtrlPos ? dt * position.SpeedDown : sign(position.SpeedDown) * 0.01); // odejmuj do X
|
||||
ramped += safe_clamp(position.SetCtrlVal - ramped, 0.0,
|
||||
MainCtrlActualPos == MainCtrlPos ? dt * position.SpeedUp : sign(position.SpeedUp) * 0.01); // dodawaj do X
|
||||
ramped = safe_clamp(ramped, position.MinCtrlVal, position.MaxCtrlVal);
|
||||
eimic = UniCtrlValStep > 0.0 ? stepped_uc_value(eimic, ramped, position, UniCtrlValStep, MainCtrlActualPos != MainCtrlPos, eimic_step_progress) : ramped;
|
||||
}
|
||||
if (MainCtrlActualPos == MainCtrlPos)
|
||||
LastRelayTime += dt;
|
||||
@@ -11765,6 +11822,8 @@ void TMoverParameters::LoadFIZ_UCList(std::string const &Input)
|
||||
extract_value(UniCtrlIntegratedBrakeCtrl, "IntegratedBrake", Input, "");
|
||||
extract_value(UniCtrlIntegratedLocalBrakeCtrl, "IntegratedLocBrake", Input, "");
|
||||
extract_value(UniCtrlIntegratedBrakePNCtrl, "IntegratedBrakePN", Input, "");
|
||||
extract_value(UniCtrlValStep, "CtrlValStep", Input, "");
|
||||
UniCtrlValStep = std::max(UniCtrlValStep, 0.0);
|
||||
}
|
||||
|
||||
void TMoverParameters::LoadFIZ_DList(std::string const &Input)
|
||||
|
||||
115
tests/unit/test_uc_steps.cpp
Normal file
115
tests/unit/test_uc_steps.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
#include "drive.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
// the universal controller (EIMCtrlType 3) setting its power demand in steps (UCList CtrlValStep), as the 6Dg does
|
||||
// in steps of 5% (eu07/maszyna#412). the 214M railbus's controller: 3 lowers the power to 0, 4 holds it, 5 raises it
|
||||
// to 1, at 0.15 a second after IniCDelay (1 s)
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int lower{3};
|
||||
constexpr int hold{4};
|
||||
constexpr int raise{5};
|
||||
|
||||
// the railbus started up, its brakes released and its direction set, its controller holding no power
|
||||
void get_ready(vehicle &Railbus, test::track const &Track) {
|
||||
auto driven{test::driving(Railbus)};
|
||||
REQUIRE(test::start_up(driven, Track));
|
||||
test::release_brakes(driven.cab);
|
||||
for (int i = 0; i < 3 && Railbus->DirActive <= 0; ++i) {
|
||||
Railbus->DirectionForward();
|
||||
}
|
||||
while (Railbus->MainCtrlPos < hold && Railbus->IncMainCtrl(1)) {
|
||||
;
|
||||
}
|
||||
while (Railbus->MainCtrlPos > hold && Railbus->DecMainCtrl(1)) {
|
||||
;
|
||||
}
|
||||
REQUIRE(Railbus->MainCtrlPos == hold);
|
||||
Railbus.run(2.0, Track);
|
||||
REQUIRE(Railbus->eimic == doctest::Approx(0.0));
|
||||
}
|
||||
|
||||
void move_to(vehicle &Railbus, int const Position) {
|
||||
while (Railbus->MainCtrlPos < Position && Railbus->IncMainCtrl(1)) {
|
||||
;
|
||||
}
|
||||
while (Railbus->MainCtrlPos > Position && Railbus->DecMainCtrl(1)) {
|
||||
;
|
||||
}
|
||||
REQUIRE(Railbus->MainCtrlPos == Position);
|
||||
}
|
||||
|
||||
bool on_step(double const Value, double const Step) {
|
||||
return std::abs(Value / Step - std::round(Value / Step)) < 1e-6;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("controls: the universal controller with CtrlValStep sets its power in whole steps") {
|
||||
test::track const line{0.15, 0.0};
|
||||
vehicle railbus{definition::fiz("21xm_v1/214ma").set("UCList", "CtrlValStep", 0.05), 0.0, "test", 1};
|
||||
REQUIRE(railbus->UniCtrlValStep == doctest::Approx(0.05));
|
||||
get_ready(railbus, line);
|
||||
|
||||
// a tap on the raising position: one step at once, kept by the holding one
|
||||
move_to(railbus, raise);
|
||||
railbus.step(line);
|
||||
CHECK(railbus->eimic == doctest::Approx(0.05));
|
||||
move_to(railbus, hold);
|
||||
railbus.run(2.0, line);
|
||||
CHECK(railbus->eimic == doctest::Approx(0.05));
|
||||
|
||||
// held there: after the initial delay a step each third of a second (0.15 a second), never in between
|
||||
move_to(railbus, raise);
|
||||
for (int i = 0; i < 310; ++i) { // 3.1 s
|
||||
railbus.step(line);
|
||||
CAPTURE(i);
|
||||
CHECK(on_step(railbus->eimic, 0.05));
|
||||
}
|
||||
// the first step at once, 1 s of the initial delay, then 2.1 s of 0.15 a second (6 steps)
|
||||
CHECK(railbus->eimic == doctest::Approx(0.40));
|
||||
move_to(railbus, hold);
|
||||
railbus.run(2.0, line);
|
||||
CHECK(railbus->eimic == doctest::Approx(0.40));
|
||||
|
||||
// up to the full power, and not past it
|
||||
move_to(railbus, raise);
|
||||
railbus.run(10.0, line);
|
||||
CHECK(railbus->eimic == doctest::Approx(1.0));
|
||||
|
||||
// down the same way: a tap is one step, holding it goes on in steps down to nothing
|
||||
move_to(railbus, lower);
|
||||
railbus.step(line);
|
||||
CHECK(railbus->eimic == doctest::Approx(0.95));
|
||||
move_to(railbus, hold);
|
||||
railbus.run(1.0, line);
|
||||
CHECK(railbus->eimic == doctest::Approx(0.95));
|
||||
move_to(railbus, lower);
|
||||
for (int i = 0; i < 800; ++i) { // 8 s
|
||||
railbus.step(line);
|
||||
CAPTURE(i);
|
||||
CHECK(on_step(railbus->eimic, 0.05));
|
||||
}
|
||||
CHECK(railbus->eimic == doctest::Approx(0.0));
|
||||
}
|
||||
|
||||
TEST_CASE("controls: the universal controller without CtrlValStep sets its power continuously, as before") {
|
||||
test::track const line{0.15, 0.0};
|
||||
vehicle railbus{definition::fiz("21xm_v1/214ma"), 0.0, "test", 1};
|
||||
REQUIRE(railbus->UniCtrlValStep == 0.0);
|
||||
get_ready(railbus, line);
|
||||
// a tap moves it by 0.01, held it goes on at 0.15 a second after the initial delay
|
||||
move_to(railbus, raise);
|
||||
railbus.step(line);
|
||||
CHECK(railbus->eimic == doctest::Approx(0.01));
|
||||
railbus.run(2.0 - 0.01, line);
|
||||
CHECK(railbus->eimic == doctest::Approx(0.01 + 0.15).epsilon(0.05));
|
||||
}
|
||||
Reference in New Issue
Block a user