mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-08 05:10:41 +01:00
Test/core unit coverage (#235)
* test: real vehicles and golden traces in the unit tests The game's own vehicles (dynamic/ of the release used for the tests) as JSON of what the game's vehicle loader reads of their .fiz files, includes expanded: test_fiz.cpp converts them on demand and checks the loader reads the same sections, values and rows as of the game's file (fiz.h). Chosen to cover every engine type, brake valve, brake handle, local brake, coupler type, door type and brake delay set the game data uses. Golden traces (golden.h) characterise the simulation, compared within a relative tolerance or exactly, re-recorded with EU07_UNIT_TESTS_UPDATE_GOLDEN=1: - the parameters of every real vehicle as loaded, - the brakes of every real vehicle through charge, service steps, release, overcharge and emergency, on every brake delay setting, - every position of every driver's and local brake handle, - every powered vehicle started up the way the AI does it, driven to full power and braked to a stop (drive.h), - the real electric units and a locomotive with wagons driven whole, as trains of coupled vehicles stepped the way the game steps them (consist.h), - scenarios of the controls (scenario.h): doors, reversing and cab change, slip and sand, emergency stops, releasers, the ep and the electrodynamic brake, heating, loading, a collision, and frames of several physics iterations. * test: commands passed between vehicles Every command RunCommand knows run on every real vehicle and recorded, commands travelling through a train with a vehicle facing backwards, a coupling without the control cable, and loading and unloading by commands. * test: every switch of the cab, sent to the next vehicle Each switch sending its state to the train, each way and to each range, with the controllers and direction among them, on every real vehicle driving another of its kind, recorded for both. * test: the switches of the cab worked on a pair under the catenary The same switches with two seconds for the vehicles to act on each, so the pantographs rise, the main switch closes and the auxiliaries start. * test: gauges of trains in multiple and the damage descriptions The ammeters and the brake force the AI expects, recorded on the electric units and locomotives in multiple driven, the damage described on the driver's panel and ammeters showing the current of controlled vehicles. * test: give load commands their place, as the game does The loading test set its commands with SetInternalCommand, which leaves TCommand::Location as it is: uninitialised in a fresh vehicle, so the distance check of Load= and UnLoad= read garbage and the test failed now and then. The game gives them through PutCommand with the place of the platform, and so do the tests now. * test: brake valves and handles no vehicle of the game data has Fitted to a wagon and to an EU07: the valve variants and handles the loader knows that no real vehicle uses, the CV1 ones and the test handle among them, and a name the loader doesn't know. * test: braking from speed with the automatic ED brake, and a draisine Trains with the EP09, the E6ACT and the EW58 braked by ep, light and full service applications from speed, and the draisine pumped from rest and rolling. Only the E6ACT brings its electrodynamic brake in here. * test: the EP09's electrodynamic brake in service braking held to a stop start_up() took a vehicle for ready once its line breaker was closed and its reservoir full, which a train made already moving is at once: the EP09's manually started converter was never switched on, so there was no 110 V and no electrodynamic brake. It now waits for the converter. The EP09 with wagons is braked from 120 km/h by light, medium, high and full service applications held to a stop: the motors brake, the air of its cylinders is let out and given back as the train slows down. The flag of the electrodynamic brake stays on at a standstill below 2.1 bar. C strings given to CAPTURE are shown as text. * test: the converter switched on before a train is ready, the EW58's ep-staged electrodynamic brake start_up() called a train ready as soon as its line breaker closed and the air was there, so the converter of a unit having it in another car than the cab (the EW58's middle car) was never switched on, and its electrodynamic brake, gated by the 110 V, never came in. The converter and the compressor now always get switched on first. The EW58 brakes electrically by the stages of the ep brake, not by the pipe alone. * test: the ET42 and the 214M railbus among the real vehicles The ET42's halves (its own series motor branch: the motors in series at the high current setting) and the 214MA, a diesel railbus with the hydraulic torque converter, the retarder and the controller of an induction motor drive, converted from the game data and recorded in every sweep of the real vehicles. * test: the wagons' hand brakes released with the train's brakes; the 754, SM31 and SU46 release_brakes() released the hand brake of the driver's vehicle only, so every wagon set up braked kept its hand brake on and got dragged along. It now releases the hand and spring brakes of the whole train, as TController::AutoRewident() does when the AI takes it over, and the traces of the trains with wagons are recorded anew. The 754, the SM31 and the SU46 join the real vehicles for the kinds of the diesel-electrics' field shunting relays the others lack (RelayType 0, 1 and 46). * test: traction on a lost and too high catenary voltage, the ET42, the diesel-electrics' shunting relays The line breaker opened by the voltage relays of a series motor locomotive and by the limits of an induction motor one. The ET42 at the high current setting, which keeps its halves' motors in series, and its switched electrodynamic brake, whose current trips the overload relay from the top speed of the low setting. The field shunting of the diesel-electrics through each kind of their relays, at full power and notched back. * test: the EW58's electrodynamic brake stages, the EU47's speed control and braking at the voltage's limit The stages of the EW58's motor brake set by the positions of its ep handle, the first one alone over 100 km/h. The EU47's second controller holding, raising and lowering the speed set, its local brake setting the flag of the electrodynamic brake without the motors braking, and its brake feeding back less current into a catenary over the drive's MaxV. * test: diesel engines too cold and too hot to start, the 214M railbus's controller and retarder The heat of the diesel engines: at -10 degrees the ones with the lowest water temperature set don't start until the heater warms them, at 88 degrees the ones with a second water circuit don't start while it cools, and the SM42 run hot at full power is kept under its highest temperature by its fans and shutters. The 214M railbus's controller from the air brake through the retarder and neutral to power, its torque converter's lock-up and its gearbox. The controller helpers of the traction tests (full power, waiting for the line contactors, and notching back) move to test::scenario. * test: couplers coupled, uncoupled, broken and colliding; loads assigned, loaded and unloaded Coupling by hand touching or apart and of the same kind or not, with the sounds of what changes; uncoupling a screw coupler pressed together, stretched, with the hoses alone or broken; the automatic couplers of electric units coupling on contact, without the control cable between two kinds; a coupler broken with its brake hose; collisions over 15 km/h derailing. The pantographs set up by the pantstate load, a load of one kind at a time up to the capacity, and the steps of loading and unloading. * test: the battery drained and charged, the pantographs' tank and pressure switch, the 214M's speed control The EU07's battery drained without the converter by the lights and the small compressor until it opens the line breaker and nothing starts, charged by the converter, and switched off. The pantographs on their own leaking tank until the pressure switch opens the line breaker, and the small compressor pumping it up and priming the switch. The 214M railbus's speed control set by its buttons, steps and power limit, braking down with the retarder, and standing by. * test: the MHZ handles' buttons, the valves at speed, every brake material, the NESt3's relays The overload and the high pressure buttons of the MHZ handles. The KE and the LSt at speed in the R and P settings, under the anti-slip request and the releaser button. Every material of the brake shoes and disks the loader takes, braking a wagon from speed, the ones no game vehicle has among them. The CV1_R and the Oerlikon valve's relays set by its name (-ED, AL2 without ESt3) fitted to a wagon. * test: the loader's lists and lines: the 218M, SA134 and 22WEc, a compressor list, Pmax by speed, skipped lines The 218M (V2NList), the SA134 (HTCList) and the Elf 22WEc (ffBrakeList) join the real vehicles for the lists the others lack. Definitions made by the tests for what no game file has: a compressor list, whose table of whole numbers reads a factor of 0.9 as 0; the compressor's limits apart for the rear cab; the highest power of an induction motor drive by the speed, extrapolated past the table; and the lines the loader skips or trims (comments, a hash anywhere, leading spaces, carriage returns). * test: what the cab and the AI call on a vehicle: gauges of the train, the split ED brake, spring brake, cut-off The engine rotation of up to three vehicles in multiple and the lamps of the overload relay and the starting resistors read through the control cable; the engine's idle speed and the ET42's second controller shown in its dynamic brake; the controller of the electrodynamic brake apart from the local brake, which no game vehicle has yet; the spring brake shut off and released, the ep brake's fuse and the handle stepped by the AI; damaged motors cut off; the cab activated by itself; a road vehicle moved across a road, for which the tests' track gets a width; and the lamps and the buzzer of the security system left unattended. * test: the EP05 and its camshaft among the real vehicles, the headlights' colour and brightness The EP05, whose camshaft closes the line breaker and the line contactors by the camshaft's own position, converted from the game data and recorded in every sweep of the real vehicles. The Headlights section, which only the 214M's own file has, in a definition made by the test. * test: what the unit tests reach of the simulation core, what's dead or left, and what they found COVERAGE.md: the blocks of Mover.cpp, hamulce.cpp, Oerlikon_ESt.cpp and friction.cpp the tests run, the code nothing in the game runs, the code only data no game vehicle has would run, what's reachable and left, and the behaviour the tests found that may deserve a look. * test: check invariants of the physics on every step of every golden trace Rules any vehicle keeps whatever a test does (no NaN, cylinders and pipes within their limits, no current with the line breaker or contactors open, no force without power, distance as the speed runs, no acceleration over 5 g), checked on every step, with no comparison to a recorded file. The traces where a test or a game vehicle breaks one are excused with the reason; the vehicles' cases are in the findings of COVERAGE.md. * test: key figures of every golden trace, per part of the run Duration, speeds, distance, time to stop, the brake pipe's lowest pressure and time to recover, the peaks of the cylinders, the motor current and the tractive force, for each part between two events, in data/golden/<name>.figures. Compared within 0.5% or the last decimal, so they hold on any compiler, and an intended change of behaviour shows in a few readable lines. Traces sampled by hand keep none. * test: keep the golden samples out of the repository, recorded on the code before a change The samples of the golden traces are 29 MB and only mean something against the code before the change they check, so they're recorded locally before it (EU07_UNIT_TESTS_UPDATE_GOLDEN=1) and compared after it, and ignored by git. The key figures and the invariants stay, and are what the CI checks. Without samples recorded a trace compares only its key figures, but with EU07_UNIT_TESTS_GOLDEN_EXACT=1, the check of a change which shouldn't alter anything, it fails, so the check can't pass by having nothing to compare. * fix: draw the noise of the control pipe pressure in one order on every compiler The order of the two Random(10) calls in 'Random(10) - Random(10)' is unspecified: GCC draws them the other way round than MSVC Release, which mirrored the control pipe pressure around 5 bar and failed 32 unit tests on the Linux CI. The draws are sequenced in the order of MSVC Release, which the golden traces were recorded with. * test: count the start-up rounds with an integer, not a double (SonarCloud S2193) * test: behaviour in CHECKs, the key figures out of the repository The key figures of the golden traces are recorded with their samples on the code before a change, and compared after it, instead of being kept: a trace without them checks the invariants and its test's CHECKs, which is what the CI runs. The scenarios of the controls state what they show in CHECKs, and the runs of every real vehicle what holds for each of them. Writing them showed scenarios which didn't do what they were named for: the cab change stopped in the engine room, the slip runs put the controller to full power at once and never got the line contactors closed, and the train stopped by the alarm chain never got its pipe charged again. They do it now; the rest went to the findings. * test: the SonarCloud findings in the unit tests std::format for the texts put together, emplace_back, const references, string_view parameters, std::array and std::vector for the C arrays, the ranges algorithms, names no longer shadowing the coupler ends, comments in the empty loops; start_up(), trace::check() and the converter of the definitions split up. BrakeForceR() is const, which it always was in effect, so the gauges test needs no const_cast. The golden traces compare bit for bit.
This commit is contained in:
@@ -2437,7 +2437,7 @@ class TMoverParameters
|
||||
double Adhesive(double staticfriction) const;
|
||||
double TractionForce(double dt);
|
||||
double FrictionForce() const;
|
||||
double BrakeForceR(double ratio, double velocity);
|
||||
double BrakeForceR(double ratio, double velocity) const;
|
||||
double BrakeForceP(double press, double velocity) const;
|
||||
double BrakeForce(const TTrackParam &Track);
|
||||
double CouplerForce(int const End, double dt);
|
||||
|
||||
@@ -5144,7 +5144,7 @@ void TMoverParameters::ComputeTotalForce(double dt)
|
||||
FTotal = FTrain - Sign(V) * FStand;
|
||||
}
|
||||
|
||||
double TMoverParameters::BrakeForceR(double ratio, double velocity)
|
||||
double TMoverParameters::BrakeForceR(double ratio, double velocity) const
|
||||
{
|
||||
double press = 0;
|
||||
if (MBPM > 2)
|
||||
@@ -10482,7 +10482,10 @@ void TMoverParameters::LoadFIZ_Brake(std::string const &line)
|
||||
P2FTrans = 0;
|
||||
}
|
||||
|
||||
CntrlPipePress = 5 + 0.001 * (Random(10) - Random(10)); // Ra 2014-07: trochę niedokładności
|
||||
// Ra 2014-07: trochę niedokładności
|
||||
// the draws are sequenced: the order of the operands of '-' is unspecified, and GCC and MSVC draw them the other way round
|
||||
auto const firstdraw{Random(10)};
|
||||
CntrlPipePress = 5 + 0.001 * (Random(10) - firstdraw);
|
||||
extract_value(CntrlPipePress, "HiPP", line, "");
|
||||
HighPipePress = CntrlPipePress;
|
||||
LowPipePress = std::min(HighPipePress, 3.5);
|
||||
|
||||
@@ -6,20 +6,28 @@
|
||||
|
||||
set(UNIT_TESTS_NAME eu07_unit_tests)
|
||||
|
||||
# a new test_*.cpp file or data/*.json definition is picked up on its own
|
||||
# a new test_*.cpp file or file in data/ (definitions, real vehicles, golden traces) is picked up on its own
|
||||
file(GLOB UNIT_TEST_CASES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/test_*.cpp")
|
||||
file(GLOB UNIT_TEST_DATA CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/data/*.json")
|
||||
file(GLOB_RECURSE UNIT_TEST_DATA CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/data/*")
|
||||
|
||||
add_executable(${UNIT_TESTS_NAME}
|
||||
main.cpp
|
||||
vehicle.cpp
|
||||
fiz.cpp
|
||||
drive.cpp
|
||||
consist.cpp
|
||||
scenario.cpp
|
||||
golden.cpp
|
||||
invariants.cpp
|
||||
figures.cpp
|
||||
engine_stubs.cpp
|
||||
${UNIT_TEST_CASES})
|
||||
|
||||
# the core library brings the game's build settings along
|
||||
target_link_libraries(${UNIT_TESTS_NAME} PRIVATE eu07_core)
|
||||
target_include_directories(${UNIT_TESTS_NAME} PRIVATE "${DEPS_DIR}/doctest")
|
||||
target_compile_definitions(${UNIT_TESTS_NAME} PRIVATE EU07_UNIT_TESTS_DATA="${CMAKE_CURRENT_SOURCE_DIR}/data")
|
||||
# the names the tests CAPTURE are often C strings, shown as text rather than pointers
|
||||
target_compile_definitions(${UNIT_TESTS_NAME} PRIVATE EU07_UNIT_TESTS_DATA="${CMAKE_CURRENT_SOURCE_DIR}/data" DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING)
|
||||
if (MSVC)
|
||||
target_compile_options(${UNIT_TESTS_NAME} PRIVATE /bigobj)
|
||||
endif()
|
||||
|
||||
117
tests/unit/COVERAGE.md
Normal file
117
tests/unit/COVERAGE.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Coverage of the simulation core by the unit tests
|
||||
|
||||
These tests characterise the physics of the vehicles (`McZapkie/Mover.cpp`, `hamulce.cpp`, `Oerlikon_ESt.cpp`, `friction.cpp`). They exist to show that refactors of those files, such as splitting `TractionForce` or `RunCommand`, leave the behaviour as it was. This page lists:
|
||||
|
||||
- what the tests reach;
|
||||
- what nothing in the game ever runs;
|
||||
- what only data no game vehicle has would run;
|
||||
- what is left to test;
|
||||
- the behaviour the tests found that may deserve a look.
|
||||
|
||||
## How it was measured
|
||||
|
||||
Coverage was measured on Windows with MSVC's SanitizerCoverage (`/fsanitize-coverage=trace-pc-guard`) on the unit test binary. The counts are basic blocks, which comes close to branch coverage: both sides of a condition are blocks of their own. The tool is local and not part of the build, by decision (2026-10). Any block-coverage tool run over `eu07_unit_tests` gives comparable numbers.
|
||||
|
||||
| File | Blocks run, at the start | Now |
|
||||
|---|---|---|
|
||||
| `Mover.cpp` | 8.9% | 80.7% (3323 of 4118) |
|
||||
| `hamulce.cpp` | 30% | 76.3% (649 of 851) |
|
||||
| `Oerlikon_ESt.cpp` | 58% | 87.4% (118 of 135) |
|
||||
| `friction.cpp` | 9% | 90.9% (10 of 11) |
|
||||
|
||||
The aim is branch coverage with the rest explained below, not 100%.
|
||||
|
||||
## Code nothing in the game runs
|
||||
|
||||
Nothing creates these objects or calls these functions anywhere in the game, which was checked against the whole source tree. A refactor can delete them, or leave them untested.
|
||||
|
||||
- **Brake valves that never get created:**
|
||||
- `TESt`, `TESt3` and `TESt3AL2`, including `Init`, `PLC` and `SetLP`. The valve names ESt3, ESt3AL2 and ESt4 all create `TNESt3`.
|
||||
- `TESt4R::GetPF`, overridden by `TLSt` and never called by it.
|
||||
- `TESt::CheckState`, `CVs`, `BVs`, `GetPF` and `EStParams`, and `TNESt3::EStParams`.
|
||||
- **`TFV4a`** (`GetPF`, `Init`): the FV4a handle of the vehicle definitions creates `TFV4aM`.
|
||||
- **Base implementations always overridden:** `TFricMat::GetFC` (every material, the default P10 too, has its own) and `TPrzekladnik::Update` (every relay has its own).
|
||||
- **Functions without callers:**
|
||||
- In `hamulce.cpp`: `PF_old`, `TBrake::GetBCF`, `TDriverHandle::OvrldButton`, `TReservoir::pa` and `TBrakeCyl::pa`.
|
||||
- In `Mover.cpp`: `BrakeVP`, `PipeRatio`, `RealPipeRatio`, `IncBrakeLevel`, `DecBrakeLevel`, `IncBrakePress`, `DecBrakePress`, `MainCtrlActualPowerPos` and `GetExternalCommand`.
|
||||
- **Inverter failures** of the induction motor drives (`inverter::Failure_Drive`, `Failure_Const`, `Activate`): nothing ever sets them. The cab only shows them. The branches reading them in `TractionForce` can't be reached.
|
||||
|
||||
## Code only data no game vehicle has would run
|
||||
|
||||
Where it was worth it, a test fits the missing parameter to a real vehicle or builds a definition with it (`definition::set()`). Those cases are marked "tested" below. The rest is reachable only by a vehicle definition the game data doesn't have:
|
||||
|
||||
- **Tested, fitted or handmade:**
|
||||
- The valves CV1, CV1_R, CV1_L_TR, the W, K and Hik variants, SW, NESt3 and M483 (`brake cycle: the valves the game knows…`).
|
||||
- An Oerlikon valve named with -ED or AL2 without ESt3 (its relays `TPrzekED` and `TPrzekCiagly`).
|
||||
- The brake materials FR513, FR510, P10yBg and P10yBgu (`brake cycle: every material…`).
|
||||
- The handles test, D2, Westinghouse, MHZ_EN57 and St113 fitted to an EU07.
|
||||
- A `CompressorList`, a `PmaxList` and a `Headlights` section.
|
||||
- The rear cab's compressor limits (`MinCP_B`, `MaxCP_B`).
|
||||
- The controller of the electrodynamic brake apart from the local brake (`SplitEDPneumaticBrake`).
|
||||
- **Not tested:**
|
||||
- The retarder's clutch (`R_IsClutch`, `R_ClutchSpeed`) and the retarder worked by the local brake (`R_WithIndividual`).
|
||||
- The automatic relays of type 2 (`RelayType=2`).
|
||||
- The variant of `CheckLocomotiveParameters` for a definition whose `RList` doesn't match its powered axles.
|
||||
|
||||
## Reachable, not tested yet
|
||||
|
||||
These are run by the game, by vehicles it has or by the cab, the AI or the scenery, but no test reaches them yet. Most of them are the far sides of conditions inside functions the tests do run.
|
||||
|
||||
- **Entry points from outside the core:**
|
||||
- `TBrake::ForceEmptiness` and its overrides: a scenario's vehicle set up with empty brakes (`DynObj.cpp`).
|
||||
- `TBrake::GetSoundFlag`: the sounds of the brakes.
|
||||
- `LoadFIZ` and `reload_FIZ`: the file loading around `LoadFIZ_Text`, which the tests call directly.
|
||||
- `TSecuritySystem::set_cabsignal_lock`.
|
||||
- `TMHZ_EN57::GetEP`: an MHZ_EN57 handle in the EP mode of the brake.
|
||||
- **Inside the functions the tests run** (blocks run of the function's total):
|
||||
- `TractionForce` (305 of 373): the inverter failures above. The rest are mostly halves of conditions:
|
||||
- the `SST` table of the series-excited diesel-electrics;
|
||||
- the speed control's brake intervention with the air under `BrakeInterventionVel`;
|
||||
- a diesel-electric's generator tripping on overcurrent;
|
||||
- the `ffBrakeList` of the 22WEc, whose electrodynamic brake no test applies.
|
||||
- `AutoRelayCheck` (87 of 119): the ET22's group switch under some sequences, the relays at reverse with `BackwardsBranchesAllowed`, and the shunting of the EZTs.
|
||||
- `update_doors` (134 of 160), `PantographsCheck` (44 of 64) and `PowerCouplersCheck` (70 of 88): door modes and pantograph valve kinds only some game vehicles have, and the 24 V circuit across couplers.
|
||||
- `RelayReset` (29 of 43) and `MainSwitchCheck` (16 of 27): relays tripping in states the drive cycles don't reach.
|
||||
- `UpdatePipePressure` (108 of 130): the pressure switch lock of an electric unit's pantographs, which the EW58's automatic valve keeps away. Also the EP mode of the EN57's handle and the `LockPipe` thresholds (`LPOn`, `LPOff`), which no vehicle sets.
|
||||
- `TCV1L_TR::GetPF` (9 of 20), `TKE::GetPF` (28 of 37) and the MHZ handles: settings (G with the CV1L_TR, the KE's anti-slip pressure `ASBP`) that no real vehicle has together.
|
||||
|
||||
## What the tests found
|
||||
|
||||
The tests record the behaviour as it is. The following points may deserve a look by someone who knows how the real vehicles behave.
|
||||
|
||||
- **`Random(10) - Random(10)` (`Mover.cpp`, the noise of the control pipe pressure `CntrlPipePress`):** the order the two calls were evaluated in isn't specified. MSVC Release, MSVC Debug and GCC gave different traces, a control pipe pressure mirrored around 5 bar, which failed 32 tests on the Linux CI. Fixed: the draws are sequenced in the order of MSVC Release, which the golden traces were recorded with.
|
||||
- **`TCommand::Location` isn't initialised** in a new vehicle. The game always sets it through `PutCommand()`, but a test calling `RunCommand()` directly got different results run to run.
|
||||
- **`CompressorList` is `int[4][9]`** (`MOVER.h`), though its factors are fractions: 0.9 is read as 0. No game vehicle has the list yet.
|
||||
- **A train whose pipe leaks under 2.75 bar before its start-up can't be released:**
|
||||
- Where this happens: an FV4a handle and an LSt valve, for example 4 minutes standing with wagons, waiting for a hot engine.
|
||||
- The cause: the pipe gets cut off the main reservoir (`lock_old` in `UpdatePipePressure`). The AI presses its unlock button only for the lock set by `LPOn` and `LPOff` (`control_main_pipe`).
|
||||
- The same after every emergency stop of such a train, by the alarm chain or the radio-stop: reset, it stays with its pipe empty until the releaser is held (`b_rls`), which the test of the emergency stops does.
|
||||
- **EW58:**
|
||||
- Its electrodynamic brake comes in only by the stages of the ep brake (TUHEX), never by the brake pipe alone.
|
||||
- It needs 110 V, from the converter of the middle car only.
|
||||
- **ET42:**
|
||||
- At the high current setting the controller stops at the last series position, and the train crawls.
|
||||
- From the low setting's top speed (over 100 km/h) the dynamic brake's current trips the overload relay at once.
|
||||
- **EU47:** its local brake sets the flag of the electrodynamic brake, which keeps the train brake's air out, but the motors don't brake. The local brake's air does it.
|
||||
- **EP09:** the flag of the automatic electrodynamic brake stays on at a standstill while the cylinders hold less than 2.1 bar, and it flicks on while a high application is released.
|
||||
- **Diesel engines with a second water circuit (SU45, ST44) started at 88 degrees:** they don't start until that circuit, over its limit (74 or 75 degrees), cools. Off, it cools slowly.
|
||||
- **Brake cylinders over the vehicle's highest pressure** (found by the invariants, see the README):
|
||||
- The K valve of the SM03 and the EU04 fills the cylinders to the pressure of the auxiliary reservoir in a full service or emergency application: 4.27 bar of the SM03's MaxBP 3.5, 3.19 bar of the EU04's 2.8.
|
||||
- The ESt3d_PZZ valve of the SN61 does so in an emergency: 4.6 bar of its MaxBP 3.8.
|
||||
- The EU07's LSt overshoots a little, to 4.0 bar of its 3.8.
|
||||
- **Diesel engines driven over their top speed:** a lower gear taken at speed drives the engine through the wheels over its `nmax`, the SM03's by 10%, the WMB10's by 25%. The cutoff (`nmax_cutoff`) only takes the fuel off.
|
||||
- **The ELF's C car's main reservoir over its governor:** the cars share the supply pipe, the A car's governor stops at 9 bar, the C car's at 8.5, so the C car's reservoir reaches 8.64 bar.
|
||||
- **Wagons thrown about as a train starts with full physics of the couplers:** the slack taken up throws them at up to 5.7 g, and back within a step.
|
||||
- **Nothing limits the speed:** a light train at full power runs well past its Vmax (the 754 past 160 km/h, against a Vmax of 100).
|
||||
- **Vehicles that don't do what they should, as driven by the tests:**
|
||||
- An EN57 doesn't get ready (main reservoir).
|
||||
- An EN57AKL alone doesn't charge its pipe.
|
||||
- The TEM2 barely moves, and the SM31 crawls at 0.3 km/h at full power, its motors taking 444 A.
|
||||
- The draisine can't start from rest (the pump's force is under the resistance of a standing draisine).
|
||||
- The Elf and the Impuls, their doors opened with the steps permitted, close the doors as they start off but keep the steps out, which keeps them from moving.
|
||||
- The ED72 holds an ep application with its handle at running, and with the ep brake switched off too; only the ep release position lets it off. The EW58 releases at running.
|
||||
- The road vehicle (MAN) is only slowed down by a minute of full service.
|
||||
- **A train run with five physics steps in a frame:** an EU07 with wagons takes no current, its controller at full power, and rolls at a few km/h. The test steps the vehicles the way `TDynamicObject` does (`FastComputeMovement` for the steps before the last one), so the game may do the same.
|
||||
- **Game data:**
|
||||
- The 214M's file has `TurboPos` and `MotorParamTable` twice, and the EN57AL's `Engine` twice. The loader reads each in turn, so the later one overrides what both set.
|
||||
- A wagon set up braked keeps its hand brake on until someone releases it. The AI does that for the whole train (`AutoRewident`), so a test has to as well.
|
||||
@@ -10,6 +10,9 @@ The code under test is `eu07_core`, the library of the simulation parts the game
|
||||
game uses it. The python library gets linked along with the game's settings, but the tests don't
|
||||
use it and run without it.
|
||||
|
||||
[COVERAGE.md](COVERAGE.md) says how much of the simulation core the tests reach, what's left and why, and
|
||||
what they found.
|
||||
|
||||
## Running
|
||||
|
||||
- **With the build**: building the game (`WITH_TESTS`, on by default) runs them at the end, once the
|
||||
@@ -46,24 +49,127 @@ TEST_CASE("brakes: service braking stops a heavier wagon too") {
|
||||
- `definition::load("<name>")` reads `data/<name>.json`, with the sections and keys of the game's
|
||||
vehicle definitions; `set()` and `remove()` change it for the test. Table sections give their
|
||||
rows as `"rows": [[...], ...]`, keys starting with `_` are comments. A section the loader doesn't
|
||||
know is an error (the table of them is in `vehicle.cpp`); a misspelt key isn't caught, so check
|
||||
know is an error (the table of them is in `fiz.cpp`); a misspelt key isn't caught, so check
|
||||
in the test that the value the test is about made it to the vehicle. Keep the definitions
|
||||
physically sensible: some parts need keys others don't (the ESt brake valves need `Brake.Size`),
|
||||
and a test on a half-defined vehicle tests the definition rather than the simulation.
|
||||
- `definition::fiz("<dir>/<name>")` is one of the game's own vehicles, `data/fiz/<dir>/<name>.json`,
|
||||
in the same form, converted from the game's `.fiz` with the files it includes (the list and how to
|
||||
add one: `data/fiz/README.md`). The conversion keeps what the game's loader reads of the file and
|
||||
checks it reads the same of the converted one (`fiz.h`), so the vehicle is the game's.
|
||||
- The random numbers of the simulation are reseeded before every test case, so a test gives the
|
||||
same result alone or among the others.
|
||||
same result alone or among the others. Loading a vehicle draws some too (the scatter of its brake
|
||||
pipe pressure), so a test making vehicles in a loop calls `test::reseed_random()` before each.
|
||||
- Logic which lives in classes too big to set up in a test (the AI driver, the cab) goes into free
|
||||
functions on the vehicle state the class calls, and the test calls them the same way: see
|
||||
`vehicle/handover.h`, which `TController::TakeControl()` uses, and `test_handover.cpp`.
|
||||
- `vehicle` creates the vehicle the way `TDynamicObject::Init()` does and steps it the way the
|
||||
simulation loop does, on a straight track of the given friction and gradient. `pair` puts two of
|
||||
them on that track facing each other with the given ends and runs them together, as the
|
||||
simulation runs the vehicles of a scene: the coupler and buffer forces, collisions and automatic
|
||||
coupling come from the physics (`test_couplers.cpp`). Longer consists aren't supported yet.
|
||||
simulation loop does, on a straight track of the given friction, gradient, catenary voltage and
|
||||
physics iterations a frame. With a cab (`vehicle{definition, 0.0, "name", 1}`) it has a driver.
|
||||
- `consist` (`consist.h`) couples vehicles into a train and steps them together, coupler forces,
|
||||
air, control and power passing between them. The physics reaches a neighbour through its
|
||||
`TDynamicObject`, for its `MoverParameters` only; the tests have a stand-in of it with just that.
|
||||
- `drive.h` has the driver's part, made of the AI's steps: `start_up()` (battery, pumps,
|
||||
pantographs, line breaker, converter, compressor), `drive()` (running, acknowledging the
|
||||
vigilance), `release_brakes()`, `drive_cycle()` (a whole run from start-up to a stop).
|
||||
- `scenario` (`scenario.h`) puts a train, its driver and a golden trace for each vehicle together,
|
||||
for a test of a feature: `act()` marks an event in the traces, `wait()` runs the train.
|
||||
- `pair` (`vehicle.h`) puts two vehicles on that track facing each other with the given ends and
|
||||
runs them together, as the simulation runs the vehicles of a scene: the coupler and buffer
|
||||
forces, collisions and automatic coupling come from the physics (`test_couplers.cpp`).
|
||||
- Check behaviour (speeds, pressures, states the player sees) rather than internal flags, and make
|
||||
the test check its own preconditions (`REQUIRE` that the braking skidded, before checking what a
|
||||
skid leads to).
|
||||
|
||||
## Golden traces
|
||||
|
||||
A golden trace pins down how the simulation behaves now, for changes which mustn't alter it, like
|
||||
restructuring a function: the values of some channels of a vehicle over a run, compared with the
|
||||
ones recorded from the code before, in `data/golden/<name>.csv`. A difference fails the test, naming
|
||||
the channel, the time and both rows.
|
||||
|
||||
The samples and their key figures aren't kept in the repository (tens of megabytes, and they only mean
|
||||
something against the code before the change): record them before the change, and compare after it.
|
||||
|
||||
```
|
||||
git switch master
|
||||
EU07_UNIT_TESTS_UPDATE_GOLDEN=1 eu07_unit_tests # records data/golden/**/*.csv, ignored by git
|
||||
git switch my-refactor
|
||||
EU07_UNIT_TESTS_GOLDEN_EXACT=1 eu07_unit_tests # compares every sample, bit for bit
|
||||
```
|
||||
|
||||
The recorded files stay through switching branches. Without them, a trace checks the invariants and
|
||||
its test's own `CHECK`s, which is what the CI does: every test states the behaviour it's about in
|
||||
`CHECK`s, a scenario of a feature what the feature does (the doors open, the train stops), a run of
|
||||
every real vehicle what holds for each of them (it brakes harder by every step, it runs off and stops).
|
||||
|
||||
```cpp
|
||||
test::trace trace{"eu07/notch up", test::channels::motion() + test::channels::traction()};
|
||||
eu07.record(trace); // samples every 10th step
|
||||
eu07->MainSwitch(true);
|
||||
trace.mark("main switch"); // shows in the event column of the row
|
||||
eu07.run(30.0);
|
||||
trace.check();
|
||||
```
|
||||
|
||||
- `EU07_UNIT_TESTS_UPDATE_GOLDEN=1` records the samples and the key figures, for a new test or a
|
||||
change which alters the behaviour on purpose; the diff of the key figures shows what it altered,
|
||||
review it like code.
|
||||
- Without `EU07_UNIT_TESTS_GOLDEN_EXACT=1`, samples recorded are compared within a relative 1e-9, as
|
||||
GCC and glibc's maths functions can differ from MSVC's in the last bits, and a trace without them
|
||||
passes. With it they're compared exactly, and a trace without them or its key figures fails, so a
|
||||
run of the refactoring check can't pass by having nothing to compare.
|
||||
- Keep the runs short (tens of seconds): the simulation feeds back on itself, and a last bit grows.
|
||||
- A trace with no assertion about what the behaviour should be is a characterisation, bugs included;
|
||||
put the behaviour the test is about into `CHECK`s besides.
|
||||
|
||||
### Key figures
|
||||
|
||||
Next to its samples, every trace records the figures a person reads (`figures.h`), for each part of
|
||||
the run between two events, in `data/golden/<name>.figures`: the duration, the speeds, the distance,
|
||||
the time to stop, the brake pipe's lowest pressure and the time to get back to 4.9 bar, the peaks of
|
||||
the brake cylinders, the motor current and the tractive force.
|
||||
|
||||
```
|
||||
[brake]
|
||||
duration = 60.00 s
|
||||
speed at the start = 118.5 km/h
|
||||
distance = 944.3 m
|
||||
stopped after = 45.97 s
|
||||
brake cylinders peak = 3.997 bar
|
||||
```
|
||||
|
||||
They're compared within 0.5% or the last decimal written, loose enough for any compiler, and the
|
||||
differences are told by part and figure:
|
||||
|
||||
```
|
||||
key figures of "traction/4e_v1/4e" differ:
|
||||
[brake] distance: 944.3 m now, 980.0 m recorded
|
||||
```
|
||||
|
||||
`EU07_UNIT_TESTS_UPDATE_GOLDEN=1` records them with the samples. After a change which alters the
|
||||
behaviour, their comparison says in a few lines what the thousands of changed samples mean. A trace
|
||||
sampled by hand, at times of its own (the commands and switches tests), records none.
|
||||
|
||||
### Invariants
|
||||
|
||||
Every trace also checks, on every step of its vehicle and not only on the recorded ones, the rules
|
||||
which hold for any vehicle whatever a test does (`invariants.h`): no NaN, the brake cylinders under
|
||||
the vehicle's highest pressure, the pipes under the highest governor setting, no motor current with
|
||||
the line breaker open, no tractive force without power, the distance counted as the speed runs, no
|
||||
acceleration over 5 g, and a few more. They compare nothing with a recorded file, so they hold on
|
||||
any compiler, and they still check a behaviour recorded anew on purpose makes sense. A broken rule
|
||||
fails the test, naming the time, the last event and the values:
|
||||
|
||||
```
|
||||
invariant "no motor current with the line breaker open" broken in traction/et42 fuse/0 at 63.200 s,
|
||||
after "dynamic brake": Mains=0 Im=-412.5 Itot=-412.5
|
||||
```
|
||||
|
||||
Where a test makes a vehicle break a rule (a collision), or a game vehicle breaks one as it is, the
|
||||
list of excuses in `invariants.cpp` names the trace, the rule and the reason; the second kind goes
|
||||
into the findings of [COVERAGE.md](COVERAGE.md) too.
|
||||
|
||||
## Code to test, and when the tests fail to link
|
||||
|
||||
A source joins the tested code by moving from `SOURCES` to `CORE_SOURCES` in the main
|
||||
|
||||
106
tests/unit/consist.cpp
Normal file
106
tests/unit/consist.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "stdafx.h"
|
||||
#include "consist.h"
|
||||
|
||||
#include "vehicle/DynObj.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
consist::consist() = default;
|
||||
consist::~consist() = default;
|
||||
|
||||
vehicle &consist::add(definition const &Definition, int Cab, int Coupling, double Velocity, double Gap) {
|
||||
auto added{std::make_unique<vehicle>(Definition, Velocity, std::format("test{}", m_vehicles.size()), Cab)};
|
||||
auto &mover{added->mover()};
|
||||
|
||||
std::vector<std::byte> object(sizeof(TDynamicObject));
|
||||
reinterpret_cast<TDynamicObject *>(object.data())->MoverParameters = &mover; // NOSONAR see m_objects
|
||||
|
||||
auto position{0.0};
|
||||
if (false == m_vehicles.empty()) {
|
||||
auto &last{m_vehicles.back()->mover()};
|
||||
position = m_positions.back() - 0.5 * (last.Dim.L + mover.Dim.L) - Gap;
|
||||
mover.Loc = TLocation{position, 0.0, 0.0};
|
||||
if (Coupling != coupling::faux) {
|
||||
last.Attach(end::rear, end::front, &mover, Coupling, true, false);
|
||||
mover.Attach(end::front, end::rear, &last, Coupling, true, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mover.Loc = TLocation{position, 0.0, 0.0};
|
||||
}
|
||||
m_vehicles.push_back(std::move(added));
|
||||
m_positions.push_back(position);
|
||||
m_objects.push_back(std::move(object));
|
||||
update_neighbours();
|
||||
return *m_vehicles.back();
|
||||
}
|
||||
|
||||
void consist::update_neighbours() {
|
||||
// TDynamicObject::update_neighbours(), for vehicles coupled in a line
|
||||
for (std::size_t i = 0; i < m_vehicles.size(); ++i) {
|
||||
auto &mover{m_vehicles[i]->mover()};
|
||||
for (int end = end::front; end <= end::rear; ++end) {
|
||||
auto &neighbour{mover.Neighbours[end]};
|
||||
auto const other{end == end::front ? static_cast<std::ptrdiff_t>(i) - 1 : static_cast<std::ptrdiff_t>(i) + 1};
|
||||
if (other < 0 || other >= static_cast<std::ptrdiff_t>(m_vehicles.size())) {
|
||||
neighbour = neighbour_data();
|
||||
continue;
|
||||
}
|
||||
auto const &othermover{m_vehicles[other]->mover()};
|
||||
auto const otherend{end == end::front ? end::rear : end::front};
|
||||
auto const distance{TMoverParameters::CouplerDist(&mover, &othermover) - mover.Couplers[end].adapter_length -
|
||||
othermover.Couplers[otherend].adapter_length};
|
||||
// a vehicle not coupled is a collision source when it's within the range the game scans
|
||||
if (mover.Couplers[end].Connected == nullptr && distance > std::max(10.0, std::abs(mover.V)) + 40.0) {
|
||||
neighbour = neighbour_data();
|
||||
continue;
|
||||
}
|
||||
neighbour.vehicle = reinterpret_cast<TDynamicObject *>(m_objects[other].data()); // NOSONAR see m_objects
|
||||
neighbour.vehicle_end = otherend;
|
||||
neighbour.distance = static_cast<float>(distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void consist::step(track const &Track, double Dt) {
|
||||
for (auto const &vehicle : m_vehicles) {
|
||||
vehicle->begin_step();
|
||||
}
|
||||
update_neighbours();
|
||||
for (int iteration = 1; iteration < Track.iterations; ++iteration) {
|
||||
for (auto const &vehicle : m_vehicles) {
|
||||
vehicle->forces(Dt);
|
||||
}
|
||||
for (std::size_t i = 0; i < m_vehicles.size(); ++i) {
|
||||
m_positions[i] += m_vehicles[i]->fast_move(Track, Dt, TLocation{m_positions[i], 0.0, 0.0});
|
||||
}
|
||||
}
|
||||
for (auto const &vehicle : m_vehicles) {
|
||||
vehicle->forces(Dt);
|
||||
}
|
||||
// the average pressure in the train's brake pipe weighed by the vehicles' lengths, TDynamicObject::GetEPP(),
|
||||
// over the whole train (the game's stops at a vehicle without the brake hose coupled)
|
||||
auto pipe{0.0};
|
||||
auto length{0.0};
|
||||
for (auto const &vehicle : m_vehicles) {
|
||||
pipe += vehicle->mover().PipePress * vehicle->mover().Dim.L;
|
||||
length += vehicle->mover().Dim.L;
|
||||
}
|
||||
pipe /= length;
|
||||
for (std::size_t i = 0; i < m_vehicles.size(); ++i) {
|
||||
m_positions[i] += m_vehicles[i]->move(Track, Dt, TLocation{m_positions[i], 0.0, 0.0}, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
void consist::run(double Seconds, track const &Track, double Dt) {
|
||||
auto const steps{std::lround(Seconds / (Dt * Track.iterations))};
|
||||
for (long i = 0; i < steps; ++i) {
|
||||
step(Track, Dt);
|
||||
}
|
||||
}
|
||||
|
||||
double consist::gap(std::size_t Index) const {
|
||||
return TMoverParameters::CouplerDist(&m_vehicles[Index]->mover(), &m_vehicles[Index + 1]->mover());
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
57
tests/unit/consist.h
Normal file
57
tests/unit/consist.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "vehicle.h"
|
||||
|
||||
class TDynamicObject;
|
||||
|
||||
namespace test {
|
||||
|
||||
// vehicles coupled into a train on a straight track, all facing forward, from the front one back, stepped the
|
||||
// way vehicle_table::update() steps the vehicles of the game: the constants and neighbours of all of them,
|
||||
// their forces, then their movement. couplers carry the forces, the air, the control and the power between
|
||||
// the vehicles as in the game:
|
||||
// test::consist en57;
|
||||
// en57.add(definition::fiz("en57_v1/5bgb"), 1); // driven from the front cab
|
||||
// en57.add(definition::fiz("en57_v1/6ba_840"));
|
||||
// en57.add(definition::fiz("en57_v1/5bgb"));
|
||||
class consist {
|
||||
public:
|
||||
// everything a coupler can join, as two vehicles of a train coupled by a crew
|
||||
static constexpr int full_coupling{coupling::coupler | coupling::brakehose | coupling::mainhose | coupling::control | coupling::gangway | coupling::heating |
|
||||
coupling::permanent | coupling::power110v | coupling::power24v | coupling::highvoltage};
|
||||
|
||||
consist();
|
||||
~consist();
|
||||
consist(consist const &) = delete;
|
||||
consist &operator=(consist const &) = delete;
|
||||
|
||||
// a vehicle at the back of the train, its front coupler joined to the rear one of the last vehicle with
|
||||
// the given coupling (coupling flags), Gap [m] between their buffers. Cab as for a vehicle. a vehicle
|
||||
// with no coupling (coupling::faux) is free on the same track, as one about to be coupled or hit
|
||||
vehicle &add(definition const &Definition, int Cab = 0, int Coupling = full_coupling, double Velocity = 0.0, double Gap = 0.0);
|
||||
|
||||
vehicle &operator[](std::size_t Index) { return *m_vehicles[Index]; }
|
||||
std::size_t size() const { return m_vehicles.size(); }
|
||||
|
||||
void step(track const &Track = {}, double Dt = 0.01);
|
||||
void run(double Seconds, track const &Track = {}, double Dt = 0.01);
|
||||
|
||||
// distance between the couplers of the vehicle and the one behind it [m], negative when the buffers press
|
||||
double gap(std::size_t Index) const;
|
||||
|
||||
private:
|
||||
void update_neighbours();
|
||||
|
||||
std::vector<std::unique_ptr<vehicle>> m_vehicles;
|
||||
std::vector<double> m_positions; // of the vehicles' middles along the track
|
||||
// the physics reaches a neighbouring vehicle through its TDynamicObject, for its MoverParameters alone.
|
||||
// the game's object can't be made without the rest of the game, so it's a stand-in: storage of its size
|
||||
// with that one member set, never constructed, which only the physics ever looks into
|
||||
std::vector<std::vector<std::byte>> m_objects;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
14
tests/unit/data/fiz/11xa_v2/93a.json
Normal file
14
tests/unit/data/fiz/11xa_v2/93a.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"_source": "pkp/11xa_v2/93a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "40000", "Vmax": "120", "HeatingP": "32", "LightP": "0.56"},
|
||||
"Load": {"MaxLoad": "8", "LoadQ": "pieces", "LoadAccepted": "Workers", "OverLoadFactor": "1.5", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "24.5", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.50", "Bd": "17.2", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "ESt4", "Size": "200", "NBpA": "4", "MBF": "90", "MaxBP": "4.0", "BCN": "2", "BCR": "0.1778", "BCD": "0.150", "BCM": "8.17", "BCS": "1.4", "BSA": "4.0", "BM": "P10-Bgu", "BVV": "200", "BRE": "0.87"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.11", "FmaxB": "320", "kC": "4500", "DmaxC": "0.1", "FmaxC": "850", "beta": "0.58", "AllowedFlag": "115"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocalBrake": "ManualBrake", "BrakeDelays": "R", "ASB": "Yes", "MCPN": "1", "rows": []},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "WheelsDriven", "LMaxVoltage": "24", "AlterLight": "Accu", "AlterLMaxVoltage": "24", "AlterLCap": "495", "AlterLRS": "Generator"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"},
|
||||
"Doors": {"OpenCtrl": "Passenger", "CloseCtrl": "Mixed", "OpenSpeed": "70", "CloseSpeed": "400", "DoorMaxShiftL": "80", "DoorMaxShiftR": "80", "DoorOpenMethod": "Fold", "DoorClosureWarning": "No"}
|
||||
}
|
||||
14
tests/unit/data/fiz/14xa_v1/173a.json
Normal file
14
tests/unit/data/fiz/14xa_v1/173a.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"_source": "pkp/14xa_v1/173a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "42000", "Mred": "1600", "Vmax": "160", "HeatingP": "42", "LightP": "0.56"},
|
||||
"Load": {"MaxLoad": "30", "LoadQ": "pieces", "LoadAccepted": "Passengers", "OverLoadFactor": "1.5", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "24.5", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.70", "Bd": "17.2", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "ESt4HBG300-s216", "Size": "375", "NBpA": "4", "MBF": "90", "MaxBP": "3.8", "BCN": "2", "BCR": "0.2032", "BCD": "0.150", "BCM": "9.04", "BCS": "1.6", "BSA": "4.0", "BM": "P10-Bgu", "BVV": "375", "BRE": "0.95"},
|
||||
"Doors": {"OpenCtrl": "Passenger", "CloseCtrl": "AutomaticCtrl", "OpenSpeed": "0.36", "CloseSpeed": "0.48", "DoorCloseDelay": "2.2", "DoorMaxShiftL": "0.9", "DoorMaxShiftR": "0.9", "DoorOpenMethod": "Plug", "DoorClosureWarning": "yes", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.043", "PlatformMaxShift": "-45", "PlatformSpeed": "4", "PlatformOpenMethod": "Rotate", "DoorStayOpen": "10"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.11", "FmaxB": "320", "kC": "4500", "DmaxC": "0.1", "FmaxC": "850", "beta": "0.58", "AllowedFlag": "115"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocalBrake": "ManualBrake", "BrakeDelays": "R", "ASB": "Yes", "MCPN": "1", "rows": []},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "WheelsDriven", "LMaxVoltage": "24", "AlterLight": "Accu", "AlterLMaxVoltage": "24", "AlterLCap": "495", "AlterLRS": "Generator"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"}
|
||||
}
|
||||
14
tests/unit/data/fiz/168a_v1/168a.json
Normal file
14
tests/unit/data/fiz/168a_v1/168a.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"_source": "pkp/168a_v1/168a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "42000", "Mred": "1600", "Vmax": "160", "HeatingP": "20", "LightP": "0.56"},
|
||||
"Load": {"MaxLoad": "56", "LoadQ": "pieces", "LoadAccepted": "Passengers,Luggage", "OverLoadFactor": "1.5", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "24.5", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.70", "Bd": "17.2", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "ESt4HBG300", "Size": "200", "NBpA": "4", "MBF": "90", "MaxBP": "3.8", "BCN": "2", "BCR": "0.1778", "BCD": "0.150", "BCM": "10.00", "BCS": "1.4", "BSA": "6.0", "BM": "P10-Bgu", "BVV": "200", "BRE": "0.9"},
|
||||
"Doors": {"OpenCtrl": "Passenger", "CloseCtrl": "AutomaticCtrl", "OpenSpeed": "0.44", "CloseSpeed": "0.27", "DoorCloseDelay": "2.25", "DoorMaxShiftL": "0.9", "DoorMaxShiftR": "0.9", "DoorOpenMethod": "Plug", "DoorClosureWarning": "yes", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.043", "PlatformMaxShift": "-45", "PlatformSpeed": "4", "PlatformOpenMethod": "Rotate", "DoorStayOpen": "10"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.11", "FmaxB": "320", "kC": "4500", "DmaxC": "0.1", "FmaxC": "850", "beta": "0.58", "AllowedFlag": "115"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocalBrake": "ManualBrake", "BrakeDelays": "R", "ASB": "Yes", "MCPN": "1", "rows": []},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "WheelsDriven", "LMaxVoltage": "24", "AlterLight": "Accu", "AlterLMaxVoltage": "24", "AlterLCap": "495", "AlterLRS": "Generator"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"}
|
||||
}
|
||||
78
tests/unit/data/fiz/21xm_v1/214ma.json
Normal file
78
tests/unit/data/fiz/21xm_v1/214ma.json
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"_source": "pkp/21xm_v1/214ma.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "46000", "Vmax": "120", "PWR": "390", "SandCap": "100", "Type": "dmu"},
|
||||
"Load": {"MaxLoad": "50", "OverLoadFactor": "2.2", "LoadQ": "pieces", "LoadAccepted": "passengers", "LoadSpeed": "0.5", "UnLoadSpeed": "0.7"},
|
||||
"Dimensions": {"L": "24.38", "H": "4.2", "W": "2.9", "Cx": "0.0"},
|
||||
"Wheels": {"D": "0.84", "Tw": "1.435", "AIM": "300", "Axle": "B'2'", "Ad": "2", "Bd": "17.23", "Rmin": "75", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "Size": "150", "NBpA": "4", "MBF": "2.74", "MaxBP": "2.9", "LocMaxBP": "3.8", "RV": "-1", "RM": "0.77", "BCN": "8", "BCR": "0.127", "BCD": "0.1", "BCM": "2.15", "HiPP": "5", "LoPP": "3.5", "Vv": "0.125", "MinCP": "7.5", "MaxCP": "8.5", "CompressorSpeed": "0.0138", "CompressorPower": "Main", "BCS": "0.5", "BSA": "0", "BM": "Cosid", "BVV": "88", "BRE": "0.97", "TareMaxBP": "2.2", "LPOn": "3.0", "LPOff": "4.5", "UBB1": "2", "UBB2": "8"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.25", "CloseSpeed": "0.19", "DoorCloseDelay": "0.1", "DoorMaxShiftL": "0.78", "DoorMaxShiftR": "0.78", "DoorOpenMethod": "Plug", "DoorClosureWarning": "No", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.04", "MirrorMaxShift": "75", "DoorStayOpen": "10", "DoorClosexDelay": "1.8", "DoorNeedPermit": "Yes", "DoorPermitList": "1|0|2|3", "DoorPermitListDefault": "2", "DoorAutoCloseRemote": "No"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "ControlType": "214MA"},
|
||||
"SpringBrake": {"Volume": "20", "MBF": "5.8", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "0.5", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "3", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Yes", "LocalBrake": "PneumaticBrake", "ManualBrake": "No", "MCPN": "5", "SCPN": "5", "AutoRelay": "Yes", "IniCDelay": "1.0", "SCDelay": "0.3", "BrakeDelays": "PR", "MaxBPMass": "55", "BrakeHandle": "MHZ_K5P", "LocBrakeHandle": "FD1", "WaterStart": "Battery", "OilStart": "Automatic", "FuelStart": "Automatic", "ConverterStart": "Automatic", "ConverterStartDelay": "4", "BrakeOpModes": "PN", "EIMCtrlType": "3", "DirChangeMaxPos": "4", "SBD": "0.47", "AutomaticCabActivation": "No", "InactiveCabFlag": "27", "CompartmentLightsStart": "Manual", "rows": [
|
||||
["-1","0.6","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "EmergencyBrakeDelay": "2.1", "RadioStop": "Yes", "CabDependent": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "28", "LMaxCurrent": "500"},
|
||||
"Clima": {"HMaxVoltage": "3000", "Heating": "Generator", "HGeneratorEngine": "Main", "HGeneratorMinRPM": "696", "HGeneratorMinVoltage": "2400", "HGeneratorMaxRPM": "1500", "HGeneratorMaxVoltage": "3300"},
|
||||
"Engine": {"EngineType": "DieselEngine", "Trans": "50:129", "TransEff": "0.91", "nmin": "800", "nmax": "2000", "nmax_cutoff": "1950", "AIM": "65", "EUS": "102.5", "EDS": "102.0", "IsTC": "Yes", "TC_TMMax": "1.82", "TC_CP": "0.75", "TC_LT": "3000", "TC_LR": "1", "TC_ULR": "1", "TC_FRI": "1", "TC_FRD": "2", "TC_TII": "2.93", "TC_TIO": "0", "TC_TOO": "-1.65", "TC_LS": "29.5", "TC_ULS": "40", "IsRetarder": "Yes", "R_Place": "1", "R_TII": "5.0", "R_MT": "1500", "R_MP": "250", "R_FRI": "1", "R_FRD": "1", "R_MinVel": "30", "WaterMaxTemperature": "105", "WaterCoolingTemperature": "90", "WaterFlowTemperature": "35", "WaterAuxCircuit": "Yes"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "0|30|40|50|60|70|80|90|100|120", "OverrideManual": "Yes", "InitPwr": "0.3", "MaxPwrVel": "5", "StartVel": "2", "VelStep": "5", "PwrStep": "0.1", "MinPwr": "0.3", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "120", "Offset": "-0.5", "kPpos": "0.1", "kPneg": "0.4", "kIpos": "0.06", "kIneg": "0.06", "BrakeIntervention": "Yes", "PowerUpSpeed": "0.3", "PowerDownSpeed": "0.3"},
|
||||
"TurboPos": {"TurboPos": "1"},
|
||||
"MotorParamTable": {"minVelfullengage": "3.0", "engageDia": "1", "engageMaxForce": "3000", "engagefriction": "1", "rows": []},
|
||||
"MotorParamTable0": {"minVelfullengage": "3.0", "engageDia": "1", "engageMaxForce": "3000", "engagefriction": "1", "rows": [
|
||||
["0","0","0","0","-1","-1","0","1"],
|
||||
["1","2.81","-1","-1","38.2","42.4","0.18","1"],
|
||||
["2","1.84","17.4","29.9","53.8","59.8","0.13","1"],
|
||||
["3","1.36","26.6","45.0","70.8","78.7","0","1"],
|
||||
["4","1.00","61.1","61.1","90.4","100.4","0","1"],
|
||||
["5","0.80","80.2","80.2","200","200","0","1"]
|
||||
]},
|
||||
"DList": {"Size": "5", "Mmax": "2450", "nMmax": "21.7", "nmax": "33", "Mnmax": "2160", "nominalfill": "1.0", "Mstand": "250.0", "NomFuelConsRate": "220", "rows": [
|
||||
["0","0.15","0"],
|
||||
["1","0.20","2"],
|
||||
["2","0.40","2"],
|
||||
["3","0.60","2"],
|
||||
["4","0.80","2"],
|
||||
["5","1.00","2"]
|
||||
]},
|
||||
"DMList": {"rows": [
|
||||
["0","0"],
|
||||
["80","637"],
|
||||
["400","796"],
|
||||
["800","1592"],
|
||||
["1050","2090"],
|
||||
["1300","2200"],
|
||||
["1550","2124"],
|
||||
["1800","2070"],
|
||||
["2000","1676"]
|
||||
]},
|
||||
"UCList": {"Size": "5", "IntegratedBrakePN": "Yes", "IntegratedBrake": "Yes", "rows": [
|
||||
["0","3","0","0","0","0.15","0.15","0","1","0"],
|
||||
["1","2","0","0","0","0.15","0.15","1","3","0"],
|
||||
["2","1","-1","0","-1","0.15","0.15","3","3","1"],
|
||||
["3","1","-1","1","0","0.00","0.15","3","4","1"],
|
||||
["4","0","-1","1","0","0.15","0.00","4","5","3"],
|
||||
["5","0","0","1","1","0.15","0.15","4","5","3"]
|
||||
]},
|
||||
"LightsList": {"Size": "5", "Wrap": "no", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["21","34"],
|
||||
["22","34"],
|
||||
["34","34"],
|
||||
["16","1"]
|
||||
]},
|
||||
"WiperList": {"Size": "5", "Angle": "75", "Default": "1", "rows": [
|
||||
["3","0.5","0.5","0.0"],
|
||||
["0","0.8","0.0","0.5"],
|
||||
["3","0.8","6.0","0.5"],
|
||||
["3","0.8","3.0","0.0"],
|
||||
["3","0.8","1.0","0.0"]
|
||||
]}
|
||||
}
|
||||
84
tests/unit/data/fiz/21xm_v1/218ma_a_kd.json
Normal file
84
tests/unit/data/fiz/21xm_v1/218ma_a_kd.json
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"_source": "pkp/21xm_v1/218ma_a_kd.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "38500", "Vmax": "120", "PWR": "360", "SandCap": "100", "Type": "dmu"},
|
||||
"Load": {"MaxLoad": "50", "OverLoadFactor": "2.2", "LoadQ": "pieces", "LoadAccepted": "passengers", "LoadSpeed": "0.5", "UnLoadSpeed": "0.7"},
|
||||
"Dimensions": {"L": "20.75", "H": "4.2", "W": "2.9", "Cx": "0.10"},
|
||||
"Wheels": {"D": "0.84", "Tw": "1.435", "AIM": "300", "Axle": "B'1'", "Ad": "2", "Bd": "17.23", "Rmin": "75", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "Size": "150", "NBpA": "4", "MBF": "2.74", "MaxBP": "2.9", "LocMaxBP": "3.8", "RV": "-1", "RM": "0.77", "BCN": "6", "BCR": "0.127", "BCD": "0.1", "BCM": "2.15", "HiPP": "5", "LoPP": "3.5", "Vv": "0.125", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.015", "CompressorPower": "Main", "BCS": "0.5", "BSA": "0", "BM": "Cosid", "BVV": "88", "BRE": "0.97", "TareMaxBP": "2.2", "LPOn": "3.0", "LPOff": "4.5", "UBB1": "2", "UBB2": "8"},
|
||||
"SpringBrake": {"Volume": "15", "MBF": "4.35", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "0.5", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.25", "CloseSpeed": "0.19", "DoorCloseDelay": "0.1", "DoorMaxShiftL": "0.78", "DoorMaxShiftR": "0.78", "DoorOpenMethod": "Plug", "DoorClosureWarning": "No", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.04", "MirrorMaxShift": "75", "DoorStayOpen": "10", "DoorNeedPermit": "Yes", "DoorPermitList": "1|0|2|3", "DoorPermitListDefault": "2", "DoorAutoCloseRemote": "No"},
|
||||
"BuffCoupl1": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39"},
|
||||
"BuffCoupl2": {"CType": "Articulated", "AllowedFlag": "-55"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "3", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Yes", "LocalBrake": "PneumaticBrake", "ManualBrake": "No", "MCPN": "5", "SCPN": "5", "AutoRelay": "Yes", "IniCDelay": "1.0", "SCDelay": "0.3", "BrakeDelays": "PR", "MaxBPMass": "55", "BrakeHandle": "MHZ_K5P", "LocBrakeHandle": "FD1", "WaterStart": "Battery", "OilStart": "Automatic", "FuelStart": "Automatic", "ConverterStart": "Automatic", "ConverterStartDelay": "4", "BrakeOpModes": "PN", "EIMCtrlType": "3", "DirChangeMaxPos": "4", "SBD": "0.47", "AutomaticCabActivation": "No", "InactiveCabFlag": "27", "CompartmentLightsStart": "Manual", "rows": [
|
||||
["-1","0.6","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "2.1", "RadioStop": "Yes", "CabDependent": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "28", "LMaxCurrent": "500"},
|
||||
"Engine": {"EngineType": "DieselEngine", "Trans": "50:129", "TransEff": "0.95", "nmin": "800", "nmax": "1800", "nmax_cutoff": "1850", "nreg_acc": "150", "AIM": "30", "EUS": "102.5", "EDS": "102.0", "IsTC": "Yes", "TC_TMMax": "1.82", "TC_CP": "0.85", "TC_LT": "2500", "TC_LR": "1", "TC_ULR": "1", "TC_FRI": "1", "TC_FRD": "2", "TC_TII": "2.93", "TC_TIO": "0", "TC_TOO": "-1.65", "TC_LS": "22", "TC_ULS": "40", "IsRetarder": "Yes", "R_Place": "1", "R_TII": "5.0", "R_MT": "1500", "R_MP": "250", "R_FRI": "1", "R_FRD": "1", "R_MinVel": "1", "WaterMaxTemperature": "105", "WaterCoolingTemperature": "95", "WaterFlowTemperature": "75", "WaterAuxCircuit": "No", "WaterCoolingFanSpeed": "-100", "NominalCoolingPower": "300"},
|
||||
"Clima": {"HMaxVoltage": "3000", "Heating": "Generator", "HGeneratorEngine": "Main", "HGeneratorMinRPM": "696", "HGeneratorMinVoltage": "2400", "HGeneratorMaxRPM": "1500", "HGeneratorMaxVoltage": "3300"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "0|30|40|50|60|70|80|90|100|120", "OverrideManual": "Yes", "InitPwr": "0.3", "MaxPwrVel": "5", "StartVel": "2", "VelStep": "5", "PwrStep": "0.1", "MinPwr": "0.3", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "120", "Offset": "-0.5", "kPpos": "0.1", "kPneg": "0.4", "kIpos": "0.06", "kIneg": "0.06", "BrakeIntervention": "Yes", "PowerUpSpeed": "0.17", "PowerDownSpeed": "0.17"},
|
||||
"TurboPos": {"TurboPos": "1"},
|
||||
"MotorParamTable": {"minVelfullengage": "3.0", "engageDia": "1", "engageMaxForce": "2300", "engagefriction": "1", "rows": []},
|
||||
"MotorParamTable0": {"minVelfullengage": "3.0", "engageDia": "1", "engageMaxForce": "2300", "engagefriction": "1", "rows": [
|
||||
["0","0","0","0","-1","-1","0","1"],
|
||||
["1","2.81","-1","-1","31.3","33.7","0.17","1"],
|
||||
["2","1.84","17.4","29.9","47.9","51.5","0.11","1"],
|
||||
["3","1.36","26.6","45.0","64.8","69.7","0","1"],
|
||||
["4","1.00","61.1","61.1","84.2","90.8","0","1"],
|
||||
["5","0.80","80.2","80.2","200","200","0","1"]
|
||||
]},
|
||||
"DList": {"Size": "5", "Mmax": "2450", "nMmax": "21.7", "nmax": "30", "Mnmax": "2160", "nominalfill": "1.0", "Mstand": "250.0", "NomFuelConsRate": "220", "rows": [
|
||||
["0","0.15","0"],
|
||||
["1","0.20","2"],
|
||||
["2","0.40","2"],
|
||||
["3","0.60","2"],
|
||||
["4","0.80","2"],
|
||||
["5","1.00","2"]
|
||||
]},
|
||||
"DMList": {"rows": [
|
||||
["0","0"],
|
||||
["80","637"],
|
||||
["400","796"],
|
||||
["800","1592"],
|
||||
["1050","2090"],
|
||||
["1300","2200"],
|
||||
["1550","2032"],
|
||||
["1800","1910"],
|
||||
["2000","1547"]
|
||||
]},
|
||||
"V2NList": {"rows": [
|
||||
["0","1200"],
|
||||
["40","1800"],
|
||||
["120","1800"]
|
||||
]},
|
||||
"UCList": {"Size": "5", "IntegratedBrakePN": "Yes", "IntegratedBrake": "Yes", "rows": [
|
||||
["0","3","0","0","0","0.15","0.15","0","1","0"],
|
||||
["1","2","0","0","0","0.15","0.15","1","3","0"],
|
||||
["2","1","-1","0","-1","0.15","0.15","3","3","1"],
|
||||
["3","1","-1","1","0","0.00","0.15","3","4","1"],
|
||||
["4","0","-1","1","0","0.15","0.00","4","5","3"],
|
||||
["5","0","0","1","1","0.15","0.15","4","5","3"]
|
||||
]},
|
||||
"LightsList": {"Size": "5", "Wrap": "no", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["21","34"],
|
||||
["22","34"],
|
||||
["34","34"],
|
||||
["16","1"]
|
||||
]},
|
||||
"WiperList": {"Size": "5", "Angle": "75", "Default": "1", "rows": [
|
||||
["3","0.5","0.5","0.0"],
|
||||
["0","0.8","0.0","0.5"],
|
||||
["3","0.8","6.0","0.5"],
|
||||
["3","0.8","3.0","0.0"],
|
||||
["3","0.8","1.0","0.0"]
|
||||
]}
|
||||
}
|
||||
11
tests/unit/data/fiz/3wl_v2/3wl.json
Normal file
11
tests/unit/data/fiz/3wl_v2/3wl.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"_source": "pkp/3wl_v2/3wl.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "10500", "Vmax": "100"},
|
||||
"Load": {"MaxLoad": "30", "LoadQ": "tonns", "LoadAccepted": "Coal,Sand,sand2,ruda,tluczen,scrap,scrap2", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "9.87", "H": "3", "W": "3", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1", "Tw": "1.435", "AIM": "300", "Axle": "1'1'", "Bd": "6", "Rmin": "30", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "ESt3", "Size": "12", "MBF": "72", "MaxBP": "3.8", "BCN": "1", "BCR": "0.1524", "BCD": "0.14", "BCMlo": "3.05", "BCMHi": "10.67", "NBpA": "4", "BM": "P10-Bg", "BCS": "2.7", "BSA": "8.00", "BVV": "50", "BRE": "0.8"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9000", "DmaxB": "0.12", "FmaxB": "350", "kC": "4500", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.52", "AllowedFlag": "3"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocalBrake": "ManualBrake", "BrakeDelays": "GP", "rows": []}
|
||||
}
|
||||
11
tests/unit/data/fiz/430w_v2/430w.json
Normal file
11
tests/unit/data/fiz/430w_v2/430w.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"_source": "pkp/430w_v2/430w.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "20500", "Vmax": "100"},
|
||||
"Load": {"MaxLoad": "59.5", "LoadQ": "tonns", "LoadAccepted": "coal,piasek,piasek2,ruda,tluczen,zlom,zlom2,siarka", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "14.028", "H": "3.235", "W": "3.04", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "Tw": "1.435", "AIM": "300", "Axle": "2'2'", "Ad": "2", "Bd": "8.5", "Rmin": "75", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "ESt3AL2HBG300", "Size": "100", "MBF": "144", "MaxBP": "3.8", "TareMaxBP": "1.3", "BCN": "1", "BCR": "0.2032", "BCD": "0.145", "BCM": "12.00", "NBpA": "4", "BM": "P10-Bg", "BCS": "2.7", "BSA": "16.00", "BVV": "100", "BRE": "0.9"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9000", "DmaxB": "0.12", "FmaxB": "350", "kC": "4500", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.52", "AllowedFlag": "3"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocalBrake": "ManualBrake", "BrakeDelays": "GP", "rows": []}
|
||||
}
|
||||
81
tests/unit/data/fiz/4e_v1/4e.json
Normal file
81
tests/unit/data/fiz/4e_v1/4e.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"_source": "pkp/4e_v1/4e.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "80000", "Mred": "16000", "Vmax": "125", "PWR": "2000", "SandCap": "500"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "15.915", "H": "4.348", "W": "2.903", "Cx": "0.38"},
|
||||
"Wheels": {"D": "1.250", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "3.05", "Bd": "8.55", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.0", "MaxASBP": "1.1", "RM": "0.635", "BCN": "8", "BCR": "0.1143", "BCD": "0.05", "BCM": "5.18", "Vv": "0.828", "MinCP": "7.0", "MaxCP": "8.7", "BCS": "1", "BSA": "0.5", "BM": "P10-Bgu", "BVV": "278", "CompressorSpeed": "0.0566", "BRE": "0.9"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103", "ControlType": "4e"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "7", "BDelay3": "39", "BDelay4": "17", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "DynamicBrake": "Passive", "MCPN": "43", "SCPN": "6", "AutoRelay": "No", "IniCDelay": "0.5", "SCDelay": "0.26", "SCDDelay": "0.05", "BrakeDelays": "GPR", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "MotorBlowersStart": "Converter", "rows": [
|
||||
["-1","0.6","-1","12","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.43","-1","9","Pneumatic"],
|
||||
["2","0.40","-1","9","Pneumatic"],
|
||||
["3","0.37","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0","-1","18","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareMinSpeed": "10", "AwareDelay": "60", "SoundSignalDelay": "3", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "4", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "1250", "MinH": "0.48", "MaxH": "2.5", "CSW": "1.4", "MinV": "1900", "MinPress": "3.5", "MaxPress": "5.0", "PhysicalLayout": "3"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "18:79", "WindingRes": "0.14", "nmax": "2390", "MotorBlowersSpeed": "-1310"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","21.8","105","0.11","140.9","105","0.11"],
|
||||
["1","20.22","140","0.07","130.7","140","0.07"],
|
||||
["2","21.06","190","0.09","136.2","190","0.09"],
|
||||
["3","23.95","160","0.25","154.8","160","0.25"],
|
||||
["4","21.73","255","0.16","140.5","255","0.16"],
|
||||
["5","24.66","170","0.35","159.4","170","0.35"],
|
||||
["6","23","800","0.02","148.7","800","0.02"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.5", "ImaxLo": "600", "ImaxHi": "750", "IminLo": "350", "IminHi": "470"},
|
||||
"RList": {"Size": "43", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "0.2", "rows": [
|
||||
["0","0","0","0","0"],
|
||||
["1","24.891","1","4","0"],
|
||||
["2","16.821","1","4","0"],
|
||||
["3","12.301","1","4","0"],
|
||||
["4","9.771","1","4","0"],
|
||||
["5","8.111","1","4","0"],
|
||||
["6","6.915","1","4","0"],
|
||||
["7","6.481","1","4","0"],
|
||||
["8","6.047","1","4","0"],
|
||||
["9","5.629","1","4","0"],
|
||||
["10","5.211","1","4","0"],
|
||||
["11","4.827","1","4","0"],
|
||||
["12","4.443","1","4","0"],
|
||||
["13","4.099","1","4","0"],
|
||||
["14","3.755","1","4","0"],
|
||||
["15","3.442","1","4","0"],
|
||||
["16","3.129","1","4","0"],
|
||||
["17","2.838","1","4","0"],
|
||||
["18","2.547","1","4","0"],
|
||||
["19","2.286","1","4","0"],
|
||||
["20","2.025","1","4","0"],
|
||||
["21","1.780","1","4","0"],
|
||||
["22","1.535","1","4","0"],
|
||||
["23","1.275","1","4","0"],
|
||||
["24","1.095","1","4","0"],
|
||||
["25","0.775","1","4","0"],
|
||||
["26","0.525","1","4","0"],
|
||||
["27","0.275","1","4","0"],
|
||||
["28","0.000","1","4","0"],
|
||||
["29","5.44","2","2","0"],
|
||||
["30","4.41","2","2","0"],
|
||||
["31","3.85","2","2","0"],
|
||||
["32","3.29","2","2","0"],
|
||||
["33","2.82","2","2","0"],
|
||||
["34","2.36","2","2","0"],
|
||||
["35","1.93","2","2","0"],
|
||||
["36","1.56","2","2","0"],
|
||||
["37","1.21","2","2","0"],
|
||||
["38","0.89","2","2","0"],
|
||||
["39","0.61","2","2","0"],
|
||||
["40","0.34","2","2","0"],
|
||||
["41","0.21","2","2","0"],
|
||||
["42","0.10","2","2","0"],
|
||||
["43","0.00","2","2","0"]
|
||||
]}
|
||||
}
|
||||
66
tests/unit/data/fiz/README.md
Normal file
66
tests/unit/data/fiz/README.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Real vehicle definitions
|
||||
|
||||
The game's own vehicles (`dynamic/` of the MaSzyna release used for the tests, 2026-10), to test the simulation on the vehicles players drive. Chosen to cover every engine type, brake valve, brake handle, local brake, coupler type, door type and brake delay set the game data uses. `pkp/` is left out of the paths, the other operators keep theirs.
|
||||
|
||||
They aren't the game's files: each `.json` here holds what the game's vehicle loader reads of the `.fiz`, with the files it includes, in the form of the tests' own definitions (`vehicle.h`): the values of every section line, and the rows of the lists. `test_fiz.cpp` converts them, using the game's parser for the includes, and checks the loader reads the same of the converted definition as of the game's file (`fiz.h`): the same sections with the same values, the same rows read by the same lists, in the same order. Comments, and lines the loader skips, are left out.
|
||||
|
||||
Convert them again, from the game data in `<game>/dynamic`, and add vehicles (paths as in the table, without the extension, separated by commas), with:
|
||||
|
||||
EU07_UNIT_TESTS_FIZ_SOURCE=<game>/dynamic EU07_UNIT_TESTS_FIZ_ADD=sm42_v1/6d1 eu07_unit_tests -tc="fiz: conversion*"
|
||||
|
||||
Every `.json` here is a vehicle picked up by `test_fiz.cpp`: record the parameters of an added one with `EU07_UNIT_TESTS_UPDATE_GOLDEN=1`.
|
||||
|
||||
| Path | Vehicle | Engine | Brake valve | Brake handle | Local brake | Coupler |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `11xa_v2/93a.fiz` | 11XA | - | ESt4 | - | ManualBrake | Screw |
|
||||
| `14xa_v1/173a.fiz` | 14XA | - | ESt4HBG300-s216 | - | ManualBrake | Screw |
|
||||
| `168a_v1/168a.fiz` | 168A | - | ESt4HBG300 | - | ManualBrake | Screw |
|
||||
| `21xm_v1/218ma_a_kd.fiz` | 218M | DieselEngine | EStED | MHZ_K5P | PneumaticBrake | Screw |
|
||||
| `21xm_v1/214ma.fiz` | 214M | DieselEngine | EStED | MHZ_K5P | PneumaticBrake | Screw |
|
||||
| `3wl_v2/3wl.fiz` | 3WL | - | ESt3 | - | ManualBrake | Screw |
|
||||
| `430w_v2/430w.fiz` | 430W | - | ESt3AL2HBG300 | - | ManualBrake | Screw |
|
||||
| `4e_v1/4e.fiz` | 4E | ElectricSeriesMotor | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `bdhpumn_v3/bdhpumn.fiz` | BDHPUMN | - | KE | - | ManualBrake | Screw |
|
||||
| `bhp_v1/bhp-b.fiz` | BHP | - | ESt3AL2 | - | ManualBrake | Articulated |
|
||||
| `br285_v1/br285.fiz` | BR285 | DieselElectric | KE | MHZ_6P | PneumaticBrake | Screw |
|
||||
| `cd/810_v2/810.fiz` | 810 | DieselEngine | ESt3_PZZ | FV4a | PneumaticBrake | Screw |
|
||||
| `cd/754_v1/754.fiz` | 754 | DumbDE | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `dr2_v1/dr2.fiz` | DR2 | WheelsDriven | - | - | ManualBrake | None |
|
||||
| `e186_v2/eu47.fiz` | E186 | ElectricInductionMotor | EStED | MHZ_6P | PneumaticBrake | Screw |
|
||||
| `e6act_v2/e6acta.fiz` | E6ACT | ElectricInductionMotor | EStED | MHZ_K5P | PneumaticBrake | Screw |
|
||||
| `ed72_v1/5bs-rb.fiz` | ED72 | - | EP2 | FVel6 | ManualBrake | Automatic |
|
||||
| `elf_v1/22wec-a.fiz` | ELF 22WEc | ElectricInductionMotor | EStED | MHZ_K5P | PneumaticBrake | Automatic |
|
||||
| `elf_v1/21we-a.fiz` | ELF | ElectricInductionMotor | EStED | MHZ_K5P | PneumaticBrake | Automatic |
|
||||
| `en57_v1/5bgb.fiz` | EN57 | - | EP2 | FVel6 | ManualBrake | Automatic |
|
||||
| `en57_v1/6ba_840.fiz` | EN57 | - | EP2 | FVel6 | ManualBrake | Automatic |
|
||||
| `en57_v1/6bai.fiz` | EN57 | - | K | St113 | ManualBrake | Automatic |
|
||||
| `en57akl_v1/akl_ra.fiz` | EN57AKL | ElectricInductionMotor | EStED | MHZ_EN57 | PneumaticBrake | Automatic |
|
||||
| `ep05_v2/ep05.fiz` | EP05 | ElectricSeriesMotor | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `ep09_v2/104e.fiz` | EP09 | ElectricSeriesMotor | EStED | FV4a | PneumaticBrake | Screw |
|
||||
| `et22_v3/201e-rn.fiz` | ET22 | ElectricSeriesMotor | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `et22_v3/201e-w.fiz` | ET22 | ElectricSeriesMotor | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `et42_v2/112e-a.fiz` | ET42 | ElectricSeriesMotor | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `et42_v2/112e-b.fiz` | ET42 | ElectricSeriesMotor | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `eu04_v1/eu04-01.fiz` | EU04 | ElectricSeriesMotor | K | Knorr | PneumaticBrake | Screw |
|
||||
| `ew58_v1/ew58-d.fiz` | EW58 | - | EP1 | - | ManualBrake | Automatic |
|
||||
| `ew58_v1/ew58-sa.fiz` | EW58 | ElectricSeriesMotor | EP1 | FVE408 | ManualBrake | Automatic |
|
||||
| `impuls_v1/31we-a_pr.fiz` | IMPULS | ElectricInductionMotor | EStED | MHZ_6P | PneumaticBrake | Automatic |
|
||||
| `road/man/nl293.fiz` | MAN (road) | DieselEngine | - | - | HydraulicBrake | Bare |
|
||||
| `sa134_v1/218mc_a.fiz` | SA134 | DieselEngine | EStED | MHZ_K5P | PneumaticBrake | Screw |
|
||||
| `sieciowiec_v1/a.fiz` | SIECIOWIEC | - | - | - | NoBrake | Screw |
|
||||
| `sm03_v1/sm03.fiz` | SM03 | DieselEngine | K | Knorr | PneumaticBrake | Screw |
|
||||
| `sm31_v1/411d.fiz` | SM31 | DumbDE | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `sm40_v1/sm40.fiz` | SM40 | DieselElectric | K | Knorr | PneumaticBrake | Screw |
|
||||
| `sm42_v1/6d1.fiz` | SM42 | DumbDE | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `sn61_v2/sn61.fiz` | SN61 | DieselEngine | ESt3d_PZZ | FV4a | PneumaticBrake | Screw |
|
||||
| `st44_v2/m62-1151.fiz` | ST44 | DieselElectric | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `st45_v2/301dd.fiz` | ST45 | DumbDE | SW | MHZ_K8P | PneumaticBrake | Screw |
|
||||
| `static/sug/sug_kielce.fiz` | SUG | ElectricSeriesMotor | W | Knorr | PneumaticBrake | Screw |
|
||||
| `su45_v2/301d.fiz` | SU45 | DumbDE | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `su46_v2/303d.fiz` | SU46 | DumbDE | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `tem2_v2/tem2a.fiz` | TEM2 | DieselElectric | LSt | M394 | PneumaticBrake | Screw |
|
||||
| `wm15_v1/wm15.fiz` | WM15 | Dumb | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `wmb10_v1/wmb10.fiz` | WMB10 | DieselEngine | LSt | FV4a | PneumaticBrake | Screw |
|
||||
| `z1_v2/152a.fiz` | Z1 | - | KE | - | ManualBrake | Screw |
|
||||
|
||||
The paths are those of the game's `.fiz` files. `elf_v1/inverter.fiz` is a part the Elf units include, not a vehicle. The 218M (V2NList), the SA134 (HTCList) and the 22WEc (ffBrakeList) are there for lists the others lack, the EP05 for its camshaft. The 214MA stands for the 214M railbus, whose own file repeats a section (TurboPos and MotorParamTable twice), which the definitions here can't hold.
|
||||
14
tests/unit/data/fiz/bdhpumn_v3/bdhpumn.json
Normal file
14
tests/unit/data/fiz/bdhpumn_v3/bdhpumn.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"_source": "pkp/bdhpumn_v3/bdhpumn.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "42200", "Vmax": "120", "HeatingP": "40", "LightP": "0.56"},
|
||||
"Load": {"MaxLoad": "132", "LoadQ": "pieces", "LoadAccepted": "Passengers", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "26.8", "H": "4.7", "W": "2.88", "Cx": "0.15"},
|
||||
"Wheels": {"D": "0.96", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.5", "Bd": "19.5", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "KE", "NBpA": "6", "MBF": "15", "MaxBP": "3.8", "BCN": "12", "BCR": "0.127", "BCD": "0.04", "BCM": "1.5", "BCS": "1.2", "BSA": "0", "BM": "Disk1", "BVV": "125", "TareMaxBP": "2.3"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "Mixed", "OpenSpeed": "0.5", "CloseSpeed": "1.0", "DoorCloseDelay": "0", "DoorMaxShiftL": "0.65", "DoorMaxShiftR": "0.65", "DoorOpenMethod": "Shift", "DoorMaxShiftPlug": "0.028", "DoorStayOpen": "5.0", "DoorClosureWarning": "no", "DoorBlocked": "Yes", "DoorAutoCloseRemote": "No", "DoorNeedPermit": "no"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.11", "FmaxB": "320", "kC": "4500", "DmaxC": "0.1", "FmaxC": "850", "beta": "0.58", "AllowedFlag": "115"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocalBrake": "ManualBrake", "BrakeDelays": "P", "MaxBPMass": "63", "rows": []},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "WheelsDriven", "LMaxVoltage": "24", "AlterLight": "Accu", "AlterLMaxVoltage": "24", "AlterLCap": "495", "AlterLRS": "Generator"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000", "AlterHeating": "PowerCable", "AlterHPowerTrans": "SteamPower", "AlterHSteamPress": "0.45"}
|
||||
}
|
||||
15
tests/unit/data/fiz/bhp_v1/bhp-b.json
Normal file
15
tests/unit/data/fiz/bhp_v1/bhp-b.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"_source": "pkp/bhp_v1/bhp-b.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "36000", "Vmax": "120", "HeatingP": "37.5", "LightP": "0.56"},
|
||||
"Load": {"LoadAccepted": "Passengers,Luggage", "MaxLoad": "110", "LoadQ": "pieces", "OverLoadFactor": "2", "LoadSpeed": "3", "UnLoadSpeed": "4"},
|
||||
"Dimensions": {"L": "19.75", "H": "4.750", "W": "2.720", "Cx": "0.4"},
|
||||
"Wheels": {"D": "0.94", "AIM": "300", "Tw": "1.435", "Axle": "2'3'", "Ad": "3.0", "Bd": "17", "Rmin": "80", "BearingType": "Roll"},
|
||||
"BuffCoupl1": {"CType": "Articulated", "AllowedFlag": "83", "PowerFlag": "256"},
|
||||
"BuffCoupl2": {"CType": "Screw", "kB": "9200", "DmaxB": "0.11", "FmaxB": "320", "kC": "4500", "DmaxC": "0.1", "FmaxC": "850", "beta": "0.58", "AllowedFlag": "67"},
|
||||
"Brake": {"BrakeValve": "ESt3AL2", "Size": "100", "MBF": "144", "MaxBP": "3.8", "TareMaxBP": "2.5", "BCN": "2", "BCR": "0.1403", "BCD": "0.14", "BCM": "10.38", "NBpA": "4", "BM": "P10-Bgu", "BCS": "2.7", "BSA": "5.00", "BVV": "100", "BRE": "0.85"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocalBrake": "ManualBrake", "BrakeDelays": "P", "MaxBPMass": "55", "rows": []},
|
||||
"Doors": {"OpenCtrl": "Passenger", "CloseCtrl": "Mixed", "OpenSpeed": "0.55", "CloseSpeed": "0.75", "DoorMaxShiftL": "0.65", "DoorMaxShiftR": "0.65", "DoorOpenMethod": "Shift"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000", "AlterHeating": "PowerCable", "AlterHPowerTrans": "SteamPower", "AlterHSteamPress": "0.45"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "WheelsDriven", "LMaxVoltage": "24", "AlterLight": "Accu", "AlterLMaxVoltage": "24", "AlterLCap": "375", "AlterLRS": "Generator"}
|
||||
}
|
||||
69
tests/unit/data/fiz/br285_v1/br285.json
Normal file
69
tests/unit/data/fiz/br285_v1/br285.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"_source": "pkp/br285_v1/br285.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "82400", "Mred": "12000", "Vmax": "140", "PWR": "2200", "SandCap": "700"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "18.900", "H": "3.95", "W": "2.977", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.250", "AIM": "4000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "1.75", "Bd": "10.3", "Rmin": "80"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "8", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "3.5", "ValveOnArea": "0.0002", "ValveOffArea": "0.0002", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"BuffCoupl": {"ControlType": "br285", "CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103"},
|
||||
"Brake": {"BrakeValve": "KE", "NBpA": "4", "MBF": "50", "MaxBP": "3.8", "BCN": "8", "RM": "1.4", "BCR": "0.127", "BCD": "0.04", "BCM": "2.7", "BCS": "0.8", "BSA": "0", "BM": "Disk2", "BVV": "125", "Vv": "0.8", "CompressorSpeed": "0.04", "CompressorPower": "Converter", "MinCP": "8", "MaxCP": "10", "UBB3": "8", "LPOn": "3.0", "LPOff": "4.5", "HandlePipeUnlockPos": "2", "EmergencyCutsOffHandle": "Yes"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "3", "BDelay3": "35", "BDelay4": "36", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "6", "SCPN": "4", "AutoRelay": "Yes", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GPR", "BrakeHandle": "MHZ_6P", "LocBrakeHandle": "FD1", "ConverterStart": "Manual", "ConverterStartDelay": "3", "FuelStart": "Automatic", "OilStart": "Automatic", "BrakeOpModes": "PN", "EIMCtrlType": "3", "DirChangeMaxPos": "3", "HAO": "No", "HMO": "Yes", "HGDP1": "2", "rows": [
|
||||
["-1","0.8","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal,SeparateAcknowledge", "AwareDelay": "30", "SoundSignalDelay": "2.5", "MaxHoldTime": "1.0", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "100"},
|
||||
"Clima": {"HMaxVoltage": "3000", "Heating": "Generator", "HGeneratorEngine": "Main", "HGeneratorMinRPM": "600", "HGeneratorMinVoltage": "2400", "HGeneratorMaxRPM": "1860", "HGeneratorMaxVoltage": "3300"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "OverrideManual": "No", "InitPwr": "1.0", "MaxPwrVel": "-1", "StartVel": "-1", "VelStep": "5", "PwrStep": "0.01", "MinPwr": "0.0", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "140", "Offset": "0", "kPpos": "0.1", "kPneg": "0.2", "kIpos": "0.03", "kIneg": "0.03", "BrakeIntervention": "No", "SpeedCtrlType": "Time", "SpeedCtrlDelay": "0.5"},
|
||||
"Engine": {"EngineType": "DieselElectric", "Trans": "18:64", "Ftmax": "300000", "Vhyp": "24", "Vadd": "5.5", "Cr": "1", "WaterMinTemperature": "40", "WaterFlowTemperature": "70", "WaterCoolingTemperature": "82", "WaterMaxTemperature": "91", "WaterShutters": "Yes", "WaterAuxCircuit": "Yes", "WaterAuxCoolingTemperature": "50", "WaterAuxMaxTemperature": "74", "WaterAuxShutters": "Yes", "OilMinPressure": "0.15", "HeatKFO2": "33"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","8.35","50","2000","48.2","0","0"]
|
||||
]},
|
||||
"Switches": {"Converter": "impulse"},
|
||||
"WWList": {"Size": "6", "rows": [
|
||||
["600","0","0","0"],
|
||||
["800","600","1404","6000"],
|
||||
["950","900","1404","6000"],
|
||||
["1050","1100","1404","6000"],
|
||||
["1250","1500","1404","6000"],
|
||||
["1450","1850","1404","6000"],
|
||||
["1860","2188","1404","6000"]
|
||||
]},
|
||||
"LightsList": {"Size": "12", "Wrap": "Yes", "Default": "1", "rows": [
|
||||
["21","34"],
|
||||
["34","0"],
|
||||
["37","34"],
|
||||
["21","34"],
|
||||
["38","34"],
|
||||
["22","34"],
|
||||
["17","17"],
|
||||
["17","17"],
|
||||
["42","42"],
|
||||
["4","4"],
|
||||
["17","17"],
|
||||
["16","1"]
|
||||
]},
|
||||
"WiperList": {"Size": "4", "Angle": "70", "rows": [
|
||||
["0","0.8","0.0","0.5"],
|
||||
["3","0.8","5.0","0.5"],
|
||||
["3","0.8","0.5","0.0"],
|
||||
["3","0.6","0.5","0.0"],
|
||||
["endL"]
|
||||
]},
|
||||
"UCList": {"Size": "6", "IntegratedBrakePN": "no", "IntegratedLocBrake": "no", "IntegratedBrake": "no", "rows": [
|
||||
["0","0","-1","0","-1","0.15","0.15","0","1","1"],
|
||||
["1","0","-1","0","0","0.00","0.00","1","3","1"],
|
||||
["2","0","-1","0","0","0.15","0.00","1","3","1"],
|
||||
["3","0","0","0","0","0.00","0.00","1","5","3"],
|
||||
["4","0","0","1","0","0.00","0.15","3","5","5"],
|
||||
["5","0","0","1","0","0.00","0.00","3","6","5"],
|
||||
["6","0","0","1","1","0.15","0.15","5","6","5"]
|
||||
]}
|
||||
}
|
||||
56
tests/unit/data/fiz/cd/754_v1/754.json
Normal file
56
tests/unit/data/fiz/cd/754_v1/754.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"_source": "cd/754_v1/754.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "74500", "Mred": "15000", "Vmax": "100", "PWR": "1460", "SandCap": "400", "HeatingP": "300"},
|
||||
"Dimensions": {"L": "16.54", "H": "4.335", "W": "2.900", "Cx": "-0.1"},
|
||||
"Wheels": {"D": "1.000", "AIM": "4000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "2.4", "Bd": "9.0", "Rmin": "100"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.1", "LocMaxBP": "4.5", "MaxASBP": "1.5", "RM": "0.69", "BCN": "8", "BCR": "0.114", "BCD": "0.06", "BCM": "8.1", "HiPP": "5", "LoPP": "3.5", "Vv": "0.8", "MinCP": "7.0", "MaxCP": "8.5", "CompressorSpeed": "0.069", "BCS": "1", "BSA": "2", "BM": "P10-Bgu", "CompressorPower": "Converter", "BVV": "240", "BRE": "0.9"},
|
||||
"BuffCoupl": {"ControlType": "cd754", "CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103"},
|
||||
"Cntrl": {"BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "6", "BDelay3": "36", "BDelay4": "32", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "14", "SCPN": "3", "AutoRelay": "Yes", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GPR", "rows": [
|
||||
["-1","0.7","-1","15","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.29","-1","9","Pneumatic"],
|
||||
["6","0","-1","15","Pneumatic"]
|
||||
]},
|
||||
"LightsList": {"Size": "8", "Wrap": "No", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["388","34"],
|
||||
["21","34"],
|
||||
["1","16"],
|
||||
["16","1"],
|
||||
["22","34"],
|
||||
["38","38"],
|
||||
["34","34"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "227.8"},
|
||||
"Engine": {"EngineType": "DumbDE", "Trans": "18:62", "Ftmax": "215000", "Flat": "0", "Vhyp": "7.2", "Vadd": "5.5", "Cr": "1.0", "RelayType": "0"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","20","100","3000","20.8","1340","1713"],
|
||||
["1","18.5","110","2700","25","1340","1713"],
|
||||
["2","17.2","135","2500","30","1340","1713"],
|
||||
["3","14.3","170","2000","48.5","1340","1713"]
|
||||
]},
|
||||
"WWList": {"Size": "14", "rows": [
|
||||
["500","0","0","0"],
|
||||
["500","0","0","0"],
|
||||
["550","122","78","273"],
|
||||
["550","122","78","273"],
|
||||
["600","244","147","547"],
|
||||
["650","365","221","820"],
|
||||
["700","287","295","1094"],
|
||||
["750","609","369","1367"],
|
||||
["800","730","442","1641"],
|
||||
["850","852","516","1914"],
|
||||
["900","973","590","2187"],
|
||||
["950","1095","664","2461"],
|
||||
["1000","1216","737","2734"],
|
||||
["1050","1338","811","3007"],
|
||||
["1100","1460","885","3281"]
|
||||
]}
|
||||
}
|
||||
41
tests/unit/data/fiz/cd/810_v2/810.json
Normal file
41
tests/unit/data/fiz/cd/810_v2/810.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"_source": "cd/810_v2/810.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "Type": "dmu", "M": "20000", "Vmax": "80", "PWR": "155", "SandCap": "25"},
|
||||
"Load": {"MaxLoad": "55", "OverLoadFactor": "2.2", "LoadQ": "pieces", "LoadAccepted": "passengers", "LoadSpeed": "0.5", "UnLoadSpeed": "0.7"},
|
||||
"Dimensions": {"L": "13.86", "H": "2.8", "W": "3.00", "Cx": "0.38"},
|
||||
"Wheels": {"D": "0.84", "Tw": "1.435", "AIM": "300", "Axle": "1'A'", "Bd": "8", "Rmin": "100", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeType": "Oerlikon", "BrakeValve": "ESt3_PZZ", "Size": "100", "NBpA": "4", "MBF": "45.0", "MaxBP": "3.8", "BCN": "2", "BCR": "0.127", "BCD": "0.14", "BCM": "3.25", "HiPP": "5.0", "LoPP": "3.5", "Vv": "0.257", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.0136", "BM": "P10-Bg", "BVV": "75", "BRE": "0.87", "AirLeakRate": "1.15", "CompressorPower": "Converter"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "3"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.35", "CloseSpeed": "0.625", "DoorMaxShiftL": "0.9", "DoorMaxShiftR": "0.9", "DoorOpenMethod": "Plug", "DoorClosureWarning": "No", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.02", "DoorNeedPermit": "Yes", "DoorPermitList": "1|0|2", "DoorPermitListDefault": "2", "DoorAutoCloseRemote": "No"},
|
||||
"Cntrl": {"BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "8", "SCPN": "2", "AutoRelay": "Yes", "IniCDelay": "0.5", "SCDelay": "0.3", "ManualBrake": "Yes", "WaterStart": "Battery", "OilStart": "Automatic", "FuelStart": "Automatic", "ConverterStart": "Automatic", "ConverterStartDelay": "4", "CompartmentLightsStart": "Manual", "rows": [
|
||||
["-1","1.0","-1","12","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.43","-1","9","Pneumatic"],
|
||||
["2","0.4","-1","9","Pneumatic"],
|
||||
["3","0.37","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.3","-1","9","Pneumatic"],
|
||||
["6","0","-1","16","Pneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"HMaxVoltage": "3000", "Heating": "Generator", "HGeneratorEngine": "Main", "HGeneratorMinRPM": "600", "HGeneratorMinVoltage": "2400", "HGeneratorMaxRPM": "2150", "HGeneratorMaxVoltage": "3300"},
|
||||
"Security": {"AwareSystem": "Active", "AwareDelay": "30", "SoundSignalDelay": "0.1", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "5", "RadioStop": "No"},
|
||||
"Engine": {"EngineType": "DieselEngine", "Trans": "13:51", "nmin": "600", "nmax": "2150", "nmax_cutoff": "2500", "AIM": "60", "EUS": "2.5", "EDS": "2.5", "IsTC": "Yes", "TC_TMMax": "2.70", "TC_CP": "0.85", "TC_LT": "850", "TC_LR": "1", "TC_ULR": "1", "TC_FRI": "1", "TC_FRD": "1", "TC_TII": "0.60", "TC_TIO": "0", "TC_TOO": "0", "TC_LS": "55", "TC_ULS": "45", "IsRetarder": "No", "WaterMaxTemperature": "105", "WaterCoolingTemperature": "90", "WaterFlowTemperature": "75", "WaterAuxCircuit": "No", "WaterCoolingFanSpeed": "-100", "NominalCoolingPower": "154"},
|
||||
"MotorParamTable": {"minVelfullengage": "-0.1", "engageDia": "1", "engageMaxForce": "1900", "engagefriction": "1", "rows": [
|
||||
["0","0","0","-1","1"],
|
||||
["1","2.120","-1","33","1"],
|
||||
["2","1.000","25","200","1"]
|
||||
]},
|
||||
"DList": {"Size": "8", "Mmax": "850", "nMmax": "29", "nmax": "41", "Mnmax": "750", "nominalfill": "0.9", "Mstand": "100.0", "rows": [
|
||||
["0","0.1","0"],
|
||||
["1","0.2","1"],
|
||||
["2","0.3","2"],
|
||||
["3","0.4","2"],
|
||||
["4","0.5","2"],
|
||||
["5","0.6","2"],
|
||||
["6","0.7","2"],
|
||||
["7","0.8","2"],
|
||||
["8","1.0","2"]
|
||||
]}
|
||||
}
|
||||
13
tests/unit/data/fiz/dr2_v1/dr2.json
Normal file
13
tests/unit/data/fiz/dr2_v1/dr2.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"_source": "pkp/dr2_v1/dr2.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "300", "Vmax": "40", "PWR": "6"},
|
||||
"Dimensions": {"L": "1.65", "H": "0.79", "W": "1.47", "Cx": "0.058"},
|
||||
"Load": {"MaxLoad": "3", "LoadQ": "pieces", "LoadAccepted": "Passengers", "LoadSpeed": "0.5", "UnLoadSpeed": "0.5"},
|
||||
"Wheels": {"D": "0.4", "AIM": "4.8", "Tw": "1.435", "Axle": "1'A", "Bd": "0.86", "Rmin": "20", "BearingType": "Slide"},
|
||||
"BuffCoupl": {"CType": "None"},
|
||||
"Brake": {"BrakeType": "Individual", "MBF": "0.2"},
|
||||
"Cntrl": {"BrakeSystem": "Individual", "LocalBrake": "ManualBrake", "MCPN": "1", "SCDelay": "0.2", "rows": []},
|
||||
"Power": {"EnginePower": "Internal", "PowerType": "BioPower"},
|
||||
"Engine": {"EngineType": "WheelsDriven", "Trans": "9:2", "Ftmax": "1200"}
|
||||
}
|
||||
61
tests/unit/data/fiz/e186_v2/eu47.json
Normal file
61
tests/unit/data/fiz/e186_v2/eu47.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"_source": "pkp/e186_v2/eu47.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "81000", "Mred": "9000", "Vmax": "160", "PWR": "5600", "SandCap": "760"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "18.900", "H": "3.95", "W": "2.977", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.250", "AIM": "4000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "1.75", "Bd": "10.3", "Rmin": "100"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "50", "MaxBP": "3.8", "BCN": "8", "RM": "1.4", "BCR": "0.127", "BCD": "0.04", "BCM": "2.7", "BCS": "0.8", "BSA": "0", "BM": "Disk2", "BVV": "125", "Vv": "0.8", "CompressorSpeed": "0.04", "CompressorPower": "Converter", "MinCP": "8", "MaxCP": "10", "UBB3": "8", "LPOn": "3.0", "LPOff": "4.5", "HandlePipeUnlockPos": "2", "EmergencyCutsOffHandle": "Yes"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "8", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "3.5", "ValveOnArea": "0.0002", "ValveOffArea": "0.0002", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103", "ControlType": "EU47"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BrakeOpModes": "PN", "BCPN": "4", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Automatic", "LocalBrake": "PneumaticBrake", "MCPN": "7", "SCPN": "4", "AutoRelay": "No", "MainInitTime": "10", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GPR", "BrakeHandle": "MHZ_6P", "LocBrakeHandle": "FD1", "ScndS": "Yes", "SBD": "0", "ConverterStart": "Automatic", "ConverterStartDelay": "10", "PantCompressorStart": "Automatic", "PantAutoValve": "Yes", "EIMCtrlType": "1", "HAO": "No", "HMO": "No", "HGDP1": "0.0", "HGDP2": "1", "OMP": "0.4", "DirChangeMaxPos": "3", "LocalBrakeTraxx": "Yes", "PantEPValveStart": "Manual", "PantEPValveSpring": "No", "rows": [
|
||||
["-1","0.8","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal,SeparateAcknowledge", "AwareDelay": "30", "SoundSignalDelay": "2.5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "5", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "4", "MaxVoltage": "3900", "MaxCurrent": "2000", "MinH": "0.48", "MinV": "1900", "MaxH": "2.5", "CSW": "1.5", "PhysicalLayout": "3"},
|
||||
"Engine": {"EngineType": "ElectricInductionMotor", "Trans": "48:251", "dfic": "861", "dfmax": "1.84", "p": "2", "cfu": "43.7", "cim": "13.4", "icif": "0.679", "Uzmax": "2183", "Uzh": "2183", "DU": "20", "I0": "20", "fcfu": "43.7", "F0": "300", "a1": "0.4", "Pmax": "5600", "Fh": "150", "Ph": "2600", "Vh0": "5", "Vh1": "10", "Imax": "1950", "abed": "1", "Flat": "Yes"},
|
||||
"Switches": {"Pantograph": "Impulse"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "OverrideManual": "No", "InitPwr": "1.0", "MaxPwrVel": "-1", "StartVel": "-1", "VelStep": "5", "PwrStep": "0.01", "MinPwr": "0.0", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "160", "Offset": "0", "kPpos": "0.1", "kPneg": "0.2", "kIpos": "0.03", "kIneg": "0.03", "BrakeIntervention": "No", "SpeedCtrlType": "Time", "SpeedCtrlDelay": "0.5"},
|
||||
"Doors": {"DoorPermitList": "0|3", "DoorPermitListDefault": "1"},
|
||||
"Circuit": {"ImaxHi": "500"},
|
||||
"ffList": {"Size": "7", "rows": [
|
||||
["0","0.4"],
|
||||
["6.3","0.4"],
|
||||
["7.1","0.6"],
|
||||
["25.6","0.6"],
|
||||
["26.4","0.7"],
|
||||
["29.6","0.7"],
|
||||
["30.4","1.0"],
|
||||
["60.8","2.0"]
|
||||
]},
|
||||
"LightsList": {"Size": "12", "Wrap": "Yes", "Default": "1", "rows": [
|
||||
["21","34"],
|
||||
["34","0"],
|
||||
["37","34"],
|
||||
["21","34"],
|
||||
["38","34"],
|
||||
["22","34"],
|
||||
["17","17"],
|
||||
["17","17"],
|
||||
["42","42"],
|
||||
["4","4"],
|
||||
["17","17"],
|
||||
["16","1"]
|
||||
]},
|
||||
"WiperList": {"Size": "4", "Angle": "70", "rows": [
|
||||
["0","0.8","0.0","0.5"],
|
||||
["3","0.8","5.0","0.5"],
|
||||
["3","0.8","0.5","0.0"],
|
||||
["3","0.6","0.5","0.0"],
|
||||
["endL"]
|
||||
]}
|
||||
}
|
||||
41
tests/unit/data/fiz/e6act_v2/e6acta.json
Normal file
41
tests/unit/data/fiz/e6act_v2/e6acta.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"_source": "pkp/e6act_v2/e6acta.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "115000", "Mred": "9000", "Vmax": "120", "PWR": "5004", "SandCap": "700"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "20.33", "H": "4.325", "W": "3.0", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.250", "AIM": "4000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "3.9", "Bd": "14.2", "Rmin": "150", "BearingType": "Roll"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "35"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "50", "MaxBP": "4.4", "BCN": "12", "MaxLBP": "4.4", "RM": "1.4", "BCR": "0.127", "BCD": "0.04", "BCM": "2.7", "BCS": "0.8", "BSA": "0", "BRE": "0.97", "BM": "P10-Bgu", "BVV": "100", "Vv": "0.8", "CompressorSpeed": "0.04", "MinCP": "8", "MaxCP": "10", "DynamicBrake": "Automatic", "LPOn": "3.0", "LPOff": "4.5", "UBB1": "8", "UBB2": "1", "HandlePipeUnlockPos": "0", "EmergencyCutsOffHandle": "Yes"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "2.9", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Automatic", "LocalBrake": "PneumaticBrake", "MCPN": "10", "SCPN": "12", "AutoRelay": "No", "MainInitTime": "5", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GP", "BrakeHandle": "MHZ_K5P", "LocBrakeHandle": "FD1", "ConverterStart": "Automatic", "ConverterStartDelay": "10", "PantCompressorStart": "Mixed", "PantAutoValve": "Yes", "LocalBrakeTraxx": "Yes", "HAO": "No", "HMO": "No", "HGDP1": "0.0", "HGDP2": "1", "BrakeOpModes": "PN", "AutomaticCabActivation": "No", "InactivaCabEmergencyBrake": "Yes", "InactiveCabFlag": "15", "rows": [
|
||||
["-1","0.8","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "2.1", "CabDependent": "Yes", "RadioStop": "Yes"},
|
||||
"Circuit": {"ImaxHi": "500"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "4600", "MaxCurrent": "1600", "MinH": "0.8", "MaxH": "1.8", "CSW": "1.5", "MinV": "2000", "InsetV": "2000", "PhysicalLayout": "3"},
|
||||
"Engine": {"EngineType": "ElectricInductionMotor", "Trans": "54:253", "dfic": "1021", "dfmax": "0.92", "p": "2", "cfu": "48.9", "cim": "15", "icif": "0.664", "Uzmax": "2150", "Uzh": "2150", "DU": "20", "I0": "20", "fcfu": "48.9", "F0": "420", "a1": "1.53", "Pmax": "5100", "Fh": "200", "Ph": "3000", "Vh0": "5", "Vh1": "10", "Imax": "1870", "abed": "1", "eped": "10"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "OverrideManual": "No", "InitPwr": "1.0", "MaxPwrVel": "-1", "StartVel": "-1", "VelStep": "10", "PwrStep": "0.01", "MinPwr": "0.0", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "120", "Offset": "-0.1", "kPpos": "0.2", "kPneg": "0.4", "kIpos": "0.02", "kIneg": "0.00", "BrakeIntervention": "No", "SpeedCtrlDelay": "0.5"},
|
||||
"ffList": {"Size": "2", "rows": [
|
||||
["0","0.40"],
|
||||
["19.6","0.805"],
|
||||
["25.7","1.055"]
|
||||
]},
|
||||
"LightsList": {"Size": "7", "Wrap": "no", "Default": "4", "rows": [
|
||||
["16","1"],
|
||||
["21","34"],
|
||||
["22","34"],
|
||||
["0","0"],
|
||||
["34","34"],
|
||||
["17","34"],
|
||||
["38","34"]
|
||||
]}
|
||||
}
|
||||
25
tests/unit/data/fiz/ed72_v1/5bs-ra.json
Normal file
25
tests/unit/data/fiz/ed72_v1/5bs-ra.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"_source": "pkp/ed72_v1/5bs-ra.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "35500", "Vmax": "110", "PWR": "0", "SandCap": "0", "Type": "ezt"},
|
||||
"Load": {"MaxLoad": "54", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "1"},
|
||||
"Dimensions": {"L": "20.87", "H": "4", "W": "2.9", "Cx": "0.2"},
|
||||
"Wheels": {"D": "0.94", "AIM": "2000", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EP2", "NBpA": "4", "MBF": "85.0", "MaxBP": "4", "BCN": "1", "BCR": "0.203", "BCD": "0.15", "BCM": "9.39", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "5.8", "MaxCP": "7.2", "CompressorSpeed": "0.013", "TareMaxBP": "2.5", "BVV": "88", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "5", "BRE": "0.9", "CompressorPower": "Coupler2"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.4", "CloseSpeed": "0.4", "DoorCloseDelay": "0.5", "DoorMaxShiftL": "0.625", "DoorMaxShiftR": "0.625", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes", "DoorBlocked": "Yes"},
|
||||
"BuffCoupl1": {"ControlType": "ed72", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39"},
|
||||
"BuffCoupl2": {"ControlType": "ed72", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-119"},
|
||||
"Cntrl": {"BrakeHandle": "FVel6", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "52", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "ManualBrake", "MCPN": "3", "SCPN": "3", "IniCDelay": "0.0", "SCDelay": "0.975", "CoupledCtrl": "Yes", "ScndS": "Yes", "BatteryStart": "Disabled", "ConverterStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes", "MagnetLocation": "5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Switches": {"Pantograph": "impulse", "Converter": "impulse"}
|
||||
}
|
||||
25
tests/unit/data/fiz/ed72_v1/5bs-rb.json
Normal file
25
tests/unit/data/fiz/ed72_v1/5bs-rb.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"_source": "pkp/ed72_v1/5bs-rb.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "35500", "Vmax": "110", "PWR": "0", "SandCap": "0", "Type": "ezt"},
|
||||
"Load": {"MaxLoad": "54", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "1"},
|
||||
"Dimensions": {"L": "20.87", "H": "4", "W": "2.9", "Cx": "0.2"},
|
||||
"Wheels": {"D": "0.94", "AIM": "2000", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EP2", "NBpA": "4", "MBF": "85.0", "MaxBP": "4", "BCN": "1", "BCR": "0.203", "BCD": "0.15", "BCM": "9.39", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "5.8", "MaxCP": "7.2", "CompressorSpeed": "0.013", "TareMaxBP": "2.5", "BVV": "88", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "5", "BRE": "0.9", "CompressorPower": "Coupler1"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.315", "CloseSpeed": "0.325", "DoorMaxShiftL": "0.625", "DoorCloseDelay": "1.6", "DoorMaxShiftR": "0.625", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes", "DoorBlocked": "Yes"},
|
||||
"BuffCoupl1": {"ControlType": "ed72", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-119"},
|
||||
"BuffCoupl2": {"ControlType": "ed72", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39"},
|
||||
"Cntrl": {"BrakeHandle": "FVel6", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "52", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "ManualBrake", "MCPN": "3", "SCPN": "3", "IniCDelay": "0.0", "SCDelay": "0.975", "CoupledCtrl": "Yes", "ScndS": "Yes", "ConverterStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes", "MagnetLocation": "5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Switches": {"Pantograph": "impulse", "Converter": "impulse"}
|
||||
}
|
||||
47
tests/unit/data/fiz/ed72_v1/6bs-sa.json
Normal file
47
tests/unit/data/fiz/ed72_v1/6bs-sa.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"_source": "pkp/ed72_v1/6bs-sa.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "55500", "Vmax": "110", "PWR": "608", "SandCap": "500", "Type": "ezt"},
|
||||
"Load": {"MaxLoad": "76", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.77", "H": "4.12", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.0", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "2.75", "Bd": "15.6", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EP2", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.1", "BCN": "2", "BCR": "0.178", "BCD": "0.15", "BCM": "7.32", "HiPP": "5", "LoPP": "3.5", "Vv": "0.1", "MinCP": "5.8", "MaxCP": "7.2", "CompressorSpeed": "0.0", "TareMaxBP": "2.8", "BVV": "100", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "4", "BRE": "0.9"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.38", "CloseSpeed": "0.475", "DoorCloseDelay": "2.0", "DoorMaxShiftL": "0.625", "DoorMaxShiftR": "0.625", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes", "DoorBlocked": "Yes"},
|
||||
"BuffCoupl1": {"ControlType": "ed72", "CType": "Automatic", "kB": "19200", "DmaxB": "0.05", "FmaxB": "740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-119"},
|
||||
"BuffCoupl2": {"ControlType": "ed72", "CType": "Automatic", "kB": "19200", "DmaxB": "0.05", "FmaxB": "740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-127"},
|
||||
"Cntrl": {"BrakeSystem": "ElectroPneumatic", "MaxBPMass": "75", "BCPN": "1", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "DynamicBrake": "Passive", "MCPN": "3", "SCPN": "3", "AutoRelay": "Yes", "IniCDelay": "0.0", "SCDelay": "0.975", "CoupledCtrl": "Yes", "ScndS": "Yes", "BatteryStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","-1","-1","0","ElectroPneumatic"],
|
||||
["1","-1","0.35","4","ElectroPneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "1", "MaxVoltage": "3600", "MaxCurrent": "1200", "MinH": "0.38", "MinV": "1900", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "1"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "19:70", "WindingRes": "0.3836", "nmax": "2390"},
|
||||
"Switches": {"Pantograph": "Impulse"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","21.52","81","-0.02","148","81","-0.02","1"],
|
||||
["1","21.68","120","-0.02","148.2","120","-0.02","1"],
|
||||
["2","21.17","130","0.01","142.3","130","0.01","1"],
|
||||
["3","22.46","70","0.24","150.1","70","0.24","0"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "280", "ImaxHi": "281", "IminLo": "135", "IminHi": "175"},
|
||||
"RList": {"Size": "14", "RVent": "No", "rows": [
|
||||
["0","0","0","0","0"],
|
||||
["1","17.682","1","4","0"],
|
||||
["2","14.182","1","4","1"],
|
||||
["2","10.682","1","4","1"],
|
||||
["2","8.474","1","4","1"],
|
||||
["2","6.266","1","4","1"],
|
||||
["2","4.605","1","4","1"],
|
||||
["2","2.944","1","4","1"],
|
||||
["2","1.472","1","4","1"],
|
||||
["2","0","1","4","1"],
|
||||
["3","8.841","2","2","1"],
|
||||
["3","5.341","2","2","1"],
|
||||
["3","3.133","2","2","1"],
|
||||
["3","1.472","2","2","1"],
|
||||
["3","0","2","2","0"]
|
||||
]}
|
||||
}
|
||||
47
tests/unit/data/fiz/ed72_v1/6bs-sb.json
Normal file
47
tests/unit/data/fiz/ed72_v1/6bs-sb.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"_source": "pkp/ed72_v1/6bs-sb.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "55500", "Vmax": "110", "PWR": "608", "SandCap": "500", "Type": "ezt"},
|
||||
"Load": {"MaxLoad": "76", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.77", "H": "4.12", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.0", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "2.75", "Bd": "15.6", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EP2", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.1", "BCN": "2", "BCR": "0.178", "BCD": "0.15", "BCM": "7.32", "HiPP": "5", "LoPP": "3.5", "Vv": "0.1", "MinCP": "5.8", "MaxCP": "7.2", "CompressorSpeed": "0.0", "TareMaxBP": "2.8", "BVV": "100", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "4", "BRE": "0.9"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.335", "CloseSpeed": "0.34", "DoorCloseDelay": "1.5", "DoorMaxShiftL": "0.625", "DoorMaxShiftR": "0.625", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes", "DoorBlocked": "Yes"},
|
||||
"BuffCoupl1": {"ControlType": "ed72", "CType": "Automatic", "kB": "19200", "DmaxB": "0.05", "FmaxB": "740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-127"},
|
||||
"BuffCoupl2": {"ControlType": "ed72", "CType": "Automatic", "kB": "19200", "DmaxB": "0.05", "FmaxB": "740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-119"},
|
||||
"Cntrl": {"BrakeSystem": "ElectroPneumatic", "MaxBPMass": "75", "BCPN": "1", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "DynamicBrake": "Passive", "MCPN": "3", "SCPN": "3", "AutoRelay": "Yes", "IniCDelay": "0.0", "SCDelay": "0.975", "CoupledCtrl": "Yes", "ScndS": "Yes", "BatteryStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","-1","-1","0","ElectroPneumatic"],
|
||||
["1","-1","0.35","4","ElectroPneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "1200", "MinH": "0.38", "MinV": "1900", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "2"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "19:70", "WindingRes": "0.3836", "nmax": "2390"},
|
||||
"Switches": {"Pantograph": "Impulse"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","21.52","81","-0.02","148","81","-0.02","1"],
|
||||
["1","21.68","120","-0.02","148.2","120","-0.02","1"],
|
||||
["2","21.17","130","0.01","142.3","130","0.01","1"],
|
||||
["3","22.46","70","0.24","150.1","70","0.24","0"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "280", "ImaxHi": "281", "IminLo": "135", "IminHi": "175"},
|
||||
"RList": {"Size": "14", "RVent": "No", "rows": [
|
||||
["0","0","0","0","0"],
|
||||
["1","17.682","1","4","0"],
|
||||
["2","14.182","1","4","1"],
|
||||
["2","10.682","1","4","1"],
|
||||
["2","8.474","1","4","1"],
|
||||
["2","6.266","1","4","1"],
|
||||
["2","4.605","1","4","1"],
|
||||
["2","2.944","1","4","1"],
|
||||
["2","1.472","1","4","1"],
|
||||
["2","0","1","4","1"],
|
||||
["3","8.841","2","2","1"],
|
||||
["3","5.341","2","2","1"],
|
||||
["3","3.133","2","2","1"],
|
||||
["3","1.472","2","2","1"],
|
||||
["3","0","2","2","0"]
|
||||
]}
|
||||
}
|
||||
52
tests/unit/data/fiz/elf_v1/21we-a.json
Normal file
52
tests/unit/data/fiz/elf_v1/21we-a.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"_source": "pkp/elf_v1/21we-a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "28650", "Vmax": "160", "PWR": "800", "SandCap": "500", "Type": "ezt", "HeatingP": "37"},
|
||||
"Load": {"MaxLoad": "108", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2.3", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.081", "H": "4.228", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.850", "AIM": "8000", "Tw": "1.435", "Axle": "Bo'", "Ad": "2.83", "Bd": "16.3", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.1", "MaxLBP": "4.2", "RM": "0.74", "RV": "-1", "BCN": "4", "BCR": "0.127", "BCD": "0.05", "BCM": "1.9075", "HiPP": "5", "LoPP": "3.5", "Vv": "0.5", "MinCP": "7.7", "MaxCP": "9.0", "CompressorSpeed": "0.025", "BVV": "150", "BM": "Cosid", "BCS": "1", "BSA": "0.00", "BRE": "0.95", "TareMaxBP": "2.6", "CompressorPower": "Converter", "LPOn": "3.0", "LPOff": "4.5", "UBB1": "2", "UBB2": "8"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "2.9", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.24", "CloseSpeed": "0.2", "DoorMaxShiftL": "0.74", "DoorMaxShiftR": "0.74", "DoorOpenMethod": "Plug", "DoorStayOpen": "5.0", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.05", "DoorCloseDelay": "1.8", "PlatformMaxShift": "0.270", "PlatformSpeed": "0.4", "PlatformOpenMethod": "Shift", "MirrorMaxShift": "45", "DoorNeedPermit": "Yes", "DoorPermitList": "1|0|2|3", "DoorPermitListDefault": "2", "DoorAutoCloseRemote": "Yes", "MirrorVelClose": "25"},
|
||||
"BuffCoupl1": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39", "ControlType": "en62"},
|
||||
"BuffCoupl2": {"CType": "Articulated", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-255"},
|
||||
"Cntrl": {"BrakeHandle": "MHZ_K5P", "LocBrakeHandle": "FD1", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "37", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "LocalBrake": "PneumaticBrake", "MCPN": "4", "EIMCtrlType": "2", "SCPN": "1", "MainInitTime": "10", "IniCDelay": "1.0", "SCDelay": "0.2", "CoupledCtrl": "No", "SBD": "0.6", "ASB": "Yes", "CompressorStart": "Automatic", "ConverterStart": "Automatic", "ConverterStartDelay": "10.0", "PantCompressorStart": "Mixed", "PantAutoValve": "Yes", "BrakeDelays": "PR", "BrakeOpModes": "PN", "DirChangeMaxPos": "3", "HAO": "No", "HMO": "Yes", "HGDP1": "0", "ReleaseParkingBySpringBrake": "Yes", "MotorBlowersStart": "Converter", "CompartmentLightsStart": "Manual", "AutomaticCabActivation": "No", "InactivaCabEmergencyBrake": "Yes", "InactiveCabFlag": "3", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Circuit": {"ImaxHi": "500"},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "0.1", "EmergencyBrakeDelay": "2.1", "CabDependent": "Yes", "RadioStop": "Yes", "EmergencyBrakeWarningSignal": "2", "MagnetLocation": "4.5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main", "HMaxVoltage": "400"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "1", "MaxVoltage": "4000", "MinV": "2000", "MaxCurrent": "1200", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "1"},
|
||||
"Blending": {"MED_amax": "1.04", "MED_EPVC": "No", "MED_Ncor": "No", "MED_FirstDelayED": "2", "MED_ScndDelayED": "1"},
|
||||
"Engine": {"EngineType": "ElectricInductionMotor", "Trans": "40:218", "dfic": "470", "dfmax": "0.790", "p": "2", "cfu": "33.43", "cim": "10.22", "icif": "0.67", "Uzmax": "2340", "Uzh": "2340", "DU": "20", "I0": "20", "fcfu": "33.5", "F0": "75", "a1": "0.0", "Pmax": "980", "Fh": "48", "Ph": "830", "Vh0": "2", "Vh1": "5", "Imax": "377", "abed": "0", "Flat": "Yes", "edep": "1.0", "MotorBlowersSpeed": "-29", "InvNo": "2", "InvCtrCplFlag": "255"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "0|40|50|60|70|80|100|120|140|160", "OverrideManual": "Yes", "InitPwr": "0.3", "MaxPwrVel": "5", "StartVel": "2", "VelStep": "5", "PwrStep": "0.1", "MinPwr": "0.3", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "160", "Offset": "-0.5", "kPpos": "0.1", "kPneg": "0.4", "kIpos": "0.06", "kIneg": "0.06", "BrakeIntervention": "No", "PowerUpSpeed": "0.3", "PowerDownSpeed": "0.3"},
|
||||
"AI": {"Pantstate": "1"},
|
||||
"ffList": {"Size": "10", "rows": [
|
||||
["0","2.49"],
|
||||
["22.1","2.49"],
|
||||
["24.1","2.50"],
|
||||
["31.3","2.50"],
|
||||
["32.3","2.53"],
|
||||
["39.3","3.0"],
|
||||
["65","5.0"],
|
||||
["91","7.0"],
|
||||
["124","9.0"],
|
||||
["161","11.7"],
|
||||
["177","13.0"]
|
||||
]},
|
||||
"LightsList": {"Size": "5", "Wrap": "no", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["21","34"],
|
||||
["22","34"],
|
||||
["34","34"],
|
||||
["16","1"]
|
||||
]}
|
||||
}
|
||||
25
tests/unit/data/fiz/elf_v1/21we-b.json
Normal file
25
tests/unit/data/fiz/elf_v1/21we-b.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"_source": "pkp/elf_v1/21we-b.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "50000", "Vmax": "160", "PWR": "0", "SandCap": "500", "Type": "ezt", "HeatingP": "37"},
|
||||
"Load": {"MaxLoad": "108", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2.3", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "16.5", "H": "4.12", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.850", "AIM": "670", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.83", "Bd": "16.3", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "2", "MBF": "85.0", "MaxBP": "3.1", "MaxLBP": "4.2", "RM": "0.74", "RV": "-1", "BCN": "8", "BCR": "0.127", "BCD": "0.05", "BCM": "1.9075", "HiPP": "5", "LoPP": "3.5", "Vv": "0.1", "MinCP": "7.7", "MaxCP": "9.0", "CompressorSpeed": "0.0000001", "BVV": "176", "BM": "Cosid", "BCS": "1", "BSA": "0.00", "BRE": "0.95", "TareMaxBP": "1.9"},
|
||||
"SpringBrake": {"Volume": "20", "MBF": "5.8", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.24", "CloseSpeed": "0.2", "DoorMaxShiftL": "0.74", "DoorMaxShiftR": "0.74", "DoorOpenMethod": "Plug", "DoorStayOpen": "5.0", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.05", "DoorCloseDelay": "1.8", "PlatformMaxShift": "0.270", "PlatformSpeed": "0.4", "PlatformOpenMethod": "Shift", "MirrorMaxShift": "45", "DoorNeedPermit": "Yes", "DoorPermitList": "1|0|2|3", "DoorPermitListDefault": "2", "DoorAutoCloseRemote": "Yes"},
|
||||
"BuffCoupl1": {"CType": "Articulated", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-255"},
|
||||
"BuffCoupl2": {"CType": "Articulated", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-255"},
|
||||
"Cntrl": {"BrakeHandle": "MHZ_K5P", "LocBrakeHandle": "FD1", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "74", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "LocalBrake": "PneumaticBrake", "MCPN": "4", "EIMCtrlType": "2", "SCPN": "1", "IniCDelay": "0.0", "SCDelay": "0.8", "CoupledCtrl": "No", "SBD": "0.6", "ASB": "Automatic", "CompressorStart": "Automatic", "ConverterStart": "Automatic", "ConverterStartDelay": "10.15", "BrakeDelays": "PR", "BrakeOpModes": "PN", "ReleaseParkingBySpringBrake": "Yes", "CompartmentLightsStart": "Manual", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "400"}
|
||||
}
|
||||
52
tests/unit/data/fiz/elf_v1/21we-c.json
Normal file
52
tests/unit/data/fiz/elf_v1/21we-c.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"_source": "pkp/elf_v1/21we-c.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "28650", "Vmax": "160", "PWR": "800", "SandCap": "500", "Type": "ezt", "HeatingP": "37"},
|
||||
"Load": {"MaxLoad": "95", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2.3", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "20.70", "H": "4.228", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.850", "AIM": "8000", "Tw": "1.435", "Axle": "Bo'", "Ad": "2.83", "Bd": "16.3", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.1", "MaxLBP": "4.2", "RM": "0.74", "RV": "-1", "BCN": "4", "BCR": "0.127", "BCD": "0.05", "BCM": "1.9075", "HiPP": "5", "LoPP": "3.5", "Vv": "0.5", "MinCP": "7.0", "MaxCP": "8.5", "CompressorSpeed": "0.025", "BVV": "150", "BM": "Cosid", "BCS": "1", "BSA": "0.00", "BRE": "0.95", "TareMaxBP": "2.6", "CompressorPower": "Converter", "LPOn": "3.0", "LPOff": "4.5", "UBB1": "2", "UBB2": "8"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "2.9", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.24", "CloseSpeed": "0.2", "DoorMaxShiftL": "0.74", "DoorMaxShiftR": "0.74", "DoorOpenMethod": "Plug", "DoorStayOpen": "5.0", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.05", "DoorCloseDelay": "1.8", "PlatformMaxShift": "0.270", "PlatformSpeed": "0.4", "PlatformOpenMethod": "Shift", "MirrorMaxShift": "45", "DoorNeedPermit": "Yes", "DoorPermitList": "1|0|2|3", "DoorPermitListDefault": "2", "DoorAutoCloseRemote": "Yes", "MirrorVelClose": "25"},
|
||||
"BuffCoupl1": {"CType": "Articulated", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-255"},
|
||||
"BuffCoupl2": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39", "ControlType": "en62"},
|
||||
"Cntrl": {"BrakeHandle": "MHZ_K5P", "LocBrakeHandle": "FD1", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "37", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "LocalBrake": "PneumaticBrake", "MCPN": "4", "EIMCtrlType": "2", "SCPN": "1", "MainInitTime": "10", "IniCDelay": "1.0", "SCDelay": "0.2", "CoupledCtrl": "No", "SBD": "0.6", "ASB": "Yes", "CompressorStart": "Automatic", "ConverterStart": "Automatic", "ConverterStartDelay": "10.0", "PantCompressorStart": "Mixed", "PantAutoValve": "Yes", "BrakeDelays": "PR", "BrakeOpModes": "PN", "DirChangeMaxPos": "3", "HAO": "No", "HMO": "Yes", "HGDP1": "0", "ReleaseParkingBySpringBrake": "Yes", "MotorBlowersStart": "Converter", "CompartmentLightsStart": "Manual", "AutomaticCabActivation": "No", "InactivaCabEmergencyBrake": "Yes", "InactiveCabFlag": "3", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Circuit": {"ImaxHi": "500"},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "0.1", "EmergencyBrakeDelay": "2.1", "CabDependent": "Yes", "RadioStop": "Yes", "EmergencyBrakeWarningSignal": "2", "MagnetLocation": "4.5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main", "HMaxVoltage": "400"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "1", "MaxVoltage": "4000", "MinV": "2000", "MaxCurrent": "1200", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "2"},
|
||||
"Blending": {"MED_amax": "1.04", "MED_EPVC": "No", "MED_Ncor": "No", "MED_FirstDelayED": "2", "MED_ScndDelayED": "1"},
|
||||
"Engine": {"EngineType": "ElectricInductionMotor", "Trans": "40:218", "dfic": "470", "dfmax": "0.790", "p": "2", "cfu": "33.43", "cim": "10.22", "icif": "0.67", "Uzmax": "2340", "Uzh": "2340", "DU": "20", "I0": "20", "fcfu": "33.5", "F0": "75", "a1": "0.0", "Pmax": "980", "Fh": "48", "Ph": "830", "Vh0": "2", "Vh1": "5", "Imax": "377", "abed": "0", "Flat": "Yes", "edep": "1.0", "MotorBlowersSpeed": "-29", "InvNo": "2", "InvCtrCplFlag": "255"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "0|40|50|60|70|80|100|120|140|160", "OverrideManual": "Yes", "InitPwr": "0.3", "MaxPwrVel": "5", "StartVel": "2", "VelStep": "5", "PwrStep": "0.1", "MinPwr": "0.3", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "160", "Offset": "-0.5", "kPpos": "0.1", "kPneg": "0.4", "kIpos": "0.06", "kIneg": "0.06", "BrakeIntervention": "No", "PowerUpSpeed": "0.3", "PowerDownSpeed": "0.3"},
|
||||
"AI": {"Pantstate": "2"},
|
||||
"ffList": {"Size": "10", "rows": [
|
||||
["0","2.49"],
|
||||
["22.1","2.49"],
|
||||
["24.1","2.50"],
|
||||
["31.3","2.50"],
|
||||
["32.3","2.53"],
|
||||
["39.3","3.0"],
|
||||
["65","5.0"],
|
||||
["91","7.0"],
|
||||
["124","9.0"],
|
||||
["161","11.7"],
|
||||
["177","13.0"]
|
||||
]},
|
||||
"LightsList": {"Size": "5", "Wrap": "no", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["21","34"],
|
||||
["22","34"],
|
||||
["34","34"],
|
||||
["16","1"]
|
||||
]}
|
||||
}
|
||||
54
tests/unit/data/fiz/elf_v1/22wec-a.json
Normal file
54
tests/unit/data/fiz/elf_v1/22wec-a.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"_source": "pkp/elf_v1/22wec-a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "29000", "Vmax": "120", "PWR": "800", "SandCap": "500", "Type": "ezt", "HeatingP": "37"},
|
||||
"Load": {"MaxLoad": "108", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2.3", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.081", "H": "4.228", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.850", "AIM": "8000", "Tw": "1.435", "Axle": "Bo'", "Ad": "2.83", "Bd": "16.3", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.1", "MaxLBP": "4.2", "RM": "0.74", "RV": "-1", "BCN": "4", "BCR": "0.127", "BCD": "0.05", "BCM": "1.9075", "HiPP": "5", "LoPP": "3.5", "Vv": "0.5", "MinCP": "7.7", "MaxCP": "9.0", "CompressorSpeed": "0.025", "BVV": "150", "BM": "Cosid", "BCS": "1", "BSA": "0.00", "BRE": "0.95", "TareMaxBP": "2.6", "CompressorPower": "Converter", "LPOn": "3.0", "LPOff": "4.5", "UBB1": "2", "UBB2": "8"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "2.9", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.24", "CloseSpeed": "0.2", "DoorMaxShiftL": "0.74", "DoorMaxShiftR": "0.74", "DoorOpenMethod": "Plug", "DoorStayOpen": "5.0", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.05", "DoorCloseDelay": "1.8", "PlatformMaxShift": "0.270", "PlatformSpeed": "0.4", "PlatformOpenMethod": "Shift", "MirrorMaxShift": "45", "DoorNeedPermit": "Yes", "DoorPermitList": "1|0|2|3", "DoorPermitListDefault": "2", "DoorAutoCloseRemote": "Yes", "MirrorVelClose": "25"},
|
||||
"BuffCoupl1": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39"},
|
||||
"BuffCoupl2": {"CType": "Articulated", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-255"},
|
||||
"Cntrl": {"BrakeHandle": "MHZ_K5P", "LocBrakeHandle": "FD1", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "35", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "LocalBrake": "PneumaticBrake", "MCPN": "4", "EIMCtrlType": "2", "SCPN": "1", "MainInitTime": "10", "IniCDelay": "1.0", "SCDelay": "0.2", "CoupledCtrl": "No", "SBD": "0.6", "ASB": "Yes", "CompressorStart": "Automatic", "ConverterStart": "Automatic", "ConverterStartDelay": "10.15", "BrakeDelays": "PR", "BrakeOpModes": "PN", "DirChangeMaxPos": "3", "HAO": "No", "HMO": "Yes", "HGDP1": "0", "ReleaseParkingBySpringBrake": "Yes", "MotorBlowersStart": "Converter", "CompartmentLightsStart": "Manual", "PantEPValveSpring": "No", "PantCompressorStart": "Automatic", "PantAutoValve": "Yes", "AutomaticCabActivation": "No", "InactivaCabEmergencyBrake": "Yes", "InactiveCabFlag": "9", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "0.1", "EmergencyBrakeDelay": "2.1", "CabDependent": "Yes", "RadioStop": "Yes", "EmergencyBrakeWarningSignal": "2", "MagnetLocation": "4.5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main", "HMaxVoltage": "400"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "1", "MaxVoltage": "4000", "MinV": "2000", "MaxCurrent": "1200", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "1"},
|
||||
"Switches": {"PantographPresets": "1|3|2"},
|
||||
"Circuit": {"ImaxHi": "500"},
|
||||
"Blending": {"MED_amax": "1.04", "MED_EPVC": "No", "MED_Ncor": "No", "MED_FirstDelayED": "2", "MED_ScndDelayED": "1"},
|
||||
"Engine": {"EngineType": "ElectricInductionMotor", "Trans": "40:218", "dfic": "470", "dfmax": "0.790", "p": "2", "cfu": "33.43", "cim": "10.22", "icif": "0.67", "Uzmax": "2340", "Uzh": "2340", "DU": "20", "I0": "20", "fcfu": "33.5", "F0": "75", "a1": "0.0", "Pmax": "990", "Fh": "48", "Ph": "830", "Vh0": "2", "Vh1": "5", "Imax": "377", "abed": "0", "Flat": "Yes", "edep": "1.0", "MotorBlowersSpeed": "-29", "InvNo": "2", "InvCtrCplFlag": "255"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "0|10|20|30|40|50|60|80|100|120", "OverrideManual": "Yes", "InitPwr": "0.3", "MaxPwrVel": "5", "StartVel": "2", "VelStep": "5", "PwrStep": "0.1", "MinPwr": "0.3", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "160", "Offset": "-0.5", "kPpos": "0.1", "kPneg": "0.4", "kIpos": "0.06", "kIneg": "0.06", "BrakeIntervention": "No", "PowerUpSpeed": "0.3", "PowerDownSpeed": "0.3"},
|
||||
"AI": {"Pantstate": "1"},
|
||||
"ffList": {"Size": "3", "rows": [
|
||||
["0","2.0"],
|
||||
["33.7","2.08"],
|
||||
["34.0","2.12"],
|
||||
["130.4","8.10"]
|
||||
]},
|
||||
"ffBrakeList": {"Size": "4", "rows": [
|
||||
["0","2.0"],
|
||||
["33.7","2.08"],
|
||||
["34.8","2.08"],
|
||||
["34.8","2.17"],
|
||||
["130.4","8.10"]
|
||||
]},
|
||||
"LightsList": {"Size": "6", "Wrap": "no", "Default": "1", "rows": [
|
||||
["21","34"],
|
||||
["22","34"],
|
||||
["16","1"],
|
||||
["34","34"],
|
||||
["17","34"],
|
||||
["38","34"]
|
||||
]}
|
||||
}
|
||||
26
tests/unit/data/fiz/en57_v1/5bgaiii_led_spot.json
Normal file
26
tests/unit/data/fiz/en57_v1/5bgaiii_led_spot.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"_source": "pkp/en57_v1/5bgaiii_led_spot.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "34000", "Vmax": "110", "PWR": "0", "SandCap": "500", "Type": "ezt", "HeatingP": "19.6"},
|
||||
"Load": {"MaxLoad": "95", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.286", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "AIM": "2000", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"BuffCoupl1": {"ControlType": "en57", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39"},
|
||||
"BuffCoupl2": {"ControlType": "en57", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-887", "PowerFlag": "768"},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes", "MagnetLocation": "5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"},
|
||||
"Switches": {"Pantograph": "impulse", "Converter": "impulse"},
|
||||
"Brake": {"BrakeValve": "EP2", "NBpA": "4", "MBF": "85.0", "MaxBP": "4", "BCN": "1", "BCR": "0.203", "BCD": "0.15", "BCM": "9.39", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "5.8", "MaxCP": "7.2", "CompressorSpeed": "0.013", "TareMaxBP": "2.5", "BVV": "88", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "5", "BRE": "0.9", "CompressorPower": "Coupler2"},
|
||||
"Cntrl": {"BrakeHandle": "FVel6", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "52", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "ManualBrake", "MCPN": "3", "SCPN": "3", "IniCDelay": "0.0", "SCDelay": "0.975", "CoupledCtrl": "Yes", "CompartmentLightsStart": "Manual", "BatteryStart": "Disabled", "ConverterStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.315", "CloseSpeed": "0.315", "DoorCloseDelay": "1.6", "DoorMaxShiftL": "0.625", "DoorMaxShiftR": "0.625", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes", "DoorBlocked": "Yes"}
|
||||
}
|
||||
26
tests/unit/data/fiz/en57_v1/5bgb.json
Normal file
26
tests/unit/data/fiz/en57_v1/5bgb.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"_source": "pkp/en57_v1/5bgb.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "34000", "Vmax": "110", "PWR": "0", "SandCap": "500", "Type": "ezt", "HeatingP": "19.6"},
|
||||
"Load": {"MaxLoad": "90", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.288", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "AIM": "2000", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"BuffCoupl1": {"ControlType": "en57", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-887", "PowerFlag": "768"},
|
||||
"BuffCoupl2": {"ControlType": "en57", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39"},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes", "MagnetLocation": "5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"},
|
||||
"Switches": {"Pantograph": "impulse", "Converter": "impulse"},
|
||||
"Brake": {"BrakeValve": "EP2", "NBpA": "4", "MBF": "85.0", "MaxBP": "4", "BCN": "1", "BCR": "0.203", "BCD": "0.15", "BCM": "9.39", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "5.8", "MaxCP": "7.2", "CompressorSpeed": "0.013", "TareMaxBP": "2.5", "BVV": "88", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "5", "BRE": "0.9", "CompressorPower": "Coupler1"},
|
||||
"Cntrl": {"BrakeHandle": "FVel6", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "52", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "ManualBrake", "MCPN": "3", "SCPN": "3", "IniCDelay": "0.0", "SCDelay": "0.975", "CoupledCtrl": "Yes", "CompartmentLightsStart": "Manual", "ConverterStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.315", "CloseSpeed": "0.315", "DoorCloseDelay": "1.6", "DoorMaxShiftL": "0.625", "DoorMaxShiftR": "0.625", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes", "DoorBlocked": "Yes"}
|
||||
}
|
||||
26
tests/unit/data/fiz/en57_v1/6ba_840.json
Normal file
26
tests/unit/data/fiz/en57_v1/6ba_840.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"_source": "pkp/en57_v1/6ba_840.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "34000", "Vmax": "110", "PWR": "0", "SandCap": "500", "Type": "ezt", "HeatingP": "19.6"},
|
||||
"Load": {"MaxLoad": "95", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.286", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "AIM": "2000", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"BuffCoupl1": {"ControlType": "en57", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39"},
|
||||
"BuffCoupl2": {"ControlType": "en57", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-887", "PowerFlag": "768"},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes", "MagnetLocation": "5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"},
|
||||
"Switches": {"Pantograph": "impulse", "Converter": "impulse"},
|
||||
"Brake": {"BrakeValve": "EP2", "NBpA": "4", "MBF": "85.0", "MaxBP": "4", "BCN": "1", "BCR": "0.203", "BCD": "0.15", "BCM": "9.39", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "5.8", "MaxCP": "7.2", "CompressorSpeed": "0.013", "TareMaxBP": "2.5", "BVV": "88", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "5", "BRE": "0.9", "CompressorPower": "Coupler2"},
|
||||
"Cntrl": {"BrakeHandle": "FVel6", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "52", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "ManualBrake", "MCPN": "3", "SCPN": "3", "IniCDelay": "0.0", "SCDelay": "0.975", "CoupledCtrl": "Yes", "CompartmentLightsStart": "Manual", "BatteryStart": "Disabled", "ConverterStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.32", "CloseSpeed": "0.242", "DoorCloseDelay": "3.35", "DoorMaxShiftL": "0.625", "DoorMaxShiftR": "0.625", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorNeedPermit": "Yes", "DoorAutoCloseVel": "10.0"}
|
||||
}
|
||||
25
tests/unit/data/fiz/en57_v1/6bai.json
Normal file
25
tests/unit/data/fiz/en57_v1/6bai.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"_source": "pkp/en57_v1/6bai.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "34000", "Vmax": "110", "PWR": "0", "SandCap": "500", "Type": "ezt", "HeatingP": "19.6"},
|
||||
"Load": {"MaxLoad": "80", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.286", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "AIM": "2000", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "K", "NBpA": "4", "MBF": "85.0", "MaxBP": "12", "BCN": "1", "BCR": "0.203", "BCD": "0.15", "BCM": "12.00", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "5.8", "MaxCP": "7.2", "CompressorSpeed": "0.013", "TareMaxBP": "2.5", "BVV": "88", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "5", "BRE": "0.9", "CompressorPower": "Coupler2"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.315", "CloseSpeed": "0.315", "DoorCloseDelay": "1.6", "DoorMaxShiftL": "0.625", "DoorMaxShiftR": "0.625", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes", "DoorBlocked": "Yes"},
|
||||
"BuffCoupl1": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39"},
|
||||
"BuffCoupl2": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-887", "PowerFlag": "768"},
|
||||
"Cntrl": {"BrakeHandle": "St113", "BrakeSystem": "ElectroPneumatic", "LocalBrake": "ManualBrake", "MaxBPMass": "52", "BCPN": "5", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "DynamicBrake": "Passive", "MCPN": "3", "SCPN": "3", "IniCDelay": "0.0", "SCDelay": "0.975", "CoupledCtrl": "Yes", "CompartmentLightsStart": "Manual", "BatteryStart": "Disabled", "ConverterStart": "Disabled", "rows": [
|
||||
["-1","0.5","-1","9","Pneumatic"],
|
||||
["0","-1","0.0","6","ElectroPneumatic"],
|
||||
["1","-1","0.35","4","ElectroPneumatic"],
|
||||
["2","-1","-1","0","Pneumatic"],
|
||||
["3","-1","-1","3","Pneumatic"],
|
||||
["4","0.34","-1","4","Pneumatic"],
|
||||
["5","0.0","-1","9","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes", "MagnetLocation": "5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"},
|
||||
"Switches": {"Pantograph": "impulse", "Converter": "impulse"}
|
||||
}
|
||||
40
tests/unit/data/fiz/en57akl_v1/akl_ra.json
Normal file
40
tests/unit/data/fiz/en57akl_v1/akl_ra.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"_source": "pkp/en57akl_v1/akl_ra.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "38000", "Vmax": "120", "PWR": "0", "SandCap": "500", "Type": "ezt", "HeatingP": "20"},
|
||||
"Load": {"MaxLoad": "80", "LoadQ": "pieces", "LoadAccepted": "Passengers", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.286", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "AIM": "2000", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.7", "Bd": "14.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.5", "MaxLBP": "3.5", "BCN": "1", "BCR": "0.203", "BCD": "0.105", "BCM": "9.39", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "6.2", "MaxCP": "7.2", "CompressorSpeed": "0.01416667", "TareMaxBP": "2.5", "BVV": "107", "BM": "P10-Bgu", "BCS": "1.5", "BSA": "5", "BRE": "0.9", "CompressorPower": "Coupler2", "UBB1": "2", "UBB2": "8", "LPOn": "3.0", "LPOff": "4.5"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "29", "MaxSP": "7.2", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0001", "ValveOffArea": "0.0001", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.2", "CloseSpeed": "0.2", "DoorCloseDelay": "2.5", "DoorMaxShiftL": "0.58", "DoorMaxShiftR": "0.58", "DoorOpenMethod": "Plug", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.035", "DoorNeedPermit": "Yes", "DoorStayOpen": "5.0", "DoorAutoCloseVel": "10.0"},
|
||||
"BuffCoupl1": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39"},
|
||||
"BuffCoupl2": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-119", "PowerFlag": "1792"},
|
||||
"Cntrl": {"BrakeHandle": "MHZ_EN57", "LocBrakeHandle": "FD1", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "52", "BCPN": "10", "BDelay1": "15", "BDelay2": "4", "MainInitTime": "10", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "10", "SCPN": "1", "SpeedCtrlATOF": "1", "EIMCtrlAddZeros": "Yes", "IniCDelay": "0.0", "SCDelay": "0.8", "CoupledCtrl": "No", "BrakeOpModes": "PNEPMED", "CompressorStart": "Automatic", "CompartmentLightsStart": "Manual", "ConverterStart": "Disabled", "BatteryStart": "Disabled", "AutomaticCabActivation": "No", "InactivaCabEmergencyBrake": "Yes", "InactiveCabFlag": "15", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Blending": {"MED_Vmax": "95", "MED_Vmin": "1", "MED_Vref": "100", "MED_amax": "0.8", "MED_EPVC": "Yes", "MED_Ncor": "No"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "OverrideManual": "No", "InitPwr": "1.0", "MaxPwrVel": "-1", "StartVel": "-1", "VelStep": "10", "PwrStep": "0.00", "MinPwr": "1.0", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "120", "Offset": "-0.1", "kPpos": "0.2", "kPneg": "0.4", "kIpos": "0.00", "kIneg": "0.00", "BrakeIntervention": "No", "SpeedCtrlATOF": "1"},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "2.1", "CabDependent": "Yes", "RadioStop": "Yes", "MagnetLocation": "5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"},
|
||||
"Switches": {"Pantograph": "impulse", "Converter": "impulse"},
|
||||
"AI": {"Pantstate": "2", "IdlePantUp": "Yes"},
|
||||
"Engine": {"EngineType": "ElectricInductionMotor", "Trans": "46:252", "dfic": "377", "dfmax": "0.98", "p": "2", "cfu": "46.8", "cim": "14.2", "icif": "0.671", "Uzmax": "2340", "Uzh": "2340", "DU": "20", "I0": "20", "fcfu": "49", "F0": "130", "a1": "0", "Pmax": "0", "Fh": "130", "Ph": "1000", "Vh0": "5", "Vh1": "10", "Imax": "557", "abed": "0", "edep": "0.95"},
|
||||
"LightsList": {"Size": "7", "Wrap": "No", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["34","34"],
|
||||
["38","34"],
|
||||
["22","34"],
|
||||
["16","1"],
|
||||
["1","16"],
|
||||
["21","34"]
|
||||
]}
|
||||
}
|
||||
84
tests/unit/data/fiz/ep05_v2/ep05.json
Normal file
84
tests/unit/data/fiz/ep05_v2/ep05.json
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"_source": "pkp/ep05_v2/ep05.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "82500", "Mred": "12000", "Vmax": "160", "PWR": "2032", "SandCap": "100", "Type": "ep05"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "16.14", "H": "3.987", "W": "2.950", "Cx": "0.2"},
|
||||
"Wheels": {"D": "1.250", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "3.05", "Bd": "8.55", "Rmin": "120", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.8", "MaxASBP": "1.3", "RM": "0.56", "BCN": "4", "BCR": "0.1524", "BCD": "0.05", "BCM": "7.13", "Vv": "1.07", "MinCP": "7.5", "MaxCP": "9.0", "BCS": "1.2", "BSA": "0.0", "BM": "P10-Bgu", "BVV": "220", "CompressorSpeed": "0.06", "BRE": "0.85"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103", "ControlType": "EP05"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "ManualBrake": "Yes", "LocalBrake": "PneumaticBrake", "DynamicBrake": "Passive", "MCPN": "46", "SCPN": "0", "CoupledCtrl": "Yes", "AutoRelay": "Yes", "SCIM": "1", "IniCDelay": "0.4", "SCDelay": "0.26", "BrakeDelays": "P", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "Camshaft": "Yes", "rows": [
|
||||
["-1","0.60","-1","15","Pneumatic"],
|
||||
["0","0.50","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0.00","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "48", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "1600", "MinH": "0.38", "MinV": "1900", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "3"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "44:77", "WindingRes": "0.126", "nmax": "1270"},
|
||||
"Switches": {"PantographPresets": "0|2|3|1"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","56.48","80","0.4","370","80","0.445","0"],
|
||||
["1","45.15","150","0.3","296","150","0.29","0"],
|
||||
["2","41.45","300","0.2","271","300","0.16","0"],
|
||||
["3","39.29","400","0.13","257","400","0.13","0"],
|
||||
["4","38.36","700","0.04","251","700","0.04","0"],
|
||||
["5","33.83","850","0.01","221","850","0.01","0"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "800", "ImaxHi": "800", "IminLo": "350", "IminHi": "450"},
|
||||
"RList": {"Size": "46", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "0.1", "rows": [
|
||||
["0","0","0","0","0","0"],
|
||||
["1","100.000","1","4","0","0"],
|
||||
["2","14.308","1","4","0","0"],
|
||||
["3","10.558","1","4","0","0"],
|
||||
["4","8.908","1","4","0","0"],
|
||||
["5","7.668","1","4","0","0"],
|
||||
["6","6.428","1","4","0","0"],
|
||||
["7","5.744","1","4","0","0"],
|
||||
["8","5.060","1","4","0","0"],
|
||||
["9","4.616","1","4","0","0"],
|
||||
["10","4.172","1","4","0","0"],
|
||||
["11","3.813","1","4","0","0"],
|
||||
["12","3.454","1","4","0","0"],
|
||||
["13","3.100","1","4","0","0"],
|
||||
["14","2.746","1","4","0","0"],
|
||||
["15","2.456","1","4","0","0"],
|
||||
["16","2.215","1","4","0","0"],
|
||||
["17","1.974","1","4","0","0"],
|
||||
["18","1.629","1","4","0","0"],
|
||||
["19","1.284","1","4","0","0"],
|
||||
["20","1.054","1","4","0","0"],
|
||||
["21","0.824","1","4","0","0"],
|
||||
["22","0.593","1","4","0","0"],
|
||||
["23","0.362","1","4","0","0"],
|
||||
["24","0.181","1","4","0","0"],
|
||||
["25","0.000","1","4","0","0"],
|
||||
["26","0.000","1","4","0","1"],
|
||||
["27","0.000","1","4","0","2"],
|
||||
["28","0.000","1","4","0","3"],
|
||||
["29","0.000","1","4","0","4"],
|
||||
["30","0.000","1","4","0","4"],
|
||||
["31","0.000","1","4","0","4"],
|
||||
["32","0.000","1","4","0","4"],
|
||||
["33","2.086","2","2","0","0"],
|
||||
["34","1.727","2","2","0","0"],
|
||||
["35","1.373","2","2","0","0"],
|
||||
["36","1.228","2","2","0","0"],
|
||||
["37","0.987","2","2","0","0"],
|
||||
["38","0.642","2","2","0","0"],
|
||||
["39","0.412","2","2","0","0"],
|
||||
["40","0.181","2","2","0","0"],
|
||||
["41","0.00","2","2","0","0"],
|
||||
["42","0.00","2","2","0","1"],
|
||||
["43","0.00","2","2","0","2"],
|
||||
["44","0.00","2","2","0","3"],
|
||||
["45","0.00","2","2","0","4"],
|
||||
["46","0.00","2","2","0","5"]
|
||||
]}
|
||||
}
|
||||
76
tests/unit/data/fiz/ep09_v2/104e.json
Normal file
76
tests/unit/data/fiz/ep09_v2/104e.json
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"_source": "pkp/ep09_v2/104e.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "10", "UnLoadSpeed": "0.1"},
|
||||
"Param": {"Category": "train", "M": "85400", "Mred": "12000", "Vmax": "160", "PWR": "2920", "SandCap": "730"},
|
||||
"Dimensions": {"L": "16.74", "H": "4.12", "W": "2.96", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.2", "Tw": "1.435", "AIM": "2000", "Axle": "Bo'Bo'", "Ad": "3.2", "Bd": "7.97", "Rmin": "120", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.6", "MaxASBP": "1.3", "RM": "0.72", "BCN": "8", "BCR": "0.1143", "BCD": "0.05", "BCM": "5.18", "HiPP": "5", "LoPP": "3.5", "Vv": "0.834", "MinCP": "8.5", "MaxCP": "10.0", "CompressorSpeed": "0.058", "BCS": "1", "BSA": "2", "BM": "P10-Bgu", "BVV": "278", "CompressorPower": "Main"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "8", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "3.5", "ValveOnArea": "0.0002", "ValveOffArea": "0.0002", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "99"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "27", "BDelay2": "4", "BDelay3": "55", "BDelay4": "25", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "ManualBrake": "No", "DynamicBrake": "Automatic", "DBAM": "1", "MCPN": "31", "SCPN": "5", "AutoRelay": "No", "SCIM": "255", "IniCDelay": "0.5", "SCDelay": "0.25", "SCDDelay": "0.25", "BrakeDelays": "GPR", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "rows": [
|
||||
["-1","0.7","-1","9","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.44","-1","9","Pneumatic"],
|
||||
["2","0.40","-1","9","Pneumatic"],
|
||||
["3","0.36","-1","9","Pneumatic"],
|
||||
["4","0.32","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0","-1","35","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "3", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "4", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "2000", "MinH": "0.38", "MinV": "1900", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "3"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "38:73", "WindingRes": "0.07", "nmax": "1530"},
|
||||
"Switches": {"Pantograph": "Continuos", "RelayResetButton1": "1", "RelayResetButton2": "4"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","52.81","78","0.53","356.8","78","0.53"],
|
||||
["1","42.73","120","0.42","288.7","120","0.42"],
|
||||
["2","38.38","193","0.33","259.3","193","0.33"],
|
||||
["3","36.60","320","0.24","247.3","320","0.24"],
|
||||
["4","36.66","534","0.16","247.7","534","0.16"],
|
||||
["5","40.29","1100","0.06","272.2","1100","0.06"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.00", "ImaxLo": "850", "ImaxHi": "850", "IminLo": "520", "IminHi": "650"},
|
||||
"RList": {"Size": "31", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "0.1", "rows": [
|
||||
["0","0","0","0","0","0"],
|
||||
["1","10.758","1","4","0","2"],
|
||||
["2","10.758","1","4","0","0"],
|
||||
["3","7.994","1","4","0","0"],
|
||||
["4","6.156","1","4","0","0"],
|
||||
["5","4.808","1","4","0","0"],
|
||||
["6","4.032","1","4","0","0"],
|
||||
["7","3.342","1","4","0","0"],
|
||||
["8","3.014","1","4","0","0"],
|
||||
["9","2.686","1","4","0","0"],
|
||||
["10","2.375","1","4","0","0"],
|
||||
["11","2.064","1","4","0","0"],
|
||||
["12","1.772","1","4","0","0"],
|
||||
["13","1.480","1","4","0","0"],
|
||||
["14","1.196","1","4","0","0"],
|
||||
["15","0.912","1","4","0","0"],
|
||||
["16","0.683","1","4","0","0"],
|
||||
["17","0.454","1","4","0","0"],
|
||||
["18","0.227","1","4","0","0"],
|
||||
["19","0","1","4","0","255"],
|
||||
["20","5.379","2","2","0","0"],
|
||||
["21","3.997","2","2","0","0"],
|
||||
["22","3.078","2","2","0","0"],
|
||||
["23","2.404","2","2","0","0"],
|
||||
["24","2.016","2","2","0","0"],
|
||||
["25","1.671","2","2","0","0"],
|
||||
["26","1.343","2","2","0","0"],
|
||||
["27","1.032","2","2","0","0"],
|
||||
["28","0.740","2","2","0","0"],
|
||||
["29","0.456","2","2","0","0"],
|
||||
["30","0.227","2","2","0","0"],
|
||||
["31","0","2","2","0","255"]
|
||||
]},
|
||||
"WiperList": {"Size": "4", "Angle": "83", "rows": [
|
||||
["0","1.0","0.0","0.5"],
|
||||
["3","1.0","5.0","0.5"],
|
||||
["3","1.0","0.0","0.5"],
|
||||
["3","0.5","0.0","0.5"]
|
||||
]}
|
||||
}
|
||||
86
tests/unit/data/fiz/et22_v3/201e-rn.json
Normal file
86
tests/unit/data/fiz/et22_v3/201e-rn.json
Normal file
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"_source": "pkp/et22_v3/201e-rn.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "120000", "Mred": "18000", "Vmax": "125", "PWR": "3120", "SandCap": "700", "Type": "et22"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "19.240", "H": "4.055", "W": "3.005", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.250", "AIM": "2000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "3.05", "Bd": "10.30", "Rmin": "120", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.2", "MaxASBP": "1.8", "BCN": "8", "BCR": "0.1143", "BCD": "0.05", "BCM": "7.75", "HiPP": "5", "LoPP": "3.5", "Vv": "1", "MinCP": "7.5", "MaxCP": "8.5", "CompressorSpeed": "0.0566", "BVV": "250", "RM": "0.677", "BSA": "0", "BCS": "1", "BM": "P10-Bgu", "CompressorPower": "Main", "BRE": "0.75"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "99"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "17", "BDelay2": "7", "BDelay3": "45", "BDelay4": "25", "BrakeDelays": "GPR", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "ManualBrake": "Yes", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "DynamicBrake": "Passive", "MCPN": "48", "SCPN": "6", "AutoRelay": "No", "IniCDelay": "0.5", "SCDelay": "0.26", "SCDDelay": "0.05", "MotorBlowersStart": "Converter", "MotorBlowersSpeed": "-1310", "rows": [
|
||||
["-1","0.6","-1","12","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.43","-1","9","Pneumatic"],
|
||||
["2","0.40","-1","9","Pneumatic"],
|
||||
["3","0.37","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0","-1","18","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "1800", "MinH": "0.38", "MinV": "1900", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "3"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "18:79", "WindingRes": "0.14", "nmax": "2390"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","21.4","105","0.12","141.5","105","0.12"],
|
||||
["1","19.57","140","0.07","129.3","140","0.07"],
|
||||
["2","20.42","190","0.09","134.7","190","0.09"],
|
||||
["3","22.97","160","0.25","152.1","160","0.25"],
|
||||
["4","22.12","255","0.16","145.8","255","0.16"],
|
||||
["5","24.18","170","0.35","158.2","170","0.35"],
|
||||
["6","22.76","800","0.02","149","800","0.02"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "600", "ImaxHi": "750", "IminLo": "350", "IminHi": "450"},
|
||||
"RList": {"Size": "48", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "0.2", "rows": [
|
||||
["0","0","0","0","0"],
|
||||
["1","25.88","1","6","0"],
|
||||
["2","15.05","1","6","0"],
|
||||
["3","11.02","1","6","0"],
|
||||
["4","8.98","1","6","0"],
|
||||
["5","7.54","1","6","0"],
|
||||
["6","6.28","1","6","0"],
|
||||
["7","5.50","1","6","0"],
|
||||
["8","5.11","1","6","0"],
|
||||
["9","4.67","1","6","0"],
|
||||
["10","4.11","1","6","0"],
|
||||
["11","3.61","1","6","0"],
|
||||
["12","3.06","1","6","0"],
|
||||
["13","2.70","1","6","0"],
|
||||
["14","2.38","1","6","0"],
|
||||
["15","2.05","1","6","0"],
|
||||
["16","1.69","1","6","0"],
|
||||
["17","1.36","1","6","0"],
|
||||
["18","1.00","1","6","0"],
|
||||
["19","0.84","1","6","0"],
|
||||
["20","0.29","1","6","0"],
|
||||
["21","0.00","1","6","0"],
|
||||
["22","5.53","2","3","0"],
|
||||
["23","4.53","2","3","0"],
|
||||
["24","3.58","2","3","0"],
|
||||
["25","3.03","2","3","0"],
|
||||
["26","2.60","2","3","0"],
|
||||
["27","2.26","2","3","0"],
|
||||
["28","1.97","2","3","0"],
|
||||
["29","1.60","2","3","0"],
|
||||
["30","1.46","2","3","0"],
|
||||
["31","1.26","2","3","0"],
|
||||
["32","1.00","2","3","0"],
|
||||
["33","0.61","2","3","0"],
|
||||
["34","0.35","2","3","0"],
|
||||
["35","0.23","2","3","0"],
|
||||
["36","0.00","2","3","0"],
|
||||
["37","2.64","3","2","0"],
|
||||
["38","2.23","3","2","0"],
|
||||
["39","1.78","3","2","0"],
|
||||
["40","1.49","3","2","0"],
|
||||
["41","1.29","3","2","0"],
|
||||
["42","1.11","3","2","0"],
|
||||
["43","0.95","3","2","0"],
|
||||
["44","0.78","3","2","0"],
|
||||
["45","0.62","3","2","0"],
|
||||
["46","0.47","3","2","0"],
|
||||
["47","0.22","3","2","0"],
|
||||
["48","0.00","3","2","0"]
|
||||
]}
|
||||
}
|
||||
86
tests/unit/data/fiz/et22_v3/201e-w.json
Normal file
86
tests/unit/data/fiz/et22_v3/201e-w.json
Normal file
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"_source": "pkp/et22_v3/201e-w.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "120000", "Mred": "18000", "Vmax": "125", "PWR": "3120", "SandCap": "700", "Type": "et22"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "19.240", "H": "4.055", "W": "3.005", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.250", "AIM": "2000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "3.05", "Bd": "10.30", "Rmin": "120", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.2", "MaxASBP": "1.8", "BCN": "8", "BCR": "0.1143", "BCD": "0.05", "BCM": "7.75", "HiPP": "5", "LoPP": "3.5", "Vv": "1", "MinCP": "7.5", "MaxCP": "8.5", "CompressorSpeed": "0.0566", "BVV": "250", "RM": "0.677", "BSA": "0", "BCS": "1", "BM": "P10-Bgu", "CompressorPower": "Main", "BRE": "0.75"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "99"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "17", "BDelay2": "7", "BDelay3": "45", "BDelay4": "25", "BrakeDelays": "GPR", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "ManualBrake": "Yes", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "DynamicBrake": "Passive", "MCPN": "48", "SCPN": "6", "AutoRelay": "No", "IniCDelay": "0.5", "SCDelay": "0.26", "SCDDelay": "0.05", "MotorBlowersStart": "Converter", "MotorBlowersSpeed": "-1310", "rows": [
|
||||
["-1","0.6","-1","12","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.43","-1","9","Pneumatic"],
|
||||
["2","0.40","-1","9","Pneumatic"],
|
||||
["3","0.37","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0","-1","18","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "1800", "MinH": "0.38", "MinV": "1900", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "3"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "18:79", "WindingRes": "0.14", "nmax": "2390"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","21.4","105","0.12","141.5","105","0.12"],
|
||||
["1","19.57","140","0.07","129.3","140","0.07"],
|
||||
["2","20.42","190","0.09","134.7","190","0.09"],
|
||||
["3","22.97","160","0.25","152.1","160","0.25"],
|
||||
["4","22.12","255","0.16","145.8","255","0.16"],
|
||||
["5","24.18","170","0.35","158.2","170","0.35"],
|
||||
["6","22.76","800","0.02","149","800","0.02"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "600", "ImaxHi": "750", "IminLo": "350", "IminHi": "450"},
|
||||
"RList": {"Size": "48", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "0.2", "rows": [
|
||||
["0","0","0","0","0"],
|
||||
["1","25.88","1","6","0"],
|
||||
["2","15.05","1","6","0"],
|
||||
["3","11.02","1","6","0"],
|
||||
["4","8.98","1","6","0"],
|
||||
["5","7.54","1","6","0"],
|
||||
["6","6.28","1","6","0"],
|
||||
["7","5.50","1","6","0"],
|
||||
["8","5.11","1","6","0"],
|
||||
["9","4.67","1","6","0"],
|
||||
["10","4.11","1","6","0"],
|
||||
["11","3.61","1","6","0"],
|
||||
["12","3.06","1","6","0"],
|
||||
["13","2.70","1","6","0"],
|
||||
["14","2.38","1","6","0"],
|
||||
["15","2.05","1","6","0"],
|
||||
["16","1.69","1","6","0"],
|
||||
["17","1.36","1","6","0"],
|
||||
["18","1.00","1","6","0"],
|
||||
["19","0.84","1","6","0"],
|
||||
["20","0.29","1","6","0"],
|
||||
["21","0.00","1","6","0"],
|
||||
["22","5.53","2","3","0"],
|
||||
["23","4.53","2","3","0"],
|
||||
["24","3.58","2","3","0"],
|
||||
["25","3.03","2","3","0"],
|
||||
["26","2.60","2","3","0"],
|
||||
["27","2.26","2","3","0"],
|
||||
["28","1.97","2","3","0"],
|
||||
["29","1.60","2","3","0"],
|
||||
["30","1.46","2","3","0"],
|
||||
["31","1.26","2","3","0"],
|
||||
["32","1.00","2","3","0"],
|
||||
["33","0.61","2","3","0"],
|
||||
["34","0.35","2","3","0"],
|
||||
["35","0.23","2","3","0"],
|
||||
["36","0.00","2","3","0"],
|
||||
["37","2.64","3","2","0"],
|
||||
["38","2.23","3","2","0"],
|
||||
["39","1.78","3","2","0"],
|
||||
["40","1.49","3","2","0"],
|
||||
["41","1.29","3","2","0"],
|
||||
["42","1.11","3","2","0"],
|
||||
["43","0.95","3","2","0"],
|
||||
["44","0.78","3","2","0"],
|
||||
["45","0.62","3","2","0"],
|
||||
["46","0.47","3","2","0"],
|
||||
["47","0.22","3","2","0"],
|
||||
["48","0.00","3","2","0"]
|
||||
]}
|
||||
}
|
||||
77
tests/unit/data/fiz/et42_v2/112e-a.json
Normal file
77
tests/unit/data/fiz/et42_v2/112e-a.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"_source": "pkp/et42_v2/112e-a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "82000", "Vmax": "100", "PWR": "2240", "SandCap": "850", "Type": "et42"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "15.43", "H": "4.62", "W": "2.95", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.250", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "3.05", "Bd": "8.55", "Rmin": "125", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.0", "MaxASBP": "1.5", "BCN": "4", "BCR": "0.127", "BCD": "0.12", "BCM": "5.76", "Vv": "1.2", "MinCP": "7.5", "MaxCP": "9.0", "BCS": "1", "BSA": "0.5", "BM": "P10-Bg", "BVV": "300", "CompressorSpeed": "0.0392", "CompressorPower": "Main", "BRE": "0.7"},
|
||||
"BuffCoupl1": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "99"},
|
||||
"BuffCoupl2": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-127"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BrakeDelays": "GP", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "ManualBrake": "Yes", "DynamicBrake": "Switch", "MCPN": "38", "SCPN": "5", "AutoRelay": "No", "SCIM": "255", "IniCDelay": "0.5", "SCDelay": "0.1", "rows": [
|
||||
["-1","0.60","-1","15","Pneumatic"],
|
||||
["0","0.50","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0.00","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "1", "MaxVoltage": "3600", "MaxCurrent": "1300", "MinH": "0.42", "MinV": "1900", "MaxH": "1.77", "CSW": "1.4", "PhysicalLayout": "1"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "25:86", "WindingRes": "0.5", "nmax": "1500"},
|
||||
"Switches": {"Pantograph": "Continuos", "MotorConnectors": "Toggle"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","21.86","205","142","150"],
|
||||
["1","21.49","244","139","187"],
|
||||
["2","21.48","299","138","234"],
|
||||
["3","19.77","320","136","297"],
|
||||
["4","23.75","581","126","333"],
|
||||
["5","24.47","768","123","412"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "650", "ImaxHi": "651", "IminLo": "415", "IminHi": "415"},
|
||||
"RList": {"Size": "38", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "0.2", "rows": [
|
||||
["0","0","0","0","0","0"],
|
||||
["1","10.566","1","4","0","5"],
|
||||
["2","10.566","1","4","0","3"],
|
||||
["3","10.566","1","4","0","0"],
|
||||
["4","9.136","1","4","0","0"],
|
||||
["5","7.706","1","4","0","0"],
|
||||
["6","6.881","1","4","0","0"],
|
||||
["7","6.056","1","4","0","0"],
|
||||
["8","5.682","1","4","0","0"],
|
||||
["9","5.308","1","4","0","0"],
|
||||
["10","4.932","1","4","0","0"],
|
||||
["11","4.556","1","4","0","0"],
|
||||
["12","4.211","1","4","0","0"],
|
||||
["13","3.866","1","4","0","0"],
|
||||
["14","3.538","1","4","0","0"],
|
||||
["15","3.21","1","4","0","0"],
|
||||
["16","2.899","1","4","0","0"],
|
||||
["17","2.588","1","4","0","0"],
|
||||
["18","2.296","1","4","0","0"],
|
||||
["19","2.004","1","4","0","0"],
|
||||
["20","1.72","1","4","0","0"],
|
||||
["21","1.436","1","4","0","0"],
|
||||
["22","1.055","1","4","0","0"],
|
||||
["23","0.674","1","4","0","0"],
|
||||
["24","0.337","1","4","0","0"],
|
||||
["25","0.00","1","4","0","255"],
|
||||
["26","5.283","2","2","0","0"],
|
||||
["27","4.568","2","2","0","0"],
|
||||
["28","3.853","2","2","0","0"],
|
||||
["29","3.028","2","2","0","0"],
|
||||
["30","2.654","2","2","0","0"],
|
||||
["31","2.278","2","2","0","0"],
|
||||
["32","1.933","2","2","0","0"],
|
||||
["33","1.605","2","2","0","0"],
|
||||
["34","1.294","2","2","0","0"],
|
||||
["35","1.002","2","2","0","0"],
|
||||
["36","0.718","2","2","0","0"],
|
||||
["37","0.337","2","2","0","0"],
|
||||
["38","0.0","2","2","0","255"]
|
||||
]}
|
||||
}
|
||||
77
tests/unit/data/fiz/et42_v2/112e-b.json
Normal file
77
tests/unit/data/fiz/et42_v2/112e-b.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"_source": "pkp/et42_v2/112e-b.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "82000", "Vmax": "100", "PWR": "2240", "SandCap": "850", "Type": "et42"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "15.43", "H": "4.62", "W": "2.95", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.250", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "3.05", "Bd": "8.55", "Rmin": "125", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.0", "MaxASBP": "1.5", "BCN": "4", "BCR": "0.127", "BCD": "0.12", "BCM": "5.76", "Vv": "1.2", "MinCP": "7.5", "MaxCP": "9.0", "BCS": "1", "BSA": "0.5", "BM": "P10-Bg", "BVV": "300", "CompressorSpeed": "0.0392", "CompressorPower": "Main", "BRE": "0.7"},
|
||||
"BuffCoupl1": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-127"},
|
||||
"BuffCoupl2": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "99"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BrakeDelays": "GP", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "ManualBrake": "Yes", "DynamicBrake": "Switch", "MCPN": "38", "SCPN": "5", "AutoRelay": "No", "SCIM": "255", "IniCDelay": "0.5", "SCDelay": "0.1", "rows": [
|
||||
["-1","0.60","-1","15","Pneumatic"],
|
||||
["0","0.50","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0.00","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "1", "MaxVoltage": "3600", "MaxCurrent": "1300", "MinH": "0.42", "MinV": "1900", "MaxH": "1.77", "CSW": "1.4", "PhysicalLayout": "1"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "25:86", "WindingRes": "0.5", "nmax": "1500"},
|
||||
"Switches": {"Pantograph": "Continuos", "MotorConnectors": "Toggle"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","21.86","205","142","150"],
|
||||
["1","21.49","244","139","187"],
|
||||
["2","21.48","299","138","234"],
|
||||
["3","19.77","320","136","297"],
|
||||
["4","23.75","581","126","333"],
|
||||
["5","24.47","768","123","412"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "650", "ImaxHi": "651", "IminLo": "415", "IminHi": "415"},
|
||||
"RList": {"Size": "38", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "0.2", "rows": [
|
||||
["0","0","0","0","0","0"],
|
||||
["1","10.566","1","4","0","5"],
|
||||
["2","10.566","1","4","0","3"],
|
||||
["3","10.566","1","4","0","0"],
|
||||
["4","9.136","1","4","0","0"],
|
||||
["5","7.706","1","4","0","0"],
|
||||
["6","6.881","1","4","0","0"],
|
||||
["7","6.056","1","4","0","0"],
|
||||
["8","5.682","1","4","0","0"],
|
||||
["9","5.308","1","4","0","0"],
|
||||
["10","4.932","1","4","0","0"],
|
||||
["11","4.556","1","4","0","0"],
|
||||
["12","4.211","1","4","0","0"],
|
||||
["13","3.866","1","4","0","0"],
|
||||
["14","3.538","1","4","0","0"],
|
||||
["15","3.21","1","4","0","0"],
|
||||
["16","2.899","1","4","0","0"],
|
||||
["17","2.588","1","4","0","0"],
|
||||
["18","2.296","1","4","0","0"],
|
||||
["19","2.004","1","4","0","0"],
|
||||
["20","1.72","1","4","0","0"],
|
||||
["21","1.436","1","4","0","0"],
|
||||
["22","1.055","1","4","0","0"],
|
||||
["23","0.674","1","4","0","0"],
|
||||
["24","0.337","1","4","0","0"],
|
||||
["25","0.00","1","4","0","255"],
|
||||
["26","5.283","2","2","0","0"],
|
||||
["27","4.568","2","2","0","0"],
|
||||
["28","3.853","2","2","0","0"],
|
||||
["29","3.028","2","2","0","0"],
|
||||
["30","2.654","2","2","0","0"],
|
||||
["31","2.278","2","2","0","0"],
|
||||
["32","1.933","2","2","0","0"],
|
||||
["33","1.605","2","2","0","0"],
|
||||
["34","1.294","2","2","0","0"],
|
||||
["35","1.002","2","2","0","0"],
|
||||
["36","0.718","2","2","0","0"],
|
||||
["37","0.337","2","2","0","0"],
|
||||
["38","0.0","2","2","0","255"]
|
||||
]}
|
||||
}
|
||||
67
tests/unit/data/fiz/eu04_v1/eu04-01.json
Normal file
67
tests/unit/data/fiz/eu04_v1/eu04-01.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"_source": "pkp/eu04_v1/eu04-01.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "87200", "Mred": "12000", "Vmax": "110", "PWR": "1680", "SandCap": "500", "type": "EU04"},
|
||||
"Dimensions": {"L": "16.238", "H": "4.343", "W": "2.903", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.350", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "3.05", "Bd": "8.55", "Rmin": "140", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "K", "NBpA": "4", "MBF": "85.0", "MaxBP": "2.8", "RM": "0.43", "LocMaxBP": "3.5", "BCN": "8", "BCR": "0.1524", "BCD": "0.12", "BCM": "8.7", "HiPP": "5", "LoPP": "3.5", "Vv": "0.83", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.03", "BCS": "0.8", "BSA": "0", "BM": "P10-Bgu", "BVV": "200", "BRE": "0.8"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103"},
|
||||
"Cntrl": {"BrakeDelays": "GPRR", "BrakeHandle": "Knorr", "LocBrakeHandle": "Knorr", "BrakeSystem": "Pneumatic", "BCPN": "4", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ManualBrake": "Yes", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "DynamicBrake": "Passive", "MCPN": "31", "SCPN": "8", "AutoRelay": "Optional", "IniCDelay": "0.4", "SCDelay": "0.4", "rows": [
|
||||
["-1","0.90","0","15","Pneumatic"],
|
||||
["0","0.50","0","9","Pneumatic"],
|
||||
["1","-1","-1","0","Pneumatic"],
|
||||
["2","-1","-1","5","Pneumatic"],
|
||||
["3","0.001","-1","9","Pneumatic"],
|
||||
["4","0.00","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "1000", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "3"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "21:81", "WindingRes": "0.1411", "nmax": "2075"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","23.9","200","-0.08","155.9","200","-0.08","1"],
|
||||
["1","23.28","200","-0.07","151.8","200","-0.07","1"],
|
||||
["2","22.45","200","-0.06","146.5","200","-0.06","1"],
|
||||
["3","22.18","200","0","144.7","200","0","1"],
|
||||
["4","23.09","300","-0.05","150.6","300","-0.05","1"],
|
||||
["5","22.89","290","-0.02","149.3","290","-0.02","1"],
|
||||
["6","23.59","360","-0.02","153.9","360","-0.02","1"],
|
||||
["7","23.95","410","0.01","156.2","410","0.01","1"],
|
||||
["8","21.94","410","0.05","143.1","410","0.05","0"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "650", "ImaxHi": "650", "IminLo": "350", "IminHi": "450"},
|
||||
"RList": {"Size": "31", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "50", "rows": [
|
||||
["0","0","0","0","0"],
|
||||
["1","16.9","1","4","1"],
|
||||
["2","12.4","1","4","1"],
|
||||
["3","9.77","1","4","1"],
|
||||
["4","8.0","1","4","1"],
|
||||
["5","6.4","1","4","1"],
|
||||
["6","4.94","1","4","1"],
|
||||
["7","4.38","1","4","1"],
|
||||
["8","3.9","1","4","1"],
|
||||
["9","3.37","1","4","1"],
|
||||
["10","2.86","1","4","1"],
|
||||
["11","2.5","1","4","1"],
|
||||
["12","2.1","1","4","1"],
|
||||
["13","1.78","1","4","1"],
|
||||
["14","1.49","1","4","1"],
|
||||
["15","1.18","1","4","1"],
|
||||
["16","0.89","1","4","1"],
|
||||
["17","0.66","1","4","1"],
|
||||
["18","0.42","1","4","1"],
|
||||
["19","0.2","1","4","1"],
|
||||
["20","0.0","1","4","1"],
|
||||
["21","6.09","2","2","1"],
|
||||
["22","3.9","2","2","1"],
|
||||
["23","3.1","2","2","1"],
|
||||
["24","2.57","2","2","1"],
|
||||
["25","2.185","2","2","1"],
|
||||
["26","1.58","2","2","1"],
|
||||
["27","1.115","2","2","1"],
|
||||
["28","0.795","2","2","1"],
|
||||
["29","0.5","2","2","1"],
|
||||
["30","0.23","2","2","1"],
|
||||
["31","0.0","2","2","0"]
|
||||
]}
|
||||
}
|
||||
20
tests/unit/data/fiz/ew58_v1/ew58-d.json
Normal file
20
tests/unit/data/fiz/ew58_v1/ew58-d.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"_source": "pkp/ew58_v1/ew58-d.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "42200", "Mred": "1800", "Vmax": "120", "PWR": "2", "SandCap": "0", "Type": "ezt", "HeatingP": "18"},
|
||||
"Load": {"MaxLoad": "220", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "6", "UnLoadSpeed": "6"},
|
||||
"Dimensions": {"L": "21.7", "H": "4.12", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.92", "AIM": "2000", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.75", "Bd": "15.6", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EP1", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.8", "BCN": "4", "BCR": "0.1143", "BCD": "0.08", "BCM": "12.156", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.013", "TareMaxBP": "2.4", "BVV": "150", "BM": "P10-Bg", "BCS": "1.5", "BSA": "16.00", "BRE": "0.83"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.35", "CloseSpeed": "0.35", "DoorCloseDelay": "0.5", "DoorMaxShiftL": "0.53", "DoorMaxShiftR": "0.53", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes"},
|
||||
"BuffCoupl": {"ControlType": "ew58", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-127"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "MaxBPMass": "68", "BCPN": "1", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "ManualBrake", "DynamicBrake": "Passive", "MCPN": "4", "SCPN": "9", "SCIM": "1", "AutoRelay": "Yes", "IniCDelay": "0.0", "SCDelay": "0.8", "CoupledCtrl": "No", "BrakeDelays": "R", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","-1","-1","0","ElectroPneumatic"],
|
||||
["1","-1","0.35","4","ElectroPneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "1200", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4", "MinPress": "3.5", "PhysicalLayout": "3"},
|
||||
"DCEMUED": {"CouplerCheck": "3", "EP_max_Vel": "48"},
|
||||
"Switches": {"Pantograph": "Continous"}
|
||||
}
|
||||
68
tests/unit/data/fiz/ew58_v1/ew58-sa.json
Normal file
68
tests/unit/data/fiz/ew58_v1/ew58-sa.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"_source": "pkp/ew58_v1/ew58-sa.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "52400", "Mred": "4980", "Vmax": "120", "PWR": "820", "SandCap": "500", "Type": "ezt", "HeatingP": "21"},
|
||||
"Load": {"MaxLoad": "220", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "6", "UnLoadSpeed": "6"},
|
||||
"Dimensions": {"L": "21.55", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.0", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EP1", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.8", "BCN": "4", "BCR": "0.1143", "BCD": "0.08", "BCM": "12.156", "HiPP": "5", "LoPP": "3.5", "TareMaxBP": "2.9", "BVV": "150", "BM": "P10-Bg", "BCS": "1.5", "BSA": "16.00", "BRE": "0.83"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.35", "CloseSpeed": "0.35", "DoorCloseDelay": "0.5", "DoorMaxShiftL": "0.53", "DoorMaxShiftR": "0.53", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes"},
|
||||
"BuffCoupl1": {"ControlType": "ew58", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39"},
|
||||
"BuffCoupl2": {"ControlType": "ew58", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-127"},
|
||||
"Cntrl": {"BrakeHandle": "FVE408", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "68", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "ManualBrake", "MCPN": "4", "SCPN": "9", "DBAM": "2", "IniCDelay": "0.0", "SCDelay": "0.3", "CoupledCtrl": "No", "SCIM": "1", "AutoRelay": "Yes", "DynamicBrake": "Automatic", "ConverterStart": "Disabled", "BatteryStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "0", "MaxVoltage": "3750", "MaxCurrent": "800"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "750", "Trans": "18:69", "WindingRes": "0.1097", "nmax": "2390"},
|
||||
"Blending": {"MED_amax": "1.00"},
|
||||
"DCEMUED": {"CouplerCheck": "2", "EP_min_Im": "80"},
|
||||
"Switches": {"Pantograph": "Continous", "RelayResetButton1": "101"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","11.3","90","0.21","79.5","90","0.21","1"],
|
||||
["1","12.39","110","0.24","83.9","110","0.24","1"],
|
||||
["2","11.88","123","0.23","80.5","123","0.23","1"],
|
||||
["3","11.37","135","0.22","77.2","135","0.22","1"],
|
||||
["4","11.05","180","0.2","74.6","180","0.2","1"],
|
||||
["5","10.73","225","0.18","72.1","225","0.18","1"],
|
||||
["6","10.26","250","0.18","68.7","250","0.18","1"],
|
||||
["7","9.8","275","0.19","65.4","275","0.19","1"],
|
||||
["8","9.34","300","0.19","62","300","0.19","1"],
|
||||
["9","8.15","455","0.1","55.5","455","0.1","0"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "580", "ImaxHi": "581", "IminLo": "360", "IminHi": "455", "TUHEX_Sum1": "365", "TUHEX_Sum2": "500", "TUHEX_Sum3": "610", "TUHEX_Diff": "10", "TUHEX_MaxIw": "280", "TUHEX_MinIw": "11", "TUHEX_Stages": "3"},
|
||||
"RList": {"Size": "22", "RVent": "No", "DynBrakeRes1": "4.3", "DynBrakeRes2": "1.956", "rows": [
|
||||
["0","0","0","0","0","0"],
|
||||
["1","17.001","1","4","0","0"],
|
||||
["2","10.677","1","4","1","0"],
|
||||
["2","7.573","1","4","1","0"],
|
||||
["2","5.505","1","4","1","0"],
|
||||
["2","4.477","1","4","1","0"],
|
||||
["2","3.589","1","4","1","0"],
|
||||
["2","2.821","1","4","1","0"],
|
||||
["2","2.157","1","4","1","0"],
|
||||
["2","1.585","1","4","1","0"],
|
||||
["2","1.116","1","4","1","0"],
|
||||
["2","0.688","1","4","1","0"],
|
||||
["2","0.320","1","4","1","0"],
|
||||
["2","0.000","1","4","1","0"],
|
||||
["3","0.000","1","4","1","1"],
|
||||
["3","0.000","1","4","1","2"],
|
||||
["3","0.000","1","4","1","3"],
|
||||
["3","0.000","1","4","1","4"],
|
||||
["3","0.000","1","4","1","5"],
|
||||
["4","0.000","1","4","1","6"],
|
||||
["4","0.000","1","4","1","7"],
|
||||
["4","0.000","1","4","1","8"],
|
||||
["4","0.000","1","4","1","9"]
|
||||
]}
|
||||
}
|
||||
68
tests/unit/data/fiz/ew58_v1/ew58-sb.json
Normal file
68
tests/unit/data/fiz/ew58_v1/ew58-sb.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"_source": "pkp/ew58_v1/ew58-sb.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "52400", "Mred": "4980", "Vmax": "120", "PWR": "820", "SandCap": "500", "Type": "ezt", "HeatingP": "21"},
|
||||
"Load": {"MaxLoad": "220", "LoadQ": "pieces", "LoadAccepted": "Passengers,Pantstate", "OverLoadFactor": "2", "LoadSpeed": "6", "UnLoadSpeed": "6"},
|
||||
"Dimensions": {"L": "21.55", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.0", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EP1", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.8", "BCN": "4", "BCR": "0.1143", "BCD": "0.08", "BCM": "12.156", "HiPP": "5", "LoPP": "3.5", "TareMaxBP": "2.5", "BVV": "150", "BM": "P10-Bg", "BCS": "1.5", "BSA": "16.00", "BRE": "0.83"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.35", "CloseSpeed": "0.35", "DoorCloseDelay": "0.5", "DoorMaxShiftL": "0.53", "DoorMaxShiftR": "0.53", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes"},
|
||||
"BuffCoupl1": {"CControlType": "ew58", "Type": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "-127"},
|
||||
"BuffCoupl2": {"ControlType": "ew58", "CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39"},
|
||||
"Cntrl": {"BrakeHandle": "FVE408", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "68", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "ManualBrake", "MCPN": "4", "SCPN": "9", "DBAM": "2", "IniCDelay": "0.0", "SCDelay": "0.3", "CoupledCtrl": "No", "SCIM": "1", "AutoRelay": "Yes", "DynamicBrake": "Automatic", "ConverterStart": "Disabled", "BatteryStart": "Disabled", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Clima": {"Heating": "Main"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "0", "MaxVoltage": "3750", "MaxCurrent": "800"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "750", "Trans": "18:69", "WindingRes": "0.1097", "nmax": "2390"},
|
||||
"Blending": {"MED_amax": "1.00"},
|
||||
"DCEMUED": {"CouplerCheck": "1", "EP_min_Im": "80"},
|
||||
"Switches": {"Pantograph": "Continous", "RelayResetButton1": "101"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","11.3","90","0.21","79.5","90","0.21","1"],
|
||||
["1","12.39","110","0.24","83.9","110","0.24","1"],
|
||||
["2","11.88","123","0.23","80.5","123","0.23","1"],
|
||||
["3","11.37","135","0.22","77.2","135","0.22","1"],
|
||||
["4","11.05","180","0.2","74.6","180","0.2","1"],
|
||||
["5","10.73","225","0.18","72.1","225","0.18","1"],
|
||||
["6","10.26","250","0.18","68.7","250","0.18","1"],
|
||||
["7","9.8","275","0.19","65.4","275","0.19","1"],
|
||||
["8","9.34","300","0.19","62","300","0.19","1"],
|
||||
["9","8.15","455","0.1","55.5","455","0.1","0"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "580", "ImaxHi": "581", "IminLo": "360", "IminHi": "455", "TUHEX_Sum1": "365", "TUHEX_Sum2": "500", "TUHEX_Sum3": "610", "TUHEX_Diff": "10", "TUHEX_MaxIw": "280", "TUHEX_MinIw": "11", "TUHEX_Stages": "3"},
|
||||
"RList": {"Size": "22", "RVent": "No", "DynBrakeRes1": "4.3", "DynBrakeRes2": "1.956", "rows": [
|
||||
["0","0","0","0","0","0"],
|
||||
["1","17.001","1","4","0","0"],
|
||||
["2","10.677","1","4","1","0"],
|
||||
["2","7.573","1","4","1","0"],
|
||||
["2","5.505","1","4","1","0"],
|
||||
["2","4.477","1","4","1","0"],
|
||||
["2","3.589","1","4","1","0"],
|
||||
["2","2.821","1","4","1","0"],
|
||||
["2","2.157","1","4","1","0"],
|
||||
["2","1.585","1","4","1","0"],
|
||||
["2","1.116","1","4","1","0"],
|
||||
["2","0.688","1","4","1","0"],
|
||||
["2","0.320","1","4","1","0"],
|
||||
["2","0.000","1","4","1","0"],
|
||||
["3","0.000","1","4","1","1"],
|
||||
["3","0.000","1","4","1","2"],
|
||||
["3","0.000","1","4","1","3"],
|
||||
["3","0.000","1","4","1","4"],
|
||||
["3","0.000","1","4","1","5"],
|
||||
["4","0.000","1","4","1","6"],
|
||||
["4","0.000","1","4","1","7"],
|
||||
["4","0.000","1","4","1","8"],
|
||||
["4","0.000","1","4","1","9"]
|
||||
]}
|
||||
}
|
||||
50
tests/unit/data/fiz/impuls_v1/31we-a_pr.json
Normal file
50
tests/unit/data/fiz/impuls_v1/31we-a_pr.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"_source": "pkp/impuls_v1/31we-a_pr.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "31800", "Vmax": "160", "PWR": "1000", "SandCap": "200", "Type": "ezt"},
|
||||
"Load": {"MaxLoad": "42", "LoadQ": "pieces", "LoadAccepted": "Passengers", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "1"},
|
||||
"Dimensions": {"L": "21.06", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.840", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.37", "MaxLBP": "4.37", "BCN": "4", "BCR": "0.127", "BCD": "0.05", "BCM": "1.9075", "HiPP": "5", "LoPP": "3.5", "Vv": "0.125", "MinCP": "7.5", "MaxCP": "9.0", "MinCP_B": "8.5", "MaxCP_B": "10.0", "CompressorSpeed": "0.00625", "BVV": "125", "BM": "Cosid", "BCS": "1", "BSA": "0.00", "BRE": "0.95", "TareMaxBP": "3.85", "CompressorPower": "Converter", "LPOn": "2.8", "LPOff": "4.3", "UBB1": "2", "EmergencyCutsOffHandle": "Yes"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "2.9", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.21", "CloseSpeed": "0.19", "DoorCloseDelay": "2.1", "DoorOpenWithPermit": "1", "DoorMaxShiftL": "0.7", "DoorMaxShiftR": "0.7", "DoorOpenMethod": "Plug", "DoorMaxShiftPlug": "0.028", "DoorStayOpen": "5.0", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorAutoCloseRemote": "Yes", "PlatformMaxShift": "0.270", "PlatformSpeed": "0.4", "PlatformOpenMethod": "Shift", "MirrorMaxShift": "45", "DoorNeedPermit": "Yes", "MirrorVelClose": "20", "DoorsPermitLightBlinking": "2"},
|
||||
"BuffCoupl1": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39", "ControlType": "31we_pr"},
|
||||
"BuffCoupl2": {"CType": "Articulated", "AllowedFlag": "-255", "ControlType": "impuls"},
|
||||
"Cntrl": {"BrakeHandle": "MHZ_6P", "LocBrakeHandle": "FD1", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "37.8", "BCPN": "4", "BDelay1": "15", "BDelay2": "4", "LocalBrake": "PneumaticBrake", "MCPN": "10", "SCPN": "1", "IniCDelay": "0.0", "SCDelay": "0.8", "CoupledCtrl": "No", "EIMCtrlAddZeros": "Yes", "SBD": "0.65", "ASB": "Yes", "ConverterStart": "Automatic", "ConverterStartDelay": "8", "MainInitTime": "2", "BrakeOpModes": "PN", "MotorBlowersStart": "Converter", "EIMCtrlEmergency": "Yes", "PantEPValveStart": "Automatic", "PantEPValveSpring": "No", "SpringBrakeCutsOffDrive": "No", "SpringBrakeDriveEmergencyVel": "2", "ReleaseParkingBySpringBrakeWhenDoorIsOpen": "Yes", "CompartmentLightsStart": "Manual", "HAO": "Yes", "OMP": "0.8", "AutomaticCabActivation": "No", "InactivaCabEmergencyBrake": "Yes", "InactiveCabFlag": "239", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "2.1", "CabDependent": "Yes", "RadioStop": "Yes", "MagnetLocation": "4.5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "24", "LMaxCurrent": "300"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "0", "MaxVoltage": "3900", "MinV": "2100", "MaxCurrent": "1200", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4"},
|
||||
"Engine": {"EngineType": "ElectricInductionMotor", "InvNo": "2", "Trans": "60:252", "dfic": "794", "dfmax": "1.500", "p": "2", "cfu": "40.1", "cim": "12.24", "icif": "0.679", "Uzmax": "2200", "Uzh": "1500", "DU": "20", "I0": "10", "fcfu": "47.6", "fcfuh": "31.4", "F0": "100", "a1": "0", "Pmax": "1260", "Fh": "48", "Ph": "800", "Vh0": "5", "Vh1": "15", "Imax": "475", "abed": "0", "edep": "3.0", "eimclf": "Yes", "MotorBlowersSpeed": "-15", "MotorBlowersSustainTime": "300", "MotorBlowersStartVelocity": "0.1"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "10|20|40|60|80|100|120|140|160", "OverrideManual": "No", "InitPwr": "1.0", "MaxPwrVel": "-1", "StartVel": "-1", "VelStep": "10", "PwrStep": "0.0", "MinPwr": "0.2", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "160", "Offset": "-0.5", "kPpos": "0.2", "kPneg": "0.4", "kIpos": "0.00", "kIneg": "0.00", "BrakeIntervention": "No", "SpeedCtrlATOF": "2"},
|
||||
"AI": {"Pantstate": "2", "LocalBrakeAccFactor": "0.5", "IdlePantUp": "No"},
|
||||
"Blending": {"MED_amax": "1.08", "MED_EPVC": "No", "MED_Ncor": "No", "MED_FrEDFactor": "0", "MED_FirstDelayED": "0.5", "MED_ScndDelayED": "0.25"},
|
||||
"Switches": {"PantographPresets": "0|1|2|3"},
|
||||
"Circuit": {"ImaxHi": "500"},
|
||||
"LightsList": {"Size": "8", "Wrap": "No", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["388","34"],
|
||||
["21","34"],
|
||||
["1","16"],
|
||||
["16","1"],
|
||||
["22","34"],
|
||||
["38","38"],
|
||||
["34","34"]
|
||||
]},
|
||||
"ffList": {"Size": "5", "rows": [
|
||||
["0","0.5"],
|
||||
["24","1.0"],
|
||||
["35","1.0"],
|
||||
["42","1.3"],
|
||||
["42","1.3"],
|
||||
["74","2.3"]
|
||||
]}
|
||||
}
|
||||
20
tests/unit/data/fiz/impuls_v1/31we-b_pr.json
Normal file
20
tests/unit/data/fiz/impuls_v1/31we-b_pr.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"_source": "pkp/impuls_v1/31we-b_pr.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "38700", "Vmax": "160", "PWR": "2", "SandCap": "0", "Type": "ezt"},
|
||||
"Load": {"MaxLoad": "48", "LoadQ": "pieces", "LoadAccepted": "Passengers", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "15.92", "H": "4.12", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.84", "AIM": "500", "Tw": "1.435", "Axle": "2'1'", "Ad": "2.75", "Bd": "15.92", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "2", "MBF": "85.0", "MaxBP": "4.06", "MaxLBP": "4.06", "BCN": "6", "BCR": "0.127", "BCD": "0.05", "BCM": "1.9075", "HiPP": "5", "LoPP": "3.5", "Vv": "0.01", "MinCP": "10.0", "MaxCP": "12.0", "CompressorSpeed": "0.0000001", "BVV": "187", "BM": "Cosid", "BCS": "1", "BSA": "0.00", "BRE": "0.95", "TareMaxBP": "3.09", "CompressorPower": "Converter"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "2.9", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.8", "PressOn": "4.5", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.21", "CloseSpeed": "0.19", "DoorCloseDelay": "2.1", "DoorOpenWithPermit": "1", "DoorMaxShiftL": "0.7", "DoorMaxShiftR": "0.7", "DoorOpenMethod": "Plug", "DoorMaxShiftPlug": "0.028", "DoorStayOpen": "5.0", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorAutoCloseRemote": "Yes", "PlatformMaxShift": "0.270", "PlatformSpeed": "0.4", "PlatformOpenMethod": "Shift", "MirrorMaxShift": "45", "DoorNeedPermit": "Yes"},
|
||||
"BuffCoupl": {"CType": "Articulated", "AllowedFlag": "-255", "ControlType": "impuls"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocBrakeHandle": "FD1", "MaxBPMass": "53", "BCPN": "2", "BDelay1": "15", "BDelay2": "4", "LocalBrake": "PneumaticBrake", "DynamicBrake": "Passive", "MCPN": "10", "SCPN": "0", "AutoRelay": "Yes", "IniCDelay": "0.0", "SCDelay": "0.8", "CoupledCtrl": "Yes", "ASB": "Yes", "CompartmentLightsStart": "Manual", "HAO": "Yes", "OMP": "0.8", "PantEPValveStart": "Automatic", "PantEPValveSpring": "No", "PantCompressorStart": "Automatic", "PantAutoValve": "Yes", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","-1","-1","0","ElectroPneumatic"],
|
||||
["1","-1","0.35","4","ElectroPneumatic"],
|
||||
["2","-1","-1","0","ElectroPneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "24", "LMaxCurrent": "300"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "1", "MaxVoltage": "3900", "MinV": "2100", "MaxCurrent": "1200", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "1"}
|
||||
}
|
||||
20
tests/unit/data/fiz/impuls_v1/31we-c_pr.json
Normal file
20
tests/unit/data/fiz/impuls_v1/31we-c_pr.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"_source": "pkp/impuls_v1/31we-c_pr.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "38700", "Vmax": "160", "PWR": "2", "SandCap": "0", "Type": "ezt"},
|
||||
"Load": {"MaxLoad": "46", "LoadQ": "pieces", "LoadAccepted": "Passengers", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "15.92", "H": "4.12", "W": "2.96", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.84", "AIM": "500", "Tw": "1.435", "Axle": "1'2'", "Ad": "2.75", "Bd": "15.92", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "2", "MBF": "85.0", "MaxBP": "4.06", "MaxLBP": "4.06", "BCN": "6", "BCR": "0.127", "BCD": "0.05", "BCM": "1.9075", "HiPP": "5", "LoPP": "3.5", "Vv": "0.01", "MinCP": "10.0", "MaxCP": "12.0", "CompressorSpeed": "0.0000001", "BVV": "187", "BM": "Cosid", "BCS": "1", "BSA": "0.00", "BRE": "0.95", "TareMaxBP": "3.09", "CompressorPower": "Converter"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "2.9", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.8", "PressOn": "4.5", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.21", "CloseSpeed": "0.19", "DoorCloseDelay": "2.1", "DoorOpenWithPermit": "1", "DoorMaxShiftL": "0.7", "DoorMaxShiftR": "0.7", "DoorOpenMethod": "Plug", "DoorMaxShiftPlug": "0.028", "DoorStayOpen": "5.0", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorAutoCloseRemote": "Yes", "PlatformMaxShift": "0.270", "PlatformSpeed": "0.4", "PlatformOpenMethod": "Shift", "MirrorMaxShift": "45", "DoorNeedPermit": "Yes"},
|
||||
"BuffCoupl": {"CType": "Articulated", "AllowedFlag": "-255", "ControlType": "impuls"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocBrakeHandle": "FD1", "MaxBPMass": "53", "BCPN": "2", "BDelay1": "15", "BDelay2": "4", "LocalBrake": "PneumaticBrake", "DynamicBrake": "Passive", "MCPN": "10", "SCPN": "0", "AutoRelay": "Yes", "IniCDelay": "0.0", "SCDelay": "0.8", "CoupledCtrl": "Yes", "ASB": "Yes", "CompartmentLightsStart": "Manual", "HAO": "Yes", "OMP": "0.8", "PantEPValveStart": "Automatic", "PantEPValveSpring": "No", "PantCompressorStart": "Automatic", "PantAutoValve": "Yes", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","-1","-1","0","ElectroPneumatic"],
|
||||
["1","-1","0.35","4","ElectroPneumatic"],
|
||||
["2","-1","-1","0","ElectroPneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "24", "LMaxCurrent": "300"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "1", "MaxVoltage": "3900", "MinV": "2100", "MaxCurrent": "1200", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4", "PhysicalLayout": "2"}
|
||||
}
|
||||
50
tests/unit/data/fiz/impuls_v1/31we-d_pr.json
Normal file
50
tests/unit/data/fiz/impuls_v1/31we-d_pr.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"_source": "pkp/impuls_v1/31we-d_pr.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "31800", "Vmax": "160", "PWR": "1000", "SandCap": "200", "Type": "ezt"},
|
||||
"Load": {"MaxLoad": "54", "LoadQ": "pieces", "LoadAccepted": "Passengers", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "1"},
|
||||
"Dimensions": {"L": "21.06", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "0.840", "AIM": "2000", "Tw": "1.435", "Axle": "Bo'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.37", "MaxLBP": "4.37", "BCN": "4", "BCR": "0.127", "BCD": "0.05", "BCM": "1.9075", "HiPP": "5", "LoPP": "3.5", "Vv": "0.125", "MinCP": "8.5", "MaxCP": "10.0", "MinCP_B": "7.5", "MaxCP_B": "9.0", "CompressorSpeed": "0.00625", "BVV": "125", "BM": "Cosid", "BCS": "1", "BSA": "0.00", "BRE": "0.95", "TareMaxBP": "3.85", "CompressorPower": "Converter", "LPOn": "2.8", "LPOff": "4.3", "UBB1": "2", "EmergencyCutsOffHandle": "Yes"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "2.9", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.21", "CloseSpeed": "0.19", "DoorCloseDelay": "2.1", "DoorOpenWithPermit": "1", "DoorMaxShiftL": "0.7", "DoorMaxShiftR": "0.7", "DoorOpenMethod": "Plug", "DoorMaxShiftPlug": "0.028", "DoorStayOpen": "5.0", "DoorClosureWarningAuto": "Yes", "DoorBlocked": "Yes", "DoorAutoCloseRemote": "Yes", "PlatformMaxShift": "0.270", "PlatformSpeed": "0.4", "PlatformOpenMethod": "Shift", "MirrorMaxShift": "45", "DoorNeedPermit": "Yes", "MirrorVelClose": "20", "DoorsPermitLightBlinking": "2"},
|
||||
"BuffCoupl1": {"CType": "Articulated", "AllowedFlag": "-255", "ControlType": "impuls"},
|
||||
"BuffCoupl2": {"CType": "Automatic", "kB": "4200", "DmaxB": "0.05", "FmaxB": "1740", "kC": "6800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "AutomaticFlag": "39", "ControlType": "31we_pr"},
|
||||
"Cntrl": {"BrakeHandle": "MHZ_6P", "LocBrakeHandle": "FD1", "BrakeSystem": "ElectroPneumatic", "MaxBPMass": "37.8", "BCPN": "4", "BDelay1": "15", "BDelay2": "4", "LocalBrake": "PneumaticBrake", "MCPN": "10", "SCPN": "1", "IniCDelay": "0.0", "SCDelay": "0.8", "CoupledCtrl": "No", "EIMCtrlAddZeros": "Yes", "SBD": "0.65", "ASB": "Yes", "ConverterStart": "Automatic", "ConverterStartDelay": "8", "MainInitTime": "2", "BrakeOpModes": "PN", "MotorBlowersStart": "Converter", "EIMCtrlEmergency": "Yes", "PantEPValveStart": "Automatic", "PantEPValveSpring": "No", "SpringBrakeCutsOffDrive": "No", "SpringBrakeDriveEmergencyVel": "2", "ReleaseParkingBySpringBrakeWhenDoorIsOpen": "Yes", "CompartmentLightsStart": "Manual", "HAO": "Yes", "OMP": "0.8", "AutomaticCabActivation": "No", "InactivaCabEmergencyBrake": "Yes", "InactiveCabFlag": "239", "rows": [
|
||||
["-1","0.5","0.0","6","ElectroPneumatic"],
|
||||
["0","0.5","-1","4","ElectroPneumatic"],
|
||||
["1","0.5","0.35","4","ElectroPneumatic"],
|
||||
["2","0.5","0.35","4","Pneumatic"],
|
||||
["3","0.5","0.35","4","Pneumatic"],
|
||||
["4","-1","0.35","4","Pneumatic"],
|
||||
["5","0.34","-1","4","Pneumatic"],
|
||||
["6","-1","-1","0","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "2.1", "CabDependent": "Yes", "RadioStop": "Yes", "MagnetLocation": "4.5"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "24", "LMaxCurrent": "300"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "0", "MaxVoltage": "3900", "MinV": "2100", "MaxCurrent": "1200", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4"},
|
||||
"Engine": {"EngineType": "ElectricInductionMotor", "InvNo": "2", "Trans": "60:252", "dfic": "794", "dfmax": "1.500", "p": "2", "cfu": "40.1", "cim": "12.24", "icif": "0.679", "Uzmax": "2200", "Uzh": "1500", "DU": "20", "I0": "10", "fcfu": "47.6", "fcfuh": "31.4", "F0": "100", "a1": "0", "Pmax": "1260", "Fh": "48", "Ph": "800", "Vh0": "5", "Vh1": "15", "Imax": "475", "abed": "0", "edep": "3.0", "eimclf": "Yes", "MotorBlowersSpeed": "-15", "MotorBlowersSustainTime": "300", "MotorBlowersStartVelocity": "0.1"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "10|20|40|60|80|100|120|140|160", "OverrideManual": "No", "InitPwr": "1.0", "MaxPwrVel": "-1", "StartVel": "-1", "VelStep": "10", "PwrStep": "0.0", "MinPwr": "0.2", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "160", "Offset": "-0.5", "kPpos": "0.2", "kPneg": "0.4", "kIpos": "0.00", "kIneg": "0.00", "BrakeIntervention": "No", "SpeedCtrlATOF": "2"},
|
||||
"AI": {"Pantstate": "1", "LocalBrakeAccFactor": "0.5", "IdlePantUp": "No"},
|
||||
"Blending": {"MED_amax": "1.08", "MED_EPVC": "No", "MED_Ncor": "No", "MED_FrEDFactor": "0", "MED_FirstDelayED": "0.5", "MED_ScndDelayED": "0.25"},
|
||||
"Switches": {"PantographPresets": "0|1|2|3"},
|
||||
"Circuit": {"ImaxHi": "500"},
|
||||
"LightsList": {"Size": "8", "Wrap": "No", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["388","34"],
|
||||
["21","34"],
|
||||
["1","16"],
|
||||
["16","1"],
|
||||
["22","34"],
|
||||
["38","38"],
|
||||
["34","34"]
|
||||
]},
|
||||
"ffList": {"Size": "5", "rows": [
|
||||
["0","0.5"],
|
||||
["24","1.0"],
|
||||
["35","1.0"],
|
||||
["42","1.3"],
|
||||
["42","1.3"],
|
||||
["74","2.3"]
|
||||
]}
|
||||
}
|
||||
36
tests/unit/data/fiz/road/man/nl293.json
Normal file
36
tests/unit/data/fiz/road/man/nl293.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"_source": "road/man/nl293.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "road", "M": "12000", "Vmax": "90", "PWR": "206"},
|
||||
"Load": {"LoadAccepted": "Passengers,Luggage", "MaxLoad": "44", "LoadQ": "pieces", "OverLoadFactor": "1.2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "10.5", "H": "3", "W": "2.6", "Cx": "0.4"},
|
||||
"Wheels": {"D": "1.0", "AIM": "300", "Tw": "2.3", "Axle": "1'A", "Bd": "4.615", "Rmin": "10.5"},
|
||||
"Brake": {"BrakeType": "Hydraulic", "NBpA": "2", "MBF": "14.75", "MaxBP": "0.5", "BCN": "4", "BCR": "0.2", "BCD": "0.2", "BCM": "2.0"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "30", "CloseSpeed": "38", "DoorMaxShiftL": "88", "DoorMaxShiftR": "88", "DoorOpenMethod": "Fold", "DoorClosureWarning": "Yes"},
|
||||
"BuffCoupl": {"CType": "Bare"},
|
||||
"Cntrl": {"BrakeSystem": "Individual", "BCPN": "10", "LocalBrake": "HydraulicBrake", "MCPN": "10", "SCPN": "5", "IniCDelay": "1.0", "SCDelay": "0.25", "AutoRelay": "Yes", "OilStart": "Automatic", "FuelStart": "Automatic", "rows": []},
|
||||
"Light": {"Light": "Accu", "LMaxVoltage": "12", "LCap": "340", "LRS": "Generator", "LMaxCurrent": "10"},
|
||||
"Power": {"EnginePower": "Internal"},
|
||||
"Engine": {"EngineType": "DieselEngine", "Trans": "10:54", "nmin": "600", "nmax": "2000", "nmax_cutoff": "1900", "AIM": "50", "EUS": "2.5", "EDS": "2.5", "IsTC": "Yes", "TC_TMMax": "1.52", "TC_CP": "0.85", "TC_LT": "1700", "TC_LR": "2.0", "TC_ULR": "2.0", "TC_FRI": "1", "TC_FRD": "1", "TC_TII": "1.63", "TC_TIO": "0", "TC_TOO": "0", "TC_LS": "33", "TC_ULS": "25.4", "IsRetarder": "Yes", "R_Place": "2", "R_TII": "2.0", "R_MT": "1000", "R_MP": "100", "R_FRI": "1", "R_FRD": "1", "R_MinVel": "30"},
|
||||
"MotorParamTable": {"minVelfullengage": "2.0", "engageDia": "1", "engageMaxForce": "1600", "engagefriction": "1", "rows": [
|
||||
["0","0","0","-1","1"],
|
||||
["1","2.81","-1","18.8","1"],
|
||||
["2","1.84","15.2","28.6","1"],
|
||||
["3","1.36","25.4","38.8","1"],
|
||||
["4","1.00","34.6","52.7","1"],
|
||||
["5","0.80","43.2","200","1"]
|
||||
]},
|
||||
"DList": {"Size": "10", "nMmax": "20.83", "Mmax": "1400", "Mnmax": "1050", "nmax": "31.67", "nominalfill": "1", "Mstand": "150", "rows": [
|
||||
["0","0.1","0"],
|
||||
["1","0.1","2"],
|
||||
["2","0.2","2"],
|
||||
["3","0.3","2"],
|
||||
["4","0.4","2"],
|
||||
["5","0.5","2"],
|
||||
["6","0.6","2"],
|
||||
["7","0.7","2"],
|
||||
["8","0.8","2"],
|
||||
["9","0.9","2"],
|
||||
["10","1.0","2"]
|
||||
]}
|
||||
}
|
||||
94
tests/unit/data/fiz/sa134_v1/218mc_a.json
Normal file
94
tests/unit/data/fiz/sa134_v1/218mc_a.json
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"_source": "pkp/sa134_v1/218mc_a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "41000", "Vmax": "120", "PWR": "382", "SandCap": "100", "Type": "dmu"},
|
||||
"Load": {"MaxLoad": "50", "OverLoadFactor": "2.2", "LoadQ": "pieces", "LoadAccepted": "passengers", "LoadSpeed": "0.5", "UnLoadSpeed": "0.7"},
|
||||
"Dimensions": {"L": "20.75", "H": "4.2", "W": "2.9", "Cx": "0.0"},
|
||||
"Wheels": {"D": "0.84", "Tw": "1.435", "AIM": "300", "Axle": "B'1'", "Ad": "2", "Bd": "17.23", "Rmin": "75", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "EStED", "Size": "150", "NBpA": "4", "MBF": "85.0", "MaxBP": "2.9", "LocMaxBP": "3.8", "RV": "-1", "RM": "0.77", "BCN": "6", "BCR": "0.127", "BCD": "0.1", "BCM": "2.15", "HiPP": "5", "LoPP": "3.5", "Vv": "0.50", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.0208", "CompressorPower": "Main", "BCS": "0.5", "BSA": "0", "BM": "Cosid", "BVV": "150", "BRE": "0.97", "TareMaxBP": "2.2", "LPOn": "3.0", "LPOff": "4.5", "UBB1": "2", "UBB2": "8"},
|
||||
"SpringBrake": {"Volume": "15", "MBF": "4.35", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "0.5", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"Doors": {"OpenCtrl": "Mixed", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.23", "CloseSpeed": "0.19", "DoorCloseDelay": "2.45", "DoorMaxShiftL": "0.78", "DoorMaxShiftR": "0.78", "DoorOpenMethod": "Plug", "DoorClosureWarning": "No", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.04", "MirrorMaxShift": "75", "DoorStayOpen": "10", "DoorNeedPermit": "Yes", "DoorPermitList": "1|0|2|3", "DoorPermitListDefault": "2", "DoorAutoCloseRemote": "No"},
|
||||
"BuffCoupl1": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "ControlType": "218M"},
|
||||
"BuffCoupl2": {"CType": "Articulated", "AllowedFlag": "-55", "ControlType": "218M"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "3", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Yes", "LocalBrake": "PneumaticBrake", "ManualBrake": "No", "MCPN": "5", "SCPN": "1", "AutoRelay": "Yes", "IniCDelay": "1.0", "SCDelay": "0.3", "BrakeDelays": "PR", "MaxBPMass": "55", "BrakeHandle": "MHZ_K5P", "LocBrakeHandle": "FD1", "WaterStart": "Battery", "OilStart": "Automatic", "FuelStart": "Automatic", "ConverterStart": "Automatic", "ConverterStartDelay": "4", "BrakeOpModes": "PN", "EIMCtrlType": "3", "DirChangeMaxPos": "4", "SBD": "0.47", "AutomaticCabActivation": "No", "InactiveCabFlag": "27", "CompartmentLightsStart": "Manual", "rows": [
|
||||
["-1","0.6","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "2.4", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "2.1", "RadioStop": "Yes", "CabDependent": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "24", "LMaxCurrent": "155"},
|
||||
"Engine": {"EngineType": "DieselEngine", "Trans": "69:229", "TransEff": "0.90", "nmin": "850", "nmax": "2100", "nmax_cutoff": "2150", "nmin_hdrive": "1000", "nmin_hdrive_factor": "800", "nmin_retarder": "1400", "MaxVelANS": "255", "AIM": "150", "EUS": "2.5", "EDS": "2.5", "IsTC": "Yes", "TC_TMMax": "4.23", "TC_CP": "0.80", "TC_LT": "3000", "TC_LR": "1", "TC_ULR": "1", "TC_FRI": "0.25", "TC_FRD": "1", "TC_TII": "1.97", "TC_TIO": "0", "TC_TOO": "0", "TC_LS": "80", "TC_ULS": "75", "IsRetarder": "Yes", "R_Place": "0", "R_TII": "18.0", "R_MT": "2000", "R_MP": "300", "R_FRI": "1", "R_FRD": "1", "R_MinVel": "16", "R_EngageVel": "95", "WaterMaxTemperature": "105", "WaterCoolingTemperature": "95", "WaterFlowTemperature": "75", "WaterAuxCircuit": "No", "WaterCoolingFanSpeed": "-100", "NominalCoolingPower": "300"},
|
||||
"Clima": {"HMaxVoltage": "3000", "Heating": "Generator", "HGeneratorEngine": "Main", "HGeneratorMinRPM": "696", "HGeneratorMinVoltage": "2400", "HGeneratorMaxRPM": "1500", "HGeneratorMaxVoltage": "3300"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "0|30|40|50|60|70|80|90|100|120", "OverrideManual": "Yes", "InitPwr": "0.3", "MaxPwrVel": "5", "StartVel": "2", "VelStep": "5", "PwrStep": "0.1", "MinPwr": "0.3", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "120", "Offset": "-0.5", "kPpos": "0.1", "kPneg": "0.4", "kIpos": "0.06", "kIneg": "0.06", "BrakeIntervention": "Yes"},
|
||||
"TurboPos": {"TurboPos": "1"},
|
||||
"MotorParamTable": {"minVelfullengage": "-0.1", "engageDia": "1", "engageMaxForce": "3300", "engagefriction": "5.0", "rows": [
|
||||
["0","0","0","-1","1"],
|
||||
["1","0.72","-1","200","1"]
|
||||
]},
|
||||
"DList": {"Size": "10", "Mmax": "2750", "nMmax": "18.3", "nmax": "33.3", "Mnmax": "2142", "nominalfill": "1.0", "Mstand": "250.0", "NomFuelConsRate": "220", "rows": [
|
||||
["0","0.15","0"],
|
||||
["1","0.10","2"],
|
||||
["2","0.20","2"],
|
||||
["3","0.30","2"],
|
||||
["4","0.40","2"],
|
||||
["5","0.50","2"],
|
||||
["6","0.60","2"],
|
||||
["7","0.70","2"],
|
||||
["8","0.80","2"],
|
||||
["9","0.90","2"],
|
||||
["10","1.00","2"]
|
||||
]},
|
||||
"DMList": {"rows": [
|
||||
["0","0"],
|
||||
["80","591"],
|
||||
["400","738"],
|
||||
["800","1477"],
|
||||
["1300","2400"],
|
||||
["1500","2400"],
|
||||
["1750","2071"],
|
||||
["2000","1824"],
|
||||
["2200","1508"]
|
||||
]},
|
||||
"HTCList": {"rows": [
|
||||
["0.000","4.89"],
|
||||
["0.061","4.44"],
|
||||
["0.159","3.63"],
|
||||
["0.236","3.12"],
|
||||
["0.293","2.81"],
|
||||
["0.354","2.46"],
|
||||
["0.427","2.14"],
|
||||
["0.492","1.87"],
|
||||
["0.565","1.62"],
|
||||
["0.642","1.39"],
|
||||
["0.720","1.23"],
|
||||
["0.800","1.00"],
|
||||
["1.000","0.00"]
|
||||
]},
|
||||
"UCList": {"Size": "5", "IntegratedBrakePN": "Yes", "IntegratedBrake": "Yes", "rows": [
|
||||
["0","3","0","0","0","0.15","0.15","0","1","0"],
|
||||
["1","2","0","0","0","0.15","0.15","1","3","0"],
|
||||
["2","1","-1","0","-1","0.15","0.15","3","3","1"],
|
||||
["3","1","-1","1","0","0.00","0.15","3","4","1"],
|
||||
["4","0","-1","1","0","0.15","0.00","4","5","3"],
|
||||
["5","0","0","1","1","0.15","0.15","4","5","3"]
|
||||
]},
|
||||
"LightsList": {"Size": "5", "Wrap": "no", "Default": "1", "rows": [
|
||||
["0","0"],
|
||||
["21","34"],
|
||||
["22","34"],
|
||||
["34","34"],
|
||||
["16","1"]
|
||||
]},
|
||||
"WiperList": {"Size": "5", "Angle": "-75", "Default": "1", "rows": [
|
||||
["3","0.5","0.5","0.0"],
|
||||
["0","0.8","0.0","0.5"],
|
||||
["3","0.8","6.0","0.5"],
|
||||
["3","0.8","3.0","0.0"],
|
||||
["3","0.8","1.0","0.0"]
|
||||
]}
|
||||
}
|
||||
13
tests/unit/data/fiz/sieciowiec_v1/a.json
Normal file
13
tests/unit/data/fiz/sieciowiec_v1/a.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"_source": "pkp/sieciowiec_v1/a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "35500", "Vmax": "80", "HeatingP": "20", "LightP": "0.56"},
|
||||
"Load": {"MaxLoad": "80", "LoadQ": "pieces", "LoadAccepted": "Passengers,Luggage", "OverLoadFactor": "2", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "21.13", "H": "4", "W": "2.9", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.00", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.83", "Bd": "13.9", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeType": "None", "NBpA": "0", "MBF": "0", "MaxBP": "0"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.11", "FmaxB": "320", "kC": "4500", "DmaxC": "0.1", "FmaxC": "850", "beta": "0.58", "AllowedFlag": "115"},
|
||||
"Cntrl": {"MCPN": "1", "BrakeSystem": "Individual", "LocalBrake": "NoBrake", "rows": []},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "WheelsDriven", "LMaxVoltage": "24", "AlterLight": "Accu", "AlterLMaxVoltage": "24", "AlterLCap": "495", "AlterLRS": "Generator"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000", "AlterHeating": "PowerCable", "AlterHPowerTrans": "SteamPower", "AlterHSteamPress": "0.45"}
|
||||
}
|
||||
41
tests/unit/data/fiz/sm03_v1/sm03.json
Normal file
41
tests/unit/data/fiz/sm03_v1/sm03.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"_source": "pkp/sm03_v1/sm03.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "23200", "Vmax": "25.68", "PWR": "111.855", "SandCap": "200"},
|
||||
"Dimensions": {"L": "6.94", "H": "3.21", "W": "2.97", "Cx": "0.3"},
|
||||
"Wheels": {"D": "0.94", "Tw": "1.435", "AIM": "250", "Axle": "B", "Ad": "2.5", "Bd": "2.5", "Rmin": "50", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "K", "NBpA": "2", "MBF": "85.0", "MaxBP": "3.5", "LocMaxBP": "5.0", "BCN": "1", "BCR": "0.114", "BCD": "0.12", "BCM": "10.0", "HiPP": "5", "LoPP": "3.5", "Vv": "0.3", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.0125", "CompressorPower": "Main", "BCS": "0.8", "BSA": "0", "BM": "P10-Bg", "BVV": "40", "BRE": "0.9"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "3"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "4", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "ManualBrake": "Yes", "DynamicBrake": "Passive", "MCPN": "9", "SCPN": "7", "AutoRelay": "No", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "P", "BrakeHandle": "Knorr", "LocBrakeHandle": "Knorr", "FuelStart": "Automatic", "ConverterStart": "Automatic", "rows": [
|
||||
["-1","0.6","0","15","Pneumatic"],
|
||||
["0","0.5","0","9","Pneumatic"],
|
||||
["1","-1","-1","0","Pneumatic"],
|
||||
["2","-1","-1","5","Pneumatic"],
|
||||
["3","0.34","-1","9","Pneumatic"],
|
||||
["4","0.0","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "24", "LMaxCurrent": "100"},
|
||||
"Engine": {"EngineType": "DieselEngine", "Trans": "1:1", "nmin": "900", "nmax": "1500", "nmax_cutoff": "1550", "AIM": "100", "OilMinPressure": "0.343", "OilMaxPressure": "0.686", "WaterCoolingTemperature": "80", "WaterShutters": "yes", "WaterAuxCircuit": "no", "HeatKFO": "160", "HeatKFO2": "180", "HeatKFS": "160", "HeatKFE": "7", "HeatKW": "2", "HeatKV": "0.3", "IsTC": "No", "TC_TMMax": "1.00", "TC_CP": "0.9", "TC_LT": "1000", "TC_LR": "1", "TC_ULR": "1", "TC_FRI": "1", "TC_FRD": "1", "TC_TII": "0.8", "TC_TIO": "0", "TC_TOO": "0", "TC_LS": "3.5", "TC_ULS": "3.0", "EUS": "0.35", "EDS": "1.0"},
|
||||
"MotorParamTable": {"minVelfullengage": "3.8", "engageDia": "1", "engageMaxForce": "800", "engagefriction": "1", "rows": [
|
||||
["0","0","0","-1"],
|
||||
["1","46.88","-1","5.73"],
|
||||
["2","0","0","-1"],
|
||||
["3","28.65","2.9","9.42"],
|
||||
["4","0","0","-1"],
|
||||
["5","17.12","4.7","15.69"],
|
||||
["6","0","0","-1"],
|
||||
["7","10.46","10.6","100"]
|
||||
]},
|
||||
"DList": {"Size": "9", "Mmax": "784.5", "nMmax": "15", "Mnmax": "686.4", "nmax": "25", "nominalfill": "1", "Mstand": "200.0", "rows": [
|
||||
["0","0.1","0"],
|
||||
["1","0.2","2"],
|
||||
["2","0.3","2"],
|
||||
["3","0.4","2"],
|
||||
["4","0.5","2"],
|
||||
["5","0.6","2"],
|
||||
["6","0.7","2"],
|
||||
["7","0.8","2"],
|
||||
["8","0.9","2"],
|
||||
["9","1.0","2"]
|
||||
]}
|
||||
}
|
||||
43
tests/unit/data/fiz/sm31_v1/411d.json
Normal file
43
tests/unit/data/fiz/sm31_v1/411d.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"_source": "pkp/sm31_v1/411d.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "116400", "Mred": "15000", "Vmax": "80", "PWR": "880", "SandCap": "400"},
|
||||
"Dimensions": {"L": "17.00", "H": "4.292", "W": "2.904", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.100", "AIM": "4000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "2.6", "Bd": "13.1", "Rmin": "80"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.3", "LocMaxBP": "4.3", "MaxASBP": "1.3", "BCN": "12", "BCR": "0.114", "BCD": "0.06", "BCM": "5.84", "HiPP": "5", "LoPP": "3.5", "Vv": "0.8", "MinCP": "7.5", "MaxCP": "8.0", "CompressorSpeed": "0.03", "BCS": "1", "BSA": "2", "BM": "P10-Bgu", "CompressorPower": "Converter", "BVV": "130", "BRE": "0.9"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "35"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "11", "SCPN": "2", "AutoRelay": "Yes", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GP", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "ConverterStart": "Automatic", "ConverterStartDelay": "7", "rows": [
|
||||
["-1","0.60","-1","15","Pneumatic"],
|
||||
["0","0.50","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0.00","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "100"},
|
||||
"Engine": {"AIM": "1.6", "EngineType": "DumbDE", "Trans": "19:70", "Ftmax": "392000", "Vhyp": "4", "Vadd": "5", "Cr": "1", "RelayType": "1"},
|
||||
"TurboPos": {"TurboPos": "5"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","17.567","64","1500","15","30","0"],
|
||||
["1","16.29","123.7","1750","32","43","0"],
|
||||
["2","15","183.3","2000","49","200","0"]
|
||||
]},
|
||||
"Circuit": {"ImaxLo": "2800", "IminLo": "2000"},
|
||||
"WWList": {"Size": "11", "rows": [
|
||||
["496","0","0","0"],
|
||||
["496","30","870","3000"],
|
||||
["496","75","870","3000"],
|
||||
["496","105","870","3000"],
|
||||
["496","135","870","3000"],
|
||||
["568","213","870","3000"],
|
||||
["640","305","870","3000"],
|
||||
["712","395","870","3000"],
|
||||
["784","495","870","3000"],
|
||||
["856","595","870","3000"],
|
||||
["928","705","870","3000"],
|
||||
["1000","800","870","3000"]
|
||||
]}
|
||||
}
|
||||
48
tests/unit/data/fiz/sm40_v1/sm40.json
Normal file
48
tests/unit/data/fiz/sm40_v1/sm40.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"_source": "pkp/sm40_v1/sm40.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "62000", "Mred": "10000", "Vmax": "80", "PWR": "1175", "SandCap": "400"},
|
||||
"Dimensions": {"L": "11.30", "H": "4.44", "W": "3.05", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.04", "AIM": "4000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "1.75", "Bd": "10.3", "Rmin": "100"},
|
||||
"Brake": {"BrakeValve": "K", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.0", "LocMaxBP": "5.0", "BCN": "4", "BCR": "0.236", "BCD": "0.1", "BCM": "6.54", "HiPP": "5", "LoPP": "3.5", "Vv": "0.50", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.0208", "CompressorPower": "Main", "BCS": "0.8", "BSA": "0", "BM": "P10-Bg", "BVV": "127", "BRE": "0.75"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "850", "beta": "0.5", "AllowedFlag": "39"},
|
||||
"Cntrl": {"ControlType": "sm40", "BrakeSystem": "Pneumatic", "BCPN": "4", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "0", "LocalBrake": "PneumaticBrake", "ManualBrake": "Yes", "MCPN": "20", "SCPN": "1", "AutoRelay": "Yes", "IniCDelay": "0.4", "SCDelay": "0.4", "BrakeDelays": "GP", "BrakeHandle": "Knorr", "LocBrakeHandle": "Knorr", "ConverterStart": "Automatic", "rows": [
|
||||
["-1","0.90","0","15","Pneumatic"],
|
||||
["0","0.50","0","9","Pneumatic"],
|
||||
["1","-1","-1","0","Pneumatic"],
|
||||
["2","-1","-1","5","Pneumatic"],
|
||||
["3","0.001","-1","9","Pneumatic"],
|
||||
["4","0.00","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "100"},
|
||||
"Engine": {"EngineType": "DieselElectric", "Trans": "17:77", "Ftmax": "184500", "Flat": "1", "Vhyp": "5.5", "Vadd": "5.5", "Cr": "1.0", "RelayType": "41"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","5.84","137","300","91","25","0"],
|
||||
["1","3.32","191","400","230","0","2700"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "3350", "ImaxHi": "3350", "IminLo": "400", "IminHi": "400"},
|
||||
"WWList": {"Size": "20", "rows": [
|
||||
["470","0","0","0"],
|
||||
["900","0","0","0"],
|
||||
["900","0","0","0"],
|
||||
["800","75","360","2600"],
|
||||
["800","100","405","2600"],
|
||||
["800","125","450","2600"],
|
||||
["800","145","450","2600"],
|
||||
["845","180","495","2600"],
|
||||
["890","230","540","2600"],
|
||||
["930","270","585","2600"],
|
||||
["970","315","630","2600"],
|
||||
["1005","355","675","2600"],
|
||||
["1100","360","410","2600"],
|
||||
["1100","365","285","2600"],
|
||||
["1100","370","405","2600"],
|
||||
["1100","375","440","2600"],
|
||||
["1100","380","468","2600"],
|
||||
["1100","385","490","2600"],
|
||||
["1100","390","502","2600"],
|
||||
["1100","400","512","2600"],
|
||||
["1100","412","540","2600"]
|
||||
]}
|
||||
}
|
||||
42
tests/unit/data/fiz/sm42_v1/6d1.json
Normal file
42
tests/unit/data/fiz/sm42_v1/6d1.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"_source": "pkp/sm42_v1/6d1.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "74000", "Mred": "10000", "Vmax": "90", "PWR": "590", "SandCap": "300"},
|
||||
"Dimensions": {"L": "14.24", "H": "4.285", "W": "3.170", "Cx": "0.2"},
|
||||
"Wheels": {"D": "1.100", "AIM": "4000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "2.6", "Bd": "7.524", "Rmin": "80"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.0", "MaxASBP": "1.8", "BCN": "4", "BCR": "0.1143", "BCD": "0.05", "BCM": "6.68", "HiPP": "5.0", "LoPP": "3.5", "Vv": "0.8", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.057", "CompressorPower": "Engine", "BVV": "200", "BRE": "0.85"},
|
||||
"BuffCoupl": {"ControlType": "sm42", "CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "3", "BDelay3": "36", "BDelay4": "22", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "11", "SCPN": "1", "AutoRelay": "No", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GP", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "ManualBrake": "Yes", "OilStart": "Mixed", "WaterStart": "Battery", "ConverterStart": "Automatic", "rows": [
|
||||
["-1","0.7","-1","15","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.45","-1","9","Pneumatic"],
|
||||
["2","0.41","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.28","-1","9","Pneumatic"],
|
||||
["6","0","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active", "AwareMinSpeed": "0.0", "AwareDelay": "60", "SoundSignalDelay": "2.5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "2.5", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "91"},
|
||||
"Engine": {"AIM": "1.6", "RPMDecRate": "4.0", "EngineType": "DumbDE", "Trans": "17:75", "Ftmax": "228000", "Vhyp": "7", "Vadd": "5.5", "Cr": "1", "ShuntMode": "1", "WaterCoolingTemperature": "81", "WaterCoolingFanSpeed": "-1200", "WaterMaxTemperature": "85", "OilMinPressure": "0.15", "OilMinTemperature": "25", "OilMaxTemperature": "90", "HeaterMinTemperature": "55", "HeaterMaxTemperature": "60", "HeatKFS": "35", "HeatKFO": "30", "HeatKFE": "7", "HeatKW": "0.011", "HeatKV": "0.3", "HeatKFO2": "100"},
|
||||
"TurboPos": {"TurboPos": "5"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","17.567","64","1500","15","0","0"],
|
||||
["1","15","183.3","2000","49","0","0"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.1", "ImaxLo": "1900", "ImaxHi": "1900", "IminLo": "400", "IminHi": "400"},
|
||||
"WWList": {"Size": "11", "rows": [
|
||||
["496","0","0","0","0","0","0"],
|
||||
["496","20","125","600","0","140","180"],
|
||||
["496","50","156","846","0","140","180"],
|
||||
["496","90","194","1065","0","140","180"],
|
||||
["496","135","240","1260","0","140","180"],
|
||||
["568","182","293","1428","25","150","200"],
|
||||
["640","234","353","1571","50","160","235"],
|
||||
["712","286","420","1688","80","200","270"],
|
||||
["784","348","494","1780","100","235","305"],
|
||||
["856","408","575","1845","130","300","370"],
|
||||
["928","474","664","1886","150","360","410"],
|
||||
["1000","540","760","1900","170","450","490"]
|
||||
]}
|
||||
}
|
||||
42
tests/unit/data/fiz/sn61_v2/sn61.json
Normal file
42
tests/unit/data/fiz/sn61_v2/sn61.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"_source": "pkp/sn61_v2/sn61.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "Type": "sn61", "M": "54810", "Vmax": "100", "PWR": "368", "SandCap": "100"},
|
||||
"Load": {"MaxLoad": "50", "LoadQ": "pieces", "LoadAccepted": "passengers", "LoadSpeed": "1", "UnLoadSpeed": "1"},
|
||||
"Dimensions": {"L": "24.22", "H": "4.12", "W": "2.96", "Cx": "0.5"},
|
||||
"Wheels": {"D": "0.94", "Tw": "1.435", "AIM": "300", "Axle": "B'2'", "Ad": "3.2", "Bd": "18.36", "Rmin": "100", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "ESt3d_PZZ", "Size": "150", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.8", "LocMaxBP": "3.8", "BCN": "3", "BCR": "0.127", "BCD": "0.1", "BCM": "6.54", "HiPP": "5", "LoPP": "3.5", "Vv": "0.50", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.0208", "CompressorPower": "Main", "BCS": "1.5", "BSA": "2", "BM": "P10-Bg", "BVV": "150", "BRE": "0.85"},
|
||||
"Doors": {"OpenCtrl": "Passenger", "CloseCtrl": "Passenger", "OpenSpeed": "110", "CloseSpeed": "400", "DoorMaxShiftL": "89", "DoorMaxShiftR": "89", "DoorOpenMethod": "Roll", "DoorClosureWarning": "No"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "ControlType": "sn61"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "DirChangeMaxPos": "2", "LocalBrake": "PneumaticBrake", "ManualBrake": "Yes", "MCPN": "8", "SCPN": "5", "AutoRelay": "Yes", "IniCDelay": "1.5", "SCDelay": "0.3", "BrakeDelays": "P", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "FuelStart": "Automatic", "WaterStart": "Battery", "OilStart": "Automatic", "ConverterStart": "Automatic", "rows": [
|
||||
["-1","0.6","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Engine": {"EngineType": "DieselEngine", "Trans": "39:83", "nmin": "660", "nmax": "1350", "nmax_cutoff": "1250", "AIM": "150"},
|
||||
"MotorParamTable": {"minVelfullengage": "7.8", "engageDia": "1", "engageMaxForce": "3800", "engagefriction": "1", "rows": [
|
||||
["0","0","0","-1","1"],
|
||||
["1","5.056","-1","20.3","1"],
|
||||
["2","3.325","14.7","30.8","1"],
|
||||
["3","2.259","25.4","45.3","1"],
|
||||
["4","1.486","40.9","68.9","1"],
|
||||
["5","1.000","62.4","200","1"]
|
||||
]},
|
||||
"DList": {"Size": "8", "Mmax": "3630", "nMmax": "13.333", "Mnmax": "3100", "nmax": "21", "nominalfill": "0.9", "Mstand": "300.0", "rows": [
|
||||
["0","0","0"],
|
||||
["1","0.4","0"],
|
||||
["2","0.1","0"],
|
||||
["3","0.6","1"],
|
||||
["4","0.15","3"],
|
||||
["5","0.40","3"],
|
||||
["6","0.60","3"],
|
||||
["7","0.80","3"],
|
||||
["8","1.00","4"]
|
||||
]}
|
||||
}
|
||||
56
tests/unit/data/fiz/st44_v2/m62-1151.json
Normal file
56
tests/unit/data/fiz/st44_v2/m62-1151.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"_source": "pkp/st44_v2/m62-1151.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "116000", "Mred": "20000", "Vmax": "100", "PWR": "1232", "SandCap": "400", "Type": "st44"},
|
||||
"Dimensions": {"L": "17.55", "H": "4.62", "W": "2.95", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.05", "AIM": "4000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "2.6", "Bd": "8.6", "Rmin": "80"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "124", "MaxBP": "4.1", "MaxLBP": "3.9", "MaxASBP": "1.8", "BCN": "8", "BCR": "0.1016", "BCD": "0.1", "BCM": "10.4", "HiPP": "5", "LoPP": "3.5", "Vv": "0.888", "MinCP": "7", "MaxCP": "8.5", "CompressorSpeed": "0.077", "BCS": "1", "BSA": "2", "BM": "P10-Bgu", "BVV": "222", "CompressorPower": "Main", "BRE": "0.9", "UBB1": "1", "UBB2": "2"},
|
||||
"BuffCoupl": {"ControlType": "kolomna", "CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "15", "SCPN": "2", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GP", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "AutoRelay": "Yes", "ManualBrake": "Yes", "OilStart": "Automatic", "WaterStart": "Battery", "ConverterStart": "Automatic", "rows": [
|
||||
["-1","0.7","-1","15","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.29","-1","9","Pneumatic"],
|
||||
["6","0","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "100"},
|
||||
"Clima": {"HMaxVoltage": "3000", "Heating": "Generator", "HGeneratorEngine": "Main", "HGeneratorMinRPM": "400", "HGeneratorMinVoltage": "2400", "HGeneratorMaxRPM": "750", "HGeneratorMaxVoltage": "3300"},
|
||||
"Engine": {"AIM": "3.3", "EngineType": "DieselElectric", "Trans": "15:68", "Ftmax": "396000", "Flat": "1", "Vhyp": "18", "Vadd": "0", "Cr": "1.107", "WaterFlowTemperature": "80", "WaterCoolingTemperature": "45", "WaterMaxTemperature": "95", "WaterShutters": "Yes", "WaterAuxCircuit": "Yes", "WaterAuxCoolingTemperature": "60", "WaterAuxMaxTemperature": "75", "WaterAuxShutters": "Yes", "OilMinPressure": "0.25", "OilMaxPressure": "0.8", "OilMaxTemperature": "71", "HeatKFO": "40", "HeatKFO2": "190", "HeatKW": "0.2", "WaterCoolingFanSpeed": "1.86"},
|
||||
"LightsList": {"Size": "8", "Wrap": "No", "Default": "4", "rows": [
|
||||
["38","38","/","A"],
|
||||
["38","38","/","A"],
|
||||
["34","34"],
|
||||
["0","0"],
|
||||
["21","34"],
|
||||
["1","16"],
|
||||
["16","1"],
|
||||
["22","34"]
|
||||
]},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","10","179","2000","72","2450","0"],
|
||||
["1","8","190","1600","95","2250","3600"],
|
||||
["2","7","300","1400","170","0","3450"]
|
||||
]},
|
||||
"WWList": {"Size": "15", "rows": [
|
||||
["400","0","0","0"],
|
||||
["400","40","180","1500"],
|
||||
["425","100","240","2000"],
|
||||
["450","250","300","2080"],
|
||||
["475","450","330","3660"],
|
||||
["500","500","360","3830"],
|
||||
["525","550","380","4000"],
|
||||
["550","600","405","4160"],
|
||||
["575","700","430","4330"],
|
||||
["600","750","450","4660"],
|
||||
["625","800","475","4830"],
|
||||
["650","850","500","5160"],
|
||||
["675","950","525","5330"],
|
||||
["700","1050","550","5500"],
|
||||
["725","1150","575","5660"],
|
||||
["750","1232","600","6000"]
|
||||
]}
|
||||
}
|
||||
55
tests/unit/data/fiz/st45_v2/301dd.json
Normal file
55
tests/unit/data/fiz/st45_v2/301dd.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"_source": "pkp/st45_v2/301dd.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "97000", "Mred": "15000", "Vmax": "120", "PWR": "1330", "SandCap": "400"},
|
||||
"Dimensions": {"L": "18.99", "H": "4.243", "W": "3.034", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.100", "AIM": "4000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "1.950", "Bd": "10.3", "Rmin": "100"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.1", "MaxASBP": "1.5", "RM": "0.71", "BCN": "8", "BCR": "0.114", "RV": "50", "BCD": "0.06", "BCM": "8.1", "HiPP": "5", "LoPP": "3.5", "Vv": "0.8", "MinCP": "8.0", "MaxCP": "10.0", "CompressorSpeed": "0.0613", "CompressorPower": "Converter", "BCS": "1", "BSA": "2", "BM": "P10-Bgu", "BVV": "250", "BRE": "0.9", "UBB1": "8", "HandlePipeUnlockPos": "-0.5", "LPOn": "2.75", "LPOff": "4.5"},
|
||||
"SpringBrake": {"Volume": "10", "MBF": "8", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "3.5", "ValveOnArea": "0.0002", "ValveOffArea": "0.0002", "ValvePNBArea": "0.002", "MTC": "4"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "39", "ControlType": "ST45"},
|
||||
"Cntrl": {"BrakeHandle": "MHZ_K8P", "LocBrakeHandle": "FD1", "BrakeSystem": "Pneumatic", "BCPN": "10", "BDelay1": "15", "BDelay2": "6", "BDelay3": "36", "BDelay4": "32", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "4", "SCPN": "3", "AutoRelay": "Yes", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GPR", "ConverterStart": "Automatic", "ConverterStartDelay": "5", "MotorBlowersStart": "Converter", "FuelStart": "Automatic", "OilStart": "Automatic", "WaterStart": "Battery", "EIMCtrlType": "3", "BrakeOpModes": "PN", "DirChangeMaxPos": "2", "rows": [
|
||||
["-1","0.7","-1","15","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.29","-1","9","Pneumatic"],
|
||||
["6","0","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "227.8"},
|
||||
"Engine": {"AIM": "0.9", "EngineType": "DumbDE", "Trans": "19:64", "Ftmax": "326000", "Flat": "0", "Vhyp": "7.2", "Vadd": "5.5", "Cr": "1.0", "RelayType": "45", "WaterMinTemperature": "40", "WaterFlowTemperature": "70", "WaterCoolingTemperature": "82", "WaterMaxTemperature": "91", "WaterShutters": "Yes", "WaterAuxCircuit": "Yes", "WaterAuxCoolingTemperature": "60", "WaterAuxMaxTemperature": "74", "WaterAuxShutters": "Yes", "OilMinPressure": "0.15", "HeatKFO2": "24", "HeatingRPM": "1096", "MotorBlowersSpeed": "-10", "MotorBlowersSustainTime": "600", "MotorBlowersStartVelocity": "0.1"},
|
||||
"SpeedControl": {"SpeedCtrl": "Yes", "SpeedButtons": "0|30|40|50|60|70|80|90|100|120", "OverrideManual": "Yes", "InitPwr": "0.3", "MaxPwrVel": "5", "StartVel": "2", "VelStep": "5", "PwrStep": "0.1", "MinPwr": "0.3", "MaxPwr": "1.0", "MinVel": "0", "MaxVel": "120", "Offset": "-0.5", "kPpos": "0.1", "kPneg": "0.4", "kIpos": "0.06", "kIneg": "0.06", "BrakeIntervention": "Yes"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","20","100","3000","20.8","1340","1713"],
|
||||
["1","18.5","110","2700","25","1340","1713"],
|
||||
["2","17.2","135","2500","30","1340","1713"],
|
||||
["3","14.3","170","2000","48.5","1340","1713"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "3300", "IminLo": "2500"},
|
||||
"WWList": {"Size": "4", "rows": [
|
||||
["600","0","0","0"],
|
||||
["1365","1131","816","3026"],
|
||||
["1410","1196","864","3204"],
|
||||
["1455","1264","912","3382"],
|
||||
["1500","1320","960","3560"]
|
||||
]},
|
||||
"LightsList": {"Size": "8", "Wrap": "no", "Default": "4", "rows": [
|
||||
["38","34"],
|
||||
["38","0"],
|
||||
["34","34"],
|
||||
["0","0"],
|
||||
["21","34"],
|
||||
["22","34"],
|
||||
["01","16"],
|
||||
["16","01"]
|
||||
]},
|
||||
"UCList": {"Size": "4", "IntegratedBrakePN": "no", "IntegratedBrake": "no", "rows": [
|
||||
["0","0","0","0","0","0.15","0.15","0","1","0"],
|
||||
["1","0","0","0","0","0.15","0.15","3","3","1"],
|
||||
["2","0","0","1","0","0.00","0.15","3","4","1"],
|
||||
["3","0","0","1","0","0.15","0.00","4","5","3"],
|
||||
["4","0","0","1","1","0.15","0.15","4","5","3"]
|
||||
]}
|
||||
}
|
||||
70
tests/unit/data/fiz/static/sug/sug_kielce.json
Normal file
70
tests/unit/data/fiz/static/sug/sug_kielce.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"_source": "static/sug/sug_kielce.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "120000", "Mred": "18000", "Vmax": "100", "PWR": "1860", "SandCap": "700", "Type": "et22"},
|
||||
"Load": {"MaxLoad": "52", "LoadQ": "pieces", "LoadAccepted": "pantstate", "LoadSpeed": "1", "UnLoadSpeed": "0.1"},
|
||||
"Dimensions": {"L": "16.820", "H": "4.559", "W": "3.005", "Cx": "0.585"},
|
||||
"Wheels": {"D": "1.250", "AIM": "2000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "2.1", "Bd": "8.6", "Rmin": "100", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "W", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.1", "LocMaxBP": "5.0", "BCN": "8", "BCR": "0.114", "BCD": "0.12", "BCM": "7.0", "HiPP": "5", "LoPP": "3.5", "Vv": "0.88", "MinCP": "7.0", "MaxCP": "8.0", "CompressorSpeed": "0.0567", "BCS": "0.8", "BSA": "0", "BM": "P10-Bg", "BVV": "200", "CompressorPower": "Main", "BRE": "0.75"},
|
||||
"Doors": {"OpenCtrl": "DriverCtrl", "CloseCtrl": "DriverCtrl", "OpenSpeed": "0.3", "CloseSpeed": "0.1", "DoorMaxShiftL": "0.53", "DoorMaxShiftR": "0.53", "DoorOpenMethod": "Shift", "DoorClosureWarning": "Yes"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "850", "beta": "0.5", "AllowedFlag": "0"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "4", "BDelay1": "15", "BDelay2": "4", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "ManualBrake": "Yes", "DynamicBrake": "Passive", "MCPN": "36", "SCPN": "3", "AutoRelay": "No", "IniCDelay": "0.5", "SCDelay": "0.23", "BrakeDelays": "GP", "BrakeHandle": "Knorr", "LocBrakeHandle": "Knorr", "rows": [
|
||||
["-1","0.90","0","15","Pneumatic"],
|
||||
["0","0.50","0","9","Pneumatic"],
|
||||
["1","-1","-1","0","Pneumatic"],
|
||||
["2","-1","-1","5","Pneumatic"],
|
||||
["3","0.001","-1","9","Pneumatic"],
|
||||
["4","0.00","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Power": {"EnginePower": "CurrentCollector", "CollectorsNo": "2", "MaxVoltage": "3600", "MaxCurrent": "1500", "MinH": "0.38", "MaxH": "2.4", "CSW": "1.4", "MinV": "1800", "MinPress": "3.5", "MaxPress": "5.0"},
|
||||
"Engine": {"EngineType": "ElectricSeriesMotor", "Volt": "1500", "Trans": "24:85", "WindingRes": "0.1782", "nmax": "1500"},
|
||||
"Switches": {"Pantograph": "impulse"},
|
||||
"MotorParamTable0": {"rows": [
|
||||
["0","24.84","85","0.02","167.8","85","0.02"],
|
||||
["1","21.37","180","-0.15","144.4","180","-0.15"],
|
||||
["2","20.67","230","-0.15","139.7","230","-0.15"],
|
||||
["3","21.69","190","-0.04","145","190","-0.04"]
|
||||
]},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "500", "ImaxHi": "500", "IminLo": "250", "IminHi": "250"},
|
||||
"RList": {"Size": "36", "RVent": "Automatic", "RVentnmax": "3300", "RVentCutOff": "50", "rows": [
|
||||
["0","0","0","0","0"],
|
||||
["1","26.43","1","6","0"],
|
||||
["2","18.43","1","6","0"],
|
||||
["3","13.49","1","6","0"],
|
||||
["4","10.87","1","6","0"],
|
||||
["5","9.40","1","6","0"],
|
||||
["6","7.97","1","6","0"],
|
||||
["7","6.56","1","6","0"],
|
||||
["8","5.56","1","6","0"],
|
||||
["9","4.59","1","6","0"],
|
||||
["10","3.36","1","6","0"],
|
||||
["11","2.67","1","6","0"],
|
||||
["12","2.04","1","6","0"],
|
||||
["13","1.48","1","6","0"],
|
||||
["14","0.91","1","6","0"],
|
||||
["15","0.37","1","6","0"],
|
||||
["16","0.00","1","6","0"],
|
||||
["17","3.72","2","3","0"],
|
||||
["18","2.68","2","3","0"],
|
||||
["19","2.40","2","3","0"],
|
||||
["20","1.98","2","3","0"],
|
||||
["21","1.88","2","3","0"],
|
||||
["22","1.26","2","3","0"],
|
||||
["23","0.98","2","3","0"],
|
||||
["24","0.72","2","3","0"],
|
||||
["25","0.40","2","3","0"],
|
||||
["26","0.21","2","3","0"],
|
||||
["27","0.00","2","3","0"],
|
||||
["28","1.59","3","2","0"],
|
||||
["29","1.16","3","2","0"],
|
||||
["30","0.86","3","2","0"],
|
||||
["31","0.65","3","2","0"],
|
||||
["32","0.48","3","2","0"],
|
||||
["33","0.40","3","2","0"],
|
||||
["34","0.25","3","2","0"],
|
||||
["35","0.14","3","2","0"],
|
||||
["36","0.00","3","2","0"]
|
||||
]}
|
||||
}
|
||||
47
tests/unit/data/fiz/su45_v2/301d.json
Normal file
47
tests/unit/data/fiz/su45_v2/301d.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"_source": "pkp/su45_v2/301d.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "102000", "Mred": "15000", "Vmax": "120", "PWR": "1250", "SandCap": "400", "HeatingP": "300"},
|
||||
"Dimensions": {"L": "18.99", "H": "4.238", "W": "2.900", "Cx": "0.2"},
|
||||
"Wheels": {"D": "1.100", "AIM": "4000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "1.950", "Bd": "10.3", "Rmin": "100"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.1", "LocMaxBP": "4.5", "MaxASBP": "1.5", "RM": "0.69", "BCN": "8", "BCR": "0.114", "BCD": "0.06", "BCM": "8.1", "HiPP": "5", "LoPP": "3.5", "Vv": "0.8", "MinCP": "7.0", "MaxCP": "8.5", "CompressorSpeed": "0.053", "BCS": "1", "BSA": "2", "BM": "P10-Bgu", "CompressorPower": "Engine", "BVV": "240", "BRE": "0.9"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103", "ControlType": "SU45"},
|
||||
"Cntrl": {"BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "6", "BDelay3": "36", "BDelay4": "32", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "14", "SCPN": "3", "AutoRelay": "Yes", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GPR", "MotorBlowersStart": "Manual", "ConverterStart": "Automatic", "rows": [
|
||||
["-1","0.7","-1","15","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.29","-1","9","Pneumatic"],
|
||||
["6","0","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "227.8"},
|
||||
"TurboPos": {"TurboPos": "4"},
|
||||
"Engine": {"AIM": "1.6", "EngineType": "DumbDE", "Trans": "18:62", "Ftmax": "326000", "Flat": "0", "Vhyp": "7.2", "Vadd": "5.5", "Cr": "1.0", "RelayType": "45", "WaterMinTemperature": "40", "WaterFlowTemperature": "70", "WaterCoolingTemperature": "82", "WaterMaxTemperature": "91", "WaterShutters": "Yes", "WaterAuxCircuit": "Yes", "WaterAuxCoolingTemperature": "60", "WaterAuxMaxTemperature": "74", "WaterAuxShutters": "Yes", "OilMinPressure": "0.15", "HeatKFO2": "24", "HeatingRPM": "1096", "MotorBlowersSpeed": "-10"},
|
||||
"Clima": {"HMaxVoltage": "3000", "Heating": "Generator", "HGeneratorEngine": "Main", "HGeneratorMinRPM": "696", "HGeneratorMinVoltage": "2400", "HGeneratorMaxRPM": "1500", "HGeneratorMaxVoltage": "3300"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","20","100","3000","20.8","1340","0"],
|
||||
["1","18.5","110","2700","25","1340","40"],
|
||||
["2","17.2","135","2500","30","1340","50"],
|
||||
["3","14.3","170","2000","48.5","1340","1713"]
|
||||
]},
|
||||
"WWList": {"Size": "14", "rows": [
|
||||
["696","0","0","0"],
|
||||
["696","0","0","0"],
|
||||
["629","96","78","273"],
|
||||
["763","192","147","547"],
|
||||
["830","288","221","820"],
|
||||
["897","384","295","1094"],
|
||||
["964","480","369","1367"],
|
||||
["1031","576","442","1641"],
|
||||
["1098","672","516","1914"],
|
||||
["1165","768","590","2187"],
|
||||
["1232","864","664","2461"],
|
||||
["1299","960","737","2734"],
|
||||
["1366","1056","811","3007"],
|
||||
["1433","1152","885","3281"],
|
||||
["1500","1245","960","3560"]
|
||||
]}
|
||||
}
|
||||
50
tests/unit/data/fiz/su46_v2/303d.json
Normal file
50
tests/unit/data/fiz/su46_v2/303d.json
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"_source": "pkp/su46_v2/303d.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "105000", "Mred": "15000", "Vmax": "120", "PWR": "1400", "SandCap": "400", "HeatingP": "440"},
|
||||
"Dimensions": {"L": "18.99", "H": "4.292", "W": "2.904", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.100", "AIM": "4000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "1.75", "Bd": "10.3", "Rmin": "100"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "4.4", "LocMaxBP": "4.4", "MaxASBP": "1.3", "RM": "0.71", "BCN": "12", "BCR": "0.114", "BCD": "0.06", "BCM": "5.84", "HiPP": "5", "LoPP": "3.5", "Vv": "0.9", "MinCP": "7", "MaxCP": "8.5", "CompressorSpeed": "0.05", "BCS": "1", "BSA": "2", "BM": "P10-Bgu", "CompressorPower": "Converter", "BVV": "200", "BRE": "0.8"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "103", "ControlType": "SU46"},
|
||||
"Cntrl": {"BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "6", "BDelay3": "36", "BDelay4": "32", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "15", "SCPN": "4", "AutoRelay": "Yes", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GPR", "ConverterStart": "Automatic", "ConverterStartDelay": "10", "MotorBlowersStart": "Manual", "rows": [
|
||||
["-1","0.7","-1","15","Pneumatic"],
|
||||
["0","0.5","-1","9","Pneumatic"],
|
||||
["1","0.46","-1","9","Pneumatic"],
|
||||
["2","0.42","-1","9","Pneumatic"],
|
||||
["3","0.38","-1","9","Pneumatic"],
|
||||
["4","0.34","-1","9","Pneumatic"],
|
||||
["5","0.29","-1","9","Pneumatic"],
|
||||
["6","0","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "100"},
|
||||
"Engine": {"AIM": "1.6", "EngineType": "DumbDE", "Trans": "18:62", "Ftmax": "317000", "Flat": "0", "Vhyp": "15.0", "Vadd": "3.8", "Cr": "1.0", "RelayType": "46", "HeatingRPM": "1098", "OilMinPressure": "0.055", "OilMaxPressure": "0.6", "WaterMinTemperature": "40", "WaterMaxTemperature": "92", "WaterCoolingTemperature": "76", "WaterFlowTemperature": "71", "WaterShutters": "Yes", "WaterAuxCircuit": "Yes", "WaterAuxFlowTemperature": "1", "WaterAuxMinTemperature": "35", "WaterAuxMaxTemperature": "71", "WaterAuxCoolingTemperature": "56", "WaterAuxShutters": "Yes", "HeaterMinTemperature": "50", "HeaterMaxTemperature": "85", "HeatKW": "0.068599", "HeatKV": "0.3", "HeatKFE": "1", "HeatKFS": "87.76269", "HeatKFO": "26.72716", "HeatKFO2": "57.72", "WaterCoolingFanSpeed": "0.56", "MotorBlowersSpeed": "-10"},
|
||||
"TurboPos": {"TurboPos": "4"},
|
||||
"Circuit": {"CircuitRes": "0.01", "ImaxLo": "3300", "IminLo": "2500"},
|
||||
"Clima": {"HMaxVoltage": "3000", "Heating": "Generator", "HGeneratorEngine": "Main", "HGeneratorMinRPM": "696", "HGeneratorMinVoltage": "2400", "HGeneratorMaxRPM": "1500", "HGeneratorMaxVoltage": "3300"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","16.7","100","2000","24.1","1680","0"],
|
||||
["1","16.9","155","2250","36.9","40","40"],
|
||||
["2","17.1","210","2500","50.8","1680","1680"],
|
||||
["3","17.3","265","2800","65.0","50","50"],
|
||||
["4","17.5","321","3125","79.9","0","1680"]
|
||||
]},
|
||||
"WWList": {"Size": "15", "rows": [
|
||||
["696","0","0","0"],
|
||||
["696","0","0","0"],
|
||||
["696","80","350","1000"],
|
||||
["696","80","350","1000"],
|
||||
["763","214","455","1400"],
|
||||
["830","321","500","1600"],
|
||||
["897","428","545","1800"],
|
||||
["964","535","590","2000"],
|
||||
["1031","642","635","2200"],
|
||||
["1098","748","680","2400"],
|
||||
["1165","855","725","2600"],
|
||||
["1232","962","770","2800"],
|
||||
["1299","1069","815","3000"],
|
||||
["1366","1176","865","3200"],
|
||||
["1433","1283","910","3400"],
|
||||
["1500","1390","960","3600"]
|
||||
]}
|
||||
}
|
||||
39
tests/unit/data/fiz/tem2_v2/tem2a.json
Normal file
39
tests/unit/data/fiz/tem2_v2/tem2a.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"_source": "pkp/tem2_v2/tem2a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "116000", "Mred": "20000", "Vmax": "100", "PWR": "780", "SandCap": "2000"},
|
||||
"Dimensions": {"L": "17", "H": "4.62", "W": "2.95", "Cx": "0.1"},
|
||||
"Wheels": {"D": "1.05", "AIM": "4000", "Tw": "1.435", "Axle": "Co'Co'", "Ad": "2.1", "Bd": "8.6", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "2", "MBF": "124", "MaxBP": "4.1", "MaxLBP": "3.9", "BCN": "4", "BCR": "0.127", "BCD": "0.1", "BCM": "10.77", "HiPP": "5.0", "LoPP": "3.5", "Vv": "0.888", "MinCP": "7", "MaxCP": "8.5", "CompressorSpeed": "0.077", "CompressorPower": "Main", "BCS": "1", "BSA": "0", "BM": "P10-Bgu", "BVV": "222", "BRE": "0.85"},
|
||||
"BuffCoupl1": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "3"},
|
||||
"BuffCoupl2": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "23", "ControlType": "TEM2"},
|
||||
"Cntrl": {"BrakeHandle": "M394", "LocBrakeHandle": "FD1", "BrakeDelays": "G", "BrakeSystem": "Pneumatic", "BCPN": "5", "BDelay1": "25", "BDelay2": "13", "BDelay3": "25", "BDelay4": "13", "ASB": "None", "LocalBrake": "PneumaticBrake", "MCPN": "8", "SCPN": "2", "AutoRelay": "Yes", "IniCDelay": "0.5", "SCDelay": "0.1", "rows": [
|
||||
["-1","1.0","-1","10","Pneumatic"],
|
||||
["0","0.5","-1","4","Pneumatic"],
|
||||
["1","-1","-1","0","Pneumatic"],
|
||||
["2","-1","-1","2","Pneumatic"],
|
||||
["3","0.0","-1","2","Pneumatic"],
|
||||
["4","0.0","-1","6","Pneumatic"],
|
||||
["5","0.0","-1","15","Pneumatic"]
|
||||
]},
|
||||
"Security": {"AwareSystem": "Active,CabSignal", "AwareDelay": "60", "SoundSignalDelay": "5", "MaxHoldTime": "1.0", "EmergencyBrakeDelay": "6", "RadioStop": "Yes"},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "75", "LMaxCurrent": "75"},
|
||||
"TurboPos": {"TurboPos": "3"},
|
||||
"Engine": {"AIM": "0.9", "EngineType": "DieselElectric", "Trans": "15:68", "Ftmax": "396000", "Flat": "1", "Vhyp": "15", "Vadd": "0", "Cr": "1.107", "OilMinPressure": "0.16", "OilMaxPressure": "0.3", "WaterCoolingFanSpeed": "1.41", "WaterMaxTemperature": "88", "WaterCoolingTemperature": "76", "WaterShutters": "yes"},
|
||||
"MotorParamTable": {"rows": [
|
||||
["0","24","66","2000","14","1000","0"],
|
||||
["1","18","70","1600","17","1000","1400"],
|
||||
["2","15","106","1400","26","0","1400"]
|
||||
]},
|
||||
"WWList": {"Size": "8", "rows": [
|
||||
["300","0","0","0"],
|
||||
["290","65","870","1900"],
|
||||
["270","166","870","1900"],
|
||||
["330","268","870","1900"],
|
||||
["400","370","870","1900"],
|
||||
["480","471","870","1900"],
|
||||
["570","573","870","1900"],
|
||||
["650","647","870","1900"],
|
||||
["750","780","870","1900"]
|
||||
]}
|
||||
}
|
||||
22
tests/unit/data/fiz/wm15_v1/wm15.json
Normal file
22
tests/unit/data/fiz/wm15_v1/wm15.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"_source": "pkp/wm15_v1/wm15.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "20000", "Vmax": "80", "PWR": "200", "SandCap": "400"},
|
||||
"Dimensions": {"L": "11", "H": "4.292", "W": "2.900", "Cx": "0.3"},
|
||||
"Wheels": {"D": "1.100", "AIM": "4000", "Tw": "1.435", "Axle": "Bo'Bo'", "Ad": "2.6", "Bd": "10.1", "Rmin": "80"},
|
||||
"Brake": {"BrakeValve": "LSt", "NBpA": "4", "MBF": "85.0", "MaxBP": "3.8", "BCN": "4", "BCR": "0.0625", "BCD": "0.11", "BCM": "5.14", "HiPP": "5.0", "LoPP": "3.5", "Vv": "0.250", "MinCP": "7.5", "MaxCP": "8.5", "CompressorSpeed": "0.03", "BVV": "52", "BRE": "0.8", "BM": "P10-Bg", "BCS": "0.8", "BSA": "0"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "3"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "8", "SCPN": "3", "AutoRelay": "No", "IniCDelay": "0.5", "SCDelay": "0.1", "BrakeDelays": "GP", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "rows": [
|
||||
["-1","0.8","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "110", "LMaxCurrent": "155"},
|
||||
"Power": {"EnginePower": "Internal"},
|
||||
"Engine": {"EngineType": "Dumb", "Ftmax": "250000"}
|
||||
}
|
||||
49
tests/unit/data/fiz/wmb10_v1/wmb10.json
Normal file
49
tests/unit/data/fiz/wmb10_v1/wmb10.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"_source": "pkp/wmb10_v1/wmb10.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "9800", "Vmax": "70", "PWR": "92", "SandCap": "0", "Mred": "1000"},
|
||||
"Dimensions": {"L": "8.21", "H": "2.9", "W": "2.8", "Cx": "0.2"},
|
||||
"Load": {"MaxLoad": "6", "LoadQ": "pieces", "LoadAccepted": "Passengers,naprawcze,brygada_naprawcza,konserwacja", "OverLoadFactor": "1", "LoadSpeed": "0.5", "UnLoadSpeed": "0.5"},
|
||||
"Wheels": {"D": "0.7", "AIM": "2000", "Tw": "1.435", "Axle": "1'A", "Bd": "5.1", "Rmin": "80", "BearingType": "Roll"},
|
||||
"Doors": {"OpenCtrl": "Passenger", "CloseCtrl": "Passenger", "OpenSpeed": "0.2", "CloseSpeed": "0.2", "DoorOpenMethod": "Rotate", "DoorMaxShiftL": "0.625", "DoorMaxShiftR": "0.625"},
|
||||
"Brake": {"BrakeValve": "LSt", "Size": "12", "NBpA": "1", "MBF": "11", "MaxBP": "4.0", "BCN": "2", "BCR": "0.1016", "BCD": "0.15", "BCM": "4.1", "BCS": "1.0", "BSA": "1.0", "BM": "Disk2", "BVV": "50", "BRE": "0.9", "MinCP": "6", "MaxCP": "7.3", "Vv": "0.2", "CompressorSpeed": "0.0125", "CompressorPower": "Main"},
|
||||
"SpringBrake": {"Volume": "9.4", "MBF": "11", "MaxSP": "5.5", "ResetP": "4.0", "MinFP": "3.5", "PressOff": "4.5", "PressOn": "4.2", "ValveOnArea": "0.0005", "ValveOffArea": "0.0005", "ValvePNBArea": "0.002", "MTC": "132"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.15", "FmaxB": "740", "kC": "4800", "DmaxC": "0.15", "FmaxC": "780", "beta": "0.58", "AllowedFlag": "3"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "BCPN": "6", "BDelay1": "15", "BDelay2": "4", "BDelay3": "35", "BDelay4": "25", "ASB": "Manual", "LocalBrake": "PneumaticBrake", "MCPN": "9", "SCPN": "5", "AutoRelay": "no", "IniCDelay": "0.48", "SCDelay": "0.3", "BrakeDelays": "P", "BrakeHandle": "FV4a", "LocBrakeHandle": "FD1", "FuelStart": "Automatic", "OilStart": "Automatic", "WaterStart": "Battery", "ConverterStart": "Automatic", "rows": [
|
||||
["-1","0.8","-1","20","Pneumatic"],
|
||||
["0","0.5","-1","2","Pneumatic"],
|
||||
["1","0.46","-1","2","Pneumatic"],
|
||||
["2","0.42","-1","2","Pneumatic"],
|
||||
["3","0.38","-1","2","Pneumatic"],
|
||||
["4","0.34","-1","2","Pneumatic"],
|
||||
["5","0.29","-1","2","Pneumatic"],
|
||||
["6","0","-1","40","Pneumatic"]
|
||||
]},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": "24", "LMaxCurrent": "100"},
|
||||
"Engine": {"EngineType": "DieselEngine", "Trans": "10:54", "nmin": "575", "nmax": "2700", "nmax_cutoff": "2600", "AIM": "10", "EUS": "20", "EDS": "20"},
|
||||
"MotorParamTable": {"minVelfullengage": "1.62", "engageDia": "1", "engageMaxForce": "384", "engagefriction": "1", "rows": [
|
||||
["0","0","0","-1"],
|
||||
["1","6.93","-1","10"],
|
||||
["2","4.03","4","17"],
|
||||
["3","2.36","9","30"],
|
||||
["4","1.40","18","53"],
|
||||
["5","1.00","33","100"]
|
||||
]},
|
||||
"DList": {"Size": "9", "Mmax": "450", "nMmax": "26.66", "Mnmax": "370", "nmax": "43.33", "nominalfill": "1", "Mstand": "130", "rows": [
|
||||
["0","0.4","0"],
|
||||
["1","0.46","1"],
|
||||
["2","0.52","2"],
|
||||
["3","0.58","2"],
|
||||
["4","0.64","2"],
|
||||
["5","0.70","2"],
|
||||
["6","0.76","2"],
|
||||
["7","0.82","2"],
|
||||
["8","0.88","2"],
|
||||
["9","1.0","2"]
|
||||
]},
|
||||
"LightsList": {"Size": "3", "Wrap": "No", "Default": "2", "rows": [
|
||||
["34","21"],
|
||||
["0","0"],
|
||||
["21","34"]
|
||||
]}
|
||||
}
|
||||
14
tests/unit/data/fiz/z1_v2/152a.json
Normal file
14
tests/unit/data/fiz/z1_v2/152a.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"_source": "pkp/z1_v2/152a.fiz",
|
||||
"_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads",
|
||||
"Param": {"Category": "train", "M": "48000", "Vmax": "200", "HeatingP": "54", "LightP": "0.56"},
|
||||
"Load": {"MaxLoad": "80", "LoadQ": "pieces", "LoadAccepted": "Passengers,Luggage", "OverLoadFactor": "1.5", "LoadSpeed": "1", "UnLoadSpeed": "2"},
|
||||
"Dimensions": {"L": "26.4", "H": "4", "W": "2.9", "Cx": "0.01"},
|
||||
"Wheels": {"D": "0.92", "Tw": "1.435", "Axle": "2'2'", "Ad": "2.70", "Bd": "19", "Rmin": "100", "BearingType": "Roll"},
|
||||
"Brake": {"BrakeValve": "KE", "MBF": "11", "MaxBP": "3.8", "BCN": "12", "BCR": "0.127", "BCD": "0.05", "BCM": "1.42", "NBpA": "6", "RM": "1.4", "BM": "Disk1+Mg", "BCS": "1.2", "BSA": "0", "BVV": "130", "TBF": "32"},
|
||||
"BuffCoupl": {"CType": "Screw", "kB": "9200", "DmaxB": "0.11", "FmaxB": "320", "kC": "4500", "DmaxC": "0.1", "FmaxC": "850", "beta": "0.58", "AllowedFlag": "115"},
|
||||
"Cntrl": {"BrakeSystem": "Pneumatic", "LocalBrake": "ManualBrake", "BrakeDelays": "PR+Mg", "ASB": "Yes", "rows": []},
|
||||
"Light": {"Light": "Generator", "LGeneratorEngine": "WheelsDriven", "LMaxVoltage": "24", "AlterLight": "Accu", "AlterLMaxVoltage": "24", "AlterLCap": "495", "AlterLRS": "Generator"},
|
||||
"Clima": {"Heating": "PowerCable", "HPowerTrans": "ElectricPower", "HMaxVoltage": "3000"},
|
||||
"Doors": {"OpenCtrl": "Passenger", "CloseCtrl": "AutomaticCtrl", "OpenSpeed": "0.5", "CloseSpeed": "0.20", "DoorMaxShiftL": "0.9", "DoorMaxShiftR": "0.9", "DoorOpenMethod": "Plug", "DoorClosureWarning": "yes", "DoorBlocked": "Yes", "DoorMaxShiftPlug": "0.043"}
|
||||
}
|
||||
4
tests/unit/data/golden/.gitignore
vendored
Normal file
4
tests/unit/data/golden/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# the golden traces are recorded on the code before a change, not kept: the samples and their key figures
|
||||
# (see tests/unit/README.md)
|
||||
*.csv
|
||||
*.figures
|
||||
246
tests/unit/drive.cpp
Normal file
246
tests/unit/drive.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "stdafx.h"
|
||||
#include "drive.h"
|
||||
#include "consist.h"
|
||||
#include "golden.h"
|
||||
#include "doctest.h"
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
void mark(trace *Trace, std::string const &Event) {
|
||||
if (Trace != nullptr) {
|
||||
Trace->mark(Event);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_powered(TMoverParameters const &Vehicle) {
|
||||
using enum TEngineType;
|
||||
auto const type{Vehicle.EngineType};
|
||||
return Vehicle.Power > 1.0 && (type == ElectricSeriesMotor || type == ElectricInductionMotor || type == DieselEngine || type == DieselElectric);
|
||||
}
|
||||
|
||||
driven driving(vehicle &Vehicle) {
|
||||
return {Vehicle.mover(), Vehicle.mover(), Vehicle.mover(), [&Vehicle](double Seconds, track const &Track) { Vehicle.run(Seconds, Track); }};
|
||||
}
|
||||
|
||||
driven driving(consist &Consist) {
|
||||
// the AI's mvControlling and mvPantographUnit: the first vehicle with an engine, and with pantographs
|
||||
auto *controlling{&Consist[0].mover()};
|
||||
auto *pantographs{&Consist[0].mover()};
|
||||
for (auto i = Consist.size(); i-- > 0;) {
|
||||
auto &mover{Consist[i].mover()};
|
||||
if (is_powered(mover)) {
|
||||
controlling = &mover;
|
||||
}
|
||||
if (mover.EnginePowerSource.SourceType == TPowerSource::CurrentCollector && mover.EnginePowerSource.CollectorParameters.CollectorsNo > 0) {
|
||||
pantographs = &mover;
|
||||
}
|
||||
}
|
||||
return {Consist[0].mover(), *controlling, *pantographs, [&Consist](double Seconds, track const &Track) { Consist.run(Seconds, Track); }};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void attend(TMoverParameters &Mover) {
|
||||
if (Mover.SecuritySystem.is_cabsignal_blinking() && Mover.SecuritySystem.has_separate_acknowledge()) {
|
||||
Mover.SecuritySystem.cabsignal_reset();
|
||||
}
|
||||
if (Mover.SecuritySystem.is_blinking()) {
|
||||
Mover.SecuritySystemReset();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void drive(driven Driven, track const &Track, double Seconds) {
|
||||
auto const seconds{std::lround(Seconds)};
|
||||
for (long second = 0; second < seconds; ++second) {
|
||||
attend(Driven.cab);
|
||||
Driven.run(1.0, Track);
|
||||
}
|
||||
}
|
||||
|
||||
void release_brakes(TMoverParameters &Cab) {
|
||||
Cab.BrakeLevelSet(Cab.Handle->GetPos(bh_RP));
|
||||
Cab.DecLocalBrakeLevel(LocalBrakePosNo);
|
||||
Cab.DecManualBrakeLevel(ManualBrakePosNo);
|
||||
Cab.SpringBrakeActivate(false);
|
||||
// the hand and spring brakes of the rest of the train, as TController::AutoRewident() releases them
|
||||
std::vector train{&Cab};
|
||||
std::vector pending{&Cab};
|
||||
while (false == pending.empty()) {
|
||||
auto const *vehicle{pending.back()};
|
||||
pending.pop_back();
|
||||
for (auto const &thiscoupler : vehicle->Couplers) {
|
||||
if (thiscoupler.Connected != nullptr && thiscoupler.CouplingFlag != coupling::faux && std::ranges::find(train, thiscoupler.Connected) == train.end()) {
|
||||
thiscoupler.Connected->DecManualBrakeLevel(ManualBrakePosNo);
|
||||
thiscoupler.Connected->SpringBrake.Activate = false;
|
||||
train.push_back(thiscoupler.Connected);
|
||||
pending.push_back(thiscoupler.Connected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_ready(driven const &Driven) {
|
||||
auto const &mover{Driven.controlling};
|
||||
auto const air{mover.VeselVolume <= 0.0 || mover.ScndPipePress >= 4.5};
|
||||
// the converter feeds the 110 V circuits (the electrodynamic brake's control among them); the AI switches
|
||||
// it on once the line breaker is closed, so a train already charged with air isn't ready before it runs
|
||||
auto const converter{mover.ConverterStart != start_t::manual || mover.ConverterFlag};
|
||||
return mover.Mains && air && converter;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// the pumps and the heater of a diesel's water, and the fuel pump
|
||||
void prepare_diesel(driven const &Driven) {
|
||||
Driven.cab.OilPumpSwitch(true);
|
||||
Driven.controlling.WaterPumpBreakerSwitch(true);
|
||||
Driven.controlling.WaterPumpSwitch(true);
|
||||
Driven.controlling.WaterHeaterBreakerSwitch(true);
|
||||
Driven.controlling.WaterHeaterSwitch(true);
|
||||
Driven.cab.FuelPumpSwitch(true);
|
||||
}
|
||||
|
||||
// the pantographs' own air topped up by their compressor, and the pantographs raised
|
||||
void raise_pantographs(driven const &Driven) {
|
||||
auto &pantographs{Driven.pantographs};
|
||||
if (auto const enough{(pantographs.TrainType == dt_EZT ? 2.5 : 3.5) + 0.1}; pantographs.PantPress < enough) {
|
||||
if (false == pantographs.PantAutoValve) {
|
||||
pantographs.bPantKurek3 = false; // the pantographs on their own air
|
||||
}
|
||||
pantographs.PantCompFlag = true;
|
||||
}
|
||||
else if (false == pantographs.bPantKurek3 || pantographs.PantPress <= pantographs.ScndPipePress) {
|
||||
pantographs.PantCompFlag = false;
|
||||
}
|
||||
Driven.cab.OperatePantographsValve(operation_t::enable);
|
||||
Driven.cab.OperatePantographValve(end::rear, operation_t::enable);
|
||||
}
|
||||
|
||||
// the line breaker closed, which it does only with the controller at zero, and after the relays are reset
|
||||
void close_line_breaker(driven const &Driven) {
|
||||
auto &controlling{Driven.controlling};
|
||||
while (controlling.DecMainCtrl(2)) {
|
||||
// down to zero
|
||||
}
|
||||
controlling.DecScndCtrl(2);
|
||||
Driven.cab.RelayReset(relay_t::maincircuitground | relay_t::tractionnmotoroverload | relay_t::primaryconverteroverload);
|
||||
if (controlling.EngineType == TEngineType::DieselEngine) {
|
||||
// a mechanical diesel starts at idle, the first position giving the engine fuel
|
||||
while (controlling.RList[controlling.MainCtrlPos].Mn == 0 && controlling.IncMainCtrl(1)) {
|
||||
// up to the first position with fuel
|
||||
}
|
||||
}
|
||||
Driven.cab.MainSwitch(true);
|
||||
}
|
||||
|
||||
// the converter, the compressor and the motor blowers, once the line breaker is closed
|
||||
void switch_auxiliaries_on(TMoverParameters &Cab) {
|
||||
Cab.ConverterSwitch(true);
|
||||
Cab.CompressorSwitch(true);
|
||||
for (auto const side : {end::front, end::rear}) {
|
||||
if (Cab.MotorBlowers[side].speed != 0) {
|
||||
Cab.MotorBlowersSwitchOff(false, side);
|
||||
Cab.MotorBlowersSwitch(true, side);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool start_up(driven Driven, track const &Track, double Seconds, trace *Trace) {
|
||||
auto &cab{Driven.cab};
|
||||
auto const &controlling{Driven.controlling};
|
||||
auto const &pantographs{Driven.pantographs};
|
||||
mark(Trace, "start up");
|
||||
auto const diesel{controlling.EngineType == TEngineType::DieselEngine || controlling.EngineType == TEngineType::DieselElectric};
|
||||
auto const collector{pantographs.EnginePowerSource.SourceType == TPowerSource::CurrentCollector &&
|
||||
pantographs.EnginePowerSource.CollectorParameters.CollectorsNo > 0};
|
||||
// the converter and the compressor get switched on once the line breaker is closed, wherever in the train
|
||||
// they are; a train already charged with air isn't ready before that
|
||||
auto auxiliaries{false};
|
||||
// one round of the driver's actions a second, as the AI reacts
|
||||
for (auto second = 0; second < Seconds; ++second) {
|
||||
cab.BatterySwitch(true);
|
||||
cab.CabActivisation();
|
||||
if (diesel) {
|
||||
prepare_diesel(Driven);
|
||||
}
|
||||
if (collector) {
|
||||
raise_pantographs(Driven);
|
||||
}
|
||||
if (false == collector || std::max(controlling.GetTrainsetHighVoltage(), controlling.PantographVoltage) > controlling.EnginePowerSource.CollectorParameters.MinV) {
|
||||
// a direction first, as in TController::PrepareDirection(): the relays reset only with one set
|
||||
for (int i = 0; i < 3 && cab.DirActive <= 0; ++i) {
|
||||
cab.DirectionForward();
|
||||
}
|
||||
if (false == controlling.Mains) {
|
||||
close_line_breaker(Driven);
|
||||
}
|
||||
else {
|
||||
switch_auxiliaries_on(cab);
|
||||
auxiliaries = true;
|
||||
}
|
||||
}
|
||||
drive(Driven, Track, 1.0);
|
||||
if (auxiliaries && is_ready(Driven)) {
|
||||
mark(Trace, "ready");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void drive_cycle(driven Driven, track const &Track, trace &Trace) {
|
||||
auto &cab{Driven.cab};
|
||||
auto &controlling{Driven.controlling};
|
||||
if (false == start_up(Driven, Track, 300.0, &Trace)) {
|
||||
MESSAGE("didn't get ready: Mains " << controlling.Mains << ", main reservoir " << controlling.ScndPipePress);
|
||||
}
|
||||
Trace.mark("release brakes");
|
||||
release_brakes(cab);
|
||||
drive(Driven, Track, 30.0);
|
||||
|
||||
Trace.mark("forward");
|
||||
for (int i = 0; i < 3 && cab.DirActive <= 0; ++i) {
|
||||
cab.DirectionForward();
|
||||
}
|
||||
drive(Driven, Track, 2.0);
|
||||
|
||||
Trace.mark("notch up");
|
||||
for (int i = 0; i < 60 && false == controlling.IsMainCtrlMaxPowerPos(); ++i) {
|
||||
controlling.IncMainCtrl(1);
|
||||
drive(Driven, Track, 2.0);
|
||||
}
|
||||
Trace.mark("full power");
|
||||
drive(Driven, Track, 30.0);
|
||||
|
||||
Trace.mark("second controller up");
|
||||
for (int i = 0; i < 20 && controlling.IncScndCtrl(1); ++i) {
|
||||
drive(Driven, Track, 2.0);
|
||||
}
|
||||
drive(Driven, Track, 20.0);
|
||||
Trace.mark("second controller down");
|
||||
for (int i = 0; i < 20 && controlling.DecScndCtrl(1); ++i) {
|
||||
drive(Driven, Track, 1.0);
|
||||
}
|
||||
|
||||
Trace.mark("notch down");
|
||||
for (int i = 0; i < 60 && controlling.DecMainCtrl(1); ++i) {
|
||||
drive(Driven, Track, 1.0);
|
||||
}
|
||||
Trace.mark("coast");
|
||||
drive(Driven, Track, 10.0);
|
||||
|
||||
Trace.mark("brake");
|
||||
cab.BrakeLevelSet(cab.Handle->GetPos(bh_FB));
|
||||
drive(Driven, Track, 60.0);
|
||||
Trace.mark("release");
|
||||
cab.BrakeLevelSet(cab.Handle->GetPos(bh_RP));
|
||||
drive(Driven, Track, 20.0);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
56
tests/unit/drive.h
Normal file
56
tests/unit/drive.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "vehicle.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
class trace;
|
||||
class consist;
|
||||
|
||||
// what a driver does with a vehicle, made of the steps the AI takes (TController and the driver hints of
|
||||
// application/driverhints.cpp), on the vehicle's own controls. the driver sits in a vehicle with a cab
|
||||
// (Cab != 0): a lone one, or the first one of a consist, and drives the whole of it
|
||||
|
||||
// what the driver drives: the vehicle with the driver in it, the vehicles the driver controls the engine and
|
||||
// the pantographs of (the AI's mvOccupied, mvControlling, mvPantographUnit; all the same one in a lone
|
||||
// vehicle or a locomotive), and the way to run the whole of it
|
||||
struct driven {
|
||||
TMoverParameters &cab;
|
||||
TMoverParameters &controlling;
|
||||
TMoverParameters &pantographs;
|
||||
std::function<void(double Seconds, track const &Track)> run;
|
||||
};
|
||||
driven driving(vehicle &Vehicle);
|
||||
driven driving(consist &Consist);
|
||||
|
||||
// gets the vehicle ready to run, the way TController::PrepareEngine() does: battery, cab, pumps and heating
|
||||
// of a diesel engine, pantographs, line breaker, converter, compressor and motor blowers, then waits for the
|
||||
// air. stops trying after Seconds; returns whether the vehicle got ready
|
||||
bool start_up(driven Driven, track const &Track, double Seconds = 300.0, trace *Trace = nullptr);
|
||||
|
||||
// runs the vehicle for Seconds with the driver paying attention, as TController::control_security_system()
|
||||
// does: once a second the vigilance and the cab signalling get acknowledged when they call for it
|
||||
void drive(driven Driven, track const &Track, double Seconds);
|
||||
|
||||
// releases every brake the driver has a hand on: the train brake to running, the independent brake, the
|
||||
// hand brake and the spring brake; and the hand and spring brakes of the vehicles coupled to the cab's
|
||||
void release_brakes(TMoverParameters &Cab);
|
||||
|
||||
// whether the vehicle is ready to run: line breaker closed (or the engine running), air in the main reservoir
|
||||
bool is_ready(driven const &Driven);
|
||||
|
||||
// whether the vehicle drives itself
|
||||
bool is_powered(TMoverParameters const &Vehicle);
|
||||
|
||||
// a trace mark, when there's a trace
|
||||
void mark(trace *Trace, std::string const &Event);
|
||||
|
||||
// a whole run: start up, release the brakes, notch up to full power, the second controller (field weakening,
|
||||
// shunting) up and down, notch down, coast and brake to a stop. the controllers move on a fixed schedule,
|
||||
// not the way a driver watching the ammeter would, so the relays may trip on the way
|
||||
void drive_cycle(driven Driven, track const &Track, trace &Trace);
|
||||
|
||||
} // namespace test
|
||||
222
tests/unit/figures.cpp
Normal file
222
tests/unit/figures.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include "stdafx.h"
|
||||
#include "figures.h"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
// the units of the figures, with the decimals they're written with
|
||||
struct unit {
|
||||
char const *name;
|
||||
int decimals;
|
||||
};
|
||||
unit const seconds{"s", 2};
|
||||
unit const kmh{"km/h", 1};
|
||||
unit const metres{"m", 1};
|
||||
unit const bar{"bar", 3};
|
||||
unit const amperes{"A", 0};
|
||||
unit const kilonewtons{"kN", 1};
|
||||
std::array const units{seconds, kmh, metres, bar, amperes, kilonewtons};
|
||||
|
||||
std::string line(char const *Name, double Value, unit const &Unit) {
|
||||
return std::format("{} = {:.{}f} {}", Name, Value, Unit.decimals, Unit.name);
|
||||
}
|
||||
|
||||
// the name, the value and the unit of a line of a figure, or false for the header of a part
|
||||
bool parse(std::string_view const Line, std::string &Name, double &Value, std::string &Unit) {
|
||||
auto const equals{Line.find(" = ")};
|
||||
if (equals == std::string_view::npos) {
|
||||
return false;
|
||||
}
|
||||
Name = Line.substr(0, equals);
|
||||
std::string const value{Line.substr(equals + 3)};
|
||||
auto const space{value.find(' ')};
|
||||
Value = std::strtod(value.substr(0, space).c_str(), nullptr);
|
||||
Unit = space == std::string::npos ? std::string{} : value.substr(space + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// a difference of 0.5%, or of the last decimal written
|
||||
bool close(double Recorded, double Now, std::string_view const Unit) {
|
||||
auto step{0.0};
|
||||
for (auto const &unit : units) {
|
||||
if (Unit == unit.name) {
|
||||
step = std::pow(10.0, -unit.decimals);
|
||||
}
|
||||
}
|
||||
return std::abs(Recorded - Now) <= 0.005 * std::max(std::abs(Recorded), std::abs(Now)) + step + 1e-9;
|
||||
}
|
||||
|
||||
// the drop of the brake pipe which the time to get back counts from, and the pressure it counts to
|
||||
constexpr double pipe_drop{4.8};
|
||||
constexpr double pipe_back{4.9};
|
||||
|
||||
} // namespace
|
||||
|
||||
void figures::sample(double Time, TMoverParameters const &Vehicle) {
|
||||
auto &part{m_parts.back()};
|
||||
auto const speed{Vehicle.V * 3.6};
|
||||
auto const pipe{Vehicle.PipePress};
|
||||
if (false == part.sampled) {
|
||||
part.sampled = true;
|
||||
// from the last step of the part before, so the parts add up to the run
|
||||
part.start = m_last_time < 0.0 ? Time : m_last_time;
|
||||
part.speed_start = m_last_time < 0.0 ? speed : m_last_speed;
|
||||
part.distance_start = m_last_time < 0.0 ? Vehicle.DistCounter : m_last_distance;
|
||||
part.pipe_lowest = pipe;
|
||||
}
|
||||
part.end = Time;
|
||||
part.speed_end = speed;
|
||||
part.speed_peak = std::max(part.speed_peak, std::abs(speed));
|
||||
part.distance_end = Vehicle.DistCounter;
|
||||
if (part.stopped < 0.0 && std::abs(part.speed_start) > 1.0 && std::abs(speed) < 0.05) {
|
||||
part.stopped = Time - part.start;
|
||||
}
|
||||
if (pipe < part.pipe_lowest) {
|
||||
part.pipe_lowest = pipe;
|
||||
part.pipe_back = -1.0;
|
||||
}
|
||||
part.pipe_end = pipe;
|
||||
if (part.pipe_back < 0.0 && part.pipe_lowest < pipe_drop && pipe >= pipe_back) {
|
||||
part.pipe_back = Time - part.start;
|
||||
}
|
||||
part.cylinders_peak = std::max(part.cylinders_peak, Vehicle.BrakePress);
|
||||
part.current_peak = std::max(part.current_peak, std::abs(Vehicle.Im));
|
||||
part.force_peak = std::max(part.force_peak, std::abs(Vehicle.Ft) / 1000.0);
|
||||
|
||||
m_last_time = Time;
|
||||
m_last_speed = speed;
|
||||
m_last_distance = Vehicle.DistCounter;
|
||||
// which figures the vehicle has, over the whole run, so each part has the same ones
|
||||
m_moved |= std::abs(speed) >= 0.05;
|
||||
m_piped |= pipe >= 0.1;
|
||||
m_braked |= Vehicle.BrakePress >= 0.005;
|
||||
m_current |= std::abs(Vehicle.Im) >= 0.5;
|
||||
m_force |= std::abs(Vehicle.Ft) >= 50.0;
|
||||
}
|
||||
|
||||
void figures::mark(std::string const &Event) {
|
||||
if (auto &part{m_parts.back()}; false == part.sampled) {
|
||||
// nothing ran since the last event: a part of both
|
||||
part.event = part.event == "start" ? Event : part.event + ", " + Event;
|
||||
return;
|
||||
}
|
||||
m_parts.emplace_back(Event);
|
||||
}
|
||||
|
||||
std::vector<std::string> figures::lines() const {
|
||||
std::vector<std::string> result;
|
||||
for (auto const &part : m_parts) {
|
||||
if (false == part.sampled) {
|
||||
continue;
|
||||
}
|
||||
result.push_back("[" + part.event + "]");
|
||||
result.push_back(line("duration", part.end - part.start, seconds));
|
||||
if (m_moved) {
|
||||
result.push_back(line("speed at the start", part.speed_start, kmh));
|
||||
result.push_back(line("speed at the end", part.speed_end, kmh));
|
||||
result.push_back(line("speed peak", part.speed_peak, kmh));
|
||||
result.push_back(line("distance", (part.distance_end - part.distance_start) * 1000.0, metres));
|
||||
if (part.stopped >= 0.0) {
|
||||
result.push_back(line("stopped after", part.stopped, seconds));
|
||||
}
|
||||
}
|
||||
if (m_piped) {
|
||||
result.push_back(line("brake pipe lowest", part.pipe_lowest, bar));
|
||||
result.push_back(line("brake pipe at the end", part.pipe_end, bar));
|
||||
if (part.pipe_back >= 0.0) {
|
||||
result.push_back(line("brake pipe back at 4.9 bar after", part.pipe_back, seconds));
|
||||
}
|
||||
}
|
||||
if (m_braked) {
|
||||
result.push_back(line("brake cylinders peak", part.cylinders_peak, bar));
|
||||
}
|
||||
if (m_current) {
|
||||
result.push_back(line("motor current peak", part.current_peak, amperes));
|
||||
}
|
||||
if (m_force) {
|
||||
result.push_back(line("tractive force peak", part.force_peak, kilonewtons));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct figure {
|
||||
std::string name;
|
||||
double value;
|
||||
std::string unit;
|
||||
std::string text; // the value and the unit as written
|
||||
};
|
||||
|
||||
struct recorded_part {
|
||||
std::string header;
|
||||
std::vector<figure> figures;
|
||||
};
|
||||
|
||||
std::vector<recorded_part> parts_of(std::vector<std::string> const &Lines) {
|
||||
std::vector<recorded_part> parts;
|
||||
for (auto const &line : Lines) {
|
||||
figure figure;
|
||||
if (false == parse(line, figure.name, figure.value, figure.unit)) {
|
||||
parts.emplace_back(line);
|
||||
continue;
|
||||
}
|
||||
if (parts.empty()) {
|
||||
parts.emplace_back();
|
||||
}
|
||||
figure.text = line.substr(line.find(" = ") + 3);
|
||||
parts.back().figures.push_back(figure);
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
figure const *find(std::vector<figure> const &Figures, std::string_view const Name) {
|
||||
for (auto const &figure : Figures) {
|
||||
if (figure.name == Name) {
|
||||
return &figure;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<std::string> figures::compare(std::vector<std::string> const &Recorded, std::vector<std::string> const &Now) {
|
||||
std::vector<std::string> differences;
|
||||
auto const recorded{parts_of(Recorded)};
|
||||
auto const now{parts_of(Now)};
|
||||
for (std::size_t i = 0; i < std::max(recorded.size(), now.size()); ++i) {
|
||||
if (i >= recorded.size() || i >= now.size() || recorded[i].header != now[i].header) {
|
||||
// the parts can't be paired up from here on
|
||||
differences.push_back(std::format("the parts differ from part {}: {} now, {} recorded", i + 1, i < now.size() ? now[i].header : std::string{"none"},
|
||||
i < recorded.size() ? recorded[i].header : std::string{"none"}));
|
||||
break;
|
||||
}
|
||||
auto const &header{now[i].header};
|
||||
for (auto const &figure : recorded[i].figures) {
|
||||
auto const *current{find(now[i].figures, figure.name)};
|
||||
if (current == nullptr) {
|
||||
differences.push_back(header + " " + figure.name + ": none now, " + figure.text + " recorded");
|
||||
}
|
||||
else if (current->unit != figure.unit || false == close(figure.value, current->value, figure.unit)) {
|
||||
differences.push_back(header + " " + figure.name + ": " + current->text + " now, " + figure.text + " recorded");
|
||||
}
|
||||
}
|
||||
for (auto const &figure : now[i].figures) {
|
||||
if (find(recorded[i].figures, figure.name) == nullptr) {
|
||||
differences.push_back(header + " " + figure.name + ": " + figure.text + " now, none recorded");
|
||||
}
|
||||
}
|
||||
}
|
||||
return differences;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
70
tests/unit/figures.h
Normal file
70
tests/unit/figures.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "McZapkie/MOVER.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
// the key figures of a vehicle's run, for each part of it between two events of the test: the speeds, the
|
||||
// distance, the time to stop, the brake pipe's lowest pressure and the time it took to get back, the brake
|
||||
// cylinders', the motor current's and the tractive force's peaks. a golden trace keeps them next to its
|
||||
// samples, in data/golden/<Name>.figures, which a person reads:
|
||||
//
|
||||
// [emergency]
|
||||
// duration = 40.00 s
|
||||
// speed at the start = 80.0 km/h
|
||||
// speed at the end = 0.0 km/h
|
||||
// distance = 412.3 m
|
||||
// stopped after = 38.21 s
|
||||
// brake cylinders peak = 3.800 bar
|
||||
//
|
||||
// a figure the vehicle doesn't have (no speed, no current) is left out of all the parts. they're compared
|
||||
// within 0.5%, loose enough for any compiler, so a change which alters the behaviour on purpose shows in their
|
||||
// diff in a few readable lines, where the samples change in thousands
|
||||
class figures {
|
||||
public:
|
||||
// called on every step of the vehicle
|
||||
void sample(double Time, TMoverParameters const &Vehicle);
|
||||
// a part of the run starts with the event
|
||||
void mark(std::string const &Event);
|
||||
|
||||
// the figures as the lines of the file
|
||||
std::vector<std::string> lines() const;
|
||||
// the differences of the lines from the recorded ones, beyond the tolerance, each told in a line
|
||||
static std::vector<std::string> compare(std::vector<std::string> const &Recorded, std::vector<std::string> const &Now);
|
||||
|
||||
private:
|
||||
struct part {
|
||||
std::string event;
|
||||
bool sampled{false};
|
||||
double start{0.0};
|
||||
double end{0.0};
|
||||
double speed_start{0.0};
|
||||
double speed_end{0.0};
|
||||
double speed_peak{0.0};
|
||||
double distance_start{0.0};
|
||||
double distance_end{0.0};
|
||||
double stopped{-1.0}; // after the start, if it started moving and stopped
|
||||
double pipe_lowest{0.0};
|
||||
double pipe_end{0.0};
|
||||
double pipe_back{-1.0}; // after the start, at 4.9 bar again after a drop under 4.8
|
||||
double cylinders_peak{0.0};
|
||||
double current_peak{0.0};
|
||||
double force_peak{0.0};
|
||||
};
|
||||
|
||||
std::vector<part> m_parts{part{"start"}};
|
||||
double m_last_time{-1.0};
|
||||
double m_last_speed{0.0};
|
||||
double m_last_distance{0.0};
|
||||
// the figures the vehicle has, shown in every part
|
||||
bool m_moved{false};
|
||||
bool m_piped{false};
|
||||
bool m_braked{false};
|
||||
bool m_current{false};
|
||||
bool m_force{false};
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
222
tests/unit/fiz.cpp
Normal file
222
tests/unit/fiz.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
#include "stdafx.h"
|
||||
#include "fiz.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <format>
|
||||
|
||||
#include "utilities/parser.h"
|
||||
|
||||
namespace test::fiz {
|
||||
|
||||
namespace {
|
||||
|
||||
// the lists of LoadFIZ_Parse(), as bits of the set of the ones reading a row
|
||||
constexpr unsigned brake_table{1 << 0}; // startBPT
|
||||
constexpr unsigned motor_table{1 << 1}; // startMPT
|
||||
constexpr unsigned motor_table0{1 << 2}; // startMPT0
|
||||
constexpr unsigned resistors{1 << 3}; // startRLIST
|
||||
constexpr unsigned universal{1 << 4}; // startUCLIST
|
||||
constexpr unsigned diesel{1 << 5}; // startDLIST
|
||||
constexpr unsigned diesel_momentum{1 << 6}; // startDIZELMOMENTUMLIST
|
||||
constexpr unsigned diesel_v2n{1 << 7}; // startDIZELV2NMAXLIST
|
||||
constexpr unsigned hydro{1 << 8}; // startHYDROTCLIST
|
||||
constexpr unsigned diesel_pmax{1 << 9}; // startPMAXLIST
|
||||
constexpr unsigned field{1 << 10}; // startFFLIST
|
||||
constexpr unsigned field_brake{1 << 11}; // startFFEDLIST
|
||||
constexpr unsigned generator{1 << 12}; // startWWLIST
|
||||
constexpr unsigned wipers{1 << 13}; // startWiperList
|
||||
constexpr unsigned dimmer{1 << 14}; // startDimmerList
|
||||
constexpr unsigned lights{1 << 15}; // startLIGHTSLIST
|
||||
constexpr unsigned compressors{1 << 16}; // startCOMPRESSORLIST
|
||||
|
||||
// the issection() calls of LoadFIZ_Parse()
|
||||
std::array const sections{
|
||||
section{"Param", '.'},
|
||||
section{"Load", ':'},
|
||||
section{"Dimensions", ':'},
|
||||
section{"Wheels", ':'},
|
||||
section{"Brake", ':'},
|
||||
section{"Doors", ':'},
|
||||
section{"BuffCoupl", '.'},
|
||||
section{"BuffCoupl1", '.'},
|
||||
section{"BuffCoupl2", '.'},
|
||||
section{"TurboPos", ':'},
|
||||
section{"Cntrl", '.', brake_table, ""},
|
||||
section{"Headlights", ':'},
|
||||
section{"Blending", ':'},
|
||||
section{"DCEMUED", ':'},
|
||||
section{"SpringBrake", ':'},
|
||||
section{"Light", ':'},
|
||||
section{"Security", ':'},
|
||||
section{"Clima", ':'},
|
||||
section{"Power", ':'},
|
||||
section{"SpeedControl", ':'},
|
||||
section{"Engine", ':'},
|
||||
section{"Switches", ':'},
|
||||
section{"MotorParamTable", ':', motor_table, "END-MPT"},
|
||||
section{"MotorParamTable0", ':', motor_table0, "END-MPT"},
|
||||
section{"Circuit", ':'},
|
||||
section{"AI", ':'},
|
||||
section{"RList", ':', resistors, "END-RL"},
|
||||
section{"UCList", ':', universal, "END-UCL"},
|
||||
section{"DList", ':', diesel, "END-DL"},
|
||||
section{"DMList", ':', diesel_momentum, "END-DML"},
|
||||
section{"HTCList", ':', hydro, "END-HTCL"},
|
||||
section{"PmaxList", ':', diesel_pmax, "END-PML"},
|
||||
section{"V2NList", ':', diesel_v2n, "END-V2NL"},
|
||||
section{"ffList", ':', field, "endff"},
|
||||
section{"ffBrakeList", ':', field_brake, "endff"},
|
||||
section{"WWList", ':', generator, "END-WWL"},
|
||||
section{"WiperList", ':', wipers, "endwl"},
|
||||
section{"DimmerList", ':', dimmer, "endDimmerList"},
|
||||
section{"LightsList", ':', lights, "endL"},
|
||||
section{"CompressorList", ':', compressors, "endCL"},
|
||||
};
|
||||
|
||||
// the lines closing lists, checked by the loader before the sections in this order, each closing the brake table too
|
||||
struct closing {
|
||||
std::string_view line;
|
||||
unsigned lists;
|
||||
};
|
||||
std::array const closings{
|
||||
closing{"END-MPT", motor_table | motor_table0},
|
||||
closing{"END-RL", resistors},
|
||||
closing{"END-UCL", universal},
|
||||
closing{"END-DL", diesel},
|
||||
closing{"END-DML", diesel_momentum},
|
||||
closing{"END-V2NL", diesel_v2n},
|
||||
closing{"END-HTCL", hydro},
|
||||
closing{"END-PML", diesel_pmax},
|
||||
closing{"endff", field | field_brake},
|
||||
closing{"endwl", wipers},
|
||||
closing{"endDimmerList", dimmer},
|
||||
closing{"END-WWL", generator},
|
||||
closing{"endL", lights},
|
||||
closing{"endCL", compressors},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string value(std::string const &Key, std::string const &Line) {
|
||||
std::string const input{" " + Line};
|
||||
auto const lookup{input.find(" " + Key + "=")};
|
||||
if (lookup == std::string::npos) {
|
||||
return {};
|
||||
}
|
||||
auto const start{input.find_first_not_of(' ', lookup + Key.size() + 2)};
|
||||
if (start == std::string::npos) {
|
||||
return {};
|
||||
}
|
||||
auto const end{input.find(' ', start)};
|
||||
return input.substr(start, end == std::string::npos ? std::string::npos : end - start);
|
||||
}
|
||||
|
||||
std::vector<std::string> words(std::string_view const Line) {
|
||||
std::vector<std::string> result;
|
||||
std::size_t start{0};
|
||||
while ((start = Line.find_first_not_of(" \t;", start)) != std::string_view::npos) {
|
||||
auto const end{Line.find_first_of(" \t;", start)};
|
||||
result.emplace_back(Line.substr(start, end == std::string_view::npos ? std::string_view::npos : end - start));
|
||||
start = end;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
section const *named(std::string_view Name) {
|
||||
auto const lookup{std::ranges::find(sections, Name, §ion::name)};
|
||||
return lookup == sections.end() ? nullptr : std::to_address(lookup);
|
||||
}
|
||||
|
||||
section const *opened_by(std::string_view Line) {
|
||||
auto const lookup{std::ranges::find_if(sections, [&](section const &Section) { return Line.starts_with(Section.name) && Line.size() > Section.name.size() && Line[Section.name.size()] == Section.separator; })};
|
||||
return lookup == sections.end() ? nullptr : std::to_address(lookup);
|
||||
}
|
||||
|
||||
std::vector<std::string> lines(cParser &Parser) {
|
||||
std::vector<std::string> result;
|
||||
while (Parser.ok()) {
|
||||
auto line{Parser.getToken<std::string>(false, "\n\r")};
|
||||
if (line.starts_with("//") || line.find('#') != std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
line.erase(0, line.find_first_not_of(' '));
|
||||
if (false == line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
result.push_back(line);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> keys(std::string const &Line) {
|
||||
std::vector<std::string> result;
|
||||
std::string const input{" " + Line};
|
||||
for (auto equals{input.find('=')}; equals != std::string::npos; equals = input.find('=', equals + 1)) {
|
||||
auto const start{input.rfind(' ', equals) + 1};
|
||||
auto key{input.substr(start, equals - start)};
|
||||
// a=b=c gives a, not a=b
|
||||
if (false == key.empty() && key.find('=') == std::string::npos && std::ranges::find(result, key) == result.end()) {
|
||||
result.push_back(std::move(key));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// the values the section gives, as the loader asks for them by their keys
|
||||
std::string section_values(section const &Section, std::string const &Line) {
|
||||
auto keys{fiz::keys(Line)};
|
||||
std::ranges::sort(keys);
|
||||
std::string values{Section.name};
|
||||
for (auto const &key : keys) {
|
||||
if (auto const value{fiz::value(key, Line)}; false == value.empty()) {
|
||||
values += " " + key + "=" + value;
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// the lists reading a row: the first one open, in the order of the loader's checks, which carries on past the dimmer list
|
||||
unsigned row_readers(unsigned const Active) {
|
||||
unsigned readers{0};
|
||||
for (unsigned list = brake_table; list <= compressors; list <<= 1) {
|
||||
if ((Active & list) == 0) {
|
||||
continue;
|
||||
}
|
||||
readers |= list;
|
||||
if (list != dimmer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return readers;
|
||||
}
|
||||
|
||||
std::vector<std::string> reading(std::vector<std::string> const &Lines) {
|
||||
std::vector<std::string> result;
|
||||
unsigned active{0};
|
||||
for (auto const &line : Lines) {
|
||||
if (line.empty()) {
|
||||
active &= ~brake_table;
|
||||
continue;
|
||||
}
|
||||
if (auto const close{std::ranges::find_if(closings, [&](closing const &Closing) { return line.starts_with(Closing.line); })}; close != closings.end()) {
|
||||
active &= ~(close->lists | brake_table);
|
||||
continue;
|
||||
}
|
||||
if (auto const opened{opened_by(line)}; opened != nullptr) {
|
||||
active = (active & ~brake_table) | opened->list;
|
||||
result.push_back(section_values(*opened, line));
|
||||
continue;
|
||||
}
|
||||
if (auto const readers{row_readers(active)}; readers != 0) {
|
||||
std::string row{std::format("row of {:x}:", readers)};
|
||||
for (auto const &word : words(line)) {
|
||||
row += " " + word;
|
||||
}
|
||||
result.push_back(std::move(row));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace test::fiz
|
||||
44
tests/unit/fiz.h
Normal file
44
tests/unit/fiz.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class cParser;
|
||||
|
||||
// what the game's vehicle loader (TMoverParameters::LoadFIZ_Parse) makes of the lines of a vehicle definition,
|
||||
// for the test definitions to give it the same and for checking they do
|
||||
namespace test::fiz {
|
||||
|
||||
// a section of the definition, opened by a line starting with its name and separator. a list section is
|
||||
// followed by rows, read until the line closing them (an empty line for the Cntrl brake table) and as
|
||||
// long as no other list closes first, see reading()
|
||||
struct section {
|
||||
std::string_view name;
|
||||
char separator;
|
||||
unsigned list{0}; // the bit of the list its rows go to, none for a section of values only
|
||||
char const *end{nullptr}; // the line closing the rows
|
||||
};
|
||||
|
||||
// the section of the given name, or none for a name the loader doesn't know
|
||||
section const *named(std::string_view Name);
|
||||
// the section the line opens, or none
|
||||
section const *opened_by(std::string_view Line);
|
||||
|
||||
// the lines of a definition as the loader takes them: without comments, leading spaces and line ends
|
||||
std::vector<std::string> lines(cParser &Parser);
|
||||
|
||||
// the keys of the values in the line, in the order of their first appearance: the words followed by =,
|
||||
// which extract_value() finds
|
||||
std::vector<std::string> keys(std::string const &Line);
|
||||
|
||||
// the value of the key in the line, as extract_value() gives it, empty for none (where it would throw too)
|
||||
std::string value(std::string const &Key, std::string const &Line);
|
||||
// the words of a row, as the readers of the lists get them from cParser
|
||||
std::vector<std::string> words(std::string_view Line);
|
||||
|
||||
// what the loader reads from the lines, in order: every section line with the values it gives, every row
|
||||
// with the lists reading it. two definitions reading the same load the same vehicle
|
||||
std::vector<std::string> reading(std::vector<std::string> const &Lines);
|
||||
|
||||
} // namespace test::fiz
|
||||
393
tests/unit/golden.cpp
Normal file
393
tests/unit/golden.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
#include "stdafx.h"
|
||||
#include "golden.h"
|
||||
#include "doctest.h"
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
namespace channels {
|
||||
|
||||
std::vector<channel> motion() {
|
||||
return {
|
||||
{"V", [](auto const &M) { return M.V; }},
|
||||
{"DistCounter", [](auto const &M) { return M.DistCounter; }},
|
||||
{"AccS", [](auto const &M) { return M.AccS; }},
|
||||
{"nrot", [](auto const &M) { return M.nrot; }},
|
||||
{"Ft", [](auto const &M) { return M.Ft; }},
|
||||
{"Fb", [](auto const &M) { return M.Fb; }},
|
||||
{"FStand", [](auto const &M) { return M.FStand; }},
|
||||
{"SlippingWheels", [](auto const &M) { return M.SlippingWheels ? 1.0 : 0.0; }},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<channel> traction() {
|
||||
return {
|
||||
{"Mains", [](auto const &M) { return M.Mains ? 1.0 : 0.0; }},
|
||||
{"DirActive", [](auto const &M) { return M.DirActive; }},
|
||||
{"MainCtrlPos", [](auto const &M) { return M.MainCtrlPos; }},
|
||||
{"MainCtrlActualPos", [](auto const &M) { return M.MainCtrlActualPos; }},
|
||||
{"ScndCtrlPos", [](auto const &M) { return M.ScndCtrlPos; }},
|
||||
{"ScndCtrlActualPos", [](auto const &M) { return M.ScndCtrlActualPos; }},
|
||||
{"Im", [](auto const &M) { return M.Im; }},
|
||||
{"Itot", [](auto const &M) { return M.Itot; }},
|
||||
{"EngineVoltage", [](auto const &M) { return M.EngineVoltage; }},
|
||||
{"EnginePower", [](auto const &M) { return M.EnginePower; }},
|
||||
{"enrot", [](auto const &M) { return M.enrot; }},
|
||||
{"dizel_fill", [](auto const &M) { return M.dizel_fill; }},
|
||||
{"eimv_pr", [](auto const &M) { return M.eimv_pr; }},
|
||||
{"DynamicBrakeFlag", [](auto const &M) { return M.DynamicBrakeFlag ? 1.0 : 0.0; }},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<channel> brakes() {
|
||||
return {
|
||||
{"BrakeCtrlPos", [](auto const &M) { return M.BrakeCtrlPos; }},
|
||||
{"PipePress", [](auto const &M) { return M.PipePress; }},
|
||||
{"BrakePress", [](auto const &M) { return M.BrakePress; }},
|
||||
{"LocBrakePress", [](auto const &M) { return M.LocBrakePress; }},
|
||||
{"BRP", [](auto const &M) { return M.Hamulec->GetBRP(); }},
|
||||
{"VRP", [](auto const &M) { return M.Hamulec->GetVRP(); }},
|
||||
{"CRP", [](auto const &M) { return M.Hamulec->GetCRP(); }},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<channel> air() {
|
||||
return {
|
||||
{"Compressor", [](auto const &M) { return M.Compressor; }},
|
||||
{"CompressorFlag", [](auto const &M) { return M.CompressorFlag ? 1.0 : 0.0; }},
|
||||
{"ScndPipePress", [](auto const &M) { return M.ScndPipePress; }},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<channel> handles() {
|
||||
std::vector<channel> result{
|
||||
{"BrakeCtrlPosR", [](auto const &M) { return M.BrakeCtrlPosR; }},
|
||||
{"dpMainValve", [](auto const &M) { return M.dpMainValve; }},
|
||||
{"HandleCP", [](auto const &M) { return M.Handle->GetCP(); }},
|
||||
{"HandleRP", [](auto const &M) { return M.Handle->GetRP(); }},
|
||||
{"HandleEP", [](auto const &M) { return M.Handle->GetEP(); }},
|
||||
{"LocalBrakePosA", [](auto const &M) { return M.LocalBrakePosA; }},
|
||||
{"dpLocalValve", [](auto const &M) { return M.dpLocalValve; }},
|
||||
};
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
result.emplace_back(std::format("HandleSound{}", i), [i](auto const &M) { return M.Handle->GetSound(i); });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<channel> doors() {
|
||||
std::vector<channel> result{
|
||||
{"DoorsLocked", [](auto const &M) { return M.Doors.is_locked ? 1.0 : 0.0; }},
|
||||
};
|
||||
for (int side : {side::right, side::left}) {
|
||||
auto const name{std::string{side == side::right ? "Right" : "Left"}};
|
||||
result.emplace_back(name + "Position", [side](auto const &M) { return M.Doors.instances[side].position; });
|
||||
result.emplace_back(name + "Step", [side](auto const &M) { return M.Doors.instances[side].step_position; });
|
||||
result.emplace_back(name + "Open", [side](auto const &M) { return M.Doors.instances[side].is_open ? 1.0 : 0.0; });
|
||||
result.emplace_back(name + "Closed", [side](auto const &M) { return M.Doors.instances[side].is_closed ? 1.0 : 0.0; });
|
||||
result.emplace_back(name + "Permit", [side](auto const &M) { return M.Doors.instances[side].open_permit ? 1.0 : 0.0; });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<channel> parameters() {
|
||||
std::vector<channel> result{
|
||||
{"CategoryFlag", [](auto const &M) { return M.CategoryFlag; }},
|
||||
{"TrainType", [](auto const &M) { return M.TrainType; }},
|
||||
{"EngineType", [](auto const &M) { return static_cast<int>(M.EngineType); }},
|
||||
{"Vmax", [](auto const &M) { return M.Vmax; }},
|
||||
{"Mass", [](auto const &M) { return M.Mass; }},
|
||||
{"TotalMass", [](auto const &M) { return M.TotalMass; }},
|
||||
{"Mred", [](auto const &M) { return M.Mred; }},
|
||||
{"Power", [](auto const &M) { return M.Power; }},
|
||||
{"HeatingPower", [](auto const &M) { return M.HeatingPower; }},
|
||||
{"LightPower", [](auto const &M) { return M.LightPower; }},
|
||||
{"BatteryVoltage", [](auto const &M) { return M.BatteryVoltage; }},
|
||||
{"Cx", [](auto const &M) { return M.Cx; }},
|
||||
{"WheelDiameter", [](auto const &M) { return M.WheelDiameter; }},
|
||||
{"TrackW", [](auto const &M) { return M.TrackW; }},
|
||||
{"AxleInertialMoment", [](auto const &M) { return M.AxleInertialMoment; }},
|
||||
{"NPoweredAxles", [](auto const &M) { return M.NPoweredAxles; }},
|
||||
{"NAxles", [](auto const &M) { return M.NAxles; }},
|
||||
{"BearingType", [](auto const &M) { return M.BearingType; }},
|
||||
{"ADist", [](auto const &M) { return M.ADist; }},
|
||||
{"BDist", [](auto const &M) { return M.BDist; }},
|
||||
{"NBpA", [](auto const &M) { return M.NBpA; }},
|
||||
{"SandCapacity", [](auto const &M) { return M.SandCapacity; }},
|
||||
{"BrakeSystem", [](auto const &M) { return static_cast<int>(M.BrakeSystem); }},
|
||||
{"BrakeValve", [](auto const &M) { return static_cast<int>(M.BrakeValve); }},
|
||||
{"BrakeHandle", [](auto const &M) { return static_cast<int>(M.BrakeHandle); }},
|
||||
{"BrakeLocHandle", [](auto const &M) { return static_cast<int>(M.BrakeLocHandle); }},
|
||||
{"LocalBrake", [](auto const &M) { return static_cast<int>(M.LocalBrake); }},
|
||||
{"ASBType", [](auto const &M) { return M.ASBType; }},
|
||||
{"MaxBrakeForce", [](auto const &M) { return M.MaxBrakeForce; }},
|
||||
{"P2FTrans", [](auto const &M) { return M.P2FTrans; }},
|
||||
{"BrakeMethod", [](auto const &M) { return M.BrakeMethod; }},
|
||||
{"HighPipePress", [](auto const &M) { return M.HighPipePress; }},
|
||||
{"LowPipePress", [](auto const &M) { return M.LowPipePress; }},
|
||||
{"DeltaPipePress", [](auto const &M) { return M.DeltaPipePress; }},
|
||||
{"CntrlPipePress", [](auto const &M) { return M.CntrlPipePress; }},
|
||||
{"BrakeVolume", [](auto const &M) { return M.BrakeVolume; }},
|
||||
{"BrakeVVolume", [](auto const &M) { return M.BrakeVVolume; }},
|
||||
{"VeselVolume", [](auto const &M) { return M.VeselVolume; }},
|
||||
{"BrakeCylNo", [](auto const &M) { return M.BrakeCylNo; }},
|
||||
{"BrakeCylRadius", [](auto const &M) { return M.BrakeCylRadius; }},
|
||||
{"BrakeCylDist", [](auto const &M) { return M.BrakeCylDist; }},
|
||||
{"BrakeCylSpring", [](auto const &M) { return M.BrakeCylSpring; }},
|
||||
{"BrakeSlckAdj", [](auto const &M) { return M.BrakeSlckAdj; }},
|
||||
{"BrakeRigEff", [](auto const &M) { return M.BrakeRigEff; }},
|
||||
{"RapidMult", [](auto const &M) { return M.RapidMult; }},
|
||||
{"RapidVel", [](auto const &M) { return M.RapidVel; }},
|
||||
{"BrakeValveSize", [](auto const &M) { return M.BrakeValveSize; }},
|
||||
{"MinCompressor", [](auto const &M) { return M.MinCompressor; }},
|
||||
{"MaxCompressor", [](auto const &M) { return M.MaxCompressor; }},
|
||||
{"CompressorSpeed", [](auto const &M) { return M.CompressorSpeed; }},
|
||||
{"EmergencyValveOn", [](auto const &M) { return M.EmergencyValveOn; }},
|
||||
{"AirLeakRate", [](auto const &M) { return M.AirLeakRate; }},
|
||||
{"BrakeCtrlPosNo", [](auto const &M) { return M.BrakeCtrlPosNo; }},
|
||||
{"MainCtrlPosNo", [](auto const &M) { return M.MainCtrlPosNo; }},
|
||||
{"ScndCtrlPosNo", [](auto const &M) { return M.ScndCtrlPosNo; }},
|
||||
{"LightsPosNo", [](auto const &M) { return M.LightsPosNo; }},
|
||||
{"MBrake", [](auto const &M) { return M.MBrake ? 1.0 : 0.0; }},
|
||||
{"StopBrakeDecc", [](auto const &M) { return M.StopBrakeDecc; }},
|
||||
{"BrakeDelays", [](auto const &M) { return M.BrakeDelays; }},
|
||||
{"BrakeOpModes", [](auto const &M) { return M.BrakeOpModes; }},
|
||||
{"Imin", [](auto const &M) { return M.Imin; }},
|
||||
{"Imax", [](auto const &M) { return M.Imax; }},
|
||||
{"EIMCtrlType", [](auto const &M) { return M.EIMCtrlType; }},
|
||||
{"Volume", [](auto const &M) { return M.Volume; }},
|
||||
{"PantVolume", [](auto const &M) { return M.PantVolume; }},
|
||||
};
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
result.emplace_back(std::format("MaxBrakePress{}", i), [i](auto const &M) { return M.MaxBrakePress[i]; });
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
result.emplace_back(std::format("BrakeCylMult{}", i), [i](auto const &M) { return M.BrakeCylMult[i]; });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<channel> operator+(std::vector<channel> Left, std::vector<channel> const &Right) {
|
||||
Left.insert(Left.end(), Right.begin(), Right.end());
|
||||
return Left;
|
||||
}
|
||||
|
||||
} // namespace channels
|
||||
|
||||
namespace {
|
||||
|
||||
bool environment(char const *Name) {
|
||||
auto const *value{std::getenv(Name)};
|
||||
return value != nullptr && value[0] != '\0' && value[0] != '0';
|
||||
}
|
||||
|
||||
std::string number(double Value) {
|
||||
// the shortest text which reads back as the same double
|
||||
std::array<char, 32> text{};
|
||||
auto const result{std::to_chars(text.data(), text.data() + text.size(), Value)};
|
||||
return {text.data(), result.ptr};
|
||||
}
|
||||
|
||||
// a line of the file, whichever line ends the checkout gave it
|
||||
bool read_line(std::ifstream &File, std::string &Line) {
|
||||
if (false == static_cast<bool>(std::getline(File, Line))) {
|
||||
return false;
|
||||
}
|
||||
if (false == Line.empty() && Line.back() == '\r') {
|
||||
Line.pop_back();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string const &Line) {
|
||||
std::vector<std::string> fields;
|
||||
std::stringstream stream(Line);
|
||||
std::string field;
|
||||
while (std::getline(stream, field, ',')) {
|
||||
fields.push_back(field);
|
||||
}
|
||||
if (false == Line.empty() && Line.back() == ',') {
|
||||
fields.emplace_back();
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
bool same(std::string const &Recorded, std::string const &Now, bool const Exact) {
|
||||
if (Recorded == Now) {
|
||||
return true;
|
||||
}
|
||||
if (Exact) {
|
||||
return false;
|
||||
}
|
||||
char *end{nullptr};
|
||||
auto const recorded{std::strtod(Recorded.c_str(), &end)};
|
||||
auto const now{std::strtod(Now.c_str(), &end)};
|
||||
if (std::isnan(recorded) || std::isnan(now)) {
|
||||
return std::isnan(recorded) && std::isnan(now);
|
||||
}
|
||||
return std::abs(recorded - now) <= 1e-9 * std::max(std::abs(recorded), std::abs(now)) + 1e-12;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
trace::trace(std::string Name, std::vector<channel> Channels, int Every, bool Figures)
|
||||
: m_name(std::move(Name)), m_channels(std::move(Channels)), m_every(Every), m_keep_figures(Figures) {}
|
||||
|
||||
void trace::sample(double Time, TMoverParameters const &Vehicle) {
|
||||
// the invariants on every step, the first time each is broken
|
||||
for (auto const &invariant : invariants()) {
|
||||
if (std::ranges::find(m_broken, invariant.name) != m_broken.end()) {
|
||||
continue;
|
||||
}
|
||||
if (false == invariant.holds(Vehicle, Time, m_sampled ? &m_before : nullptr)) {
|
||||
m_broken.push_back(invariant.name);
|
||||
m_violations.push_back(std::format("invariant \"{}\" broken in {} at {:.3f} s{}: {}", invariant.name, m_name, Time,
|
||||
m_last_event.empty() ? std::string{} : std::format(", after \"{}\"", m_last_event), invariant.explain(Vehicle)));
|
||||
}
|
||||
}
|
||||
m_before = {Time, Vehicle.V, Vehicle.DistCounter};
|
||||
m_sampled = true;
|
||||
m_figures.sample(Time, Vehicle);
|
||||
|
||||
if (m_step++ % m_every != 0) {
|
||||
return;
|
||||
}
|
||||
// the time is a label, summed up from the steps: milliseconds are all it needs
|
||||
auto row{std::format("{:.3f}", Time)};
|
||||
for (auto const &channel : m_channels) {
|
||||
row += "," + number(channel.value(Vehicle));
|
||||
}
|
||||
row += "," + m_event;
|
||||
m_event.clear();
|
||||
m_rows.push_back(row);
|
||||
}
|
||||
|
||||
void trace::mark(std::string const &Event) {
|
||||
m_event += (m_event.empty() ? "" : " ") + Event;
|
||||
m_last_event = Event;
|
||||
m_figures.mark(Event);
|
||||
}
|
||||
|
||||
void trace::check_figures(std::filesystem::path const &Path, bool const Exact) const {
|
||||
// like the samples, the key figures are recorded on the code before a change and compared after it
|
||||
std::ifstream file(Path, std::ios::binary);
|
||||
if (false == file.is_open()) {
|
||||
if (Exact) {
|
||||
FAIL_CHECK("no key figures " << Path.string() << ", run the tests with EU07_UNIT_TESTS_UPDATE_GOLDEN=1 on the code before the change to record them");
|
||||
}
|
||||
return;
|
||||
}
|
||||
std::vector<std::string> recorded;
|
||||
std::string line;
|
||||
while (read_line(file, line)) {
|
||||
recorded.push_back(line);
|
||||
}
|
||||
auto const differences{figures::compare(recorded, m_figures.lines())};
|
||||
if (false == differences.empty()) {
|
||||
std::string text;
|
||||
for (auto const &difference : differences) {
|
||||
text += "\n " + difference;
|
||||
}
|
||||
FAIL_CHECK("key figures of " << m_name << " differ:" << text);
|
||||
}
|
||||
}
|
||||
|
||||
void trace::check() const {
|
||||
for (std::size_t i = 0; i < m_violations.size(); ++i) {
|
||||
if (false == excused(m_name, m_broken[i])) {
|
||||
FAIL_CHECK(m_violations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string header{"time"};
|
||||
for (auto const &channel : m_channels) {
|
||||
header += "," + channel.name;
|
||||
}
|
||||
header += ",event";
|
||||
|
||||
// no spaces in the file names: the build depends on the files, and make doesn't take to them
|
||||
auto name{m_name};
|
||||
std::ranges::replace(name, ' ', '_');
|
||||
std::filesystem::path const filename{name + ".csv"};
|
||||
auto const path{std::filesystem::path{EU07_UNIT_TESTS_DATA} / "golden" / filename};
|
||||
auto figurespath{path};
|
||||
figurespath.replace_extension(".figures");
|
||||
if (environment("EU07_UNIT_TESTS_UPDATE_GOLDEN")) {
|
||||
record(path, figurespath, header);
|
||||
return;
|
||||
}
|
||||
|
||||
// the samples aren't kept in the repository, they're recorded on the code before a change and compared after it
|
||||
auto const exact{environment("EU07_UNIT_TESTS_GOLDEN_EXACT")};
|
||||
if (m_keep_figures) {
|
||||
check_figures(figurespath, exact);
|
||||
}
|
||||
check_samples(path, header, exact);
|
||||
}
|
||||
|
||||
void trace::record(std::filesystem::path const &Path, std::filesystem::path const &FiguresPath, std::string const &Header) const {
|
||||
std::filesystem::create_directories(Path.parent_path());
|
||||
std::ofstream file(Path, std::ios::binary);
|
||||
file << Header << "\n";
|
||||
for (auto const &row : m_rows) {
|
||||
file << row << "\n";
|
||||
}
|
||||
if (m_keep_figures) {
|
||||
std::ofstream figuresfile(FiguresPath, std::ios::binary);
|
||||
for (auto const &line : m_figures.lines()) {
|
||||
figuresfile << line << "\n";
|
||||
}
|
||||
}
|
||||
MESSAGE("recorded the golden trace " << Path.string());
|
||||
}
|
||||
|
||||
void trace::check_samples(std::filesystem::path const &path, std::string const &header, bool const exact) const {
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if (false == file.is_open()) {
|
||||
if (exact) {
|
||||
FAIL_CHECK("no golden trace " << path.string() << ", run the tests with EU07_UNIT_TESTS_UPDATE_GOLDEN=1 on the code before the change to record it");
|
||||
}
|
||||
return;
|
||||
}
|
||||
std::string line;
|
||||
read_line(file, line);
|
||||
if (line != header) {
|
||||
FAIL_CHECK("golden trace " << m_name << " has other channels: " << line << ", the test records " << header);
|
||||
return;
|
||||
}
|
||||
auto const names{split(header)};
|
||||
std::size_t row{0};
|
||||
while (read_line(file, line)) {
|
||||
if (row >= m_rows.size()) {
|
||||
FAIL_CHECK("golden trace " << m_name << " is longer: " << m_rows.size() << " rows now, more recorded");
|
||||
return;
|
||||
}
|
||||
auto const recorded{split(line)};
|
||||
auto const now{split(m_rows[row])};
|
||||
for (std::size_t field = 0; field < names.size(); ++field) {
|
||||
auto const recordedvalue{field < recorded.size() ? recorded[field] : std::string{}};
|
||||
auto const nowvalue{field < now.size() ? now[field] : std::string{}};
|
||||
if (false == same(recordedvalue, nowvalue, exact || names[field] == "event")) {
|
||||
FAIL_CHECK("golden trace " << m_name << " differs first at time " << now.front() << " in " << names[field] << ": " << nowvalue
|
||||
<< " now, " << recordedvalue << " recorded\n now: " << m_rows[row] << "\n recorded: " << line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
++row;
|
||||
}
|
||||
if (row != m_rows.size()) {
|
||||
FAIL_CHECK("golden trace " << m_name << " is shorter: " << m_rows.size() << " rows now, " << row << " recorded");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
90
tests/unit/golden.h
Normal file
90
tests/unit/golden.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "McZapkie/MOVER.h"
|
||||
#include "figures.h"
|
||||
#include "invariants.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
// one value of the vehicle a trace follows
|
||||
struct channel {
|
||||
std::string name;
|
||||
std::function<double(TMoverParameters const &)> value;
|
||||
};
|
||||
|
||||
// sets of channels for the usual subjects of a test, which can be put together
|
||||
namespace channels {
|
||||
std::vector<channel> motion(); // speed, distance, forces
|
||||
std::vector<channel> traction(); // controllers, current, voltage, engine
|
||||
std::vector<channel> brakes(); // pressures of the brake pipe, cylinders and reservoirs
|
||||
std::vector<channel> air(); // compressor and main reservoir
|
||||
std::vector<channel> handles(); // the driver's brake handle and the local brake handle, with their sounds
|
||||
std::vector<channel> doors(); // both sides' doors and steps, their permits and the lock
|
||||
std::vector<channel> parameters(); // what the vehicle definition sets, as the loader read it
|
||||
std::vector<channel> operator+(std::vector<channel> Left, std::vector<channel> const &Right);
|
||||
} // namespace channels
|
||||
|
||||
// characterisation of the simulation: the values of the channels over a run of a vehicle, compared with the
|
||||
// ones the code gave when the trace got recorded, in tests/unit/data/golden/<Name>.csv (spaces as underscores). a difference fails the
|
||||
// test, naming the channel and the time it shows up first. the samples are tens of megabytes and only mean
|
||||
// something against the code before a change, so they stay out of the repository: running the tests with
|
||||
// EU07_UNIT_TESTS_UPDATE_GOLDEN=1 records them on the code before the change, and after it they're compared.
|
||||
// a trace with nothing recorded checks only the invariants and its test's own CHECKs, as the CI does.
|
||||
//
|
||||
// values are compared within a relative tolerance of 1e-9 (the CI builds with GCC and glibc, whose maths
|
||||
// functions can differ from MSVC's in the last bits), or exactly with EU07_UNIT_TESTS_GOLDEN_EXACT=1, which is the check to
|
||||
// run for a change which shouldn't alter anything at all, and which fails a trace with nothing recorded.
|
||||
//
|
||||
// besides the samples, a trace records the key figures of the run (figures.h) in <Name>.figures, the few
|
||||
// lines a person reads of what a change altered, and checks the invariants (invariants.h) on every step
|
||||
//
|
||||
// test::trace trace{"eu07 notch up", test::channels::motion() + test::channels::traction()};
|
||||
// eu07.record(trace);
|
||||
// ... run the vehicle ...
|
||||
// trace.check();
|
||||
class trace {
|
||||
public:
|
||||
// samples every Every-th step of the vehicle: 100, a second at the usual step, is plenty for a run of minutes,
|
||||
// as a difference stays once the simulation has taken it in
|
||||
// Figures: whether to keep the key figures, which a trace sampled by hand, at times of its own, has no use for
|
||||
trace(std::string Name, std::vector<channel> Channels, int Every = 10, bool Figures = true);
|
||||
|
||||
// called by the vehicle after every step
|
||||
void sample(double Time, TMoverParameters const &Vehicle);
|
||||
// adds an event of the test to the trace, so a difference can be told apart from the moment of the action
|
||||
void mark(std::string const &Event);
|
||||
|
||||
// compares the trace and its key figures (figures.h) with the recorded ones, or records them, and reports the
|
||||
// invariants broken
|
||||
void check() const;
|
||||
// the invariants broken in the trace (see invariants.h), the first time each, excused or not
|
||||
std::vector<std::string> const &violations() const { return m_violations; }
|
||||
|
||||
private:
|
||||
void check_figures(std::filesystem::path const &Path, bool Exact) const;
|
||||
// writes the samples and the key figures, as recorded on the code before a change
|
||||
void record(std::filesystem::path const &Path, std::filesystem::path const &FiguresPath, std::string const &Header) const;
|
||||
// compares the samples with the recorded ones
|
||||
void check_samples(std::filesystem::path const &path, std::string const &header, bool exact) const;
|
||||
|
||||
std::string m_name;
|
||||
std::vector<channel> m_channels;
|
||||
int m_every;
|
||||
long m_step{0};
|
||||
std::vector<std::string> m_rows; // formatted, as in the file
|
||||
std::string m_event; // marked since the last row
|
||||
std::string m_last_event; // the last one marked, for the invariants broken after it
|
||||
snapshot m_before{};
|
||||
bool m_sampled{false};
|
||||
std::vector<std::string> m_broken; // the names of the invariants broken so far
|
||||
std::vector<std::string> m_violations;
|
||||
bool m_keep_figures;
|
||||
figures m_figures;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
163
tests/unit/invariants.cpp
Normal file
163
tests/unit/invariants.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "stdafx.h"
|
||||
#include "invariants.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string values(std::initializer_list<std::pair<char const *, double>> Values) {
|
||||
std::string result;
|
||||
for (auto const &[name, value] : Values) {
|
||||
result += std::format("{}{}={:.6g}", result.empty() ? "" : " ", name, value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool electric(TMoverParameters const &M) {
|
||||
return M.EngineType == TEngineType::ElectricSeriesMotor || M.EngineType == TEngineType::ElectricInductionMotor;
|
||||
}
|
||||
|
||||
double max_brake_press(TMoverParameters const &M) {
|
||||
auto result{0.0};
|
||||
for (auto const press : M.MaxBrakePress) {
|
||||
result = std::max(result, press);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// the margin over a limit which a step of the simulation may overshoot it by
|
||||
constexpr double pressure_margin{0.05};
|
||||
// the highest acceleration of a vehicle, 5 g, which a collision goes well over
|
||||
constexpr double highest_acceleration{5.0 * 9.81};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<invariant> const &invariants() {
|
||||
static std::vector<invariant> const rules{
|
||||
{"every value a number",
|
||||
[](auto const &M, double, auto const *) {
|
||||
std::initializer_list<double> const values{M.V, M.AccS, M.Ft, M.Fb, M.Im, M.Itot, M.EngineVoltage,
|
||||
M.enrot, M.PipePress, M.BrakePress, M.LocBrakePress, M.ScndPipePress, M.Compressor, M.BatteryVoltage};
|
||||
return std::ranges::all_of(values, [](double const Value) { return std::isfinite(Value); });
|
||||
},
|
||||
[](auto const &M) {
|
||||
return values({{"V", M.V}, {"AccS", M.AccS}, {"Ft", M.Ft}, {"Fb", M.Fb}, {"Im", M.Im}, {"Itot", M.Itot}, {"EngineVoltage", M.EngineVoltage},
|
||||
{"enrot", M.enrot}, {"PipePress", M.PipePress}, {"BrakePress", M.BrakePress}, {"LocBrakePress", M.LocBrakePress},
|
||||
{"ScndPipePress", M.ScndPipePress}, {"Compressor", M.Compressor}, {"BatteryVoltage", M.BatteryVoltage}});
|
||||
}},
|
||||
{"brake cylinders between empty and the vehicle's highest pressure",
|
||||
[](auto const &M, double, auto const *) {
|
||||
// a step overshoots the setting a little: the EU07's LSt fills its cylinders to 4.0 bar of its 3.8
|
||||
auto const limit{1.1 * max_brake_press(M) + pressure_margin};
|
||||
return M.BrakePress >= -pressure_margin && M.BrakePress <= limit && M.LocBrakePress >= -pressure_margin && M.LocBrakePress <= limit;
|
||||
},
|
||||
[](auto const &M) { return values({{"BrakePress", M.BrakePress}, {"LocBrakePress", M.LocBrakePress}, {"max(MaxBrakePress)", max_brake_press(M)}}); }},
|
||||
{"pipes between empty and the highest governor setting",
|
||||
[](auto const &M, double, auto const *) {
|
||||
// all the air comes from the main reservoirs, which the game sets up to 10 bar, some (the Impuls) to 12;
|
||||
// the driver's valve in its filling position joins the brake pipe to them
|
||||
auto const highest{1.01 * std::max(10.0, M.MaxCompressor) + pressure_margin};
|
||||
std::initializer_list<double> const pressures{M.PipePress, M.ScndPipePress, M.Compressor};
|
||||
return std::ranges::all_of(pressures, [highest](double const Press) { return Press >= -pressure_margin && Press <= highest; });
|
||||
},
|
||||
[](auto const &M) { return values({{"PipePress", M.PipePress}, {"ScndPipePress", M.ScndPipePress}, {"Compressor", M.Compressor}}); }},
|
||||
{"main reservoir no higher than the compressor's governor",
|
||||
[](auto const &M, double, auto const *) { return M.MaxCompressor <= 0.0 || M.Compressor <= 1.01 * M.MaxCompressor + pressure_margin; },
|
||||
[](auto const &M) { return values({{"Compressor", M.Compressor}, {"MaxCompressor", M.MaxCompressor}}); }},
|
||||
{"no motor current with the line breaker open",
|
||||
[](auto const &M, double, auto const *) { return M.Mains || false == electric(M) || std::abs(M.Im) < 1.0; },
|
||||
[](auto const &M) { return values({{"Mains", M.Mains}, {"Im", M.Im}, {"Itot", M.Itot}}); }},
|
||||
{"no motor current with the line contactors open, but for the dynamic brake",
|
||||
[](auto const &M, double, auto const *) {
|
||||
// the dynamic brake closes its own circuit of the motors and the resistors
|
||||
return M.StLinFlag || M.DynamicBrakeFlag || M.EngineType != TEngineType::ElectricSeriesMotor || std::abs(M.Im) < 1.0;
|
||||
},
|
||||
[](auto const &M) {
|
||||
return values({{"StLinFlag", M.StLinFlag}, {"DynamicBrakeFlag", M.DynamicBrakeFlag}, {"Im", M.Im}, {"MainCtrlActualPos", M.MainCtrlActualPos}});
|
||||
}},
|
||||
{"no tractive force without power",
|
||||
[](auto const &M, double, auto const *) { return M.Power >= 0.01 || std::abs(M.Ft) < 1.0; },
|
||||
[](auto const &M) { return values({{"Power", M.Power}, {"Ft", M.Ft}}); }},
|
||||
{"engine fill between none and full",
|
||||
[](auto const &M, double, auto const *) { return M.dizel_fill >= 0.0 && M.dizel_fill <= 1.0; },
|
||||
[](auto const &M) { return values({{"dizel_fill", M.dizel_fill}}); }},
|
||||
{"diesel engine turning forward, no faster than its top speed",
|
||||
[](auto const &M, double, auto const *) {
|
||||
// the governor lets it overshoot a little (the SN61 by 1%)
|
||||
return M.EngineType != TEngineType::DieselEngine || (M.enrot >= 0.0 && M.enrot <= 1.05 * M.dizel_nmax);
|
||||
},
|
||||
[](auto const &M) { return values({{"enrot", M.enrot}, {"dizel_nmax", M.dizel_nmax}}); }},
|
||||
{"battery no higher than its nominal voltage",
|
||||
[](auto const &M, double, auto const *) { return M.NominalBatteryVoltage <= 0.0 || M.BatteryVoltage <= 1.05 * M.NominalBatteryVoltage; },
|
||||
[](auto const &M) { return values({{"BatteryVoltage", M.BatteryVoltage}, {"NominalBatteryVoltage", M.NominalBatteryVoltage}}); }},
|
||||
{"distance counted as the speed runs",
|
||||
[](auto const &M, double Time, auto const *Before) {
|
||||
if (Before == nullptr) {
|
||||
return true;
|
||||
}
|
||||
// the speed of the step is between the speeds at its ends, or a bit off it, as the movement is integrated;
|
||||
// through a standstill, down to none
|
||||
auto const dt{Time - Before->time};
|
||||
auto const covered{(M.DistCounter - Before->DistCounter) * 1000.0};
|
||||
auto const lowest{M.V * Before->V > 0.0 ? std::min(std::abs(M.V), std::abs(Before->V)) : 0.0};
|
||||
auto const highest{std::max(std::abs(M.V), std::abs(Before->V))};
|
||||
return covered >= lowest * dt * 0.9 - 0.01 && covered <= highest * dt * 1.1 + 0.01;
|
||||
},
|
||||
[](auto const &M) { return values({{"V", M.V}, {"DistCounter", M.DistCounter}}); }},
|
||||
{"no acceleration over 5 g",
|
||||
[](auto const &M, double Time, auto const *Before) {
|
||||
return Before == nullptr || std::abs(M.V - Before->V) <= highest_acceleration * (Time - Before->time) + 0.01;
|
||||
},
|
||||
[](auto const &M) { return values({{"V", M.V}, {"AccS", M.AccS}}); }},
|
||||
{"hand brake applied, the wheels braked on the move",
|
||||
[](auto const &M, double, auto const *) { return false == M.MBrake || M.ManualBrakePos == 0 || std::abs(M.V) < 0.5 || std::abs(M.Fb) > 0.0; },
|
||||
[](auto const &M) { return values({{"ManualBrakePos", M.ManualBrakePos}, {"V", M.V}, {"Fb", M.Fb}}); }},
|
||||
};
|
||||
return rules;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct excuse {
|
||||
char const *trace; // a part of the trace's name
|
||||
char const *invariant;
|
||||
char const *reason;
|
||||
};
|
||||
|
||||
std::vector<excuse> const excuses{
|
||||
// what the tests do
|
||||
{"couplers/collision/", "no acceleration over 5 g", "vehicles run into each other"},
|
||||
{"controls/collision/", "no acceleration over 5 g", "vehicles run into each other"},
|
||||
{"couplers/collision/", "distance counted as the speed runs", "the buffers throw the vehicle back within a step"},
|
||||
{"switches_live/", "no acceleration over 5 g", "sampled by hand, a second apart in the trace for 2 s run"},
|
||||
{"switches_live/", "distance counted as the speed runs", "sampled by hand, a second apart in the trace for 2 s run"},
|
||||
{"brake handles/", "main reservoir no higher than the compressor's governor", "the test holds the main reservoir at 8 bar"},
|
||||
{"local brake/", "main reservoir no higher than the compressor's governor", "the test holds the main reservoir at 8 bar"},
|
||||
{"brake cycle/at speed/", "brake cylinders between empty and the vehicle's highest pressure", "the rapid step of the valves at speed"},
|
||||
// the vehicles as they are
|
||||
{"elf/2", "main reservoir no higher than the compressor's governor",
|
||||
"the units' reservoirs share the supply pipe: the A car's governor stops at 9 bar, the C car's at 8.5"},
|
||||
{"sm03_v1/", "brake cylinders between empty and the vehicle's highest pressure",
|
||||
"its K valve fills the cylinders to the auxiliary reservoir's pressure (4.27 bar), over MaxBP 3.5"},
|
||||
{"eu04_v1/", "brake cylinders between empty and the vehicle's highest pressure",
|
||||
"its K valve fills the cylinders to the auxiliary reservoir's pressure (3.19 bar), over MaxBP 2.8"},
|
||||
{"sn61", "brake cylinders between empty and the vehicle's highest pressure",
|
||||
"its ESt3d_PZZ valve fills the cylinders to the auxiliary reservoir's pressure in an emergency (4.6 bar), over MaxBP 3.8"},
|
||||
{"sm03_v1/", "diesel engine turning forward, no faster than its top speed", "a lower gear at speed drives the engine over its top speed, by 10%"},
|
||||
{"wmb10_v1/", "diesel engine turning forward, no faster than its top speed", "a lower gear at speed drives the engine over its top speed, by 25%"},
|
||||
{"controls/full physics/", "no acceleration over 5 g", "the couplers' slack taken up as the train starts throws the wagons about at up to 5.7 g"},
|
||||
{"controls/full physics/", "distance counted as the speed runs", "the couplers' slack taken up as the train starts throws the wagons back within a step"},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool excused(std::string_view const Trace, std::string_view const Invariant) {
|
||||
return std::ranges::any_of(excuses, [&](excuse const &Excuse) { return Excuse.invariant == Invariant && Trace.find(Excuse.trace) != std::string_view::npos; });
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
36
tests/unit/invariants.h
Normal file
36
tests/unit/invariants.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "McZapkie/MOVER.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
// what the rules over time need of the step before
|
||||
struct snapshot {
|
||||
double time;
|
||||
double V;
|
||||
double DistCounter;
|
||||
};
|
||||
|
||||
// a rule of physics or of the vehicle's circuits, which holds for every vehicle after every step, whatever
|
||||
// the test does with it. every golden trace checks them as it samples (see golden.h), on every step, not only
|
||||
// on the recorded ones, and with no comparison to a recorded file, so they hold on any compiler. a change which
|
||||
// alters the behaviour on purpose records the traces anew, and the rules still check the new behaviour makes sense.
|
||||
struct invariant {
|
||||
std::string name;
|
||||
// Before is null at the first step of a trace
|
||||
std::function<bool(TMoverParameters const &Now, double Time, snapshot const *Before)> holds;
|
||||
// the values the rule looks at, shown when it's broken
|
||||
std::function<std::string(TMoverParameters const &Now)> explain;
|
||||
};
|
||||
|
||||
std::vector<invariant> const &invariants();
|
||||
|
||||
// the traces where the game breaks a rule, as it is, with the reason (see COVERAGE.md, what the tests found)
|
||||
bool excused(std::string_view Trace, std::string_view Invariant);
|
||||
|
||||
} // namespace test
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
|
||||
#include "utilities/Globals.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -13,8 +13,8 @@ class deterministic_random : public doctest::IReporter {
|
||||
public:
|
||||
explicit deterministic_random(doctest::ContextOptions const &) {}
|
||||
|
||||
void test_case_start(doctest::TestCaseData const &) override { reseed(); }
|
||||
void test_case_reenter(doctest::TestCaseData const &) override { reseed(); }
|
||||
void test_case_start(doctest::TestCaseData const &) override { test::reseed_random(); }
|
||||
void test_case_reenter(doctest::TestCaseData const &) override { test::reseed_random(); }
|
||||
|
||||
// the rest of doctest's reporter interface: a listener reports nothing, the console reporter does that
|
||||
void report_query(doctest::QueryData const &) override { /* nothing to report */ }
|
||||
@@ -27,12 +27,6 @@ public:
|
||||
void log_assert(doctest::AssertData const &) override { /* nothing to report */ }
|
||||
void log_message(doctest::MessageData const &) override { /* nothing to report */ }
|
||||
void test_case_skipped(doctest::TestCaseData const &) override { /* nothing to report */ }
|
||||
|
||||
private:
|
||||
static void reseed() {
|
||||
Global.random_engine.seed(1);
|
||||
Global.local_random_engine.seed(1);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
12
tests/unit/real_vehicles.h
Normal file
12
tests/unit/real_vehicles.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace test {
|
||||
|
||||
// the real vehicle definitions of data/fiz, as paths for definition::fiz(): every .json file there, sorted.
|
||||
// vehicles the game defines by including others are vehicles of their own too (201e-rn, included by 201e-w)
|
||||
std::vector<std::string> const &real_vehicles();
|
||||
|
||||
} // namespace test
|
||||
80
tests/unit/scenario.cpp
Normal file
80
tests/unit/scenario.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "stdafx.h"
|
||||
#include "scenario.h"
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
scenario::scenario(std::string Name, std::vector<channel> Channels, track const &Track) : m_name(std::move(Name)), m_channels(std::move(Channels)), m_track(Track) {
|
||||
reseed_random();
|
||||
}
|
||||
|
||||
scenario &scenario::add(std::string const &Path, int Cab, int Coupling, double Velocity, double Gap) {
|
||||
m_train.add(definition::fiz(Path), Cab, Coupling, Velocity, Gap);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void scenario::record() {
|
||||
// on the first action, once the train is complete
|
||||
if (false == m_traces.empty()) {
|
||||
return;
|
||||
}
|
||||
for (std::size_t i = 0; i < m_train.size(); ++i) {
|
||||
m_traces.push_back(std::make_unique<trace>(std::format("{}/{}", m_name, i), m_channels, 100));
|
||||
m_train[i].record(*m_traces.back());
|
||||
}
|
||||
}
|
||||
|
||||
void scenario::act(std::string const &Event) {
|
||||
record();
|
||||
for (auto const &trace : m_traces) {
|
||||
trace->mark(Event);
|
||||
}
|
||||
}
|
||||
|
||||
void scenario::wait(double Seconds) {
|
||||
record();
|
||||
drive(driver(), m_track, Seconds);
|
||||
}
|
||||
|
||||
bool scenario::start_up() {
|
||||
record();
|
||||
return test::start_up(driver(), m_track, 300.0, m_traces.front().get());
|
||||
}
|
||||
|
||||
void scenario::get_going() {
|
||||
act("get going");
|
||||
release_brakes(cab());
|
||||
for (int i = 0; i < 3 && cab().DirActive <= 0; ++i) {
|
||||
cab().DirectionForward();
|
||||
}
|
||||
wait(20.0);
|
||||
}
|
||||
|
||||
void scenario::full_power(double Seconds) {
|
||||
auto &controlling{driver().controlling};
|
||||
controlling.IncMainCtrl(1);
|
||||
for (int i = 0; i < 90 && false == controlling.StLinFlag; ++i) {
|
||||
wait(1.0);
|
||||
}
|
||||
for (int i = 0; i < 60 && false == controlling.IsMainCtrlMaxPowerPos(); ++i) {
|
||||
controlling.IncMainCtrl(1);
|
||||
wait(1.0);
|
||||
}
|
||||
wait(Seconds);
|
||||
}
|
||||
|
||||
void scenario::notch_back(int Position) {
|
||||
auto &controlling{driver().controlling};
|
||||
while (controlling.MainCtrlPos > Position && controlling.DecMainCtrl(1)) {
|
||||
wait(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void scenario::check() const {
|
||||
for (auto const &trace : m_traces) {
|
||||
trace->check();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
63
tests/unit/scenario.h
Normal file
63
tests/unit/scenario.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "consist.h"
|
||||
#include "drive.h"
|
||||
#include "golden.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
// a scenario of a test: a train of real vehicles (one vehicle is a train too), a driver in the front one,
|
||||
// and a golden trace for each vehicle (data/golden/<Name>/<number of the vehicle>.csv) with the events of
|
||||
// the scenario in them:
|
||||
// test::scenario scenario{"doors/elf", test::channels::motion() + test::channels::doors()};
|
||||
// scenario.add("elf_v1/21we-a", 1).add("elf_v1/21we-b").add("elf_v1/21we-c");
|
||||
// scenario.start_up();
|
||||
// scenario.act("open left");
|
||||
// scenario.cab().OperateDoors(side::left, true);
|
||||
// scenario.wait(10.0);
|
||||
// scenario.check();
|
||||
class scenario {
|
||||
public:
|
||||
scenario(std::string Name, std::vector<channel> Channels, track const &Track = {0.15, 0.0, catenary_3kv});
|
||||
|
||||
// adds a real vehicle at the back, see consist::add()
|
||||
scenario &add(std::string const &Path, int Cab = 0, int Coupling = consist::full_coupling, double Velocity = 0.0, double Gap = 0.0);
|
||||
|
||||
consist &train() { return m_train; }
|
||||
TMoverParameters &vehicle(std::size_t Index) { return m_train[Index].mover(); }
|
||||
TMoverParameters &cab() { return m_train[0].mover(); }
|
||||
driven driver() { return driving(m_train); }
|
||||
track &line() { return m_track; }
|
||||
|
||||
// marks the event in the traces, the action follows it
|
||||
void act(std::string const &Event);
|
||||
// runs the train with the driver attending to it
|
||||
void wait(double Seconds);
|
||||
// gets the train ready to run, see test::start_up(); returns whether it did
|
||||
bool start_up();
|
||||
// releases the brakes and sets the direction forward, for a train to move off
|
||||
void get_going();
|
||||
// the main controller up to its full power position, a notch a second, and Seconds more there. the line
|
||||
// contactors close at the first position, after their delay (InitialCtrlDelay) and once the pressure switch
|
||||
// lets them (the cylinders under 2 bar, the pipe over 3.6), so it waits there for them, as the AI does
|
||||
void full_power(double Seconds);
|
||||
// the main controller back to the given position, a notch a second
|
||||
void notch_back(int Position);
|
||||
// checks the traces
|
||||
void check() const;
|
||||
|
||||
private:
|
||||
void record();
|
||||
|
||||
std::string m_name;
|
||||
std::vector<channel> m_channels;
|
||||
track m_track;
|
||||
consist m_train;
|
||||
std::vector<std::unique_ptr<trace>> m_traces;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
112
tests/unit/test_auxiliaries.cpp
Normal file
112
tests/unit/test_auxiliaries.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "scenario.h"
|
||||
#include "drive.h"
|
||||
|
||||
// characterisation of the auxiliary circuits of vehicles: the battery drained and charged, and the air of the
|
||||
// pantographs kept in their own tank, whose pressure switch opens the line breaker, each in a scenario on real
|
||||
// vehicles recorded in golden traces (data/golden/auxiliaries/)
|
||||
|
||||
using test::scenario;
|
||||
using namespace test::channels;
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<test::channel> auxiliaries() {
|
||||
return {
|
||||
{"BatteryVoltage", [](auto const &M) { return M.BatteryVoltage; }},
|
||||
{"Battery", [](auto const &M) { return M.Battery ? 1.0 : 0.0; }},
|
||||
{"ConverterFlag", [](auto const &M) { return M.ConverterFlag ? 1.0 : 0.0; }},
|
||||
{"Power110vIsAvailable", [](auto const &M) { return M.Power110vIsAvailable ? 1.0 : 0.0; }},
|
||||
{"PantPress", [](auto const &M) { return M.PantPress; }},
|
||||
{"PantVolume", [](auto const &M) { return M.PantVolume; }},
|
||||
{"PantCompFlag", [](auto const &M) { return M.PantCompFlag ? 1.0 : 0.0; }},
|
||||
{"PantPressSwitchActive", [](auto const &M) { return M.PantPressSwitchActive ? 1.0 : 0.0; }},
|
||||
{"PantPressLockActive", [](auto const &M) { return M.PantPressLockActive ? 1.0 : 0.0; }},
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("auxiliaries: the battery drained by the lights and the pantographs' compressor, until nothing starts") {
|
||||
// without the converter the battery falls quickly to 90 V, then slowly as the lights and the small compressor
|
||||
// draw on it; at 70 V (110 / 1.57) it opens the line breaker, and the locomotive doesn't start again
|
||||
scenario scenario{"auxiliaries/battery/eu07 drained", traction() + auxiliaries()};
|
||||
scenario.add("4e_v1/4e", 1);
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &eu07{scenario.cab()};
|
||||
REQUIRE(eu07.BatteryVoltage == doctest::Approx(eu07.NominalBatteryVoltage));
|
||||
scenario.act("converter off, lights on, small compressor on");
|
||||
eu07.ConverterSwitch(false);
|
||||
eu07.iLights[end::front] = 1 | 2 | 4;
|
||||
eu07.iLights[end::rear] = 16;
|
||||
eu07.PantCompFlag = true;
|
||||
scenario.wait(30.0);
|
||||
CHECK(eu07.BatteryVoltage < 0.83 * eu07.NominalBatteryVoltage);
|
||||
CHECK(eu07.Mains);
|
||||
scenario.wait(5000.0);
|
||||
CHECK(eu07.BatteryVoltage < eu07.NominalBatteryVoltage / 1.57);
|
||||
CHECK_FALSE(eu07.Mains);
|
||||
scenario.act("start up again");
|
||||
CHECK_FALSE(scenario.start_up());
|
||||
CHECK(eu07.BatteryVoltage < eu07.NominalBatteryVoltage / 1.57);
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("auxiliaries: the battery switched off, and charged by the converter") {
|
||||
scenario scenario{"auxiliaries/battery/eu07 switched off", traction() + auxiliaries()};
|
||||
scenario.add("4e_v1/4e", 1);
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &eu07{scenario.cab()};
|
||||
scenario.act("converter off");
|
||||
eu07.ConverterSwitch(false);
|
||||
scenario.wait(10.0);
|
||||
auto const discharged{eu07.BatteryVoltage};
|
||||
CHECK(discharged < 0.83 * eu07.NominalBatteryVoltage);
|
||||
// the converter charges it back at once
|
||||
scenario.act("converter on");
|
||||
eu07.ConverterSwitch(true);
|
||||
scenario.wait(10.0);
|
||||
CHECK(eu07.BatteryVoltage == doctest::Approx(eu07.NominalBatteryVoltage));
|
||||
// switched off, the battery falls to 90 V at once, then holds
|
||||
scenario.act("battery off");
|
||||
eu07.MainSwitch(false);
|
||||
eu07.ConverterSwitch(false);
|
||||
eu07.BatterySwitch(false);
|
||||
scenario.wait(10.0);
|
||||
CHECK(eu07.BatteryVoltage == doctest::Approx(discharged).epsilon(0.01));
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("auxiliaries: the pantographs on their own tank, leaking until the pressure switch opens the line breaker") {
|
||||
// the pantographs cut off the main reservoir (bPantKurek3 off) are held up by the air of their own small tank,
|
||||
// which leaks; under MinPress the pressure switch, primed at 4.6 bar, opens the line breaker. the small
|
||||
// compressor pumps the tank up to 4.8 bar, priming the switch again. (an electric unit's switch turns its
|
||||
// converter off instead; the EW58's pantographs have an automatic valve to the main reservoir, which keeps
|
||||
// their tank up)
|
||||
scenario scenario{"auxiliaries/pantograph tank/eu07", traction() + auxiliaries()};
|
||||
scenario.add("4e_v1/4e", 1);
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &eu07{scenario.cab()};
|
||||
// started up on the small compressor, the tank gets joined to the main reservoir, which primes the switch
|
||||
scenario.act("tank joined to the main reservoir");
|
||||
eu07.bPantKurek3 = true;
|
||||
scenario.wait(30.0);
|
||||
REQUIRE(eu07.PantPressSwitchActive);
|
||||
scenario.act("tank cut off the main reservoir");
|
||||
eu07.bPantKurek3 = false;
|
||||
eu07.PantCompFlag = false;
|
||||
scenario.wait(600.0);
|
||||
CHECK(eu07.PantPress < eu07.EnginePowerSource.CollectorParameters.MinPress);
|
||||
CHECK_FALSE(eu07.PantPressSwitchActive);
|
||||
CHECK_FALSE(eu07.Mains);
|
||||
scenario.act("small compressor on");
|
||||
eu07.PantCompFlag = true;
|
||||
for (int i = 0; i < 60 && eu07.PantCompFlag; ++i) {
|
||||
scenario.wait(10.0);
|
||||
}
|
||||
CHECK_FALSE(eu07.PantCompFlag);
|
||||
CHECK(eu07.PantPress >= 4.6); // stopped at 4.8, leaking since
|
||||
CHECK(eu07.PantPressSwitchActive);
|
||||
scenario.check();
|
||||
}
|
||||
194
tests/unit/test_brake_cycle.cpp
Normal file
194
tests/unit/test_brake_cycle.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
#include "golden.h"
|
||||
#include "real_vehicles.h"
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
// characterisation of the brakes of every real vehicle: the brake pipe driven through a whole cycle, as the
|
||||
// locomotive of a train would drive it, and the distributor valve, the cylinders and the reservoirs followed
|
||||
// in golden traces (data/golden/brake cycle/). pressures in bar, the pipe runs at 5.0
|
||||
|
||||
namespace {
|
||||
|
||||
struct stage {
|
||||
char const *name;
|
||||
double pipe; // held brake pipe pressure
|
||||
double seconds;
|
||||
};
|
||||
|
||||
// charging, the service application in steps, release, the overcharge used to speed the release up and its
|
||||
// drop back, the emergency application and recharging after it
|
||||
std::array<stage, 9> const cycle{{
|
||||
{"charge", 5.0, 90.0}, {"light", 4.6, 20.0}, {"medium", 4.2, 20.0}, {"full service", 3.5, 20.0},
|
||||
{"release", 5.0, 40.0}, {"overcharge", 5.4, 15.0}, {"back to 5", 5.0, 45.0}, {"emergency", 0.0, 15.0},
|
||||
{"recharge", 5.0, 90.0},
|
||||
}};
|
||||
|
||||
// returns the pressure in the cylinders at the end of each stage, by the name of the stage
|
||||
std::map<std::string, double, std::less<>> run_cycle(vehicle &Vehicle, test::trace &Trace) {
|
||||
std::map<std::string, double, std::less<>> cylinders;
|
||||
for (auto const &stage : cycle) {
|
||||
Trace.mark(stage.name);
|
||||
Vehicle.hold_brake_pipe(stage.pipe);
|
||||
Vehicle.run(stage.seconds);
|
||||
cylinders[stage.name] = Vehicle->BrakePress;
|
||||
}
|
||||
return cylinders;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("brake cycle: every real vehicle through charge, service steps, release, overcharge and emergency") {
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz(path)};
|
||||
test::trace trace{"brake cycle/" + path, test::channels::brakes(), 100};
|
||||
real.record(trace);
|
||||
// a vehicle braked by the pipe: released once charged, braking harder by every step of the service
|
||||
// application, and by the emergency one. the release isn't checked: some vehicles don't release within
|
||||
// its 40 s, others keep a little air after the overcharge
|
||||
if (auto cylinders{run_cycle(real, trace)}; cylinders["full service"] > 0.0) {
|
||||
CHECK(cylinders["charge"] < 0.1);
|
||||
CHECK(cylinders["light"] <= cylinders["medium"]);
|
||||
CHECK(cylinders["medium"] <= cylinders["full service"] + 0.01);
|
||||
CHECK(cylinders["full service"] > 1.0);
|
||||
CHECK(cylinders["emergency"] > 0.5);
|
||||
}
|
||||
else {
|
||||
// the draisine, the road vehicle and the catenary car, which have no brake worked by the pipe
|
||||
CHECK(cylinders["emergency"] == 0.0);
|
||||
}
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("brake cycle: every brake delay setting of the real vehicles") {
|
||||
// G, P, R and their mixes change how fast the cylinders fill and empty; every vehicle offering more
|
||||
// than one setting goes through the service part of the cycle on each
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
vehicle probe{definition::fiz(path)};
|
||||
for (auto const delay : {bdelay_G, bdelay_P, bdelay_R, bdelay_R + bdelay_M, bdelay_G + bdelay_M}) {
|
||||
if ((probe->BrakeDelays & delay) != delay || delay == probe->BrakeDelayFlag) {
|
||||
continue;
|
||||
}
|
||||
CAPTURE(delay);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz(path)};
|
||||
REQUIRE(real->BrakeDelaySwitch(delay));
|
||||
test::trace trace{std::format("brake delays/{} {}", path, delay), test::channels::brakes(), 100};
|
||||
real.record(trace);
|
||||
std::map<std::string, double, std::less<>> cylinders;
|
||||
for (auto const &stage : {stage{"charge", 5.0, 90.0}, stage{"full service", 3.5, 30.0}, stage{"release", 5.0, 60.0}}) {
|
||||
trace.mark(stage.name);
|
||||
real.hold_brake_pipe(stage.pipe);
|
||||
real.run(stage.seconds);
|
||||
cylinders[stage.name] = real->BrakePress;
|
||||
}
|
||||
// every setting brakes in half a minute and releases in a minute
|
||||
CHECK(cylinders["full service"] > 1.0);
|
||||
CHECK(cylinders["release"] < 0.3);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("brake cycle: the valves the game knows but none of its vehicles has, fitted to a wagon") {
|
||||
// the variants of the Westinghouse and Knorr valves, the Hik ones, the old ESt3 and the CV1 ones, with a name
|
||||
// the game doesn't know at the end. any other name with ESt in it is an Oerlikon valve (NESt3) whose name sets
|
||||
// its relays: -ED the electrodynamic brake's one, AL2 the load-weighing one, without ESt3 the rapid one
|
||||
for (auto const *name : {"W_Lu_L", "W_Lu_XR", "W_Lu_VI", "Kg", "Kp", "Kss", "Kkg", "Kkp", "Kks", "Hikp1", "Hikss", "Hikg1", "SW", "NESt3", "M483", "CV1", "CV1_L_TR",
|
||||
"CV1_R", "ESt4-ED", "ESt4AL2", "no such valve"}) {
|
||||
CAPTURE(name);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz("3wl_v2/3wl").set("Brake", "BrakeValve", name)};
|
||||
test::trace trace{std::string{"brake cycle/fitted/"} + name, test::channels::brakes(), 100};
|
||||
real.record(trace);
|
||||
run_cycle(real, trace);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("brake cycle: the rapid setting at speed, the anti-slip brake and the releaser button") {
|
||||
// R gives the cylinders more air at speed (RM); the anti-slip request the game makes while the wheels slip and
|
||||
// slow down (3) and the releaser button (ub_Release) let the LSt's cylinders out, the KE's not
|
||||
struct valve {
|
||||
char const *name;
|
||||
char const *path;
|
||||
int delay;
|
||||
double service; // in the cylinders, full service over 100 km/h
|
||||
bool releases; // by the button
|
||||
};
|
||||
for (auto const &[name, path, delay, service, releases] : {valve{"KE", "z1_v2/152a", bdelay_R, 3.78, false}, valve{"KE in P", "z1_v2/152a", bdelay_P, 2.70, false},
|
||||
valve{"LSt", "4e_v1/4e", bdelay_R, 5.79, true}, valve{"LSt in P", "4e_v1/4e", bdelay_P, 3.68, true}}) {
|
||||
CAPTURE(name);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz(path), 160.0};
|
||||
real->DecManualBrakeLevel(ManualBrakePosNo);
|
||||
real->BrakeDelaySwitch(delay); // false when already set
|
||||
REQUIRE(real->BrakeDelayFlag == delay);
|
||||
using test::channels::operator+;
|
||||
test::trace trace{std::string{"brake cycle/at speed/"} + name, test::channels::motion() + test::channels::brakes(), 100};
|
||||
real.record(trace);
|
||||
trace.mark("charge");
|
||||
real.hold_brake_pipe(5.0);
|
||||
real.run(60.0);
|
||||
trace.mark("full service");
|
||||
real.hold_brake_pipe(3.5);
|
||||
real.run(10.0);
|
||||
CHECK(real->Vel > 100.0);
|
||||
CHECK(real->BrakePress == doctest::Approx(service).epsilon(0.01));
|
||||
trace.mark("anti-slip");
|
||||
real->Hamulec->ASB(3);
|
||||
real.run(2.0);
|
||||
real->Hamulec->ASB(0);
|
||||
real.run(3.0);
|
||||
trace.mark("releaser button");
|
||||
real->Hamulec->SetUniversalFlag(TUniversalBrake::ub_Release);
|
||||
real.run(3.0);
|
||||
real->Hamulec->SetUniversalFlag(0);
|
||||
CHECK((real->BrakePress < 1.0) == releases);
|
||||
// released for good, the pipe still at full service
|
||||
real.run(40.0);
|
||||
CHECK((real->BrakePress < 0.1) == releases);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("brake cycle: every material of the brake shoes and disks, braking a wagon from speed") {
|
||||
// the friction of the shoes (BM) against the speed and the pressing force (friction.cpp): the game's wagons
|
||||
// have P10-Bg, P10-Bgu, Cosid and the disks; FR513, FR510, P10yBg and P10yBgu none of them, nor an unknown one
|
||||
// (P10, as with no BM). Mg adds the magnetic rail brake under 3 bar in the pipe
|
||||
for (auto const *material : {"P10-Bg", "P10-Bgu", "FR513", "FR510", "Cosid", "P10yBg", "P10yBgu", "Disk1", "Disk1+Mg", "Disk2", "no such material"}) {
|
||||
CAPTURE(material);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz("3wl_v2/3wl").set("Brake", "BM", material), 100.0};
|
||||
real->DecManualBrakeLevel(ManualBrakePosNo);
|
||||
using test::channels::operator+;
|
||||
test::trace trace{std::string{"brake cycle/materials/"} + material, test::channels::motion() + test::channels::brakes(), 100};
|
||||
real.record(trace);
|
||||
trace.mark("charge");
|
||||
real.hold_brake_pipe(5.0);
|
||||
real.run(30.0);
|
||||
auto const speed{real->Vel};
|
||||
trace.mark("full service");
|
||||
real.hold_brake_pipe(3.5);
|
||||
real.run(20.0);
|
||||
CHECK(real->Vel < speed - 10.0);
|
||||
CHECK(real->Fb > 0.0);
|
||||
trace.mark("emergency");
|
||||
real.hold_brake_pipe(0.0);
|
||||
real.run(60.0);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
154
tests/unit/test_brake_handles.cpp
Normal file
154
tests/unit/test_brake_handles.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
#include "golden.h"
|
||||
#include "real_vehicles.h"
|
||||
#include "drive.h"
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
// characterisation of the driver's brake handles and the local brake handles of the real locomotives and
|
||||
// units: every position of the handle, with the main reservoir kept full, followed in golden traces
|
||||
// (data/golden/brake handles/). the vehicle runs alone, so the handle drives only its own brake pipe
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<test::channel> handle_channels() {
|
||||
using namespace test::channels;
|
||||
return brakes() + handles() + air();
|
||||
}
|
||||
|
||||
// the vehicles with a driver's brake handle
|
||||
bool has_handle(vehicle &Vehicle) {
|
||||
return Vehicle->BrakeCtrlPosNo > 1;
|
||||
}
|
||||
|
||||
void hold(vehicle &Vehicle, test::trace &Trace, std::string const &Event, double Position, double Seconds) {
|
||||
Trace.mark(Event);
|
||||
Vehicle->BrakeLevelSet(Position);
|
||||
Vehicle.run(Seconds);
|
||||
}
|
||||
|
||||
// every position of the driver's handle, recorded in the trace
|
||||
void every_position(vehicle &Vehicle, test::trace &Trace) {
|
||||
Vehicle.hold_main_reservoir(std::max(Vehicle->MaxCompressor, 8.0));
|
||||
auto &handle{*Vehicle->Handle};
|
||||
Vehicle.record(Trace);
|
||||
|
||||
hold(Vehicle, Trace, "running", handle.GetPos(bh_RP), 90.0);
|
||||
// every position from the lowest to the highest, emergency included, then back to running
|
||||
auto const lowest{static_cast<int>(std::ceil(handle.GetPos(bh_MIN)))};
|
||||
auto const highest{static_cast<int>(std::floor(handle.GetPos(bh_MAX)))};
|
||||
for (auto position = lowest; position <= highest; ++position) {
|
||||
hold(Vehicle, Trace, std::format("position {}", position), position, 15.0);
|
||||
hold(Vehicle, Trace, "running", handle.GetPos(bh_RP), 30.0);
|
||||
}
|
||||
// filling stroke, neutral and the positions of the ep brake, where the handle has them
|
||||
hold(Vehicle, Trace, "filling stroke", handle.GetPos(bh_FS), 10.0);
|
||||
hold(Vehicle, Trace, "neutral", handle.GetPos(bh_NP), 20.0);
|
||||
hold(Vehicle, Trace, "first step", handle.GetPos(bh_MB), 20.0);
|
||||
hold(Vehicle, Trace, "full service", handle.GetPos(bh_FB), 20.0);
|
||||
hold(Vehicle, Trace, "ep release", handle.GetPos(bh_EPR), 10.0);
|
||||
hold(Vehicle, Trace, "ep hold", handle.GetPos(bh_EPN), 10.0);
|
||||
hold(Vehicle, Trace, "ep brake", handle.GetPos(bh_EPB), 10.0);
|
||||
hold(Vehicle, Trace, "running", handle.GetPos(bh_RP), 60.0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("brake handles: every position of the driver's handle of every real vehicle") {
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz(path)};
|
||||
if (false == has_handle(real)) {
|
||||
continue;
|
||||
}
|
||||
test::trace trace{"brake handles/" + path, handle_channels(), 100};
|
||||
every_position(real, trace);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("brake handles: the handles the game knows but none of its vehicles has, fitted to an EU07") {
|
||||
// test is a handle for trying things out, D2 and Westinghouse fall back to the plain handle of the base class
|
||||
for (auto const *name : {"test", "D2", "Westinghouse", "MHZ_EN57", "St113", "no such handle"}) {
|
||||
CAPTURE(name);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz("4e_v1/4e").set("Cntrl", "BrakeHandle", name)};
|
||||
test::trace trace{std::string{"brake handles/fitted/"} + name, handle_channels(), 100};
|
||||
every_position(real, trace);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("brake handles: the local brake handle of every real vehicle") {
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz(path)};
|
||||
if (false == has_handle(real)) {
|
||||
continue;
|
||||
}
|
||||
real.hold_main_reservoir(std::max(real->MaxCompressor, 8.0));
|
||||
test::trace trace{"local brake/" + path, handle_channels(), 100};
|
||||
real.record(trace);
|
||||
real->BrakeLevelSet(real->Handle->GetPos(bh_RP));
|
||||
trace.mark("charge");
|
||||
real.run(60.0);
|
||||
for (auto const position : {0.25, 0.5, 1.0, 0.5, 0.0}) {
|
||||
trace.mark(std::format("local {:f}", position));
|
||||
real->LocalBrakePosA = position;
|
||||
real.run(15.0);
|
||||
}
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("brake handles: the overload and the high pressure buttons of the MHZ handles") {
|
||||
// the overload button charges the pipe over its running pressure (TP), which then decays; the high pressure
|
||||
// button gives the filling stroke its overpressure, where the handle has one only with the button pressed.
|
||||
// from the cab, with the battery on and the driver attending to the vigilance: the electro-pneumatic handles
|
||||
// work only so
|
||||
// the MHZ_EN57, whose unit doesn't charge its pipe alone, fitted to an EU07
|
||||
for (auto const &[name, definition] : std::vector<std::pair<std::string, test::definition>>{
|
||||
{"eu47", definition::fiz("e186_v2/eu47")},
|
||||
{"e6act", definition::fiz("e6act_v2/e6acta")},
|
||||
{"eu07 with MHZ_EN57", definition::fiz("4e_v1/4e").set("Cntrl", "BrakeHandle", "MHZ_EN57")}}) {
|
||||
CAPTURE(name);
|
||||
test::reseed_random();
|
||||
vehicle real{definition, 0.0, "test", 1};
|
||||
real->BatterySwitch(true);
|
||||
real->CabActivisation();
|
||||
real.hold_main_reservoir(std::max(real->MaxCompressor, 8.0));
|
||||
test::trace trace{"brake handles/buttons/" + name, handle_channels(), 100};
|
||||
real.record(trace);
|
||||
auto &handle{*real->Handle};
|
||||
auto const at{[&trace, &real](std::string const &Event, double Position, double Seconds) {
|
||||
trace.mark(Event);
|
||||
real->BrakeLevelSet(Position);
|
||||
test::drive(test::driving(real), {}, Seconds);
|
||||
}};
|
||||
at("running", handle.GetPos(bh_RP), 60.0);
|
||||
auto const running{real->PipePress};
|
||||
handle.SetUniversalFlag(TUniversalBrake::ub_Overload);
|
||||
at("overload button", handle.GetPos(bh_RP), 30.0);
|
||||
handle.SetUniversalFlag(0);
|
||||
auto const overloaded{real->PipePress};
|
||||
at("overload decaying", handle.GetPos(bh_RP), 240.0);
|
||||
auto const decayed{real->PipePress};
|
||||
handle.SetUniversalFlag(TUniversalBrake::ub_HighPressure);
|
||||
at("high pressure button, filling stroke", handle.GetPos(bh_FS), 10.0);
|
||||
auto const filled{real->PipePress};
|
||||
handle.SetUniversalFlag(0);
|
||||
at("running", handle.GetPos(bh_RP), 120.0);
|
||||
CHECK(running == doctest::Approx(5.0).epsilon(0.01));
|
||||
CHECK(overloaded > running + 0.3);
|
||||
CHECK(decayed < overloaded);
|
||||
CHECK(filled >= decayed - 0.05);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
229
tests/unit/test_cab.cpp
Normal file
229
tests/unit/test_cab.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "consist.h"
|
||||
#include "scenario.h"
|
||||
#include "drive.h"
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
#include "utilities/utilities.h"
|
||||
|
||||
// characterisation of what the cab (Train.cpp) and the AI (Driver.cpp, driverhints.cpp) call on a vehicle
|
||||
// besides the controls of test_controls.cpp: the gauges and lamps reading other vehicles of the train, the
|
||||
// controller of the electrodynamic brake apart from the local brake, the spring brake, the ep brake's fuse,
|
||||
// cutting off damaged motors, the cab activated by itself, a road vehicle's place across the road, and the
|
||||
// lamps and the buzzer of the security system
|
||||
|
||||
using test::consist;
|
||||
using test::definition;
|
||||
using test::scenario;
|
||||
using test::vehicle;
|
||||
using namespace test::channels;
|
||||
|
||||
TEST_CASE("cab: the engine rotation of up to three vehicles in multiple, on the tachometers of the SN61") {
|
||||
consist train;
|
||||
auto &first{train.add(definition::fiz("sn61_v2/sn61"), 1).mover()};
|
||||
auto &second{train.add(definition::fiz("sn61_v2/sn61")).mover()};
|
||||
auto &third{train.add(definition::fiz("sn61_v2/sn61")).mover()};
|
||||
first.enrot = -10.0;
|
||||
second.enrot = 20.0;
|
||||
third.enrot = 30.0;
|
||||
CHECK(first.ShowEngineRotation(1) == doctest::Approx(10.0));
|
||||
CHECK(first.ShowEngineRotation(2) == doctest::Approx(20.0));
|
||||
CHECK(first.ShowEngineRotation(3) == doctest::Approx(30.0));
|
||||
CHECK(first.ShowEngineRotation(4) == doctest::Approx(0.0));
|
||||
// the others look the same way along their couplers, front first
|
||||
CHECK(second.ShowEngineRotation(2) == doctest::Approx(10.0));
|
||||
CHECK(third.ShowEngineRotation(2) == doctest::Approx(20.0));
|
||||
CHECK(third.ShowEngineRotation(3) == doctest::Approx(10.0));
|
||||
// no control cable, no reading
|
||||
consist apart;
|
||||
auto const &alone{apart.add(definition::fiz("sn61_v2/sn61"), 1).mover()};
|
||||
apart.add(definition::fiz("sn61_v2/sn61"), 0, coupling::coupler | coupling::brakehose);
|
||||
CHECK(alone.ShowEngineRotation(2) == doctest::Approx(0.0));
|
||||
}
|
||||
|
||||
TEST_CASE("cab: the lamps of the overload relay and the starting resistors, read through the control cable") {
|
||||
consist unit;
|
||||
auto &trailer{unit.add(definition::fiz("ed72_v1/5bs-ra"), 1).mover()};
|
||||
auto &motor{unit.add(definition::fiz("ed72_v1/6bs-sa")).mover()};
|
||||
REQUIRE(trailer.Power < 0.01);
|
||||
REQUIRE(motor.Power > 0.01);
|
||||
CHECK_FALSE(trailer.FuseFlagCheck());
|
||||
CHECK_FALSE(trailer.ResistorsFlagCheck());
|
||||
motor.FuseFlag = true;
|
||||
motor.ResistorsFlag = true;
|
||||
CHECK(trailer.FuseFlagCheck());
|
||||
CHECK(trailer.ResistorsFlagCheck());
|
||||
CHECK(motor.FuseFlagCheck());
|
||||
CHECK(motor.ResistorsFlagCheck());
|
||||
}
|
||||
|
||||
TEST_CASE("cab: the engine's idle speed, and the ET42's second controller shown in its dynamic brake") {
|
||||
vehicle sn61{definition::fiz("sn61_v2/sn61")};
|
||||
CHECK(sn61->EngineIdleRPM() == doctest::Approx(sn61->dizel_nmin * 60.0));
|
||||
vehicle su45{definition::fiz("su45_v2/301d")};
|
||||
CHECK(su45->EngineIdleRPM() == doctest::Approx(su45->DElist[su45->MainCtrlNoPowerPos()].RPM));
|
||||
vehicle eu07{definition::fiz("4e_v1/4e")};
|
||||
CHECK(eu07->EngineIdleRPM() == std::numeric_limits<double>::max());
|
||||
|
||||
vehicle et42{definition::fiz("et42_v2/112e-a")};
|
||||
CHECK(et42->GetVirtualScndPos() == 0);
|
||||
et42->DynamicBrakeFlag = true;
|
||||
CHECK(et42->GetVirtualScndPos() == -1);
|
||||
et42->ScndCtrlPos = 1;
|
||||
CHECK(et42->GetVirtualScndPos() == 1);
|
||||
// with a speed control in place of the second controller, either end of it, for the AI
|
||||
vehicle railbus{definition::fiz("21xm_v1/214ma")};
|
||||
REQUIRE(railbus->SpeedCtrl);
|
||||
railbus->ScndCtrlPos = 1;
|
||||
CHECK(railbus->IsScndCtrlNoPowerPos());
|
||||
CHECK(railbus->IsScndCtrlMaxPowerPos());
|
||||
CHECK(eu07->IsScndCtrlNoPowerPos());
|
||||
CHECK_FALSE(eu07->IsScndCtrlMaxPowerPos());
|
||||
}
|
||||
|
||||
TEST_CASE("cab: the controller of the electrodynamic brake apart from the local brake") {
|
||||
// none of the game's vehicles has one yet (SplitEDPneumaticBrake): the electrodynamic brake follows its own
|
||||
// controller of DBPN positions, the local brake is pneumatic alone
|
||||
scenario scenario{"cab/split electrodynamic brake", motion() + traction() + brakes()};
|
||||
scenario.add("e186_v2/eu47", 1, consist::full_coupling, 100.0).add("bdhpumn_v3/bdhpumn", 0, consist::full_coupling, 100.0);
|
||||
auto &eu47{scenario.cab()};
|
||||
CHECK_FALSE(eu47.IncDynamicBrakeLevel(1.f));
|
||||
CHECK(eu47.DynamicBrakeRatio() == doctest::Approx(0.0));
|
||||
|
||||
scenario.train()[0].mover().SplitEDPneumaticBrake = true;
|
||||
REQUIRE(scenario.start_up());
|
||||
REQUIRE(eu47.DynamicBrakeCtrlPosNo == 10);
|
||||
CHECK(eu47.DynamicBrakeAvailable());
|
||||
scenario.act("dynamic brake up");
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
CHECK(eu47.IncDynamicBrakeLevel(1.f));
|
||||
}
|
||||
CHECK(eu47.DynamicBrakeRatio() == doctest::Approx(0.5));
|
||||
scenario.wait(10.0);
|
||||
CHECK(eu47.DynamicBrakeFlag);
|
||||
CHECK(eu47.Im < -50.0);
|
||||
CHECK(eu47.BrakePress < 0.1);
|
||||
scenario.act("dynamic brake full");
|
||||
CHECK(eu47.DynamicBrakeLevelSet(2.0));
|
||||
CHECK(eu47.DynamicBrakeRatio() == doctest::Approx(1.0));
|
||||
CHECK_FALSE(eu47.IncDynamicBrakeLevel(1.f));
|
||||
scenario.wait(10.0);
|
||||
scenario.act("dynamic brake off");
|
||||
for (int i = 0; i < 20 && eu47.DecDynamicBrakeLevel(1.f); ++i) {
|
||||
// down a notch at a time
|
||||
}
|
||||
CHECK(eu47.DynamicBrakeRatio() == doctest::Approx(0.0));
|
||||
// the local brake no longer brings the motors in
|
||||
scenario.act("local brake");
|
||||
eu47.IncLocalBrakeLevel(LocalBrakePosNo);
|
||||
scenario.wait(5.0);
|
||||
CHECK(eu47.BrakePress > 1.0);
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("cab: the spring brake shut off and released by hand, the ep brake's fuse, the train brake handle stepped") {
|
||||
scenario scenario{"cab/214m spring brake", motion() + brakes()};
|
||||
scenario.add("21xm_v1/214ma", 1);
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &railbus{scenario.cab()};
|
||||
scenario.act("spring brake on");
|
||||
railbus.SpringBrakeActivate(true);
|
||||
scenario.wait(10.0);
|
||||
CHECK(railbus.SpringBrake.IsActive);
|
||||
// released by hand only with its cylinder empty of the air holding it off
|
||||
auto const pressure{railbus.SpringBrake.Cylinder->P()};
|
||||
CHECK(railbus.SpringBrakeRelease() == (pressure < railbus.SpringBrake.MinForcePressure));
|
||||
scenario.act("shut off");
|
||||
CHECK(railbus.SpringBrakeShutOff(true));
|
||||
CHECK_FALSE(railbus.SpringBrakeShutOff(true));
|
||||
scenario.wait(5.0);
|
||||
CHECK(railbus.SpringBrakeShutOff(false));
|
||||
scenario.act("spring brake off");
|
||||
railbus.SpringBrakeActivate(false);
|
||||
scenario.wait(10.0);
|
||||
// the ep brake's fuse
|
||||
CHECK(railbus.EpFuseSwitch(false));
|
||||
CHECK_FALSE(railbus.EpFuseSwitch(false));
|
||||
CHECK(railbus.EpFuseSwitch(true));
|
||||
// the train brake handle stepped as the AI does, false at its ends
|
||||
scenario.act("handle stepped");
|
||||
railbus.BrakeLevelSet(railbus.Handle->GetPos(bh_RP));
|
||||
CHECK(railbus.BrakeLevelAdd(1.0));
|
||||
CHECK(railbus.BrakeCtrlPos == static_cast<int>(railbus.Handle->GetPos(bh_RP)) + 1);
|
||||
CHECK(railbus.BrakeLevelAdd(-1.0));
|
||||
CHECK_FALSE(railbus.BrakeLevelAdd(-10.0));
|
||||
CHECK_FALSE(railbus.BrakeLevelAdd(100.0));
|
||||
scenario.wait(5.0);
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("cab: damaged motors cut off in a car without a driver") {
|
||||
// cutting off takes the damage off the engine and half of the powered axles with it; only in a car nobody
|
||||
// drives, with its engine damaged
|
||||
vehicle driven{definition::fiz("ew58_v1/ew58-sa"), 0.0, "test", 1};
|
||||
driven->BatterySwitch(true);
|
||||
REQUIRE(driven->CabActivisation());
|
||||
driven->DamageFlag |= dtrain_engine;
|
||||
CHECK_FALSE(driven->CutOffEngine());
|
||||
vehicle car{definition::fiz("ew58_v1/ew58-sa")};
|
||||
auto const axles{car->NPoweredAxles};
|
||||
CHECK_FALSE(car->CutOffEngine());
|
||||
car->DamageFlag |= dtrain_engine;
|
||||
CHECK(car->CutOffEngine());
|
||||
CHECK(car->NPoweredAxles == axles / 2);
|
||||
CHECK_FALSE(TestFlag(car->DamageFlag, dtrain_engine));
|
||||
vehicle wagon{definition::fiz("3wl_v2/3wl")};
|
||||
wagon->DamageFlag |= dtrain_engine;
|
||||
CHECK_FALSE(wagon->CutOffEngine());
|
||||
}
|
||||
|
||||
TEST_CASE("cab: activated by itself, where the vehicle allows it") {
|
||||
for (auto const allowed : {false, true}) {
|
||||
CAPTURE(allowed);
|
||||
vehicle eu07{definition::fiz("4e_v1/4e").set("Cntrl", "AutomaticCabActivation", allowed ? "Yes" : "No"), 0.0, "test", 1};
|
||||
eu07->BatterySwitch(true);
|
||||
CHECK(eu07->CabActivisationAuto() == allowed);
|
||||
CHECK((eu07->CabActive != 0) == allowed);
|
||||
CHECK(eu07->CabDeactivisationAuto() == allowed);
|
||||
CHECK(eu07->CabActive == 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("cab: a road vehicle moved across its road") {
|
||||
vehicle bus{definition::fiz("road/man/nl293")};
|
||||
bus.step(test::track{0.15, 0.0, 0.0, 2, 1, 7.0});
|
||||
REQUIRE(TestFlag(bus->CategoryFlag, 2));
|
||||
CHECK(bus->ChangeOffsetH(0.5));
|
||||
CHECK(bus->OffsetTrackH == doctest::Approx(0.5));
|
||||
// off the edge of the road
|
||||
CHECK_FALSE(bus->ChangeOffsetH(100.0));
|
||||
vehicle eu07{definition::fiz("4e_v1/4e")};
|
||||
CHECK_FALSE(eu07->ChangeOffsetH(0.5));
|
||||
}
|
||||
|
||||
TEST_CASE("cab: the lamps and the buzzer of the security system left unattended") {
|
||||
scenario scenario{"cab/security system", motion() + brakes()};
|
||||
scenario.add("4e_v1/4e", 1);
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &eu07{scenario.cab()};
|
||||
scenario.get_going();
|
||||
scenario.full_power(10.0);
|
||||
auto const &security{eu07.SecuritySystem};
|
||||
CHECK_FALSE(security.is_beeping());
|
||||
scenario.act("unattended");
|
||||
// the train runs with nobody acknowledging the vigilance
|
||||
bool blinked{false};
|
||||
bool beeped{false};
|
||||
for (int i = 0; i < 120; ++i) {
|
||||
scenario.train().run(1.0, scenario.line());
|
||||
blinked |= security.is_vigilance_blinking();
|
||||
beeped |= security.is_beeping();
|
||||
}
|
||||
CHECK(blinked);
|
||||
CHECK(beeped);
|
||||
CHECK_FALSE(security.is_cabsignal_beeping());
|
||||
CHECK(eu07.PipePress < 1.0);
|
||||
CHECK(security.radiostop_available());
|
||||
scenario.check();
|
||||
}
|
||||
547
tests/unit/test_commands.cpp
Normal file
547
tests/unit/test_commands.cpp
Normal file
@@ -0,0 +1,547 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
#include "golden.h"
|
||||
#include "consist.h"
|
||||
#include "real_vehicles.h"
|
||||
|
||||
#include <format>
|
||||
#include <functional>
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
|
||||
// characterisation of the commands vehicles pass each other along the couplers (RunCommand): what each of them
|
||||
// does to every real vehicle, recorded in golden traces (data/golden/commands/), how they travel through a train of
|
||||
// vehicles coupled either way round, and the loading and unloading driven by them
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
namespace {
|
||||
|
||||
double flag(bool Value) {
|
||||
return Value ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
// what the commands change
|
||||
std::vector<test::channel> state() {
|
||||
std::vector<test::channel> result{
|
||||
{"MainCtrlPos", [](auto const &M) { return M.MainCtrlPos; }},
|
||||
{"ScndCtrlPos", [](auto const &M) { return M.ScndCtrlPos; }},
|
||||
{"LastRelayTime", [](auto const &M) { return M.LastRelayTime; }},
|
||||
{"eimic_real", [](auto const &M) { return M.eimic_real; }},
|
||||
{"TUHEX_StageActual", [](auto const &M) { return M.TUHEX_StageActual; }},
|
||||
{"TUHEX_Active", [](auto const &M) { return flag(M.TUHEX_Active); }},
|
||||
{"DynamicBrakeEMUStatus", [](auto const &M) { return flag(M.DynamicBrakeEMUStatus); }},
|
||||
{"BrakeReleaser", [](auto const &M) { return flag(M.Hamulec->Releaser()); }},
|
||||
{"WaterPumpBreaker", [](auto const &M) { return flag(M.WaterPump.breaker); }},
|
||||
{"WaterPumpEnabled", [](auto const &M) { return flag(M.WaterPump.is_enabled); }},
|
||||
{"WaterPumpDisabled", [](auto const &M) { return flag(M.WaterPump.is_disabled); }},
|
||||
{"WaterHeaterBreaker", [](auto const &M) { return flag(M.WaterHeater.breaker); }},
|
||||
{"WaterHeaterEnabled", [](auto const &M) { return flag(M.WaterHeater.is_enabled); }},
|
||||
{"WaterCircuitsLink", [](auto const &M) { return flag(M.WaterCircuitsLink); }},
|
||||
{"FuelPumpEnabled", [](auto const &M) { return flag(M.FuelPump.is_enabled); }},
|
||||
{"FuelPumpDisabled", [](auto const &M) { return flag(M.FuelPump.is_disabled); }},
|
||||
{"OilPumpEnabled", [](auto const &M) { return flag(M.OilPump.is_enabled); }},
|
||||
{"OilPumpDisabled", [](auto const &M) { return flag(M.OilPump.is_disabled); }},
|
||||
{"CompartmentLightsEnabled", [](auto const &M) { return flag(M.CompartmentLights.is_enabled); }},
|
||||
{"CompartmentLightsDisabled", [](auto const &M) { return flag(M.CompartmentLights.is_disabled); }},
|
||||
{"MainSwitch", [](auto const &M) { return flag(M.Mains); }},
|
||||
{"Heating", [](auto const &M) { return flag(M.Heating); }},
|
||||
{"DirActive", [](auto const &M) { return M.DirActive; }},
|
||||
{"DirAbsolute", [](auto const &M) { return M.DirAbsolute; }},
|
||||
{"CabActive", [](auto const &M) { return M.CabActive; }},
|
||||
{"CabMaster", [](auto const &M) { return flag(M.CabMaster); }},
|
||||
{"AutoRelayFlag", [](auto const &M) { return flag(M.AutoRelayFlag); }},
|
||||
{"ConverterAllow", [](auto const &M) { return flag(M.ConverterAllow); }},
|
||||
{"Battery", [](auto const &M) { return flag(M.Battery); }},
|
||||
{"CompressorAllow", [](auto const &M) { return flag(M.CompressorAllow); }},
|
||||
{"CompressorListPos", [](auto const &M) { return M.CompressorListPos; }},
|
||||
{"DoorLock", [](auto const &M) { return flag(M.Doors.lock_enabled); }},
|
||||
{"DoorStep", [](auto const &M) { return flag(M.Doors.step_enabled); }},
|
||||
{"DoorRemoteOnly", [](auto const &M) { return flag(M.Doors.remote_only); }},
|
||||
{"DepartureSignal", [](auto const &M) { return flag(M.DepartureSignal); }},
|
||||
{"PantsValve", [](auto const &M) { return flag(M.PantsValve.is_enabled) + 2 * flag(M.PantsValve.is_disabled); }},
|
||||
{"MaxCurrentHigh", [](auto const &M) { return flag(M.MotorOverloadRelayHighThreshold); }},
|
||||
{"Imin", [](auto const &M) { return M.Imin; }},
|
||||
{"DamageFlag", [](auto const &M) { return M.DamageFlag; }},
|
||||
{"RadioStop", [](auto const &M) { return flag(M.RadioStopFlag); }},
|
||||
{"BrakeDelayFlag", [](auto const &M) { return M.BrakeDelayFlag; }},
|
||||
{"SandDose", [](auto const &M) { return flag(M.SandDose); }},
|
||||
{"CabSignal", [](auto const &M) { return flag(M.SecuritySystem.is_cabsignal_blinking()); }},
|
||||
{"LoadAmount", [](auto const &M) { return M.LoadAmount; }},
|
||||
{"LoadStatus", [](auto const &M) { return M.LoadStatus; }},
|
||||
{"SpeedCtrlValue", [](auto const &M) { return M.SpeedCtrlValue; }},
|
||||
{"SpeedCtrlParking", [](auto const &M) { return flag(M.SpeedCtrlUnit.Parking); }},
|
||||
{"SpringBrakeActivate", [](auto const &M) { return flag(M.SpringBrake.Activate); }},
|
||||
};
|
||||
for (int end : {end::front, end::rear}) {
|
||||
auto const name{std::string{end == end::front ? "Front" : "Rear"}};
|
||||
result.emplace_back("MotorBlowers" + name + "Enabled", [end](auto const &M) { return flag(M.MotorBlowers[end].is_enabled); });
|
||||
result.emplace_back("MotorBlowers" + name + "Disabled", [end](auto const &M) { return flag(M.MotorBlowers[end].is_disabled); });
|
||||
result.emplace_back("Pant" + name + "Valve", [end](auto const &M) { return flag(M.Pantographs[end].valve.is_enabled) + 2 * flag(M.Pantographs[end].valve.is_disabled); });
|
||||
}
|
||||
for (int side : {side::right, side::left}) {
|
||||
auto const name{std::string{side == side::right ? "Right" : "Left"}};
|
||||
result.emplace_back(name + "DoorPermit", [side](auto const &M) { return flag(M.Doors.instances[side].open_permit); });
|
||||
result.emplace_back(name + "DoorRemoteOpen", [side](auto const &M) { return flag(M.Doors.instances[side].remote_open); });
|
||||
result.emplace_back(name + "DoorRemoteClose", [side](auto const &M) { return flag(M.Doors.instances[side].remote_close); });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
struct command {
|
||||
std::string name;
|
||||
double value1;
|
||||
double value2{1.0}; // the direction it comes from, 1 the front
|
||||
};
|
||||
|
||||
// every command RunCommand knows, with values taking each of its ways, and one it doesn't
|
||||
std::vector<command> const commands{
|
||||
{"MainCtrl", 1},
|
||||
{"MainCtrl", 2},
|
||||
{"MainCtrl", 0},
|
||||
{"MainCtrl", 99},
|
||||
{"ScndCtrl", 1},
|
||||
{"ScndCtrl", 0},
|
||||
{"ScndCtrl", 99},
|
||||
{"EIMIC", 0.5},
|
||||
{"EIMIC", -0.5},
|
||||
{"Brake", 1},
|
||||
{"Brake", 2},
|
||||
{"Brake", 0},
|
||||
{"BrakeReleaser", 1},
|
||||
{"BrakeReleaser", 0},
|
||||
{"WaterPumpBreakerSwitch", 1},
|
||||
{"WaterPumpSwitch", 1},
|
||||
{"WaterPumpSwitchOff", 1},
|
||||
{"WaterPumpSwitchOff", 0},
|
||||
{"WaterPumpSwitch", 0},
|
||||
{"WaterPumpBreakerSwitch", 0},
|
||||
{"WaterHeaterBreakerSwitch", 1},
|
||||
{"WaterHeaterSwitch", 1},
|
||||
{"WaterHeaterSwitch", 0},
|
||||
{"WaterHeaterBreakerSwitch", 0},
|
||||
{"WaterCircuitsLinkSwitch", 1},
|
||||
{"WaterCircuitsLinkSwitch", 0},
|
||||
{"FuelPumpSwitch", 1},
|
||||
{"FuelPumpSwitchOff", 1},
|
||||
{"FuelPumpSwitchOff", 0},
|
||||
{"FuelPumpSwitch", 0},
|
||||
{"OilPumpSwitch", 1},
|
||||
{"OilPumpSwitchOff", 1},
|
||||
{"OilPumpSwitchOff", 0},
|
||||
{"OilPumpSwitch", 0},
|
||||
{"MotorBlowersFrontSwitch", 1},
|
||||
{"MotorBlowersFrontSwitchOff", 1},
|
||||
{"MotorBlowersFrontSwitchOff", 0},
|
||||
{"MotorBlowersFrontSwitch", 0},
|
||||
{"MotorBlowersRearSwitch", 1},
|
||||
{"MotorBlowersRearSwitchOff", 1},
|
||||
{"MotorBlowersRearSwitchOff", 0},
|
||||
{"MotorBlowersRearSwitch", 0},
|
||||
{"CompartmentLightsSwitch", 1},
|
||||
{"CompartmentLightsSwitchOff", 1},
|
||||
{"CompartmentLightsSwitchOff", 0},
|
||||
{"CompartmentLightsSwitch", 0},
|
||||
{"BatterySwitch", 1},
|
||||
{"ConverterSwitch", 1},
|
||||
{"CompressorSwitch", 1},
|
||||
{"CompressorPreset", 1},
|
||||
{"CompressorPreset", 99},
|
||||
{"CompressorPreset", -1},
|
||||
{"MainSwitch", 1},
|
||||
{"HeatingSwitch", 1},
|
||||
{"HeatingSwitch", 0},
|
||||
{"Direction", 1},
|
||||
{"Direction", -1},
|
||||
{"Direction", 0},
|
||||
{"CabActivisation", 1, 1},
|
||||
{"CabActivisation", 1, -1},
|
||||
{"CabActivisation", 0, 1},
|
||||
{"AutoRelaySwitch", 1},
|
||||
{"AutoRelaySwitch", 0},
|
||||
{"RelayReset", 1},
|
||||
{"DoorPermit", 1, 1},
|
||||
{"DoorPermit", 2, 1},
|
||||
{"DoorPermit", -3, 1},
|
||||
{"DoorPermit", 1, -1},
|
||||
{"DoorPermit", 3, -1},
|
||||
{"DoorOpen", 1, 1},
|
||||
{"DoorOpen", 2, -1},
|
||||
{"DoorClose", 3, 1},
|
||||
{"DoorOpen", 3, 1},
|
||||
{"DoorClose", 1, -1},
|
||||
{"DoorLock", 0},
|
||||
{"DoorLock", 1},
|
||||
{"DoorStep", 0},
|
||||
{"DoorStep", 1},
|
||||
{"DoorMode", 1},
|
||||
{"DoorMode", 0},
|
||||
{"DepartureSignal", 1},
|
||||
{"DepartureSignal", 0},
|
||||
{"PantValve", 1},
|
||||
{"PantValve", 0x80 | 1},
|
||||
{"PantValve", 0x40 | 1, -1},
|
||||
{"PantValve", 0x80 | 0x40 | 2, -1},
|
||||
{"PantValve", 3},
|
||||
{"PantValve", 4},
|
||||
{"PantValve", 0x80 | 5},
|
||||
{"PantValve", 0x80 | 6},
|
||||
{"PantsValve", 1},
|
||||
{"PantsValve", 2},
|
||||
{"PantsValve", 3},
|
||||
{"PantsValve", 4},
|
||||
{"PantsValve", 5},
|
||||
{"PantsValve", 6},
|
||||
{"PantAllDown", 1},
|
||||
{"PantAllDown", 0},
|
||||
{"MaxCurrentSwitch", 1},
|
||||
{"MaxCurrentSwitch", 0},
|
||||
{"MinCurrentSwitch", 1},
|
||||
{"MinCurrentSwitch", 0},
|
||||
{"SetDamage", 4, 1},
|
||||
{"SetDamage", 4, -1},
|
||||
{"SetDamage", 4, 0},
|
||||
{"Emergency_brake", 1},
|
||||
{"Emergency_brake", 0},
|
||||
{"BrakeDelay", 1},
|
||||
{"BrakeDelay", 2},
|
||||
{"BrakeDelay", 4},
|
||||
{"BrakeDelay", 8},
|
||||
{"BrakeDelay", 5},
|
||||
{"Sandbox", 1},
|
||||
{"Sandbox", 0},
|
||||
{"CabSignal", 0},
|
||||
{"Load=coal", 5, 0},
|
||||
{"Load=Coal", 5, 20},
|
||||
{"UnLoad=coal", 5, 0},
|
||||
{"UnLoad=Coal", 5, 0},
|
||||
{"SpeedCntrl", 40.4},
|
||||
{"SpeedCtrlUnit.Parking", 1},
|
||||
{"SpeedCtrlUnit.Parking", 0},
|
||||
{"SpringBrakeActivate", 1},
|
||||
{"SpringBrakeActivate", 0},
|
||||
{"MainSwitch", 0},
|
||||
{"CompressorSwitch", 0},
|
||||
{"ConverterSwitch", 0},
|
||||
{"BatterySwitch", 0},
|
||||
{"SpringBrakeActivate", 1},
|
||||
{"NoSuchCommand", 1},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("commands: every command run on every real vehicle") {
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz(path), 0.0, "test", 1};
|
||||
// loading takes place where the command was given, which comes with the command (PutCommand). a
|
||||
// vehicle gets none before its first one, TCommand::Location is left uninitialised
|
||||
real->CommandIn.Location = real->Loc;
|
||||
auto done{false};
|
||||
auto channels{state()};
|
||||
channels.emplace_back("Done", [&done](auto const &) { return flag(done); });
|
||||
test::trace trace{"commands/" + path, channels, 1, false};
|
||||
trace.sample(0.0, real.mover());
|
||||
for (std::size_t i = 0; i < commands.size(); ++i) {
|
||||
auto const &command{commands[i]};
|
||||
trace.mark(std::format("{} {} {}", command.name, command.value1, command.value2));
|
||||
done = real->RunCommand(command.name, command.value1, command.value2, coupling::control);
|
||||
trace.sample(static_cast<double>(i + 1), real.mover());
|
||||
}
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// a switch of the cab, worked on the driven vehicle
|
||||
struct action {
|
||||
std::string name;
|
||||
std::function<bool(TMoverParameters &)> work;
|
||||
};
|
||||
|
||||
// every switch sending its state to the rest of the train, each way and to each range, in the order a crew
|
||||
// could work them, with the controllers and the direction among them to see what they make of the state
|
||||
std::vector<action> const actions{
|
||||
{"CabActivisation", [](auto &M) { return M.CabActivisation(); }},
|
||||
{"BatterySwitch on", [](auto &M) { return M.BatterySwitch(true, range_t::consist); }},
|
||||
{"CompartmentLightsSwitch on", [](auto &M) { return M.CompartmentLightsSwitch(true, range_t::consist); }},
|
||||
{"CompartmentLightsSwitchOff on", [](auto &M) { return M.CompartmentLightsSwitchOff(true, range_t::consist); }},
|
||||
{"CompartmentLightsSwitchOff off", [](auto &M) { return M.CompartmentLightsSwitchOff(false, range_t::unit); }},
|
||||
{"WaterPumpBreakerSwitch on", [](auto &M) { return M.WaterPumpBreakerSwitch(true, range_t::consist); }},
|
||||
{"WaterPumpSwitch on", [](auto &M) { return M.WaterPumpSwitch(true, range_t::consist); }},
|
||||
{"WaterPumpSwitchOff on", [](auto &M) { return M.WaterPumpSwitchOff(true, range_t::unit); }},
|
||||
{"WaterPumpSwitchOff off", [](auto &M) { return M.WaterPumpSwitchOff(false, range_t::consist); }},
|
||||
{"WaterHeaterBreakerSwitch on", [](auto &M) { return M.WaterHeaterBreakerSwitch(true, range_t::consist); }},
|
||||
{"WaterHeaterSwitch on", [](auto &M) { return M.WaterHeaterSwitch(true, range_t::consist); }},
|
||||
{"WaterCircuitsLinkSwitch on", [](auto &M) { return M.WaterCircuitsLinkSwitch(true, range_t::consist); }},
|
||||
{"FuelPumpSwitch on", [](auto &M) { return M.FuelPumpSwitch(true, range_t::consist); }},
|
||||
{"FuelPumpSwitchOff on", [](auto &M) { return M.FuelPumpSwitchOff(true, range_t::unit); }},
|
||||
{"FuelPumpSwitchOff off", [](auto &M) { return M.FuelPumpSwitchOff(false, range_t::consist); }},
|
||||
{"OilPumpSwitch on", [](auto &M) { return M.OilPumpSwitch(true, range_t::consist); }},
|
||||
{"OilPumpSwitchOff on", [](auto &M) { return M.OilPumpSwitchOff(true, range_t::unit); }},
|
||||
{"OilPumpSwitchOff off", [](auto &M) { return M.OilPumpSwitchOff(false, range_t::consist); }},
|
||||
{"MotorBlowersSwitch front on", [](auto &M) { return M.MotorBlowersSwitch(true, end::front, range_t::consist); }},
|
||||
{"MotorBlowersSwitch rear on", [](auto &M) { return M.MotorBlowersSwitch(true, end::rear, range_t::unit); }},
|
||||
{"MotorBlowersSwitchOff front on", [](auto &M) { return M.MotorBlowersSwitchOff(true, end::front, range_t::consist); }},
|
||||
{"MotorBlowersSwitchOff rear on", [](auto &M) { return M.MotorBlowersSwitchOff(true, end::rear, range_t::unit); }},
|
||||
{"MotorBlowersSwitchOff front off", [](auto &M) { return M.MotorBlowersSwitchOff(false, end::front, range_t::consist); }},
|
||||
{"MotorBlowersSwitchOff rear off", [](auto &M) { return M.MotorBlowersSwitchOff(false, end::rear, range_t::consist); }},
|
||||
{"OperatePantographsValve enable", [](auto &M) { return M.OperatePantographsValve(operation_t::enable, range_t::consist); }},
|
||||
{"OperatePantographValve front enable", [](auto &M) { return M.OperatePantographValve(end::front, operation_t::enable, range_t::consist); }},
|
||||
{"OperatePantographValve rear enable_on", [](auto &M) { return M.OperatePantographValve(end::rear, operation_t::enable_on, range_t::unit); }},
|
||||
{"OperatePantographValve rear enable_off", [](auto &M) { return M.OperatePantographValve(end::rear, operation_t::enable_off, range_t::unit); }},
|
||||
{"DirectionForward", [](auto &M) { return M.DirectionForward(); }},
|
||||
{"ConverterSwitch on", [](auto &M) { return M.ConverterSwitch(true, range_t::consist); }},
|
||||
{"CompressorSwitch on", [](auto &M) { return M.CompressorSwitch(true, range_t::consist); }},
|
||||
{"ChangeCompressorPreset 1", [](auto &M) { return M.ChangeCompressorPreset(1, range_t::consist); }},
|
||||
{"FuseOn", [](auto &M) { return M.FuseOn(range_t::consist); }},
|
||||
{"RelayReset all", [](auto &M) { return M.RelayReset(0xff, range_t::consist); }},
|
||||
{"UniversalResetButton 1", [](auto &M) { return M.UniversalResetButton(0, range_t::consist); }},
|
||||
{"UniversalResetButton 2", [](auto &M) { return M.UniversalResetButton(1, range_t::unit); }},
|
||||
{"MainSwitch on", [](auto &M) { return M.MainSwitch(true, range_t::consist); }},
|
||||
{"HeatingSwitch on", [](auto &M) { return M.HeatingSwitch(true, range_t::consist); }},
|
||||
{"MaxCurrentSwitch on", [](auto &M) { return M.MaxCurrentSwitch(true, range_t::consist); }},
|
||||
{"MinCurrentSwitch on", [](auto &M) { return M.MinCurrentSwitch(true); }},
|
||||
{"CurrentSwitch on", [](auto &M) { return M.CurrentSwitch(true); }},
|
||||
{"AutoRelaySwitch on", [](auto &M) { return M.AutoRelaySwitch(true); }},
|
||||
{"IncMainCtrl 1", [](auto &M) { return M.IncMainCtrl(1); }},
|
||||
{"IncMainCtrl 2", [](auto &M) { return M.IncMainCtrl(2); }},
|
||||
{"IncScndCtrl 1", [](auto &M) { return M.IncScndCtrl(1); }},
|
||||
{"IncScndCtrl 2", [](auto &M) { return M.IncScndCtrl(2); }},
|
||||
{"DecScndCtrl 1", [](auto &M) { return M.DecScndCtrl(1); }},
|
||||
{"DecScndCtrl 2", [](auto &M) { return M.DecScndCtrl(2); }},
|
||||
{"DecMainCtrl 1", [](auto &M) { return M.DecMainCtrl(1); }},
|
||||
{"DecMainCtrl 2", [](auto &M) { return M.DecMainCtrl(2); }},
|
||||
{"AutoRelaySwitch off", [](auto &M) { return M.AutoRelaySwitch(false); }},
|
||||
{"CurrentSwitch off", [](auto &M) { return M.CurrentSwitch(false); }},
|
||||
{"MinCurrentSwitch off", [](auto &M) { return M.MinCurrentSwitch(false); }},
|
||||
{"MaxCurrentSwitch off", [](auto &M) { return M.MaxCurrentSwitch(false, range_t::unit); }},
|
||||
{"DirectionBackward", [](auto &M) { return M.DirectionBackward(); }},
|
||||
{"DirectionBackward again", [](auto &M) { return M.DirectionBackward(); }},
|
||||
{"DirectionForward", [](auto &M) { return M.DirectionForward(); }},
|
||||
{"Sandbox on", [](auto &M) { return M.Sandbox(true, range_t::consist); }},
|
||||
{"SandboxManual on", [](auto &M) { return M.SandboxManual(true, range_t::consist); }},
|
||||
{"SandboxAuto on", [](auto &M) { return M.SandboxAuto(true, range_t::unit); }},
|
||||
{"SandboxAuto off", [](auto &M) { return M.SandboxAuto(false, range_t::consist); }},
|
||||
{"SandboxManual off", [](auto &M) { return M.SandboxManual(false, range_t::consist); }},
|
||||
{"Sandbox off", [](auto &M) { return M.Sandbox(false, range_t::consist); }},
|
||||
{"PermitDoors right", [](auto &M) { return M.PermitDoors(side::right, true, range_t::consist); }},
|
||||
{"PermitDoors left", [](auto &M) { return M.PermitDoors(side::left, true, range_t::unit); }},
|
||||
{"ChangeDoorPermitPreset +1", [](auto &M) { return M.ChangeDoorPermitPreset(1, range_t::consist); }},
|
||||
{"ChangeDoorPermitPreset -1", [](auto &M) { return M.ChangeDoorPermitPreset(-1, range_t::consist); }},
|
||||
{"PermitDoorStep off", [](auto &M) { return M.PermitDoorStep(false, range_t::consist); }},
|
||||
{"PermitDoorStep on", [](auto &M) { return M.PermitDoorStep(true, range_t::unit); }},
|
||||
{"LockDoors off", [](auto &M) { return M.LockDoors(false, range_t::consist); }},
|
||||
{"OperateDoors right open local", [](auto &M) { return M.OperateDoors(side::right, true, range_t::local); }},
|
||||
{"OperateDoors left open", [](auto &M) { return M.OperateDoors(side::left, true, range_t::consist); }},
|
||||
{"OperateDoors right close", [](auto &M) { return M.OperateDoors(side::right, false, range_t::unit); }},
|
||||
{"ChangeDoorControlMode remote", [](auto &M) { return M.ChangeDoorControlMode(true, range_t::consist); }},
|
||||
{"ChangeDoorControlMode local", [](auto &M) { return M.ChangeDoorControlMode(false, range_t::unit); }},
|
||||
{"LockDoors on", [](auto &M) { return M.LockDoors(true, range_t::unit); }},
|
||||
{"signal_departure on", [](auto &M) { return M.signal_departure(true, range_t::consist); }},
|
||||
{"signal_departure off", [](auto &M) { return M.signal_departure(false, range_t::unit); }},
|
||||
{"PermitDoors right off", [](auto &M) { return M.PermitDoors(side::right, false, range_t::consist); }},
|
||||
{"HeatingSwitch off", [](auto &M) { return M.HeatingSwitch(false, range_t::unit); }},
|
||||
{"MainSwitch off", [](auto &M) { return M.MainSwitch(false, range_t::consist); }},
|
||||
{"DropAllPantographs", [](auto &M) { return M.DropAllPantographs(true, range_t::consist); }},
|
||||
{"DropAllPantographs released", [](auto &M) { return M.DropAllPantographs(false, range_t::unit); }},
|
||||
{"OperatePantographsValve disable", [](auto &M) { return M.OperatePantographsValve(operation_t::disable, range_t::unit); }},
|
||||
{"OperatePantographValve front disable_on", [](auto &M) { return M.OperatePantographValve(end::front, operation_t::disable_on, range_t::consist); }},
|
||||
{"OperatePantographValve front disable_off", [](auto &M) { return M.OperatePantographValve(end::front, operation_t::disable_off, range_t::consist); }},
|
||||
{"OperatePantographValve front none", [](auto &M) { return M.OperatePantographValve(end::front, operation_t::none, range_t::local); }},
|
||||
{"CompressorSwitch off", [](auto &M) { return M.CompressorSwitch(false, range_t::unit); }},
|
||||
{"ConverterSwitch off", [](auto &M) { return M.ConverterSwitch(false, range_t::unit); }},
|
||||
{"WaterCircuitsLinkSwitch off", [](auto &M) { return M.WaterCircuitsLinkSwitch(false, range_t::unit); }},
|
||||
{"WaterHeaterSwitch off", [](auto &M) { return M.WaterHeaterSwitch(false, range_t::unit); }},
|
||||
{"WaterHeaterBreakerSwitch off", [](auto &M) { return M.WaterHeaterBreakerSwitch(false, range_t::unit); }},
|
||||
{"WaterPumpSwitch off", [](auto &M) { return M.WaterPumpSwitch(false, range_t::unit); }},
|
||||
{"WaterPumpBreakerSwitch off", [](auto &M) { return M.WaterPumpBreakerSwitch(false, range_t::unit); }},
|
||||
{"FuelPumpSwitch off", [](auto &M) { return M.FuelPumpSwitch(false, range_t::unit); }},
|
||||
{"OilPumpSwitch off", [](auto &M) { return M.OilPumpSwitch(false, range_t::unit); }},
|
||||
{"MotorBlowersSwitch front off", [](auto &M) { return M.MotorBlowersSwitch(false, end::front, range_t::unit); }},
|
||||
{"MotorBlowersSwitch rear off", [](auto &M) { return M.MotorBlowersSwitch(false, end::rear, range_t::consist); }},
|
||||
{"CompartmentLightsSwitch off", [](auto &M) { return M.CompartmentLightsSwitch(false, range_t::unit); }},
|
||||
{"BatterySwitch off", [](auto &M) { return M.BatterySwitch(false, range_t::unit); }},
|
||||
{"CabDeactivisation", [](auto &M) { return M.CabDeactivisation(); }},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("commands: every switch of the cab, sent to the next vehicle") {
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
vehicle driven{definition::fiz(path), 0.0, "driven", 1};
|
||||
vehicle next{definition::fiz(path), 0.0, "next"};
|
||||
driven->Attach(end::rear, end::front, &next.mover(), test::consist::full_coupling, true, false);
|
||||
auto done{false};
|
||||
auto channels{state()};
|
||||
for (auto const &channel : state()) {
|
||||
channels.emplace_back("next." + channel.name, [&next, value = channel.value](auto const &) { return value(next.mover()); });
|
||||
}
|
||||
channels.emplace_back("Done", [&done](auto const &) { return flag(done); });
|
||||
test::trace trace{"switches/" + path, channels, 1, false};
|
||||
trace.sample(0.0, driven.mover());
|
||||
for (std::size_t i = 0; i < actions.size(); ++i) {
|
||||
trace.mark(actions[i].name);
|
||||
done = actions[i].work(driven.mover());
|
||||
trace.sample(static_cast<double>(i + 1), driven.mover());
|
||||
}
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("commands: every switch of the cab, worked on a pair standing under the catenary") {
|
||||
// the same switches with time for the vehicles to act on them, as a crew works them: the pantographs rise,
|
||||
// the main switch closes, the converter and the compressor start, and the controllers take power
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
test::consist pair;
|
||||
pair.add(definition::fiz(path), 1);
|
||||
pair.add(definition::fiz(path));
|
||||
auto done{false};
|
||||
auto channels{state()};
|
||||
channels.insert(channels.end(), {
|
||||
{"PantFrontActive", [](auto const &M) { return flag(M.Pantographs[end::front].is_active); }},
|
||||
{"PantRearActive", [](auto const &M) { return flag(M.Pantographs[end::rear].is_active); }},
|
||||
{"PantPress", [](auto const &M) { return M.PantPress; }},
|
||||
{"GroundRelay", [](auto const &M) { return flag(M.GroundRelay); }},
|
||||
{"ConverterFlag", [](auto const &M) { return flag(M.ConverterFlag); }},
|
||||
{"CompressorFlag", [](auto const &M) { return flag(M.CompressorFlag); }},
|
||||
{"Compressor", [](auto const &M) { return M.Compressor; }},
|
||||
{"MainCtrlActualPos", [](auto const &M) { return M.MainCtrlActualPos; }},
|
||||
{"Itot", [](auto const &M) { return M.Itot; }},
|
||||
{"FuseFlag", [](auto const &M) { return flag(M.FuseFlag); }},
|
||||
{"EngineRotation", [](auto const &M) { return M.enrot; }},
|
||||
});
|
||||
auto const own{channels.size()};
|
||||
for (std::size_t i = 0; i < own; ++i) {
|
||||
channels.emplace_back("next." + channels[i].name, [&pair, value = channels[i].value](auto const &) { return value(pair[1].mover()); });
|
||||
}
|
||||
channels.emplace_back("Done", [&done](auto const &) { return flag(done); });
|
||||
test::trace trace{"switches_live/" + path, channels, 1, false};
|
||||
trace.sample(0.0, pair[0].mover());
|
||||
test::track const catenary{.voltage = test::catenary_3kv};
|
||||
for (std::size_t i = 0; i < actions.size(); ++i) {
|
||||
trace.mark(actions[i].name);
|
||||
done = actions[i].work(pair[0].mover());
|
||||
pair.run(2.0, catenary);
|
||||
trace.sample(static_cast<double>(i + 1), pair[0].mover());
|
||||
}
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// three locomotives coupled with the given coupling, the middle one facing backwards, as a train made up of
|
||||
// whatever came to hand: the commands of the front one go to the rear coupler of the middle one and from its
|
||||
// front coupler to the front one of the last, which faces backwards from the middle one, so forwards
|
||||
struct train {
|
||||
vehicle head{definition::fiz("4e_v1/4e"), 0.0, "front", 1};
|
||||
vehicle middle{definition::fiz("4e_v1/4e"), 0.0, "middle"};
|
||||
vehicle last{definition::fiz("4e_v1/4e"), 0.0, "last"};
|
||||
|
||||
explicit train(int Coupling) {
|
||||
head->Attach(end::rear, end::rear, &middle.mover(), Coupling, true, false);
|
||||
middle->Attach(end::front, end::front, &last.mover(), Coupling, true, false);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("commands: travel along the train, turned round for a vehicle facing backwards") {
|
||||
train consist{test::consist::full_coupling};
|
||||
// the driver takes the front cab, which the others follow
|
||||
REQUIRE(consist.head->CabActivisation());
|
||||
CHECK(consist.head->CabActive == 1);
|
||||
CHECK(consist.middle->CabActive == -1);
|
||||
CHECK(consist.last->CabActive == 1);
|
||||
// the command is done in each vehicle and cleared
|
||||
CHECK(consist.middle->CommandIn.Command.empty());
|
||||
CHECK(consist.last->CommandIn.Command.empty());
|
||||
|
||||
SUBCASE("door permits: the right side of the sender is the left one of a vehicle facing backwards") {
|
||||
consist.head->PermitDoors(side::right, true, range_t::consist);
|
||||
CHECK(consist.head->Doors.instances[side::right].open_permit);
|
||||
CHECK(consist.middle->Doors.instances[side::left].open_permit);
|
||||
CHECK_FALSE(consist.middle->Doors.instances[side::right].open_permit);
|
||||
CHECK(consist.last->Doors.instances[side::right].open_permit);
|
||||
// and revoked the same way
|
||||
consist.head->PermitDoors(side::right, false, range_t::consist);
|
||||
CHECK_FALSE(consist.middle->Doors.instances[side::left].open_permit);
|
||||
CHECK_FALSE(consist.last->Doors.instances[side::right].open_permit);
|
||||
}
|
||||
SUBCASE("a pantograph valve: the vehicles past one coupled by its control cable take the other pantograph") {
|
||||
consist.head->OperatePantographValve(end::front, operation_t::enable, range_t::consist);
|
||||
CHECK(consist.head->Pantographs[end::front].valve.is_enabled);
|
||||
CHECK(consist.middle->Pantographs[end::front].valve.is_enabled);
|
||||
CHECK(consist.last->Pantographs[end::rear].valve.is_enabled);
|
||||
}
|
||||
SUBCASE("sent backwards, it goes no further than the sender: nothing is coupled at its front") {
|
||||
consist.head->RunCommand("DoorLock", 0, -1, coupling::control);
|
||||
CHECK_FALSE(consist.head->Doors.lock_enabled);
|
||||
CHECK(consist.middle->Doors.lock_enabled);
|
||||
}
|
||||
SUBCASE("the same command again isn't taken by the next vehicle a second time") {
|
||||
CHECK(consist.middle->SetInternalCommand("DoorStep", 0, 1, coupling::control));
|
||||
CHECK_FALSE(consist.middle->SetInternalCommand("DoorStep", 0, 1, coupling::control));
|
||||
CHECK_FALSE(consist.head->RunInternalCommand()); // nothing to run
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("commands: don't pass a coupling without the control cable") {
|
||||
train consist{coupling::coupler | coupling::brakehose};
|
||||
consist.head->RunCommand("DoorLock", 0, 1, coupling::control);
|
||||
CHECK_FALSE(consist.head->Doors.lock_enabled);
|
||||
CHECK(consist.middle->Doors.lock_enabled);
|
||||
// a command of another coupling goes through it
|
||||
consist.head->RunCommand("DoorStep", 0, 1, coupling::brakehose);
|
||||
CHECK_FALSE(consist.middle->Doors.step_enabled);
|
||||
}
|
||||
|
||||
TEST_CASE("commands: a wagon loaded and unloaded by commands, which repeat until done") {
|
||||
vehicle wagon{definition::fiz("3wl_v2/3wl")};
|
||||
REQUIRE(wagon->MaxLoad > 0);
|
||||
test::trace trace{"commands/loading", state(), 100};
|
||||
wagon.record(trace);
|
||||
|
||||
// the game gives the commands of loading through PutCommand, with the place of the platform or the ramp
|
||||
SUBCASE("loading 12 tonnes of coal") {
|
||||
trace.mark("load");
|
||||
wagon->PutCommand("Load=Coal", 12, 0, wagon->Loc);
|
||||
wagon.run(30.0);
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(12.0).epsilon(0.1));
|
||||
CHECK(wagon->LoadType.name == "coal");
|
||||
CHECK(wagon->CommandIn.Command.empty());
|
||||
|
||||
trace.mark("unload");
|
||||
wagon->PutCommand("UnLoad=Coal", 20, 0, wagon->Loc);
|
||||
wagon.run(200.0);
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(0.0));
|
||||
CHECK(wagon->LoadType.name.empty());
|
||||
trace.check();
|
||||
}
|
||||
SUBCASE("a load the wagon doesn't take stays a command, not done") {
|
||||
wagon->PutCommand("Load=passengers", 12, 0, wagon->Loc);
|
||||
wagon.run(10.0);
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(0.0));
|
||||
CHECK_FALSE(wagon->CommandIn.Command.empty());
|
||||
}
|
||||
SUBCASE("away from the place of the command nothing is loaded") {
|
||||
wagon->PutCommand("Load=Coal", 12, 5.0, TLocation{100.0, 0.0, 0.0});
|
||||
wagon.run(10.0);
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(0.0));
|
||||
CHECK(wagon->LastLoadChangeTime == doctest::Approx(0.0));
|
||||
}
|
||||
SUBCASE("unloading an empty wagon isn't done either") {
|
||||
wagon->PutCommand("UnLoad=Coal", 12, 0, wagon->Loc);
|
||||
wagon.run(10.0);
|
||||
CHECK_FALSE(wagon->CommandIn.Command.empty());
|
||||
}
|
||||
}
|
||||
135
tests/unit/test_consist.cpp
Normal file
135
tests/unit/test_consist.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "consist.h"
|
||||
#include "drive.h"
|
||||
#include "golden.h"
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
|
||||
using test::consist;
|
||||
using test::definition;
|
||||
|
||||
// characterisation of trains of coupled vehicles: the real electric units driven whole, a locomotive with
|
||||
// wagons, the air, the control and the coupler forces between the vehicles, in golden traces
|
||||
// (data/golden/consist/), each vehicle of the train in its own
|
||||
|
||||
namespace {
|
||||
|
||||
struct unit {
|
||||
char const *name;
|
||||
std::vector<char const *> cars; // from the front, the first one driven
|
||||
};
|
||||
|
||||
std::vector<unit> const units{
|
||||
{"en57", {"en57_v1/5bgaiii_led_spot", "en57_v1/6ba_840", "en57_v1/5bgb"}},
|
||||
{"ed72", {"ed72_v1/5bs-ra", "ed72_v1/6bs-sa", "ed72_v1/6bs-sb", "ed72_v1/5bs-rb"}},
|
||||
{"ew58", {"ew58_v1/ew58-sa", "ew58_v1/ew58-d", "ew58_v1/ew58-sb"}},
|
||||
{"elf", {"elf_v1/21we-a", "elf_v1/21we-b", "elf_v1/21we-c"}},
|
||||
{"impuls", {"impuls_v1/31we-a_pr", "impuls_v1/31we-b_pr", "impuls_v1/31we-c_pr", "impuls_v1/31we-d_pr"}},
|
||||
};
|
||||
|
||||
std::vector<test::channel> car_channels() {
|
||||
using namespace test::channels;
|
||||
return motion() + traction() + air() + brakes();
|
||||
}
|
||||
|
||||
// a trace for each vehicle of the train, recording it
|
||||
std::vector<std::unique_ptr<test::trace>> record(consist &Train, std::string const &Name) {
|
||||
std::vector<std::unique_ptr<test::trace>> traces;
|
||||
for (std::size_t i = 0; i < Train.size(); ++i) {
|
||||
traces.push_back(std::make_unique<test::trace>(std::format("consist/{}/{}", Name, i), car_channels(), 100));
|
||||
Train[i].record(*traces.back());
|
||||
}
|
||||
return traces;
|
||||
}
|
||||
|
||||
// the events go to every trace
|
||||
struct all_traces {
|
||||
std::vector<std::unique_ptr<test::trace>> &traces;
|
||||
void mark(std::string const &Event) const {
|
||||
for (auto const &trace : traces) {
|
||||
trace->mark(Event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("consist: every real electric unit driven whole from its front cab") {
|
||||
for (auto const &unit : units) {
|
||||
CAPTURE(unit.name);
|
||||
test::reseed_random();
|
||||
consist train;
|
||||
for (auto const *car : unit.cars) {
|
||||
train.add(definition::fiz(car), train.size() == 0 ? 1 : 0);
|
||||
}
|
||||
auto traces{record(train, unit.name)};
|
||||
// the drive cycle marks the events in the trace it gets; the first car's carries them
|
||||
test::drive_cycle(test::driving(train), test::track{0.15, 0.0, test::catenary_3kv}, *traces.front());
|
||||
// every unit runs off and is braked to a stop, but the EN57, which doesn't get ready (COVERAGE.md)
|
||||
auto const &leading{train[0].mover()};
|
||||
CHECK((leading.DistCounter > 0.2 /* km */) != (std::string{unit.name} == "en57"));
|
||||
CHECK(leading.Vel < 0.5);
|
||||
for (auto const &trace : traces) {
|
||||
trace->check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("consist: a locomotive with wagons, driven, braked by its handle and pulled apart by the couplers") {
|
||||
test::reseed_random();
|
||||
consist train;
|
||||
train.add(definition::fiz("4e_v1/4e"), 1);
|
||||
for (auto const *wagon : {"3wl_v2/3wl", "11xa_v2/93a", "bdhpumn_v3/bdhpumn", "z1_v2/152a"}) {
|
||||
train.add(definition::fiz(wagon));
|
||||
}
|
||||
auto traces{record(train, "eu07 with wagons")};
|
||||
test::drive_cycle(test::driving(train), test::track{0.15, 0.0, test::catenary_3kv}, *traces.front());
|
||||
for (auto const &trace : traces) {
|
||||
trace->check();
|
||||
}
|
||||
// the couplers kept the train together
|
||||
for (std::size_t i = 0; i + 1 < train.size(); ++i) {
|
||||
CAPTURE(i);
|
||||
CHECK(std::abs(train.gap(i)) < 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// what the cab's ammeters show (Train.cpp, the driver's panel) and the brake force the AI expects of the
|
||||
// vehicle (Driver.cpp), read of the driven vehicle
|
||||
std::vector<test::channel> gauges() {
|
||||
std::vector<test::channel> result;
|
||||
for (int ammeter = 0; ammeter < 4; ++ammeter) {
|
||||
result.emplace_back(std::format("ShowCurrent{}", ammeter), [ammeter](auto const &M) { return M.ShowCurrent(ammeter); });
|
||||
}
|
||||
result.emplace_back("BrakeForceR0.25", [](auto const &M) { return M.BrakeForceR(0.25, M.Vel); });
|
||||
result.emplace_back("BrakeForceR1", [](auto const &M) { return M.BrakeForceR(1.0, M.Vel); });
|
||||
result.emplace_back("BrakeForceR1at20", [](auto const &M) { return M.BrakeForceR(1.0, 20.0); });
|
||||
using test::channels::operator+;
|
||||
return result + test::channels::traction();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("consist: the gauges of units and locomotives in multiple, driven") {
|
||||
auto trains{units};
|
||||
trains.push_back({"eu07 pair", {"4e_v1/4e", "4e_v1/4e"}});
|
||||
trains.push_back({"et22 pair", {"et22_v3/201e-w", "et22_v3/201e-rn"}});
|
||||
trains.push_back({"ep09 pair", {"ep09_v2/104e", "ep09_v2/104e"}});
|
||||
trains.push_back({"sn61 three", {"sn61_v2/sn61", "sn61_v2/sn61", "sn61_v2/sn61"}});
|
||||
trains.push_back({"su45 pair", {"su45_v2/301d", "su45_v2/301d"}});
|
||||
for (auto const &train : trains) {
|
||||
CAPTURE(train.name);
|
||||
test::reseed_random();
|
||||
consist vehicles;
|
||||
for (auto const *car : train.cars) {
|
||||
vehicles.add(definition::fiz(car), vehicles.size() == 0 ? 1 : 0);
|
||||
}
|
||||
test::trace trace{std::string{"gauges/"} + train.name, gauges(), 100};
|
||||
vehicles[0].record(trace);
|
||||
test::drive_cycle(test::driving(vehicles), test::track{0.15, 0.0, test::catenary_3kv}, trace);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
632
tests/unit/test_controls.cpp
Normal file
632
tests/unit/test_controls.cpp
Normal file
@@ -0,0 +1,632 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "scenario.h"
|
||||
#include "drive.h"
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
#include "utilities/utilities.h"
|
||||
|
||||
// characterisation of the controls a driver and a crew use besides driving and braking: doors, direction and
|
||||
// cab change, sanding against slip, the emergency brake, releasers, the ep and the dynamic brake, heating,
|
||||
// loading, collisions and the frame of several physics iterations, each in a scenario on real vehicles,
|
||||
// recorded in golden traces (data/golden/controls/)
|
||||
|
||||
using test::scenario;
|
||||
using namespace test::channels;
|
||||
|
||||
namespace {
|
||||
|
||||
void notch_up(scenario &Scenario, int Positions, double Seconds) {
|
||||
for (int i = 0; i < Positions; ++i) {
|
||||
Scenario.driver().controlling.IncMainCtrl(1);
|
||||
Scenario.wait(Seconds);
|
||||
}
|
||||
}
|
||||
|
||||
void notch_down(scenario &Scenario) {
|
||||
while (Scenario.driver().controlling.DecMainCtrl(1)) {
|
||||
Scenario.wait(0.5);
|
||||
}
|
||||
Scenario.driver().controlling.DecScndCtrl(2);
|
||||
}
|
||||
|
||||
void brake_to_stop(scenario &Scenario, double Seconds = 60.0) {
|
||||
Scenario.act("brake to stop");
|
||||
Scenario.cab().BrakeLevelSet(Scenario.cab().Handle->GetPos(bh_FB));
|
||||
Scenario.wait(Seconds);
|
||||
Scenario.cab().BrakeLevelSet(Scenario.cab().Handle->GetPos(bh_RP));
|
||||
Scenario.wait(20.0);
|
||||
}
|
||||
|
||||
// the pipe charged again after an emergency stop: the releaser held with the handle at running, then let go
|
||||
void recharge(scenario &Scenario) {
|
||||
auto &cab{Scenario.cab()};
|
||||
Scenario.act("releaser held, the pipe charged");
|
||||
cab.BrakeLevelSet(cab.Handle->GetPos(bh_RP));
|
||||
cab.BrakeReleaser(1);
|
||||
Scenario.wait(30.0);
|
||||
cab.BrakeReleaser(0);
|
||||
Scenario.wait(30.0);
|
||||
}
|
||||
|
||||
bool stopped(scenario &Scenario) {
|
||||
for (std::size_t i = 0; i < Scenario.train().size(); ++i) {
|
||||
if (Scenario.vehicle(i).Vel > 0.1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// the brake cylinders of every vehicle of the train under the pressure given
|
||||
bool released(scenario &Scenario, double Pressure = 0.1) {
|
||||
for (std::size_t i = 0; i < Scenario.train().size(); ++i) {
|
||||
if (Scenario.vehicle(i).BrakePress > Pressure) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool open(TMoverParameters const &Vehicle, int Side) {
|
||||
return Vehicle.Doors.instances[Side].is_open;
|
||||
}
|
||||
|
||||
// the leaf shut, whatever the step does (closed, is_closed, wants the step folded too)
|
||||
bool shut(TMoverParameters const &Vehicle, int Side) {
|
||||
return Vehicle.Doors.instances[Side].position <= 0.f;
|
||||
}
|
||||
|
||||
bool closed(TMoverParameters const &Vehicle, int Side) {
|
||||
return Vehicle.Doors.instances[Side].is_closed;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("controls: the doors of an electric unit, opened, locked, permitted and closed by driving off") {
|
||||
for (auto const &[name, cars] : std::vector<std::pair<std::string, std::vector<char const *>>>{
|
||||
{"elf", {"elf_v1/21we-a", "elf_v1/21we-b", "elf_v1/21we-c"}},
|
||||
{"en57", {"en57_v1/5bgaiii_led_spot", "en57_v1/6ba_840", "en57_v1/5bgb"}},
|
||||
{"impuls", {"impuls_v1/31we-a_pr", "impuls_v1/31we-b_pr", "impuls_v1/31we-c_pr", "impuls_v1/31we-d_pr"}}}) {
|
||||
CAPTURE(name);
|
||||
scenario scenario{"controls/doors/" + name, motion() + doors()};
|
||||
for (auto const *car : cars) {
|
||||
scenario.add(car, scenario.train().size() == 0 ? 1 : 0);
|
||||
}
|
||||
// the EN57 doesn't get ready (COVERAGE.md), its doors work all the same
|
||||
auto const ready{scenario.start_up()};
|
||||
CHECK(ready == (name != "en57"));
|
||||
auto &cab{scenario.cab()};
|
||||
auto const &last{scenario.vehicle(scenario.train().size() - 1)};
|
||||
scenario.act("permit left");
|
||||
cab.PermitDoors(side::left, true);
|
||||
scenario.wait(2.0);
|
||||
scenario.act("open left");
|
||||
cab.OperateDoors(side::left, true);
|
||||
scenario.wait(10.0);
|
||||
CHECK(open(cab, side::left));
|
||||
CHECK(open(last, side::left));
|
||||
CHECK(closed(cab, side::right));
|
||||
scenario.act("close left");
|
||||
cab.OperateDoors(side::left, false);
|
||||
scenario.wait(10.0);
|
||||
CHECK(shut(cab, side::left));
|
||||
CHECK(shut(last, side::left));
|
||||
scenario.act("open right without permit");
|
||||
cab.OperateDoors(side::right, true);
|
||||
scenario.wait(5.0);
|
||||
// the EN57 needs no permit
|
||||
CHECK(shut(cab, side::right) == cab.Doors.permit_needed);
|
||||
scenario.act("permit right, open");
|
||||
cab.PermitDoors(side::right, true);
|
||||
cab.OperateDoors(side::right, true);
|
||||
scenario.wait(10.0);
|
||||
CHECK(open(cab, side::right));
|
||||
CHECK(open(last, side::right));
|
||||
scenario.act("lock");
|
||||
cab.LockDoors(true);
|
||||
scenario.wait(5.0);
|
||||
scenario.act("permit preset, steps off, remote control");
|
||||
cab.ChangeDoorPermitPreset(1);
|
||||
cab.PermitDoorStep(false);
|
||||
cab.ChangeDoorControlMode(true);
|
||||
scenario.wait(5.0);
|
||||
cab.ChangeDoorPermitPreset(-1);
|
||||
cab.PermitDoorStep(true);
|
||||
cab.ChangeDoorControlMode(false);
|
||||
scenario.act("close all, unlock");
|
||||
cab.OperateDoors(side::right, false);
|
||||
cab.OperateDoors(side::left, false);
|
||||
cab.LockDoors(false);
|
||||
scenario.wait(10.0);
|
||||
CHECK(shut(cab, side::left));
|
||||
CHECK(shut(cab, side::right));
|
||||
scenario.act("open both and drive off");
|
||||
cab.PermitDoors(side::left, true);
|
||||
cab.PermitDoors(side::right, true);
|
||||
cab.OperateDoors(side::left, true);
|
||||
cab.OperateDoors(side::right, true);
|
||||
scenario.wait(5.0);
|
||||
CHECK_FALSE(shut(cab, side::left));
|
||||
CHECK_FALSE(shut(cab, side::right));
|
||||
scenario.get_going();
|
||||
notch_up(scenario, 4, 2.0);
|
||||
scenario.wait(20.0);
|
||||
// the doors of a train ready to run close as the driver starts off. no CHECK of the speed: the Elf and
|
||||
// the Impuls keep their steps out under the permit, which keeps them from moving (COVERAGE.md)
|
||||
CHECK(shut(cab, side::left) == ready);
|
||||
CHECK(shut(cab, side::right) == ready);
|
||||
CHECK(shut(last, side::left) == ready);
|
||||
CHECK(shut(last, side::right) == ready);
|
||||
notch_down(scenario);
|
||||
brake_to_stop(scenario);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("controls: the doors of wagons, worked from the locomotive") {
|
||||
scenario scenario{"controls/doors/eu07 with wagons", motion() + doors()};
|
||||
scenario.add("4e_v1/4e", 1).add("bdhpumn_v3/bdhpumn").add("11xa_v2/93a");
|
||||
scenario.start_up();
|
||||
auto &cab{scenario.cab()};
|
||||
auto &coach{scenario.vehicle(1)};
|
||||
auto const &freight{scenario.vehicle(2)};
|
||||
// the locomotive works the coach's doors for the consist and for the unit, not with its local controls; the
|
||||
// freight wagon's doors don't move from the locomotive
|
||||
for (auto const range : {range_t::consist, range_t::unit, range_t::local}) {
|
||||
CAPTURE(static_cast<int>(range));
|
||||
scenario.act(std::format("open right {}", static_cast<int>(range)));
|
||||
cab.PermitDoors(side::right, true, range);
|
||||
cab.OperateDoors(side::right, true, range);
|
||||
scenario.wait(10.0);
|
||||
CHECK(open(coach, side::right) == (range != range_t::local));
|
||||
CHECK(shut(coach, side::left));
|
||||
CHECK(shut(freight, side::right));
|
||||
scenario.act("close right");
|
||||
cab.OperateDoors(side::right, false, range);
|
||||
scenario.wait(10.0);
|
||||
CHECK(shut(coach, side::right));
|
||||
}
|
||||
scenario.act("wagon opens its own");
|
||||
coach.OperateDoors(side::left, true, range_t::local);
|
||||
// a second at a time, the same run as one wait. the coach's doors close by themselves 5 s after they
|
||||
// opened (DoorStayOpen)
|
||||
scenario.wait(1.0);
|
||||
CHECK_FALSE(shut(coach, side::left));
|
||||
scenario.wait(9.0);
|
||||
CHECK(shut(coach, side::left));
|
||||
coach.OperateDoors(side::left, false, range_t::local);
|
||||
scenario.wait(10.0);
|
||||
CHECK(shut(coach, side::left));
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("controls: reversing and changing the cab of a locomotive") {
|
||||
scenario scenario{"controls/reverse/eu07", motion() + traction()};
|
||||
scenario.add("4e_v1/4e", 1);
|
||||
scenario.start_up();
|
||||
scenario.get_going();
|
||||
auto &cab{scenario.cab()};
|
||||
// the speed along the vehicle, its front ahead
|
||||
notch_up(scenario, 10, 1.5);
|
||||
scenario.wait(10.0);
|
||||
CHECK(cab.V > 3.0);
|
||||
notch_down(scenario);
|
||||
brake_to_stop(scenario);
|
||||
CHECK(stopped(scenario));
|
||||
scenario.act("backward");
|
||||
cab.DirectionBackward();
|
||||
cab.DirectionBackward();
|
||||
scenario.wait(2.0);
|
||||
CHECK(cab.DirActive < 0);
|
||||
notch_up(scenario, 10, 1.5);
|
||||
scenario.wait(10.0);
|
||||
CHECK(cab.V < -3.0);
|
||||
notch_down(scenario);
|
||||
brake_to_stop(scenario);
|
||||
CHECK(stopped(scenario));
|
||||
scenario.act("neutral, change cab");
|
||||
cab.DirectionForward();
|
||||
scenario.wait(1.0);
|
||||
cab.CabDeactivisation();
|
||||
// through the engine room (cab 0) to the rear cab, as the player walks there
|
||||
cab.ChangeCab(-1);
|
||||
cab.ChangeCab(-1);
|
||||
cab.CabActivisation();
|
||||
scenario.wait(5.0);
|
||||
CHECK(cab.CabActive < 0);
|
||||
scenario.act("drive from the rear cab");
|
||||
scenario.get_going();
|
||||
notch_up(scenario, 10, 1.5);
|
||||
scenario.wait(10.0);
|
||||
// forward from the rear cab is the vehicle's backward
|
||||
CHECK(cab.V < -3.0);
|
||||
notch_down(scenario);
|
||||
brake_to_stop(scenario);
|
||||
CHECK(stopped(scenario));
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("controls: wheel slip on a slippery track, sand and the anti-slip brake") {
|
||||
for (auto const *path : {"4e_v1/4e", "sm42_v1/6d1", "e186_v2/eu47"}) {
|
||||
CAPTURE(path);
|
||||
scenario scenario{std::string{"controls/slip/"} + path, motion() + traction() + brakes(), test::track{0.04, 0.0, test::catenary_3kv}};
|
||||
scenario.add(path, 1);
|
||||
scenario.start_up();
|
||||
scenario.get_going();
|
||||
auto &cab{scenario.cab()};
|
||||
// a notch a second: the controller put to full power at once never gets the line contactors closed
|
||||
scenario.act("full power");
|
||||
scenario.full_power(0.0);
|
||||
auto slipped{cab.SlippingWheels};
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
scenario.wait(1.0);
|
||||
slipped = slipped || cab.SlippingWheels;
|
||||
}
|
||||
// the electric locomotives slip at full power, the SM42, of less power for its weight, doesn't
|
||||
CHECK(slipped == (std::string{path} != "sm42_v1/6d1"));
|
||||
scenario.act("sand");
|
||||
cab.Sandbox(true);
|
||||
scenario.wait(10.0);
|
||||
cab.Sandbox(false);
|
||||
scenario.act("manual sand");
|
||||
cab.SandboxManual(true);
|
||||
scenario.wait(5.0);
|
||||
cab.SandboxManual(false);
|
||||
scenario.act("anti-slip brake");
|
||||
cab.AntiSlippingButton();
|
||||
cab.AntiSlippingBrake();
|
||||
scenario.wait(10.0);
|
||||
CHECK(cab.Vel > 5.0);
|
||||
notch_down(scenario);
|
||||
brake_to_stop(scenario);
|
||||
CHECK(stopped(scenario));
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("controls: emergency stops by the alarm chain and the radio-stop") {
|
||||
scenario scenario{"controls/emergency/eu07 with wagons", motion() + brakes()};
|
||||
scenario.add("4e_v1/4e", 1).add("bdhpumn_v3/bdhpumn").add("3wl_v2/3wl");
|
||||
scenario.start_up();
|
||||
scenario.get_going();
|
||||
notch_up(scenario, 20, 1.0);
|
||||
scenario.wait(20.0);
|
||||
notch_down(scenario);
|
||||
auto &cab{scenario.cab()};
|
||||
CHECK(cab.Vel > 30.0);
|
||||
scenario.act("alarm chain in the wagon");
|
||||
scenario.vehicle(1).AlarmChainSwitch(true);
|
||||
scenario.wait(40.0);
|
||||
// the pipe emptied, the whole train braked to a stop
|
||||
CHECK(stopped(scenario));
|
||||
CHECK(cab.PipePress < 0.5);
|
||||
CHECK(scenario.vehicle(2).BrakePress > 1.0);
|
||||
scenario.act("alarm chain reset");
|
||||
scenario.vehicle(1).AlarmChainSwitch(false);
|
||||
scenario.wait(10.0);
|
||||
// the FV4a handle stays cut off the emptied pipe of an LSt locomotive (lock_old in UpdatePipePressure)
|
||||
// until the releaser is held
|
||||
CHECK(cab.PipePress < 0.5);
|
||||
recharge(scenario);
|
||||
CHECK(cab.PipePress > 4.5);
|
||||
scenario.get_going();
|
||||
notch_up(scenario, 20, 1.0);
|
||||
scenario.wait(20.0);
|
||||
notch_down(scenario);
|
||||
CHECK(cab.Vel > 30.0);
|
||||
scenario.act("radio-stop");
|
||||
cab.RadiostopSwitch(true);
|
||||
scenario.wait(40.0);
|
||||
CHECK(stopped(scenario));
|
||||
CHECK(cab.PipePress < 0.5);
|
||||
scenario.act("radio-stop reset");
|
||||
cab.RadiostopSwitch(false);
|
||||
scenario.wait(10.0);
|
||||
recharge(scenario);
|
||||
CHECK(cab.PipePress > 4.5);
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("controls: releasers and the universal brake buttons") {
|
||||
scenario scenario{"controls/releaser/eu07 with wagons", brakes() + air()};
|
||||
scenario.add("4e_v1/4e", 1).add("bdhpumn_v3/bdhpumn").add("3wl_v2/3wl");
|
||||
scenario.start_up();
|
||||
scenario.get_going();
|
||||
auto &cab{scenario.cab()};
|
||||
auto &wagon{scenario.vehicle(2)};
|
||||
scenario.act("service brake");
|
||||
cab.BrakeLevelSet(cab.Handle->GetPos(bh_FB));
|
||||
scenario.wait(20.0);
|
||||
CHECK(cab.BrakePress > 1.0);
|
||||
CHECK(wagon.BrakePress > 1.0);
|
||||
cab.BrakeLevelSet(cab.Handle->GetPos(bh_NP));
|
||||
auto &coach{scenario.vehicle(1)};
|
||||
// the releaser of the cab is passed along the whole train, a wagon's works on the wagon alone
|
||||
auto const coachbraked{coach.BrakePress};
|
||||
auto wagonbraked{wagon.BrakePress};
|
||||
scenario.act("releaser of the locomotive");
|
||||
cab.BrakeReleaser(1);
|
||||
scenario.wait(10.0);
|
||||
cab.BrakeReleaser(0);
|
||||
CHECK(cab.BrakePress < 0.5);
|
||||
CHECK(coach.BrakePress < coachbraked - 1.0);
|
||||
CHECK(wagon.BrakePress < wagonbraked - 0.5);
|
||||
CHECK(cab.PipePress < 4.0); // the pipe stays where the service application left it
|
||||
wagonbraked = wagon.BrakePress;
|
||||
scenario.act("releaser of the wagon");
|
||||
wagon.BrakeReleaser(1);
|
||||
scenario.wait(10.0);
|
||||
wagon.BrakeReleaser(0);
|
||||
CHECK(wagon.BrakePress < wagonbraked - 0.5);
|
||||
for (int button = 0; button < 3; ++button) {
|
||||
scenario.act(std::format("universal button {}", button));
|
||||
cab.UniversalBrakeButton(button, 1);
|
||||
scenario.wait(5.0);
|
||||
cab.UniversalBrakeButton(button, 0);
|
||||
scenario.wait(5.0);
|
||||
}
|
||||
scenario.act("running");
|
||||
cab.BrakeLevelSet(cab.Handle->GetPos(bh_RP));
|
||||
scenario.wait(60.0);
|
||||
CHECK(cab.PipePress > 4.8);
|
||||
CHECK(released(scenario));
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("controls: the ep brake of electric units") {
|
||||
for (auto const &[name, cars] : std::vector<std::pair<std::string, std::vector<char const *>>>{
|
||||
{"ed72", {"ed72_v1/5bs-ra", "ed72_v1/6bs-sa", "ed72_v1/6bs-sb", "ed72_v1/5bs-rb"}},
|
||||
{"ew58", {"ew58_v1/ew58-sa", "ew58_v1/ew58-d", "ew58_v1/ew58-sb"}}}) {
|
||||
CAPTURE(name);
|
||||
scenario scenario{"controls/ep brake/" + name, motion() + brakes() + handles()};
|
||||
for (auto const *car : cars) {
|
||||
scenario.add(car, scenario.train().size() == 0 ? 1 : 0);
|
||||
}
|
||||
scenario.start_up();
|
||||
scenario.get_going();
|
||||
auto &cab{scenario.cab()};
|
||||
scenario.act("ep on");
|
||||
cab.SwitchEPBrake(1);
|
||||
scenario.wait(5.0);
|
||||
auto const &last{scenario.vehicle(scenario.train().size() - 1)};
|
||||
auto const positions{std::vector{bh_EPB, bh_EPN, bh_EPR, bh_EPB, bh_RP}};
|
||||
for (std::size_t i = 0; i < positions.size(); ++i) {
|
||||
CAPTURE(positions[i]);
|
||||
scenario.act(std::format("handle {}", positions[i]));
|
||||
cab.BrakeLevelSet(cab.Handle->GetPos(positions[i]));
|
||||
scenario.wait(15.0);
|
||||
if (i == 2) {
|
||||
CHECK(released(scenario));
|
||||
}
|
||||
if (i == 3) {
|
||||
// the ep brake works the cylinders of every car by wire, the pipe stays charged (by the first
|
||||
// application the EW58's pipe is still charging after the start-up)
|
||||
CHECK(cab.PipePress > 4.8);
|
||||
CHECK(cab.BrakePress > 1.0);
|
||||
CHECK(last.BrakePress > 1.0);
|
||||
}
|
||||
}
|
||||
// the EW58 releases at the running position, the ED72 holds the ep application there, and with the ep
|
||||
// brake switched off as well: only the ep release position lets it off
|
||||
auto const ed72{name == "ed72"};
|
||||
CHECK(released(scenario) != ed72);
|
||||
scenario.act("ep off");
|
||||
cab.SwitchEPBrake(0);
|
||||
scenario.wait(30.0);
|
||||
CHECK(released(scenario) != ed72);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("controls: the electrodynamic brake of locomotives having one") {
|
||||
for (auto const *path : {"ep09_v2/104e", "e186_v2/eu47", "e6act_v2/e6acta", "et22_v3/201e-rn"}) {
|
||||
CAPTURE(path);
|
||||
scenario scenario{std::string{"controls/dynamic brake/"} + path, motion() + traction() + brakes()};
|
||||
scenario.add(path, 1).add("bdhpumn_v3/bdhpumn").add("bdhpumn_v3/bdhpumn");
|
||||
scenario.start_up();
|
||||
scenario.get_going();
|
||||
notch_up(scenario, 60, 1.0);
|
||||
scenario.wait(30.0);
|
||||
notch_down(scenario);
|
||||
auto &cab{scenario.cab()};
|
||||
CHECK(cab.Vel > 40.0);
|
||||
auto const speed{cab.Vel};
|
||||
scenario.act("dynamic brake on");
|
||||
cab.DynamicBrakeSwitch(true);
|
||||
scenario.wait(5.0);
|
||||
scenario.act("brake");
|
||||
cab.BrakeLevelSet(cab.Handle->GetPos(bh_FB));
|
||||
scenario.wait(40.0);
|
||||
CHECK(cab.Vel < speed);
|
||||
scenario.act("dynamic brake off");
|
||||
cab.DynamicBrakeSwitch(false);
|
||||
brake_to_stop(scenario, 30.0);
|
||||
CHECK(stopped(scenario));
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("controls: train heating from the locomotive") {
|
||||
scenario scenario{"controls/heating/eu07 with wagons", traction() + air()};
|
||||
scenario.add("4e_v1/4e", 1).add("bdhpumn_v3/bdhpumn").add("bdhpumn_v3/bdhpumn");
|
||||
scenario.start_up();
|
||||
auto &cab{scenario.cab()};
|
||||
scenario.act("heating on");
|
||||
cab.HeatingSwitch(true);
|
||||
scenario.wait(30.0);
|
||||
CHECK(cab.Heating);
|
||||
CHECK(scenario.vehicle(2).Heating);
|
||||
scenario.act("heating off");
|
||||
cab.HeatingSwitch(false);
|
||||
scenario.wait(10.0);
|
||||
CHECK_FALSE(cab.Heating);
|
||||
CHECK_FALSE(scenario.vehicle(2).Heating);
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("controls: a freight wagon loaded and braked") {
|
||||
auto emptymass{0.0};
|
||||
for (auto const *load : {"", "coal", "ruda", "unknown"}) {
|
||||
CAPTURE(load);
|
||||
scenario scenario{std::string{"controls/load/3wl "} + (*load ? load : "empty"), motion() + brakes()};
|
||||
scenario.add("4e_v1/4e", 1).add("3wl_v2/3wl");
|
||||
auto &wagon{scenario.vehicle(1)};
|
||||
auto const known{std::string{load} == "coal" || std::string{load} == "ruda"};
|
||||
CHECK(wagon.AssignLoad(load, 30.f) == (known || std::string{load}.empty()));
|
||||
wagon.ComputeMass();
|
||||
if (*load == '\0') {
|
||||
emptymass = wagon.TotalMass;
|
||||
}
|
||||
else {
|
||||
// 30 t of a load the wagon takes, none of one it doesn't
|
||||
CHECK(wagon.TotalMass == doctest::Approx(emptymass + (known ? 30000.0 : 0.0)).epsilon(0.01));
|
||||
}
|
||||
scenario.start_up();
|
||||
scenario.get_going();
|
||||
notch_up(scenario, 20, 1.0);
|
||||
scenario.wait(20.0);
|
||||
notch_down(scenario);
|
||||
CHECK(scenario.cab().Vel > 20.0);
|
||||
brake_to_stop(scenario);
|
||||
CHECK(stopped(scenario));
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("controls: a locomotive running into a standing wagon") {
|
||||
for (auto const speed : {5.0, 15.0, 40.0}) {
|
||||
CAPTURE(speed);
|
||||
scenario scenario{std::format("controls/collision/{} kmh", static_cast<int>(speed)), motion()};
|
||||
// the wagon stands in front, the locomotive comes from behind it
|
||||
scenario.add("bdhpumn_v3/bdhpumn").add("4e_v1/4e", 0, coupling::faux, speed, 30.0);
|
||||
auto const &wagon{scenario.vehicle(0)};
|
||||
scenario.wait(30.0);
|
||||
// slow, the locomotive pushes the wagon off, the buffers only touching, and both roll to a stop; fast,
|
||||
// the wagon derails where it stands
|
||||
auto const derailed{speed > 30.0};
|
||||
CHECK(TestFlag(wagon.DamageFlag, dtrain_out) == derailed);
|
||||
CHECK((std::abs(wagon.DistCounter) > 0.0001) != derailed);
|
||||
CHECK(stopped(scenario));
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("controls: a train run with five physics steps in a frame") {
|
||||
scenario scenario{"controls/full physics/eu07 with wagons", motion() + traction() + brakes(),
|
||||
test::track{0.15, 0.0, test::catenary_3kv, 0, 5}};
|
||||
scenario.add("4e_v1/4e", 1).add("bdhpumn_v3/bdhpumn").add("3wl_v2/3wl");
|
||||
scenario.start_up();
|
||||
scenario.get_going();
|
||||
notch_up(scenario, 25, 1.0);
|
||||
scenario.wait(30.0);
|
||||
notch_down(scenario);
|
||||
// no CHECKs of the run: with five steps a frame the motors take no current and the train rolls at a few
|
||||
// km/h, which is a finding (COVERAGE.md), not the behaviour to keep
|
||||
brake_to_stop(scenario);
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("controls: the automatic electrodynamic brake of the EP09, in service braking held to a stop") {
|
||||
// held for longer, a service application of the train brake makes the EP09 brake electrodynamically: the
|
||||
// pressure its distributor asks for (GetEDBCP) brings the motors in as generators, the air of its own
|
||||
// cylinders is let out, and given back as the train slows down and the motors' brake force fades
|
||||
struct application {
|
||||
char const *name;
|
||||
double steps; // past the first braking position of the handle
|
||||
};
|
||||
for (auto const &[name, steps] : {application{"light", 0.0}, application{"medium", 1.0}, application{"high", 2.0}, application{"full service", 3.0}}) {
|
||||
CAPTURE(name);
|
||||
scenario scenario{std::string{"controls/dynamic brake held/ep09 "} + name, motion() + traction() + brakes()};
|
||||
scenario.add("ep09_v2/104e", 1, test::consist::full_coupling, 120.0);
|
||||
scenario.add("bdhpumn_v3/bdhpumn", 0, test::consist::full_coupling, 120.0);
|
||||
scenario.add("bdhpumn_v3/bdhpumn", 0, test::consist::full_coupling, 120.0);
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &ep09{scenario.cab()};
|
||||
REQUIRE(ep09.Power110vIsAvailable);
|
||||
scenario.act(std::string{"brake "} + name);
|
||||
ep09.BrakeLevelSet(ep09.Handle->GetPos(bh_MB) + steps);
|
||||
scenario.wait(10.0);
|
||||
CHECK(ep09.DynamicBrakeFlag);
|
||||
CHECK(ep09.Im < -100.0);
|
||||
CHECK(ep09.BrakePress < 0.25 * ep09.Hamulec->GetEDBCP());
|
||||
scenario.wait(110.0);
|
||||
// stopped, held by the air alone. the flag of the electrodynamic brake stays on while the cylinders hold
|
||||
// less than 2.1 bar, though the motors give nothing; a stronger application drops it before the stop
|
||||
CHECK(ep09.Vel == doctest::Approx(0.0));
|
||||
CHECK(ep09.Im == doctest::Approx(0.0));
|
||||
CHECK(ep09.DynamicBrakeFlag == (ep09.BrakePress <= 2.1));
|
||||
CHECK(ep09.BrakePress == doctest::Approx(ep09.Hamulec->GetEDBCP()).epsilon(0.05));
|
||||
scenario.act("release");
|
||||
ep09.BrakeLevelSet(ep09.Handle->GetPos(bh_RP));
|
||||
scenario.wait(30.0);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("controls: the automatic electrodynamic brake under ep and service braking, from speed") {
|
||||
// ep, light and full service braking of trains running at speed, whose locomotive or unit has the automatic
|
||||
// electrodynamic brake
|
||||
struct train {
|
||||
char const *name;
|
||||
std::vector<char const *> cars; // the first one driven
|
||||
double speed; // km/h at the start
|
||||
bool epelectric; // whether the ep brake alone brings the motors in
|
||||
};
|
||||
// the EW58's motors brake by the stages of the ep brake (TUHEX), with the 110 V of the converter in its
|
||||
// middle car; the E6ACT's by its distributor, from a deeper service application
|
||||
for (auto const &[name, cars, speed, epelectric] : {
|
||||
train{"e6act with wagons", {"e6act_v2/e6acta", "bdhpumn_v3/bdhpumn", "bdhpumn_v3/bdhpumn"}, 100.0, false},
|
||||
train{"ew58", {"ew58_v1/ew58-sa", "ew58_v1/ew58-d", "ew58_v1/ew58-sb"}, 90.0, true},
|
||||
}) {
|
||||
CAPTURE(name);
|
||||
scenario scenario{std::string{"controls/dynamic brake from speed/"} + name, motion() + traction() + brakes()};
|
||||
for (auto const *car : cars) {
|
||||
scenario.add(car, car == cars.front() ? 1 : 0, test::consist::full_coupling, speed);
|
||||
}
|
||||
scenario.start_up();
|
||||
auto &cab{scenario.cab()};
|
||||
auto const brake{[&scenario, &cab](char const *Event, double Position, double Seconds) {
|
||||
scenario.act(Event);
|
||||
cab.BrakeLevelSet(Position);
|
||||
scenario.wait(Seconds);
|
||||
}};
|
||||
brake("ep brake", cab.Handle->GetPos(bh_EPB), 15.0);
|
||||
CHECK(cab.DynamicBrakeFlag == epelectric);
|
||||
CHECK((cab.Im < -100.0) == epelectric);
|
||||
brake("ep hold", cab.Handle->GetPos(bh_EPN), 5.0);
|
||||
brake("first step", cab.Handle->GetPos(bh_MB), 20.0);
|
||||
brake("deeper", cab.Handle->GetPos(bh_MB) + 1.0, 15.0);
|
||||
// the pipe alone doesn't bring the EW58's motors in
|
||||
CHECK((cab.Im < -50.0) != epelectric);
|
||||
brake("release", cab.Handle->GetPos(bh_RP), 20.0);
|
||||
brake("full service", cab.Handle->GetPos(bh_FB), 40.0);
|
||||
brake("release", cab.Handle->GetPos(bh_RP), 20.0);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("controls: a draisine pumped along by hand") {
|
||||
// the pumping force, half a stroke forwards and half backwards, is below the resistance of a draisine
|
||||
// standing, which stays where it is; a rolling one is kept going
|
||||
for (auto const speed : {0.0, 10.0}) {
|
||||
CAPTURE(speed);
|
||||
scenario scenario{std::format("controls/draisine/{}", static_cast<int>(speed)), motion() + traction()};
|
||||
scenario.add("dr2_v1/dr2", 1, test::consist::full_coupling, speed);
|
||||
auto &cab{scenario.cab()};
|
||||
cab.CabActivisation();
|
||||
scenario.act("hand brake off");
|
||||
test::release_brakes(cab);
|
||||
for (int stroke = 0; stroke < 40; ++stroke) {
|
||||
scenario.act("stroke");
|
||||
cab.IncMainCtrl(1);
|
||||
scenario.wait(0.5);
|
||||
cab.DecMainCtrl(1);
|
||||
scenario.wait(0.5);
|
||||
}
|
||||
CHECK((speed > 0.0) == (cab.Vel > 1.0));
|
||||
scenario.act("coast");
|
||||
scenario.wait(20.0);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
174
tests/unit/test_couplers_trains.cpp
Normal file
174
tests/unit/test_couplers_trains.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "consist.h"
|
||||
#include "scenario.h"
|
||||
|
||||
#include "utilities/utilities.h"
|
||||
|
||||
// characterisation of the couplers between vehicles: coupling and uncoupling by hand (Attach, DettachStatus,
|
||||
// Dettach), the automatic couplers coupling on contact, a broken coupler, and collisions which derail, on real
|
||||
// vehicles, the moving ones recorded in golden traces (data/golden/couplers/)
|
||||
|
||||
using test::consist;
|
||||
using test::definition;
|
||||
using test::scenario;
|
||||
using namespace test::channels;
|
||||
|
||||
TEST_CASE("couplers: coupled by hand, touching or apart, of the same kind or not") {
|
||||
consist train;
|
||||
auto &locomotive{train.add(definition::fiz("4e_v1/4e")).mover()};
|
||||
// the wagon's buffers touch the locomotive's, the unit's car stands a metre away
|
||||
auto &wagon{train.add(definition::fiz("3wl_v2/3wl"), 0, coupling::faux).mover()};
|
||||
train.step();
|
||||
|
||||
// nothing to couple to, or nothing to couple
|
||||
CHECK_FALSE(locomotive.Attach(end::rear, end::front, nullptr, coupling::coupler));
|
||||
CHECK_FALSE(locomotive.Attach(end::rear, end::front, &wagon, coupling::faux));
|
||||
// the hook first: the coupler alone, which sounds
|
||||
locomotive.Couplers[end::rear].sounds = 0;
|
||||
REQUIRE(locomotive.Attach(end::rear, end::front, &wagon, coupling::coupler));
|
||||
CHECK(locomotive.Couplers[end::rear].Connected == &wagon);
|
||||
CHECK(wagon.Couplers[end::front].Connected == &locomotive);
|
||||
CHECK(wagon.Couplers[end::front].CouplingFlag == coupling::coupler);
|
||||
CHECK(locomotive.Couplers[end::rear].sounds == sound::attachcoupler);
|
||||
// then the hoses: only what changes sounds
|
||||
locomotive.Couplers[end::rear].sounds = 0;
|
||||
REQUIRE(locomotive.Attach(end::rear, end::front, &wagon, coupling::coupler | coupling::brakehose | coupling::mainhose));
|
||||
CHECK(locomotive.Couplers[end::rear].sounds == (sound::attachbrakehose | sound::attachmainhose));
|
||||
// and again, quietly, the other side naming the coupler by the one it's connected to (2)
|
||||
locomotive.Couplers[end::rear].sounds = 0;
|
||||
REQUIRE(wagon.Attach(end::front, 2, &locomotive, coupling::coupler | coupling::brakehose, false, false));
|
||||
CHECK(locomotive.Couplers[end::rear].CouplingFlag == (coupling::coupler | coupling::brakehose));
|
||||
CHECK(locomotive.Couplers[end::rear].sounds == 0);
|
||||
|
||||
// a screw coupler with the buffers pressed together comes apart whole
|
||||
train.step();
|
||||
CHECK(locomotive.DettachStatus(end::rear) < 0);
|
||||
locomotive.Couplers[end::rear].sounds = 0;
|
||||
CHECK(locomotive.Dettach(end::rear));
|
||||
CHECK(locomotive.Couplers[end::rear].Connected == nullptr);
|
||||
CHECK(wagon.Couplers[end::front].Connected == nullptr);
|
||||
CHECK(locomotive.Couplers[end::rear].sounds == (sound::detach | sound::attachcoupler | sound::attachbrakehose));
|
||||
CHECK(locomotive.DettachStatus(end::rear) == 0);
|
||||
CHECK(locomotive.Dettach(end::rear));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: a screw coupler uncoupled with the buffers apart, or with the hoses alone, or broken") {
|
||||
struct state {
|
||||
char const *name;
|
||||
double gap; // between the buffers, the coupler stretched
|
||||
int coupling;
|
||||
bool damaged;
|
||||
bool apart; // whether it comes apart whole
|
||||
};
|
||||
for (auto const &[name, gap, couplingtype, damaged, apart] : {
|
||||
state{"stretched a little", 0.1, coupling::coupler | coupling::brakehose, false, false},
|
||||
state{"stretched far", 0.3, coupling::coupler | coupling::brakehose, false, true},
|
||||
state{"hoses alone", 0.1, coupling::brakehose, false, true},
|
||||
state{"broken", 0.1, coupling::coupler | coupling::brakehose, true, true},
|
||||
}) {
|
||||
CAPTURE(name);
|
||||
consist train;
|
||||
auto &locomotive{train.add(definition::fiz("4e_v1/4e")).mover()};
|
||||
auto &wagon{train.add(definition::fiz("3wl_v2/3wl"), 0, coupling::faux, 0.0, gap).mover()};
|
||||
REQUIRE(locomotive.Attach(end::rear, end::front, &wagon, couplingtype, true));
|
||||
if (damaged) {
|
||||
SetFlag(locomotive.DamageFlag, dtrain_coupling);
|
||||
}
|
||||
train.step();
|
||||
CHECK((locomotive.DettachStatus(end::rear) < 0) == apart);
|
||||
CHECK(locomotive.Dettach(end::rear) == apart);
|
||||
// what's left when it doesn't come apart is the coupler, the hoses taken off
|
||||
CHECK(locomotive.Couplers[end::rear].CouplingFlag == (apart ? coupling::faux : coupling::coupler));
|
||||
CHECK(wagon.Couplers[end::front].CouplingFlag == (apart ? coupling::faux : coupling::coupler));
|
||||
}
|
||||
// couplers of different kinds don't couple, unless forced
|
||||
consist train;
|
||||
auto &locomotive{train.add(definition::fiz("4e_v1/4e")).mover()};
|
||||
auto &unit{train.add(definition::fiz("en57_v1/5bgb"), 0, coupling::faux).mover()};
|
||||
train.step();
|
||||
CHECK_FALSE(locomotive.Attach(end::rear, end::front, &unit, coupling::coupler));
|
||||
CHECK(locomotive.Attach(end::rear, end::front, &unit, coupling::coupler, true));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: automatic couplers coupling on contact") {
|
||||
// a car running slowly into another from close by (its brakes are on), the automatic couplers of both ends
|
||||
// set to couple what their AutomaticFlag says; without one, the hook alone
|
||||
struct meeting {
|
||||
char const *name;
|
||||
char const *standing; // its rear coupler met
|
||||
char const *running; // its front coupler meets
|
||||
int coupling; // what they couple: what both flags allow, the control cable only of one kind
|
||||
};
|
||||
for (auto const &[name, standing, running, couplingtype] : {
|
||||
meeting{"en57 to en57", "en57_v1/5bgb", "en57_v1/5bgaiii_led_spot", 39},
|
||||
meeting{"impuls to en57", "en57_v1/5bgb", "impuls_v1/31we-a_pr", 39 & ~coupling::control},
|
||||
meeting{"en57 without the flag", "en57_v1/5bgaiii_led_spot", "en57_v1/6ba_840", coupling::coupler},
|
||||
}) {
|
||||
CAPTURE(name);
|
||||
scenario scenario{std::string{"couplers/automatic/"} + name, motion(), test::track{}};
|
||||
scenario.add(standing, 0, consist::full_coupling);
|
||||
scenario.add(running, 0, coupling::faux, 3.0, 0.2);
|
||||
scenario.wait(10.0);
|
||||
auto &first{scenario.vehicle(0)};
|
||||
auto &second{scenario.vehicle(1)};
|
||||
CHECK(first.Couplers[end::rear].CouplingFlag == couplingtype);
|
||||
CHECK(second.Couplers[end::front].CouplingFlag == couplingtype);
|
||||
// once coupled, not again until uncoupled; the vehicle which coupled marks it for the AI
|
||||
CHECK_FALSE(first.Couplers[end::rear].AutomaticCouplingAllowed);
|
||||
CHECK_FALSE(second.Couplers[end::front].AutomaticCouplingAllowed);
|
||||
CHECK((TestFlag(first.AIFlag, sound::attachcoupler) || TestFlag(second.AIFlag, sound::attachcoupler)));
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: a coupler broken, with its brake hose torn off") {
|
||||
consist train;
|
||||
auto &locomotive{train.add(definition::fiz("4e_v1/4e")).mover()};
|
||||
auto &wagon{train.add(definition::fiz("3wl_v2/3wl")).mover()};
|
||||
REQUIRE(locomotive.Couplers[end::rear].Connected == &wagon);
|
||||
locomotive.damage_coupler(end::rear);
|
||||
CHECK(TestFlag(locomotive.DamageFlag, dtrain_coupling));
|
||||
CHECK(locomotive.AlarmChainFlag);
|
||||
CHECK(locomotive.Couplers[end::rear].CouplingFlag == coupling::faux);
|
||||
CHECK(wagon.Couplers[end::front].CouplingFlag == coupling::faux);
|
||||
// the front coupler of the wagon, broken on its own: no hose to tear
|
||||
wagon.damage_coupler(end::front);
|
||||
CHECK(TestFlag(wagon.DamageFlag, dtrain_coupling));
|
||||
CHECK_FALSE(wagon.AlarmChainFlag);
|
||||
// articulated couplers don't break
|
||||
consist articulated;
|
||||
auto &unit{articulated.add(definition::fiz("impuls_v1/31we-a_pr")).mover()};
|
||||
articulated.add(definition::fiz("impuls_v1/31we-b_pr"));
|
||||
unit.damage_coupler(end::rear);
|
||||
CHECK_FALSE(TestFlag(unit.DamageFlag, dtrain_coupling));
|
||||
CHECK(unit.Couplers[end::rear].CouplingFlag != coupling::faux);
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: collisions fast enough to derail") {
|
||||
// a locomotive running into a standing wagon from behind, and a wagon running backwards into a standing
|
||||
// locomotive; over 15 km/h, weighed by the ratio of the masses, the vehicles derail
|
||||
struct collision {
|
||||
char const *name;
|
||||
char const *frontpath;
|
||||
double frontspeed;
|
||||
char const *back;
|
||||
double backspeed;
|
||||
bool frontout;
|
||||
bool backout;
|
||||
};
|
||||
for (auto const &[name, frontpath, frontspeed, back, backspeed, frontout, backout] : {
|
||||
collision{"locomotive into a wagon at 60", "3wl_v2/3wl", 0.0, "4e_v1/4e", 60.0, true, false},
|
||||
collision{"wagon backwards into a locomotive at 60", "3wl_v2/3wl", -60.0, "4e_v1/4e", 0.0, true, false},
|
||||
collision{"locomotive into a locomotive at 25", "4e_v1/4e", 0.0, "4e_v1/4e", 25.0, true, true},
|
||||
}) {
|
||||
CAPTURE(name);
|
||||
scenario scenario{std::string{"couplers/collision/"} + name, motion(), test::track{}};
|
||||
scenario.add(frontpath, 0, consist::full_coupling, frontspeed);
|
||||
scenario.add(back, 0, coupling::faux, backspeed, 20.0);
|
||||
scenario.wait(10.0);
|
||||
CHECK(TestFlag(scenario.vehicle(0).DamageFlag, dtrain_out) == frontout);
|
||||
CHECK(TestFlag(scenario.vehicle(1).DamageFlag, dtrain_out) == backout);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
#include "drive.h"
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
@@ -43,3 +44,108 @@ TEST_CASE("definition: rows of a table section reach the vehicle") {
|
||||
CHECK(wagon->LightsPos == 1);
|
||||
CHECK(wagon->Lights[end::front][1] == pc1);
|
||||
}
|
||||
|
||||
TEST_CASE("definition: lines the loader skips or trims: comments, a hash anywhere, leading spaces, carriage returns") {
|
||||
auto text{definition::load("wagon").text()};
|
||||
// a commented line and one with a hash set the mass the wagon doesn't get; the rest, indented and ended with
|
||||
// a carriage return, still load
|
||||
auto const param{text.find("Param")};
|
||||
REQUIRE(param != std::string::npos);
|
||||
text.insert(param, "// Param: M=11111\nParam: M=22222 # a note\n ");
|
||||
std::string crlf;
|
||||
for (auto const c : text) {
|
||||
if (c == '\n') {
|
||||
crlf += '\r';
|
||||
}
|
||||
crlf += c;
|
||||
}
|
||||
TMoverParameters wagon(0.0, "wagon", "test", 0);
|
||||
REQUIRE(wagon.LoadFIZ_Text(crlf));
|
||||
CHECK(wagon.Mass == doctest::Approx(42200.0));
|
||||
CHECK(wagon.Vmax == doctest::Approx(120.0));
|
||||
CHECK(wagon.MaxBrakePress[3] == doctest::Approx(3.8));
|
||||
}
|
||||
|
||||
TEST_CASE("definition: a compressor list, whose positions allow the compressor and scale its speed and limits") {
|
||||
// none of the game's vehicles has one. its rows are the positions after the 0th, which changes nothing: whether
|
||||
// the compressor may run (2 yes, 1 no, 0 as the switch says), its speed, and its lower and upper limits. the
|
||||
// table holds whole numbers (int CompressorList[4][9]), so a factor of 0.9 is read as 0, and both limits
|
||||
// drop to nothing
|
||||
auto eu07{definition::fiz("4e_v1/4e")
|
||||
.set("CompressorList", "Size", 3)
|
||||
.set("CompressorList", "Default", 1)
|
||||
.set("CompressorList", "rows", {{2, 2, 1, 1}, {1, 1, 1, 1}, {2, 1, 0.9, 0.9}})};
|
||||
vehicle real{eu07, 0.0, "test", 1};
|
||||
CHECK(real->CompressorListPosNo == 3);
|
||||
CHECK(real->CompressorList[3][3] == 0);
|
||||
auto driven{test::driving(real)};
|
||||
test::track const line{0.15, 0.0, test::catenary_3kv};
|
||||
REQUIRE(test::start_up(driven, line));
|
||||
CHECK(real->CompressorListPos == 1);
|
||||
test::drive(driven, line, 60.0);
|
||||
CHECK(real->CompressorAllow);
|
||||
CHECK(real->Compressor <= real->MaxCompressor + 0.05);
|
||||
CHECK(real->Compressor >= real->MinCompressor - 0.05);
|
||||
// the second position doesn't let it run
|
||||
CHECK(real->ChangeCompressorPreset(2));
|
||||
test::drive(driven, line, 2.0);
|
||||
CHECK_FALSE(real->CompressorAllow);
|
||||
CHECK_FALSE(real->CompressorFlag);
|
||||
// the third lets it, under limits of nothing: with no span between them for the governor, the reservoir over
|
||||
// the upper limit gets vented while the compressor runs on
|
||||
CHECK(real->ChangeCompressorPreset(3));
|
||||
auto const full{real->Compressor};
|
||||
test::drive(driven, line, 10.0);
|
||||
CHECK(real->CompressorAllow);
|
||||
CHECK(real->CompressorFlag);
|
||||
CHECK(real->Compressor < full - 1.0);
|
||||
// no further than the last position
|
||||
CHECK_FALSE(real->ChangeCompressorPreset(5));
|
||||
CHECK(real->CompressorListPos == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("definition: the compressor's limits set apart for the rear cab") {
|
||||
auto eu07{definition::fiz("4e_v1/4e").set("Brake", "MinCP_B", 5.0).set("Brake", "MaxCP_B", 6.0)};
|
||||
for (auto const cab : {1, -1}) {
|
||||
CAPTURE(cab);
|
||||
vehicle real{eu07, 0.0, "test", cab};
|
||||
auto driven{test::driving(real)};
|
||||
test::track const line{0.15, 0.0, test::catenary_3kv};
|
||||
REQUIRE(test::start_up(driven, line));
|
||||
test::drive(driven, line, 120.0);
|
||||
CHECK(real->CabDependentCompressor);
|
||||
CHECK(real->MaxCompressor == doctest::Approx(cab > 0 ? 8.7 : 6.0));
|
||||
CHECK(real->MinCompressor == doctest::Approx(cab > 0 ? 7.0 : 5.0));
|
||||
CHECK(real->Compressor <= real->MaxCompressor + 0.05);
|
||||
CHECK(real->Compressor >= real->MinCompressor - 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("definition: the highest power of an induction motor drive by the speed (PmaxList)") {
|
||||
// the drive's power limit (eimc_p_Pmax) follows the table, between its rows and, by the last two, past its end
|
||||
auto eu47{definition::fiz("e186_v2/eu47").set("PmaxList", "Size", 3).set("PmaxList", "rows", {{0, 1000}, {50, 3000}, {100, 5600}})};
|
||||
auto const table{[](double Speed) { return Speed < 50.0 ? 1000.0 + 40.0 * Speed : 3000.0 + 52.0 * (Speed - 50.0); }};
|
||||
for (auto const speed : {25.0, 75.0, 150.0}) {
|
||||
CAPTURE(speed);
|
||||
vehicle real{eu47, speed, "test", 1};
|
||||
auto driven{test::driving(real)};
|
||||
test::track const line{0.0, 0.0, test::catenary_3kv};
|
||||
REQUIRE(test::start_up(driven, line));
|
||||
CHECK(real->eimc[eimc_p_Pmax] == doctest::Approx(table(real->Vel)).epsilon(0.01));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("definition: the colour and the brightness of the headlights") {
|
||||
// only the 214M's own file has the section, which the definitions here can't hold (see data/fiz/README.md)
|
||||
vehicle railbus{definition::fiz("21xm_v1/214ma")
|
||||
.set("Headlights", "LampRed", 248)
|
||||
.set("Headlights", "LampGreen", 221)
|
||||
.set("Headlights", "LampBlue", 111)
|
||||
.set("Headlights", "DimmedMultiplier", 0.4)
|
||||
.set("Headlights", "NormalMultiplier", 0.9)};
|
||||
CHECK(railbus->refR == doctest::Approx(248.0));
|
||||
CHECK(railbus->refG == doctest::Approx(221.0));
|
||||
CHECK(railbus->refB == doctest::Approx(111.0));
|
||||
CHECK(railbus->dimMultiplier == doctest::Approx(0.4));
|
||||
CHECK(railbus->normMultiplier == doctest::Approx(0.9));
|
||||
}
|
||||
|
||||
179
tests/unit/test_diesel.cpp
Normal file
179
tests/unit/test_diesel.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
#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();
|
||||
}
|
||||
67
tests/unit/test_figures.cpp
Normal file
67
tests/unit/test_figures.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "figures.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
// the key figures of the golden traces (figures.h): the parts of a run between the events, and the comparison
|
||||
// with the recorded ones, which lets the last decimal and half a percent go and tells the rest in readable lines
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
TEST_CASE("figures: a run split into parts by the events, each from the last step of the part before") {
|
||||
vehicle eu07{definition::fiz("4e_v1/4e")};
|
||||
test::figures figures;
|
||||
auto &mover{eu07.mover()};
|
||||
mover.V = 10.0;
|
||||
mover.PipePress = 5.0;
|
||||
figures.sample(0.0, mover);
|
||||
figures.mark("brake");
|
||||
figures.mark("hard");
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
mover.V = 10.0 - i;
|
||||
mover.DistCounter += 0.005;
|
||||
mover.PipePress = 3.5;
|
||||
mover.BrakePress = 0.4 * i;
|
||||
figures.sample(i, mover);
|
||||
}
|
||||
figures.mark("release");
|
||||
mover.PipePress = 4.0;
|
||||
figures.sample(11.0, mover);
|
||||
mover.PipePress = 5.0;
|
||||
figures.sample(12.0, mover);
|
||||
|
||||
auto const lines{figures.lines()};
|
||||
auto const has{[&lines](std::string const &Line) { return std::ranges::find(lines, Line) != lines.end(); }};
|
||||
CHECK(lines.front() == "[start]");
|
||||
// two events with nothing run between them make one part
|
||||
CHECK(has("[brake, hard]"));
|
||||
CHECK(has("duration = 10.00 s"));
|
||||
CHECK(has("speed at the start = 36.0 km/h"));
|
||||
CHECK(has("distance = 50.0 m"));
|
||||
CHECK(has("stopped after = 10.00 s"));
|
||||
CHECK(has("brake pipe lowest = 3.500 bar"));
|
||||
CHECK(has("brake cylinders peak = 4.000 bar"));
|
||||
CHECK(has("brake pipe back at 4.9 bar after = 2.00 s"));
|
||||
// no current nor force anywhere in the run: left out of every part
|
||||
CHECK_FALSE(has("motor current peak = 0 A"));
|
||||
}
|
||||
|
||||
TEST_CASE("figures: compared within half a percent or the last decimal, the differences told by part") {
|
||||
std::vector<std::string> const recorded{"[brake]", "distance = 412.3 m", "stopped after = 38.21 s", "brake cylinders peak = 3.800 bar"};
|
||||
CHECK(test::figures::compare(recorded, recorded).empty());
|
||||
CHECK(test::figures::compare(recorded, {"[brake]", "distance = 413.9 m", "stopped after = 38.22 s", "brake cylinders peak = 3.810 bar"}).empty());
|
||||
|
||||
auto const differences{test::figures::compare(recorded, {"[brake]", "distance = 398.0 m", "brake cylinders peak = 3.800 bar", "motor current peak = 10 A"})};
|
||||
REQUIRE(differences.size() == 3);
|
||||
CHECK(differences[0] == "[brake] distance: 398.0 m now, 412.3 m recorded");
|
||||
CHECK(differences[1] == "[brake] stopped after: none now, 38.21 s recorded");
|
||||
CHECK(differences[2] == "[brake] motor current peak: 10 A now, none recorded");
|
||||
|
||||
auto const parts{test::figures::compare(recorded, {"[brake hard]", "distance = 412.3 m"})};
|
||||
REQUIRE(parts.size() == 1);
|
||||
CHECK(parts[0] == "the parts differ from part 1: [brake hard] now, [brake] recorded");
|
||||
}
|
||||
183
tests/unit/test_fiz.cpp
Normal file
183
tests/unit/test_fiz.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
#include "golden.h"
|
||||
#include "real_vehicles.h"
|
||||
#include "fiz.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include "utilities/parser.h"
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
// the real vehicle definitions in data/fiz load, as the game loads them, and give the parameters they gave
|
||||
// when the traces got recorded: the loader (LoadFIZ_Parse and the parsing of every section) stays as it was
|
||||
|
||||
TEST_CASE("fiz: every real vehicle loads and keeps its parameters") {
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz(path)};
|
||||
test::trace trace{"fiz/" + path, test::channels::parameters(), 1};
|
||||
trace.sample(0.0, real.mover());
|
||||
// what every vehicle has, the rest of its parameters are in the golden trace
|
||||
CHECK(real->Mass > 0.0);
|
||||
CHECK(real->TotalMass >= real->Mass);
|
||||
CHECK(real->Vmax > 0.0);
|
||||
CHECK(real->NAxles > 0);
|
||||
CHECK(real->WheelDiameter > 0.0);
|
||||
CHECK(real->NPoweredAxles <= real->NAxles);
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("fiz: changes made by a test reach the vehicle") {
|
||||
auto const eu07{definition::fiz("4e_v1/4e")};
|
||||
CHECK(vehicle{eu07}->Mass == doctest::Approx(80000.0));
|
||||
CHECK(vehicle{definition{eu07}.set("Param", "M", 90000)}->Mass == doctest::Approx(90000.0));
|
||||
// a key the file doesn't have is added to its section
|
||||
CHECK(vehicle{definition{eu07}.set("Brake", "MaxBP", 3.5)}->MaxBrakePress[3] == doctest::Approx(3.5));
|
||||
// removing a key brings its default back
|
||||
CHECK(vehicle{definition{eu07}.remove("Param", "Vmax")}->Vmax != doctest::Approx(125.0));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// a section of the game's definition, as data/fiz keeps it
|
||||
struct converted_section {
|
||||
std::string name;
|
||||
nlohmann::ordered_json keys = nlohmann::ordered_json::object();
|
||||
nlohmann::ordered_json rows = nlohmann::ordered_json::array();
|
||||
};
|
||||
|
||||
// the sections of the lines of the game's definition: the values of each section line, and the rows of a
|
||||
// list until the line closing it. lines the loader skips, and the lines closing the lists, are left out
|
||||
converted_section convert_section(test::fiz::section const &Section, std::string const &Line) {
|
||||
converted_section converted{std::string{Section.name}};
|
||||
for (auto const &key : test::fiz::keys(Line)) {
|
||||
if (auto const value{test::fiz::value(key, Line)}; false == value.empty()) {
|
||||
converted.keys[key] = value;
|
||||
}
|
||||
}
|
||||
return converted;
|
||||
}
|
||||
|
||||
nlohmann::ordered_json convert_row(std::string const &Line) {
|
||||
auto row = nlohmann::ordered_json::array();
|
||||
for (auto const &word : test::fiz::words(Line)) {
|
||||
row.push_back(word);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
std::vector<converted_section> convert(std::vector<std::string> const &Lines) {
|
||||
std::vector<converted_section> result;
|
||||
auto reading_rows{false};
|
||||
for (auto const &line : Lines) {
|
||||
if (auto const section{test::fiz::opened_by(line)}; section != nullptr) {
|
||||
result.push_back(convert_section(*section, line));
|
||||
reading_rows = section->list != 0;
|
||||
continue;
|
||||
}
|
||||
auto const list{result.empty() ? nullptr : test::fiz::named(result.back().name)};
|
||||
if (list == nullptr || list->end == nullptr) {
|
||||
continue;
|
||||
}
|
||||
// an empty line closes the brake table of the Cntrl section, the other lists have lines of their own
|
||||
if (std::string_view const end{list->end}; line.empty() ? end.empty() : (false == end.empty() && line.starts_with(end))) {
|
||||
reading_rows = false;
|
||||
continue;
|
||||
}
|
||||
if (reading_rows && false == line.empty()) {
|
||||
result.back().rows.push_back(convert_row(line));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// the JSON of data/fiz: a section a line, a row of a list a line
|
||||
std::string json_text(std::string const &Source, std::vector<converted_section> const &Sections) {
|
||||
std::string text{"{\n \"_source\": " + nlohmann::ordered_json(Source).dump() + ",\n"};
|
||||
text += R"( "_comment": "converted by test_fiz.cpp from the game's definition with the files it includes, keeping what the game's loader reads")";
|
||||
for (auto const §ion : Sections) {
|
||||
text += ",\n " + nlohmann::ordered_json(section.name).dump() + ": {";
|
||||
auto first{true};
|
||||
for (auto const &[key, value] : section.keys.items()) {
|
||||
text += (first ? "" : ", ") + nlohmann::ordered_json(key).dump() + ": " + value.dump();
|
||||
first = false;
|
||||
}
|
||||
if (test::fiz::named(section.name)->list != 0) {
|
||||
text += std::string{first ? "" : ", "} + "\"rows\": [";
|
||||
for (std::size_t row = 0; row < section.rows.size(); ++row) {
|
||||
text += (row == 0 ? "\n " : ",\n ") + section.rows[row].dump();
|
||||
}
|
||||
text += section.rows.empty() ? "]" : "\n ]";
|
||||
}
|
||||
text += "}";
|
||||
}
|
||||
return text + "\n}\n";
|
||||
}
|
||||
|
||||
std::vector<std::string> split(std::string_view const List) {
|
||||
std::vector<std::string> result;
|
||||
std::size_t start{0};
|
||||
while (start < List.size()) {
|
||||
auto const end{std::min(List.find(',', start), List.size())};
|
||||
if (end > start) {
|
||||
result.emplace_back(List.substr(start, end - start));
|
||||
}
|
||||
start = end + 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// converts the game's definitions of the real vehicles to data/fiz, from the folder of the game's vehicles given
|
||||
// in EU07_UNIT_TESTS_FIZ_SOURCE (dynamic/): the vehicles there already, and the ones named in EU07_UNIT_TESTS_FIZ_ADD
|
||||
// (paths without pkp/ and the extension, separated by commas). the game's parser reads the file with its includes,
|
||||
// the conversion keeps what the loader reads of it, and checks the loader reads the same of the converted one
|
||||
TEST_CASE("fiz: conversion of the game's definitions, when asked for") {
|
||||
auto const *source{std::getenv("EU07_UNIT_TESTS_FIZ_SOURCE")};
|
||||
if (source == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto paths{test::real_vehicles()};
|
||||
if (auto const *added{std::getenv("EU07_UNIT_TESTS_FIZ_ADD")}; added != nullptr) {
|
||||
for (auto const &path : split(added)) {
|
||||
paths.push_back(path);
|
||||
}
|
||||
}
|
||||
auto const root{std::filesystem::path{source}};
|
||||
for (auto const &path : paths) {
|
||||
CAPTURE(path);
|
||||
// the vehicles of the Polish railways are in pkp/, the others under their operators
|
||||
auto file{root / (path + ".fiz")};
|
||||
if (false == std::filesystem::exists(file)) {
|
||||
file = root / "pkp" / (path + ".fiz");
|
||||
}
|
||||
REQUIRE(std::filesystem::exists(file));
|
||||
cParser parser(file.filename().string(), cParser::buffer_FILE, file.parent_path().generic_string() + "/");
|
||||
auto const original{test::fiz::lines(parser)};
|
||||
|
||||
auto const target{std::filesystem::path{EU07_UNIT_TESTS_DATA} / "fiz" / (path + ".json")};
|
||||
std::filesystem::create_directories(target.parent_path());
|
||||
{
|
||||
std::ofstream output(target, std::ios::binary);
|
||||
output << json_text(std::filesystem::relative(file, root).generic_string(), convert(original));
|
||||
}
|
||||
cParser converted(definition::fiz(path).text(), cParser::buffer_TEXT);
|
||||
auto const expected{test::fiz::reading(original)};
|
||||
auto const actual{test::fiz::reading(test::fiz::lines(converted))};
|
||||
auto const mismatch{std::ranges::mismatch(expected, actual)};
|
||||
if (mismatch.in1 != expected.end() || mismatch.in2 != actual.end()) {
|
||||
std::filesystem::remove(target);
|
||||
FAIL_CHECK("the loader reads the converted definition differently, at " << (mismatch.in1 != expected.end() ? *mismatch.in1 : "the end") << " against "
|
||||
<< (mismatch.in2 != actual.end() ? *mismatch.in2 : "the end"));
|
||||
}
|
||||
}
|
||||
}
|
||||
34
tests/unit/test_invariants.cpp
Normal file
34
tests/unit/test_invariants.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "golden.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
// the invariants every golden trace checks (invariants.h) catch a vehicle in a state the simulation must
|
||||
// never reach, once each, naming the time and the last event
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
TEST_CASE("invariants: a vehicle in an impossible state, reported once with its time and the last event") {
|
||||
vehicle eu07{definition::fiz("4e_v1/4e")};
|
||||
test::trace trace{"invariants/self test", test::channels::brakes()};
|
||||
trace.sample(0.0, eu07.mover());
|
||||
CHECK(trace.violations().empty());
|
||||
|
||||
trace.mark("overfilled");
|
||||
eu07->BrakePress = 50.0;
|
||||
trace.sample(0.01, eu07.mover());
|
||||
trace.sample(0.02, eu07.mover());
|
||||
REQUIRE(trace.violations().size() == 1);
|
||||
auto const &violation{trace.violations().front()};
|
||||
CHECK(violation.find("brake cylinders") != std::string::npos);
|
||||
CHECK(violation.find("at 0.010 s") != std::string::npos);
|
||||
CHECK(violation.find("after \"overfilled\"") != std::string::npos);
|
||||
CHECK(violation.find("BrakePress=50") != std::string::npos);
|
||||
|
||||
eu07->BrakePress = 0.0;
|
||||
eu07->V = std::nan("");
|
||||
trace.sample(0.03, eu07.mover());
|
||||
CHECK(trace.violations().size() > 1);
|
||||
CHECK(trace.violations()[1].find("every value a number") != std::string::npos);
|
||||
}
|
||||
116
tests/unit/test_loads.cpp
Normal file
116
tests/unit/test_loads.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
// characterisation of the loads of vehicles besides the loading by commands (test_commands.cpp): the load
|
||||
// assigned to a vehicle (AssignLoad), with the pantographs of an electric vehicle set up by the "pantstate"
|
||||
// load of a scenario, and the steps of loading and unloading (LoadingDone)
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
TEST_CASE("loads: the pantographs of an electric vehicle set up by the amount of its pantstate load") {
|
||||
// bit 0 raises the front pantograph, bit 1 the rear one, bit 2 turns the vehicle round in the train first
|
||||
// (DoubleTr), so the bits name the pantographs the other way round
|
||||
struct setup {
|
||||
int amount;
|
||||
bool frontraised;
|
||||
bool rearraised;
|
||||
};
|
||||
for (auto const &[amount, frontraised, rearraised] : {setup{0, false, false}, setup{1, true, false}, setup{2, false, true}, setup{3, true, true}, setup{5, false, true},
|
||||
setup{6, true, false}}) {
|
||||
CAPTURE(amount);
|
||||
vehicle et42{definition::fiz("et42_v2/112e-a")};
|
||||
CHECK(et42->AssignLoad("pantstate", static_cast<float>(amount)));
|
||||
CHECK(et42->DoubleTr == ((amount & 4) != 0 ? -1 : 1));
|
||||
CHECK(et42->Pantographs[end::front].valve.is_enabled == frontraised);
|
||||
CHECK(et42->Pantographs[end::rear].valve.is_enabled == rearraised);
|
||||
// the load itself stays as it was
|
||||
CHECK(et42->LoadAmount == doctest::Approx(0.0));
|
||||
}
|
||||
// a vehicle without a current collector takes no such load
|
||||
vehicle wagon{definition::fiz("3wl_v2/3wl")};
|
||||
CHECK_FALSE(wagon->AssignLoad("pantstate", 3.f));
|
||||
}
|
||||
|
||||
TEST_CASE("loads: a load assigned, of one kind at a time, up to the vehicle's capacity, and emptied") {
|
||||
vehicle wagon{definition::fiz("3wl_v2/3wl")};
|
||||
auto const empty{wagon->TotalMass};
|
||||
REQUIRE(wagon->AssignLoad("coal", 10.f));
|
||||
CHECK(wagon->LoadTypeChange);
|
||||
CHECK(wagon->LoadType.name == "coal");
|
||||
CHECK(wagon->TotalMass > empty);
|
||||
// more of the same: the amount set, not added, and no more than the vehicle takes
|
||||
wagon->LoadTypeChange = false;
|
||||
REQUIRE(wagon->AssignLoad("coal", 1000.f));
|
||||
CHECK_FALSE(wagon->LoadTypeChange);
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(wagon->MaxLoad));
|
||||
// another kind can't be added to a load, nor can an unknown one be loaded
|
||||
CHECK_FALSE(wagon->AssignLoad("ruda", 5.f));
|
||||
CHECK(wagon->LoadType.name == "coal");
|
||||
// emptied, with no name
|
||||
REQUIRE(wagon->AssignLoad(""));
|
||||
CHECK(wagon->LoadTypeChange);
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(0.0));
|
||||
CHECK(wagon->LoadType.name.empty());
|
||||
CHECK_FALSE(wagon->AssignLoad("unknown", 5.f));
|
||||
CHECK(wagon->AssignLoad("ruda", 5.f));
|
||||
}
|
||||
|
||||
TEST_CASE("loads: the steps of loading and unloading") {
|
||||
// most of the game's wagons may be overloaded (OverLoadFactor), the 3WL not
|
||||
vehicle wagon{definition::fiz("3wl_v2/3wl").set("Load", "OverLoadFactor", 1.5)};
|
||||
REQUIRE(wagon->AssignLoad("coal", 10.f));
|
||||
auto const capacity{wagon->MaxLoad * (1.0 + wagon->OverLoadFactor)};
|
||||
|
||||
SUBCASE("no speed of the change: done at once") {
|
||||
CHECK(wagon->LoadingDone(0.0, "coal"));
|
||||
CHECK(wagon->LoadStatus == 4);
|
||||
}
|
||||
SUBCASE("no load, or another one, named: done when it was") {
|
||||
wagon->LoadStatus = 1;
|
||||
CHECK_FALSE(wagon->LoadingDone(1.0, ""));
|
||||
CHECK_FALSE(wagon->LoadingDone(1.0, "ruda"));
|
||||
wagon->LoadStatus = 4;
|
||||
CHECK(wagon->LoadingDone(1.0, ""));
|
||||
}
|
||||
SUBCASE("unloading, step by step, what was asked or all of it, the name going with the last of it") {
|
||||
wagon->CommandIn.Value1 = 4.0; // asked to unload
|
||||
wagon->LastLoadChangeTime = 2.0; // at 1 a second
|
||||
CHECK_FALSE(wagon->LoadingDone(-1.0, "coal"));
|
||||
CHECK(wagon->LoadStatus == 2);
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(8.0));
|
||||
CHECK(wagon->LastLoadChangeTime == doctest::Approx(0.0));
|
||||
// nothing done since the last step
|
||||
CHECK_FALSE(wagon->LoadingDone(-1.0, "coal"));
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(8.0));
|
||||
wagon->LastLoadChangeTime = 2.0;
|
||||
CHECK(wagon->LoadingDone(-1.0, "coal"));
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(6.0));
|
||||
wagon->CommandIn.Value1 = 100.0;
|
||||
wagon->LastLoadChangeTime = 10.0;
|
||||
CHECK(wagon->LoadingDone(-1.0, "coal"));
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(0.0));
|
||||
CHECK(wagon->LoadType.name.empty());
|
||||
}
|
||||
SUBCASE("loading, step by step, up to what was asked or what the vehicle takes, slower when overloaded") {
|
||||
wagon->CommandIn.Value1 = 5.0;
|
||||
wagon->LastLoadChangeTime = 2.0;
|
||||
CHECK_FALSE(wagon->LoadingDone(1.0, "coal"));
|
||||
CHECK(wagon->LoadStatus == 1);
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(12.0));
|
||||
wagon->LastLoadChangeTime = 3.0;
|
||||
CHECK(wagon->LoadingDone(1.0, "coal"));
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(15.0));
|
||||
wagon->CommandIn.Value1 = 1000.0;
|
||||
wagon->LastLoadChangeTime = 1000.0;
|
||||
CHECK(wagon->LoadingDone(1.0, "coal"));
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(capacity));
|
||||
CHECK(capacity == doctest::Approx(2.5 * wagon->MaxLoad));
|
||||
// over the vehicle's own capacity, the change goes at half the speed
|
||||
wagon->CommandIn.Value1 = 1000.0;
|
||||
wagon->LastLoadChangeTime = 4.0;
|
||||
CHECK_FALSE(wagon->LoadingDone(-1.0, "coal"));
|
||||
CHECK(wagon->LoadAmount == doctest::Approx(capacity - 2.0));
|
||||
}
|
||||
}
|
||||
61
tests/unit/test_queries.cpp
Normal file
61
tests/unit/test_queries.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
// characterisation of what the game's panels read of a vehicle besides the gauges recorded in the traces: the
|
||||
// description of its damage on the driver's panel (driveruipanels.cpp)
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
TEST_CASE("queries: the damage of a vehicle as the driver's panel describes it") {
|
||||
vehicle locomotive{definition::fiz("4e_v1/4e")};
|
||||
vehicle wagon{definition::fiz("3wl_v2/3wl")};
|
||||
// a powered locomotive and a wagon read some of the flags differently
|
||||
locomotive->Power = 2000.0;
|
||||
REQUIRE(wagon->Power < 0.1);
|
||||
|
||||
struct damage {
|
||||
int flag;
|
||||
char const *locomotive;
|
||||
char const *wagon;
|
||||
};
|
||||
for (auto const &[flag, locomotivetext, wagontext] : {
|
||||
damage{0, "OK", "OK"},
|
||||
damage{dtrain_thinwheel, "Thin wheel", "Load shifted"},
|
||||
damage{dtrain_wheelwear, "Wheel wear", "Wheel wear"},
|
||||
damage{dtrain_bearing, "Bearing damaged", "Bearing damaged"},
|
||||
damage{dtrain_coupling, "Coupler broken", "Coupler broken"},
|
||||
damage{dtrain_loaddamage, "Ventilator damaged", "Load damaged"},
|
||||
damage{dtrain_loaddestroyed, "Engine damaged", "LOAD DESTROYED"},
|
||||
damage{dtrain_axle, "Axle broken", "Axle broken"},
|
||||
damage{dtrain_out, "DERAILED", "DERAILED"},
|
||||
// the last flag of the list wins
|
||||
damage{dtrain_bearing | dtrain_axle, "Axle broken", "Axle broken"},
|
||||
damage{255, "WRECKED", "WRECKED"},
|
||||
}) {
|
||||
CAPTURE(flag);
|
||||
locomotive->DamageFlag = flag;
|
||||
wagon->DamageFlag = flag;
|
||||
CHECK(locomotive->EngineDescription(0) == locomotivetext);
|
||||
CHECK(wagon->EngineDescription(0) == wagontext);
|
||||
}
|
||||
// flat wheels count as worn ones
|
||||
wagon->DamageFlag = 0;
|
||||
wagon->WheelFlat = 6.0;
|
||||
CHECK(wagon->EngineDescription(0) == "Wheel wear");
|
||||
// nothing else is described
|
||||
CHECK(wagon->EngineDescription(1) == "Invalid qualifier");
|
||||
}
|
||||
|
||||
TEST_CASE("queries: the ammeters of a vehicle without power show the current of the ones it controls") {
|
||||
vehicle unpowered{definition::fiz("en57_v1/6ba_840")};
|
||||
vehicle powered{definition::fiz("en57_v1/5bgb")};
|
||||
unpowered->Attach(end::rear, end::front, &powered.mover(), coupling::control, true, false);
|
||||
powered->Power = 600.0;
|
||||
powered->Itot = 321.7;
|
||||
unpowered->Power = 0.0;
|
||||
CHECK(unpowered->ShowCurrent(0) == doctest::Approx(321.0)); // whole amperes
|
||||
powered->Power = 0.0;
|
||||
CHECK(unpowered->ShowCurrent(0) == doctest::Approx(0.0));
|
||||
}
|
||||
270
tests/unit/test_traction.cpp
Normal file
270
tests/unit/test_traction.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
#include "drive.h"
|
||||
#include "golden.h"
|
||||
#include "real_vehicles.h"
|
||||
#include "scenario.h"
|
||||
|
||||
#include "McZapkie/hamulce.h"
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
// characterisation of the drive of every real powered vehicle, driven alone from its front cab under a 3 kV
|
||||
// catenary through test::drive_cycle(), in golden traces (data/golden/traction/). the cars of the electric
|
||||
// units which take power or battery from the rest of their unit don't start alone: their traces record
|
||||
// that, test_consist.cpp drives the whole units
|
||||
|
||||
TEST_CASE("traction: every real powered vehicle started up, driven to full power and braked to a stop") {
|
||||
for (auto const &path : test::real_vehicles()) {
|
||||
CAPTURE(path);
|
||||
test::reseed_random();
|
||||
vehicle real{definition::fiz(path), 0.0, "test", 1};
|
||||
if (false == test::is_powered(real.mover())) {
|
||||
continue;
|
||||
}
|
||||
using namespace test::channels;
|
||||
test::trace trace{"traction/" + path, motion() + traction() + air() + brakes(), 100};
|
||||
real.record(trace);
|
||||
test::drive_cycle(test::driving(real), test::track{0.15, 0.0, test::catenary_3kv}, trace);
|
||||
// every vehicle getting its line breaker closed runs off and is braked to a stop. the SM31 and the TEM2
|
||||
// barely move (COVERAGE.md); the cars of a unit taking their power from another car don't start alone
|
||||
if (real->Mains) {
|
||||
auto const crawls{path == "sm31_v1/411d" || path == "tem2_v2/tem2a"};
|
||||
CHECK((real->DistCounter > 0.2 /* km */) != crawls);
|
||||
// but the road vehicle, which a minute of full service only slows down
|
||||
CHECK((real->Vel < 0.5) != (path == "road/man/nl293"));
|
||||
}
|
||||
trace.check();
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using test::scenario;
|
||||
using namespace test::channels;
|
||||
|
||||
void stop(scenario &Scenario) {
|
||||
Scenario.notch_back(0);
|
||||
Scenario.act("brake");
|
||||
Scenario.cab().BrakeLevelSet(Scenario.cab().Handle->GetPos(bh_FB));
|
||||
Scenario.wait(60.0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("traction: the line breaker opened by the catenary lost, and by too high a voltage") {
|
||||
// the voltage relays of the series motors, and the induction motors' own limits: under MinV of the current
|
||||
// collector, or over MaxV (with the overvoltage protection, OVP) and over MaxV + 200 V for the induction motors
|
||||
for (auto const &[name, vehicles] : std::vector<std::pair<std::string, std::vector<char const *>>>{
|
||||
{"eu07", {"4e_v1/4e"}}, {"et42", {"et42_v2/112e-a", "et42_v2/112e-b"}}, {"eu47", {"e186_v2/eu47"}}}) {
|
||||
CAPTURE(name);
|
||||
scenario scenario{"traction/catenary/" + name, motion() + traction()};
|
||||
for (auto const *path : vehicles) {
|
||||
scenario.add(path, scenario.train().size() == 0 ? 1 : 0);
|
||||
}
|
||||
scenario.add("bdhpumn_v3/bdhpumn");
|
||||
REQUIRE(scenario.start_up());
|
||||
scenario.get_going();
|
||||
auto &controlling{scenario.driver().controlling};
|
||||
scenario.full_power(10.0);
|
||||
REQUIRE(controlling.Mains);
|
||||
scenario.act("catenary lost");
|
||||
scenario.line().voltage = 0.0;
|
||||
scenario.wait(5.0);
|
||||
CHECK_FALSE(controlling.Mains);
|
||||
CHECK(controlling.Im == doctest::Approx(0.0));
|
||||
scenario.act("catenary back");
|
||||
scenario.line().voltage = test::catenary_3kv;
|
||||
scenario.notch_back(0);
|
||||
CHECK(scenario.start_up());
|
||||
scenario.full_power(5.0);
|
||||
scenario.act("overvoltage");
|
||||
scenario.line().voltage = controlling.EnginePowerSource.CollectorParameters.MaxV + 300.0;
|
||||
scenario.wait(5.0);
|
||||
CHECK(controlling.Mains == (controlling.EngineType == TEngineType::ElectricSeriesMotor && false == controlling.EnginePowerSource.CollectorParameters.OVP));
|
||||
scenario.line().voltage = test::catenary_3kv;
|
||||
stop(scenario);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("traction: the ET42 at the high current setting, its halves in series, and its switched electrodynamic brake") {
|
||||
for (auto const high : {false, true}) {
|
||||
CAPTURE(high);
|
||||
scenario scenario{std::string{"traction/et42/"} + (high ? "high current" : "low current"), motion() + traction() + brakes()};
|
||||
scenario.add("et42_v2/112e-a", 1).add("et42_v2/112e-b").add("3wl_v2/3wl").add("3wl_v2/3wl").add("3wl_v2/3wl");
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &et42{scenario.cab()};
|
||||
scenario.act("current setting");
|
||||
CHECK(et42.CurrentSwitch(high) == high);
|
||||
// the relay takes the setting at the next step, with the controller at zero
|
||||
scenario.get_going();
|
||||
CHECK((et42.Imax == et42.ImaxHi) == high);
|
||||
scenario.full_power(60.0);
|
||||
// at the high current setting the controller stops at the last series position: the halves' motors stay
|
||||
// in series, at half the voltage each, for a heavy start, and the train crawls
|
||||
CHECK((et42.RList[et42.MainCtrlPos].Bn > 1) != high);
|
||||
CHECK(et42.Vel > (high ? 30.0 : 90.0));
|
||||
CHECK(et42.Vel < (high ? 50.0 : 110.0));
|
||||
scenario.act("controller to zero");
|
||||
while (et42.DecMainCtrl(2)) {
|
||||
// down to zero
|
||||
}
|
||||
scenario.wait(2.0);
|
||||
scenario.act("dynamic brake");
|
||||
CHECK(et42.DynamicBrakeSwitch(true));
|
||||
scenario.wait(5.0);
|
||||
scenario.full_power(20.0);
|
||||
// the controller sets the brake's strength. from the low setting's top speed, over 100 km/h, the motors'
|
||||
// current goes over 300 A at the first position and the overload relay trips, leaving the train to roll;
|
||||
// from the high setting's, under 40 km/h, the brake stops the train
|
||||
CHECK(et42.FuseFlag != high);
|
||||
CHECK((et42.Vel == doctest::Approx(0.0)) == high);
|
||||
scenario.act("dynamic brake off");
|
||||
scenario.notch_back(0);
|
||||
et42.DynamicBrakeSwitch(false);
|
||||
stop(scenario);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("traction: the field shunting relays of the diesel-electric locomotives, at full power and notched back") {
|
||||
// each kind of the automatic relays (RelayType) the game's diesel-electrics have, run with a wagon up to full
|
||||
// shunting (and past their top speed, which nothing limits) and notched back through the positions where the
|
||||
// relays let the shunting go: by the current (0), by the speed alone (1, which keeps it at any position), by
|
||||
// the current at the full position only (41), by the position and the speed (45, 46)
|
||||
struct locomotive {
|
||||
char const *path;
|
||||
int relaytype;
|
||||
std::array<int, 4> shunting; // after notching back to 11, 10, 7 and 3
|
||||
};
|
||||
for (auto const &[path, relaytype, shunting] : {locomotive{"cd/754_v1/754", 0, {3, 3, 3, 0}}, locomotive{"sm31_v1/411d", 1, {2, 2, 2, 2}},
|
||||
locomotive{"sm40_v1/sm40", 41, {1, 1, 1, 1}}, locomotive{"su45_v2/301d", 45, {3, 2, 0, 0}},
|
||||
locomotive{"su46_v2/303d", 46, {4, 2, 0, 0}}}) {
|
||||
CAPTURE(path);
|
||||
scenario scenario{std::string{"traction/relays/"} + path, motion() + traction()};
|
||||
scenario.add(path, 1).add("bdhpumn_v3/bdhpumn");
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &controlling{scenario.driver().controlling};
|
||||
CHECK(controlling.RelayType == relaytype);
|
||||
scenario.get_going();
|
||||
scenario.full_power(120.0);
|
||||
CHECK(controlling.ScndCtrlPos == controlling.ScndCtrlPosNo);
|
||||
auto expected{shunting.begin()};
|
||||
for (auto const position : {11, 10, 7, 3}) {
|
||||
CAPTURE(position);
|
||||
scenario.act(std::format("notch back to {}", position));
|
||||
scenario.notch_back(position);
|
||||
scenario.wait(15.0);
|
||||
CHECK(controlling.ScndCtrlPos == *expected++);
|
||||
}
|
||||
stop(scenario);
|
||||
scenario.check();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("traction: the stages of the EW58's electrodynamic brake, set by the positions of its ep handle") {
|
||||
// the FVE408's positions 1 to 5 give the ep brake's strength, whose whole part is the stage of the motors'
|
||||
// brake (TUHEX): 1, 1, 2, 3, 3; over 100 km/h the motors brake at the first stage alone
|
||||
scenario scenario{"traction/ew58 brake stages", motion() + traction() + brakes()};
|
||||
for (auto const *car : {"ew58_v1/ew58-sa", "ew58_v1/ew58-d", "ew58_v1/ew58-sb"}) {
|
||||
scenario.add(car, scenario.train().size() == 0 ? 1 : 0, test::consist::full_coupling, 115.0);
|
||||
}
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &ew58{scenario.cab()};
|
||||
for (auto const &[position, stage] : {std::pair{1, 1}, std::pair{3, 2}, std::pair{4, 3}, std::pair{2, 1}, std::pair{5, 3}}) {
|
||||
CAPTURE(position);
|
||||
scenario.act(std::format("position {}", position));
|
||||
ew58.BrakeLevelSet(position);
|
||||
scenario.wait(6.0);
|
||||
CHECK(ew58.TUHEX_StageActual == stage);
|
||||
CHECK(ew58.DynamicBrakeFlag);
|
||||
CHECK(ew58.Im < 0.0);
|
||||
}
|
||||
scenario.act("release");
|
||||
ew58.BrakeLevelSet(ew58.Handle->GetPos(bh_RP));
|
||||
scenario.wait(10.0);
|
||||
CHECK(ew58.TUHEX_StageActual == 0);
|
||||
scenario.check();
|
||||
}
|
||||
|
||||
TEST_CASE("traction: the induction motor drive's speed control, its electrodynamic brake by the local brake, and at the voltage's limit") {
|
||||
scenario scenario{"traction/eu47 drive", motion() + traction() + brakes()};
|
||||
scenario.add("e186_v2/eu47", 1).add("bdhpumn_v3/bdhpumn").add("bdhpumn_v3/bdhpumn");
|
||||
REQUIRE(scenario.start_up());
|
||||
auto &eu47{scenario.cab()};
|
||||
scenario.get_going();
|
||||
// the second controller of the EU47 sets the speed to hold (SpeedCtrlType=Time): position 2 keeps the speed
|
||||
// set, 3 raises it by 10 km/h every SpeedCtrlDelay, 4 sets the top speed, 1 lowers it, 0 drops it
|
||||
REQUIRE(eu47.ScndCtrlPosNo == 4);
|
||||
REQUIRE(eu47.SpeedCtrlTypeTime);
|
||||
scenario.full_power(0.0);
|
||||
scenario.act("speed up");
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
eu47.IncScndCtrl(1);
|
||||
}
|
||||
scenario.wait(3.0);
|
||||
scenario.act("hold");
|
||||
eu47.DecScndCtrl(1);
|
||||
scenario.wait(1.0);
|
||||
CHECK(eu47.SpeedCtrlValue == doctest::Approx(60.0));
|
||||
scenario.wait(60.0);
|
||||
CHECK(eu47.Vel == doctest::Approx(60.0).epsilon(0.01));
|
||||
scenario.act("slow down");
|
||||
eu47.DecScndCtrl(1);
|
||||
scenario.wait(1.5);
|
||||
eu47.IncScndCtrl(1);
|
||||
scenario.wait(1.0);
|
||||
CHECK(eu47.SpeedCtrlValue == doctest::Approx(20.0));
|
||||
// a lower speed set only takes the power off, the train rolls on
|
||||
scenario.wait(40.0);
|
||||
CHECK(eu47.Vel > 50.0);
|
||||
scenario.act("top speed");
|
||||
eu47.IncScndCtrl(2);
|
||||
scenario.wait(5.0);
|
||||
CHECK(eu47.SpeedCtrlValue == doctest::Approx(eu47.Vmax));
|
||||
scenario.act("speed control off");
|
||||
while (eu47.DecScndCtrl(1)) {
|
||||
// down to zero
|
||||
}
|
||||
scenario.notch_back(0);
|
||||
scenario.wait(2.0);
|
||||
CHECK(eu47.SpeedCtrlValue == doctest::Approx(0.0));
|
||||
// the local brake sets the flag of the electrodynamic brake, which keeps the train brake's air out of the
|
||||
// cylinders, but the motors' brake follows the train brake alone: the local brake's air does the braking
|
||||
scenario.act("local brake");
|
||||
eu47.IncLocalBrakeLevel(LocalBrakePosNo);
|
||||
scenario.wait(5.0);
|
||||
CHECK(eu47.DynamicBrakeFlag);
|
||||
CHECK(eu47.Im == doctest::Approx(0.0));
|
||||
CHECK(eu47.BrakePress > 2.0);
|
||||
scenario.act("local brake off");
|
||||
eu47.DecLocalBrakeLevel(LocalBrakePosNo);
|
||||
scenario.wait(10.0);
|
||||
// braking back into the catenary: at its usual voltage, and at its highest, over the drive's MaxV, where
|
||||
// the drive lets less of the current go back to it (Vadd)
|
||||
for (auto const voltage : {test::catenary_3kv, eu47.EnginePowerSource.CollectorParameters.MaxV + 100.0}) {
|
||||
CAPTURE(voltage);
|
||||
scenario.line().voltage = voltage;
|
||||
scenario.act(std::format("service brake at {} V", static_cast<int>(voltage)));
|
||||
eu47.BrakeLevelSet(eu47.Handle->GetPos(bh_FB));
|
||||
scenario.wait(6.0);
|
||||
CHECK(eu47.DynamicBrakeFlag);
|
||||
CHECK(eu47.Im < -100.0);
|
||||
CHECK((eu47.Vadd > 1.0) == (voltage > eu47.EnginePowerSource.CollectorParameters.MaxV));
|
||||
eu47.BrakeLevelSet(eu47.Handle->GetPos(bh_RP));
|
||||
scenario.wait(6.0);
|
||||
}
|
||||
scenario.line().voltage = test::catenary_3kv;
|
||||
scenario.act("line breaker off");
|
||||
eu47.MainSwitch(false);
|
||||
scenario.wait(5.0);
|
||||
CHECK(eu47.Im == doctest::Approx(0.0));
|
||||
stop(scenario);
|
||||
scenario.check();
|
||||
}
|
||||
@@ -1,60 +1,26 @@
|
||||
#include "stdafx.h"
|
||||
#include "vehicle.h"
|
||||
#include "golden.h"
|
||||
#include "real_vehicles.h"
|
||||
#include "fiz.h"
|
||||
#include "vehicle/DynObj.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "utilities/Globals.h"
|
||||
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
struct section_format {
|
||||
char separator; // the game's definitions end section names with either '.' or ':'
|
||||
char const *table_end{nullptr}; // the line closing the rows of a table section
|
||||
};
|
||||
|
||||
// the sections TMoverParameters::LoadFIZ() reads, see its issection() calls. a section missing here
|
||||
// would be silently skipped by the loader, and the test would run on the defaults instead
|
||||
std::map<std::string, section_format, std::less<>> const sections{
|
||||
{"Param", {'.'}},
|
||||
{"Load", {':'}},
|
||||
{"Dimensions", {':'}},
|
||||
{"Wheels", {':'}},
|
||||
{"Brake", {':'}},
|
||||
{"Doors", {':'}},
|
||||
{"BuffCoupl", {'.'}},
|
||||
{"BuffCoupl1", {'.'}},
|
||||
{"BuffCoupl2", {'.'}},
|
||||
{"TurboPos", {':'}},
|
||||
{"Cntrl", {'.'}},
|
||||
{"Blending", {':'}},
|
||||
{"DCEMUED", {':'}},
|
||||
{"SpringBrake", {':'}},
|
||||
{"Light", {':'}},
|
||||
{"Headlights", {':'}},
|
||||
{"Clima", {':'}},
|
||||
{"Power", {':'}},
|
||||
{"SpeedControl", {':'}},
|
||||
{"Engine", {':'}},
|
||||
{"Switches", {':'}},
|
||||
{"Security", {':'}},
|
||||
{"Circuit", {':'}},
|
||||
{"AI", {':'}},
|
||||
{"LightsList", {':', "endL"}},
|
||||
{"DimmerList", {':', "endDimmerList"}},
|
||||
{"WiperList", {':', "endwl"}},
|
||||
{"CompressorList", {':', "endCL"}},
|
||||
{"RList", {':', "END-RL"}},
|
||||
{"MotorParamTable0", {':', "END-MPT"}},
|
||||
};
|
||||
|
||||
section_format const &format_of(std::string const &Section) {
|
||||
auto const lookup{sections.find(Section)};
|
||||
if (lookup == sections.end()) {
|
||||
throw definition_error("unknown vehicle definition section " + Section + ", see tests/unit/vehicle.cpp");
|
||||
fiz::section const &format_of(std::string const &Section) {
|
||||
auto const section{fiz::named(Section)};
|
||||
if (section == nullptr) {
|
||||
throw definition_error("vehicle definition section " + Section + " isn't one the loader reads, see tests/unit/fiz.cpp");
|
||||
}
|
||||
return lookup->second;
|
||||
return *section;
|
||||
}
|
||||
|
||||
std::string value_text(nlohmann::ordered_json const &Value) {
|
||||
@@ -67,9 +33,9 @@ std::string value_text(nlohmann::ordered_json const &Value) {
|
||||
return Value.dump();
|
||||
}
|
||||
|
||||
// the rows of a table section, each a list of values, and the line closing them
|
||||
std::string table_text(std::string const &Section, section_format const &Format, nlohmann::ordered_json const &Rows) {
|
||||
if (Format.table_end == nullptr) {
|
||||
// the rows of a list section, each a list of values, and the line closing them
|
||||
std::string table_text(std::string const &Section, fiz::section const &Format, nlohmann::ordered_json const &Rows) {
|
||||
if (Format.end == nullptr) {
|
||||
throw definition_error("vehicle definition section " + Section + " has no rows");
|
||||
}
|
||||
std::string text;
|
||||
@@ -79,34 +45,47 @@ std::string table_text(std::string const &Section, section_format const &Format,
|
||||
}
|
||||
text += "\n";
|
||||
}
|
||||
return text + Format.table_end + "\n";
|
||||
return text + Format.end + "\n";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
definition definition::load(std::string const &Name) {
|
||||
auto const path{std::string{EU07_UNIT_TESTS_DATA} + "/" + Name + ".json"};
|
||||
std::ifstream file(path);
|
||||
nlohmann::ordered_json sections_of(std::string const &Path) {
|
||||
std::ifstream file(Path);
|
||||
if (false == file.is_open()) {
|
||||
throw definition_error("no test vehicle definition " + path);
|
||||
throw definition_error("no test vehicle definition " + Path);
|
||||
}
|
||||
definition result;
|
||||
// not brace-initialised: json{other} makes an array of other with GCC and Clang (the initializer list constructor wins)
|
||||
auto const json = nlohmann::ordered_json::parse(file, nullptr, true, true);
|
||||
if (false == json.is_object()) {
|
||||
throw definition_error("test vehicle definition " + path + " isn't a JSON object");
|
||||
throw definition_error("test vehicle definition " + Path + " isn't a JSON object");
|
||||
}
|
||||
auto result = nlohmann::ordered_json::object();
|
||||
for (auto const &[section, keys] : json.items()) {
|
||||
// keys starting with _ are comments
|
||||
if (section.starts_with('_')) {
|
||||
continue;
|
||||
}
|
||||
format_of(section);
|
||||
result.m_sections[section] = keys;
|
||||
result[section] = keys;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
definition definition::load(std::string const &Name) {
|
||||
definition result;
|
||||
result.m_sections = sections_of(std::string{EU07_UNIT_TESTS_DATA} + "/" + Name + ".json");
|
||||
return result;
|
||||
}
|
||||
|
||||
definition definition::fiz(std::string const &Path) {
|
||||
definition result;
|
||||
result.m_sections = sections_of(std::string{EU07_UNIT_TESTS_DATA} + "/fiz/" + Path + ".json");
|
||||
auto const slash{Path.rfind('/')};
|
||||
result.m_typename = slash == std::string::npos ? Path : Path.substr(slash + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
definition &definition::set(std::string const &Section, std::string const &Key, nlohmann::ordered_json const &Value) {
|
||||
format_of(Section);
|
||||
m_sections[Section][Key] = Value;
|
||||
@@ -143,52 +122,145 @@ std::string definition::text() const {
|
||||
return text;
|
||||
}
|
||||
|
||||
vehicle::vehicle(definition const &Definition, double Velocity, std::string const &Name) {
|
||||
// the same steps as TDynamicObject::Init()
|
||||
m_mover = std::make_unique<TMoverParameters>(Velocity, Name, Name, 0);
|
||||
vehicle::vehicle(definition const &Definition, double Velocity, std::string const &Name, int Cab) : m_cab(Cab) {
|
||||
// the same steps as TDynamicObject::Init(), for a vehicle set the usual way round (iDirection 1)
|
||||
auto const typename_{Definition.type_name().empty() ? Name : Definition.type_name()};
|
||||
m_mover = std::make_unique<TMoverParameters>(Velocity, typename_, Name, Cab);
|
||||
if (false == m_mover->LoadFIZ_Text(Definition.text())) {
|
||||
throw definition_error("the test vehicle definition didn't load");
|
||||
}
|
||||
m_mover->AssignLoad("", 0.f);
|
||||
m_mover->ComputeMass();
|
||||
auto const driveractive{Velocity != 0.0};
|
||||
if (false == m_mover->CheckLocomotiveParameters(driveractive, Velocity >= 0.0 ? 1 : -1)) {
|
||||
if (false == m_mover->CheckLocomotiveParameters(driveractive, (Velocity > 0 ? 1 : -1) * Cab)) {
|
||||
throw definition_error("parameters mismatch in the test vehicle definition");
|
||||
}
|
||||
m_mover->MainCtrlPos = m_mover->MainCtrlNoPowerPos();
|
||||
m_mover->LocalBrakePosA = 0.0;
|
||||
m_mover->BrakeCtrlPos = static_cast<int>(std::floor(m_mover->Handle->GetPos(driveractive ? bh_RP : bh_NP)));
|
||||
if (driveractive) {
|
||||
m_mover->BrakeCtrlPos = static_cast<int>(std::floor(m_mover->Handle->GetPos(Cab == 0 ? bh_NP : bh_RP)));
|
||||
// a driver keeps a vehicle on standby on its independent brake
|
||||
if (Cab != 0 && m_mover->LocalBrake != TLocalBrake::ManualBrake && Velocity < 1.0) {
|
||||
m_mover->IncLocalBrakeLevel(LocalBrakePosNo);
|
||||
if (m_mover->EIMCtrlEmergency) {
|
||||
m_mover->DecLocalBrakeLevel(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_mover->BrakeCtrlPos = static_cast<int>(std::floor(m_mover->Handle->GetPos(bh_NP)));
|
||||
}
|
||||
m_mover->BrakeLevelSet(m_mover->BrakeCtrlPos);
|
||||
}
|
||||
|
||||
void vehicle::step(track const &Track, double Dt) {
|
||||
compute_forces(Dt);
|
||||
compute_movement(Track, Dt, TLocation{0.0, 0.0, 0.0});
|
||||
}
|
||||
|
||||
void vehicle::compute_forces(double Dt) {
|
||||
if (m_pipepressure >= 0.0) {
|
||||
m_mover->Pipe->CreatePress(m_pipepressure);
|
||||
begin_step();
|
||||
TLocation const location{0.0, 0.0, 0.0};
|
||||
for (int iteration = 1; iteration < Track.iterations; ++iteration) {
|
||||
forces(Dt);
|
||||
fast_move(Track, Dt, location);
|
||||
}
|
||||
m_mover->ComputeTotalForce(Dt);
|
||||
forces(Dt);
|
||||
move(Track, Dt, location, m_mover->PipePress);
|
||||
}
|
||||
|
||||
double vehicle::compute_movement(track const &Track, double Dt, TLocation const &Location) {
|
||||
namespace {
|
||||
|
||||
TTrackShape shape_of(track const &Track) {
|
||||
TTrackShape shape;
|
||||
shape.Len = 1000.0;
|
||||
shape.dHtrack = Track.gradient;
|
||||
return shape;
|
||||
}
|
||||
|
||||
TTrackParam parameters_of(track const &Track, TMoverParameters const &Mover) {
|
||||
TTrackParam param;
|
||||
param.Width = 1.435;
|
||||
param.Width = Track.width;
|
||||
param.friction = Track.friction;
|
||||
param.CategoryFlag = 1;
|
||||
TTractionParam const traction;
|
||||
// the vehicle's own kind of way: a road vehicle on rails derails as soon as it moves
|
||||
if (Track.category != 0) {
|
||||
param.CategoryFlag = Track.category;
|
||||
}
|
||||
else {
|
||||
param.CategoryFlag = Mover.CategoryFlag != 0 ? Mover.CategoryFlag : 1;
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
double vehicle::fast_move(track const &Track, double Dt, TLocation const &Location) {
|
||||
// TDynamicObject::FastUpdate(), the iterations of a frame before the last one
|
||||
auto param{parameters_of(Track, *m_mover)};
|
||||
return m_mover->FastComputeMovement(Dt, shape_of(Track), param, Location, TRotation{0.0, 0.0, 0.0});
|
||||
}
|
||||
|
||||
void vehicle::begin_step() {
|
||||
// the conditions the test keeps
|
||||
if (m_pipepressure >= 0.0) {
|
||||
m_mover->Pipe->CreatePress(m_pipepressure);
|
||||
}
|
||||
if (m_reservoirpressure >= 0.0 && m_mover->VeselVolume > 0.0) {
|
||||
m_mover->CompressedVolume = m_reservoirpressure * m_mover->VeselVolume;
|
||||
}
|
||||
// vehicle_table::update(), before the forces
|
||||
m_mover->ComputeConstans();
|
||||
}
|
||||
|
||||
void vehicle::forces(double Dt) {
|
||||
// TDynamicObject::UpdateForce()
|
||||
m_mover->ComputeTotalForce(Dt);
|
||||
}
|
||||
|
||||
double vehicle::move(track const &Track, double Dt, TLocation const &Location, double Trainpipe) {
|
||||
auto const shape{shape_of(Track)};
|
||||
auto const param{parameters_of(Track, *m_mover)};
|
||||
TRotation const rotation{0.0, 0.0, 0.0};
|
||||
return m_mover->ComputeMovement(Dt, Dt, shape, param, traction, Location, rotation);
|
||||
|
||||
// what TDynamicObject::Update() does before the movement. a raised pantograph touches the wire at once,
|
||||
// the game animates its rise
|
||||
auto &mover{*m_mover};
|
||||
mover.PantFrontVolt = mover.Pantographs[end::front].is_active ? Track.voltage : 0.0;
|
||||
mover.PantRearVolt = mover.Pantographs[end::rear].is_active ? Track.voltage : 0.0;
|
||||
TTractionParam traction;
|
||||
traction.TractionVoltage =
|
||||
mover.EnginePowerSource.SourceType == TPowerSource::CurrentCollector ? std::max(std::abs(mover.PantRearVolt), std::abs(mover.PantFrontVolt)) : 0.95 * mover.EnginePowerSource.MaxVoltage;
|
||||
traction.TractionFreq = 0;
|
||||
traction.TractionMaxCurrent = 7500;
|
||||
traction.TractionResistivity = 0.3;
|
||||
mover.PantographVoltage = traction.TractionVoltage;
|
||||
if (m_cab != 0) {
|
||||
using enum TEngineType;
|
||||
// the driver's own vehicle, which gets the average pressure of the train's brake pipe
|
||||
mover.EqvtPipePress = Trainpipe;
|
||||
if (auto const diesel{mover.EngineType == DieselEngine || mover.EngineType == DieselElectric}; diesel && mover.EIMCtrlType > 0) {
|
||||
mover.CheckEIMIC(Dt);
|
||||
if (mover.SpeedCtrl) {
|
||||
mover.CheckSpeedCtrl(Dt);
|
||||
}
|
||||
mover.eimic_real = std::min(mover.eimic, mover.eimicSpeedCtrl);
|
||||
}
|
||||
if (mover.EngineType == ElectricInductionMotor) {
|
||||
// the share of the electric and pneumatic brake over the train (TDynamicObject's MED) isn't here
|
||||
mover.CheckEIMIC(Dt);
|
||||
mover.CheckSpeedCtrl(Dt);
|
||||
mover.eimic_real = std::min(mover.eimic, mover.eimicSpeedCtrl);
|
||||
}
|
||||
}
|
||||
|
||||
// the whole frame's time, of all its iterations
|
||||
auto const frame{Dt * Track.iterations};
|
||||
auto const distance{m_mover->ComputeMovement(Dt, frame, shape, param, traction, Location, rotation)};
|
||||
m_time += frame;
|
||||
if (m_trace != nullptr) {
|
||||
m_trace->sample(m_time, *m_mover);
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
void vehicle::run(double Seconds, track const &Track, double Dt) {
|
||||
// whole steps: summing up Dt would make the step count depend on the rounding
|
||||
auto const steps{std::lround(Seconds / Dt)};
|
||||
// whole frames: summing up Dt would make their count depend on the rounding
|
||||
auto const steps{std::lround(Seconds / (Dt * Track.iterations))};
|
||||
for (long i = 0; i < steps; ++i) {
|
||||
step(Track, Dt);
|
||||
}
|
||||
@@ -253,10 +325,12 @@ void pair::find_neighbours() {
|
||||
void pair::step(track const &Track, double Dt) {
|
||||
find_neighbours();
|
||||
for (auto const &placed : m_vehicles) {
|
||||
placed.owner->compute_forces(Dt);
|
||||
placed.owner->begin_step();
|
||||
placed.owner->forces(Dt);
|
||||
}
|
||||
for (auto &placed : m_vehicles) {
|
||||
placed.position += placed.heading * placed.owner->compute_movement(Track, Dt, TLocation{placed.position, 0.0, 0.0});
|
||||
auto const &mover{placed.owner->mover()};
|
||||
placed.position += placed.heading * placed.owner->move(Track, Dt, TLocation{placed.position, 0.0, 0.0}, mover.PipePress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,4 +352,24 @@ int pair::coupling() const {
|
||||
return m_vehicles[0].owner->mover().Couplers[m_vehicles[0].end].CouplingFlag;
|
||||
}
|
||||
|
||||
void reseed_random() {
|
||||
Global.random_engine.seed(1);
|
||||
Global.local_random_engine.seed(1);
|
||||
}
|
||||
|
||||
std::vector<std::string> const &real_vehicles() {
|
||||
static std::vector<std::string> const paths{[] {
|
||||
std::vector<std::string> result;
|
||||
auto const root{std::filesystem::path{EU07_UNIT_TESTS_DATA} / "fiz"};
|
||||
for (auto const &entry : std::filesystem::recursive_directory_iterator(root)) {
|
||||
if (entry.is_regular_file() && entry.path().extension() == ".json") {
|
||||
result.push_back(std::filesystem::relative(entry.path(), root).replace_extension().generic_string());
|
||||
}
|
||||
}
|
||||
std::ranges::sort(result);
|
||||
return result;
|
||||
}()};
|
||||
return paths;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user