mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-14 20:20:51 +01:00
CurrentSwitch() asked MaxCurrentSwitch() first. Since 2e86b3a5 (2021) that one
takes any change of the motor overload relay threshold, on every engine type, and
reports it, so the first move of the switch only flipped the threshold (meaningless
on a diesel) and the shunt mode of the SM42/SP42 (and the 2Ls150 gear of the SM03)
took a second one, both on and off; the cab switch, which shows the shunt mode,
didn't move at the first click. The diesels with a shunt mode now set it alone.
209 lines
8.3 KiB
C++
209 lines
8.3 KiB
C++
#include "stdafx.h"
|
|
#include "doctest.h"
|
|
#include "scenario.h"
|
|
#include "drive.h"
|
|
|
|
#include "McZapkie/hamulce.h"
|
|
|
|
// characterisation of the diesel engines besides their drive, recorded in golden traces (data/golden/diesel/):
|
|
// the heat of the engine, its oil and its water circuits, which keep a too cold or too hot engine from starting
|
|
|
|
using test::scenario;
|
|
using namespace test::channels;
|
|
|
|
namespace {
|
|
|
|
std::vector<test::channel> heat() {
|
|
return {
|
|
{"Ts", [](auto const &M) { return M.dizel_heat.Ts; }},
|
|
{"To", [](auto const &M) { return M.dizel_heat.To; }},
|
|
{"Twy", [](auto const &M) { return M.dizel_heat.Twy; }},
|
|
{"Twy2", [](auto const &M) { return M.dizel_heat.Twy2; }},
|
|
{"PA", [](auto const &M) { return M.dizel_heat.PA ? 1.0 : 0.0; }},
|
|
{"WaterHeater", [](auto const &M) { return M.WaterHeater.is_active ? 1.0 : 0.0; }},
|
|
{"WaterPump", [](auto const &M) { return M.WaterPump.is_active ? 1.0 : 0.0; }},
|
|
{"zaluzje1", [](auto const &M) { return M.dizel_heat.zaluzje1 ? 1.0 : 0.0; }},
|
|
{"zaluzje2", [](auto const &M) { return M.dizel_heat.zaluzje2 ? 1.0 : 0.0; }},
|
|
};
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_CASE("diesel: an engine too cold to start, warmed by its heater") {
|
|
// at -10 degrees an engine with the lowest temperature of its water set (WaterMinTemperature) doesn't start,
|
|
// until the heater, which the driver switches on with the pumps, warms the water up; one without starts
|
|
struct engine {
|
|
char const *path;
|
|
bool starts; // cold
|
|
};
|
|
for (auto const &[path, starts] : {engine{"su45_v2/301d", false}, engine{"sm42_v1/6d1", false}, engine{"st44_v2/m62-1151", true}}) {
|
|
CAPTURE(path);
|
|
scenario scenario{std::string{"diesel/cold/"} + path, traction() + heat(), test::track{}};
|
|
scenario.add(path, 1);
|
|
auto &locomotive{scenario.cab()};
|
|
locomotive.dizel_HeatSet(-10.f);
|
|
CHECK(scenario.start_up() == starts);
|
|
CHECK(locomotive.dizel_heat.PA != starts);
|
|
CHECK(locomotive.WaterHeater.is_active);
|
|
scenario.act("heating");
|
|
scenario.wait(1200.0);
|
|
CHECK_FALSE(locomotive.dizel_heat.PA);
|
|
CHECK(locomotive.dizel_heat.Twy > 50.f);
|
|
CHECK(scenario.start_up());
|
|
scenario.check();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("diesel: an engine started hot, and run at full power") {
|
|
// at 88 degrees the engines with a second water circuit are over its highest temperature
|
|
// (WaterAuxMaxTemperature) and don't start while it cools; the SM42 has none, starts and gets cooled by its
|
|
// fans and shutters at full power. alone: a train's pipe, leaking under 2.75 bar while the engine
|
|
// doesn't start, gets cut off the FV4a handle of an LSt locomotive (lock_old in UpdatePipePressure)
|
|
struct engine {
|
|
char const *path;
|
|
bool starts;
|
|
};
|
|
for (auto const &[path, starts] : {engine{"su45_v2/301d", false}, engine{"sm42_v1/6d1", true}, engine{"st44_v2/m62-1151", false}}) {
|
|
CAPTURE(path);
|
|
scenario scenario{std::string{"diesel/hot/"} + path, traction() + heat(), test::track{}};
|
|
scenario.add(path, 1);
|
|
auto &locomotive{scenario.cab()};
|
|
locomotive.dizel_HeatSet(88.f);
|
|
CHECK(scenario.start_up() == starts);
|
|
CHECK(locomotive.dizel_heat.PA != starts);
|
|
if (starts) {
|
|
scenario.get_going();
|
|
scenario.full_power(300.0);
|
|
CHECK(locomotive.Vel > 50.0);
|
|
CHECK(locomotive.dizel_heat.zaluzje1);
|
|
CHECK(locomotive.dizel_heat.Twy < locomotive.dizel_heat.water.config.temp_max);
|
|
}
|
|
scenario.check();
|
|
}
|
|
}
|
|
|
|
TEST_CASE("diesel: the 214M railbus's torque converter, gears and retarder") {
|
|
// the controller of the railbus (EIMCtrlType 3) runs from the air brake (0, 1) through the retarder (2) and
|
|
// neutral (3) to holding (4) and raising (5) the power; the torque converter locks up at speed and the
|
|
// gearbox shifts by itself
|
|
scenario scenario{"diesel/214m", motion() + traction() + brakes(), test::track{}};
|
|
scenario.add("21xm_v1/214ma", 1);
|
|
REQUIRE(scenario.start_up());
|
|
auto &railbus{scenario.cab()};
|
|
scenario.get_going();
|
|
scenario.full_power(60.0);
|
|
CHECK(railbus.MainCtrlPos == 5);
|
|
CHECK(railbus.eimic_real == doctest::Approx(1.0));
|
|
CHECK(railbus.hydro_TC_Lockup);
|
|
CHECK(railbus.ScndCtrlActualPos == railbus.ScndCtrlPosNo);
|
|
struct position {
|
|
double eimic;
|
|
bool retarder;
|
|
bool air;
|
|
};
|
|
auto number{railbus.MainCtrlPos};
|
|
for (auto const &[eimic, retarder, air] : {position{1.0, false, false}, position{0.0, false, false}, position{-1.0, true, false}, position{0.0, false, true}}) {
|
|
--number;
|
|
CAPTURE(number);
|
|
scenario.act(std::format("position {}", number));
|
|
railbus.DecMainCtrl(1);
|
|
scenario.wait(8.0);
|
|
CHECK(railbus.eimic_real == doctest::Approx(eimic));
|
|
CHECK((railbus.hydro_R_Fill > 0.99) == retarder);
|
|
CHECK((railbus.hydro_R_Torque > 1000.0) == retarder);
|
|
CHECK((railbus.BrakePress > 2.0) == air);
|
|
}
|
|
scenario.act("position 0");
|
|
railbus.DecMainCtrl(1);
|
|
scenario.wait(30.0);
|
|
CHECK(railbus.Vel == doctest::Approx(0.0));
|
|
// the gearbox shifted down as the railbus slowed
|
|
CHECK(railbus.ScndCtrlActualPos < railbus.ScndCtrlPosNo);
|
|
scenario.check();
|
|
}
|
|
|
|
TEST_CASE("diesel: the 214M railbus's speed control, up to the speed of a button and braking down to a lower one") {
|
|
// the second controller's first position takes the speed of the moment to hold; the buttons, the steps and
|
|
// the power limit change it. set lower than the speed, it brakes with the retarder (and under
|
|
// BrakeInterventionVel with the air); with the main controller off its top positions it stands by
|
|
scenario scenario{"diesel/214m speed control", motion() + traction() + brakes(), test::track{}};
|
|
scenario.add("21xm_v1/214ma", 1);
|
|
REQUIRE(scenario.start_up());
|
|
auto &railbus{scenario.cab()};
|
|
REQUIRE(railbus.SpeedCtrl);
|
|
scenario.get_going();
|
|
scenario.full_power(10.0);
|
|
scenario.act("speed control on");
|
|
REQUIRE(railbus.IncScndCtrl(1));
|
|
CHECK(railbus.SpeedCtrlUnit.IsActive);
|
|
CHECK(railbus.SpeedCtrlValue == doctest::Approx(std::round(railbus.Vel)).epsilon(0.02));
|
|
scenario.act("button 80");
|
|
railbus.SpeedCtrlButton(6);
|
|
CHECK(railbus.SpeedCtrlValue == doctest::Approx(80.0));
|
|
scenario.wait(90.0);
|
|
CHECK(railbus.Vel == doctest::Approx(80.0).epsilon(0.02));
|
|
CHECK_FALSE(railbus.SpeedCtrlUnit.Standby);
|
|
scenario.act("step down, up, power down and up");
|
|
railbus.SpeedCtrlDec();
|
|
CHECK(railbus.SpeedCtrlValue == doctest::Approx(75.0));
|
|
railbus.SpeedCtrlInc();
|
|
railbus.SpeedCtrlInc();
|
|
CHECK(railbus.SpeedCtrlValue == doctest::Approx(85.0));
|
|
CHECK(railbus.SpeedCtrlUnit.DesiredPower == doctest::Approx(1.0));
|
|
CHECK(railbus.SpeedCtrlPowerDec());
|
|
CHECK(railbus.SpeedCtrlUnit.DesiredPower == doctest::Approx(0.9));
|
|
CHECK(railbus.SpeedCtrlPowerInc());
|
|
CHECK(railbus.SpeedCtrlUnit.DesiredPower == doctest::Approx(1.0));
|
|
scenario.wait(20.0);
|
|
scenario.act("button 40");
|
|
railbus.SpeedCtrlButton(2);
|
|
scenario.wait(5.0);
|
|
// the retarder does it at this speed, the air isn't needed
|
|
CHECK(railbus.eimic_real == doctest::Approx(-1.0));
|
|
CHECK(railbus.hydro_R_Fill == doctest::Approx(1.0));
|
|
CHECK(railbus.BrakePress < 0.1);
|
|
CHECK_FALSE(railbus.SpeedCtrlUnit.BrakeInterventionBraking);
|
|
scenario.wait(60.0);
|
|
CHECK(railbus.Vel == doctest::Approx(40.0).epsilon(0.05));
|
|
scenario.act("main controller back, standing by");
|
|
railbus.DecMainCtrl(1);
|
|
railbus.DecMainCtrl(1);
|
|
railbus.DecMainCtrl(1);
|
|
scenario.wait(5.0);
|
|
CHECK(railbus.SpeedCtrlUnit.Standby);
|
|
scenario.act("speed control off");
|
|
railbus.DecScndCtrl(2);
|
|
scenario.wait(5.0);
|
|
CHECK_FALSE(railbus.SpeedCtrlUnit.IsActive);
|
|
scenario.check();
|
|
}
|
|
|
|
TEST_CASE("diesel: the SM42's shunt mode, switched on and off with one move of the switch") {
|
|
// eu07/maszyna#497: the shunt mode of the diesel-electrics (ShuntMode=1) shares its switch with the motor
|
|
// overload relay threshold of the electric locomotives (CurrentSwitch()). the SM42 has no such relay, so
|
|
// the switch sets the shunt mode at the first move, at the controller's zero position only
|
|
scenario scenario{"diesel/sm42 shunt mode", motion() + traction(), test::track{}};
|
|
scenario.add("sm42_v1/6d1", 1);
|
|
REQUIRE(scenario.start_up());
|
|
auto &sm42{scenario.cab()};
|
|
REQUIRE(sm42.ShuntModeAllow);
|
|
CHECK_FALSE(sm42.ShuntMode);
|
|
scenario.act("shunt mode on");
|
|
CHECK(sm42.CurrentSwitch(true));
|
|
CHECK(sm42.ShuntMode);
|
|
scenario.get_going();
|
|
scenario.act("shunting power");
|
|
sm42.AnPos = 0.5;
|
|
CHECK(sm42.IncMainCtrl(1));
|
|
scenario.wait(60.0);
|
|
CHECK(sm42.Vel > 1.0);
|
|
// not with the controller out of its zero position
|
|
CHECK_FALSE(sm42.CurrentSwitch(false));
|
|
CHECK(sm42.ShuntMode);
|
|
scenario.notch_back(0);
|
|
scenario.act("shunt mode off");
|
|
CHECK(sm42.CurrentSwitch(false));
|
|
CHECK_FALSE(sm42.ShuntMode);
|
|
scenario.check();
|
|
}
|