mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-08 19:52:47 +01:00
Merge branch 'master' into feat/renderers-cleanup
This commit is contained in:
@@ -6,13 +6,20 @@
|
||||
|
||||
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
|
||||
editor_stubs.cpp
|
||||
# the geometry of the lines the track editor designs, standing on its own
|
||||
@@ -27,7 +34,8 @@ add_executable(${UNIT_TESTS_NAME}
|
||||
# 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,22 +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. Coupled vehicles
|
||||
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();
|
||||
}
|
||||
135
tests/unit/test_camshaft.cpp
Normal file
135
tests/unit/test_camshaft.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
// eu07/maszyna#393: running backwards, a camshaft which reached the last position of the series connection (the
|
||||
// next one already joins the motors in more branches than BackwardsBranchesAllowed) stayed there whatever the driver
|
||||
// did with the master controller, with the line contactors closed and the motors pulling, until the line contactors
|
||||
// were opened by hand
|
||||
|
||||
namespace {
|
||||
|
||||
// the starting resistances of the Skoda 181 (cd/181_v2): 6 motors in series up to position 22, then two branches of
|
||||
// 3 up to 34, then three branches of 2 up to 43; columns: position, resistance, branches, motors in a branch, auto
|
||||
nlohmann::ordered_json skoda_rlist() {
|
||||
nlohmann::ordered_json rows{nlohmann::ordered_json::array({0, 0, 0, 0, 0}), nlohmann::ordered_json::array({1, 999999, 1, 6, 0})};
|
||||
auto const series{std::vector<double>{15.87, 12.32, 10.03, 8.54, 6.98, 5.84, 5.35, 4.87, 3.88, 2.92, 2.68, 2.43, 2.19, 1.95, 1.70, 1.46, 1.22, 0.97, 0.49, 0.24, 0.00}};
|
||||
auto const seriesparallel{std::vector<double>{4.50, 3.63, 3.11, 2.42, 2.08, 1.73, 1.38, 1.04, 0.69, 0.35, 0.17, 0.00}};
|
||||
auto const parallel{std::vector<double>{2.78, 2.29, 1.80, 1.41, 1.02, 0.73, 0.44, 0.24, 0.00}};
|
||||
auto position{2};
|
||||
for (auto const resistance : series) {
|
||||
rows.push_back(nlohmann::ordered_json::array({position++, resistance, 1, 6, 0}));
|
||||
}
|
||||
for (auto const resistance : seriesparallel) {
|
||||
rows.push_back(nlohmann::ordered_json::array({position++, resistance, 2, 3, 0}));
|
||||
}
|
||||
for (auto const resistance : parallel) {
|
||||
rows.push_back(nlohmann::ordered_json::array({position++, resistance, 3, 2, 0}));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
// an electric locomotive with a camshaft, made after the Skoda 181
|
||||
definition skoda() {
|
||||
auto result{definition::load("wagon")
|
||||
.set("Param", "M", 124200)
|
||||
.set("Param", "Vmax", 90)
|
||||
.set("Dimensions", "L", 18.8)
|
||||
.set("Wheels", "D", 1.25)
|
||||
.set("Wheels", "Axle", "Co'Co'")
|
||||
.set("Engine", "EngineType", "ElectricSeriesMotor")
|
||||
.set("Engine", "Volt", 967)
|
||||
.set("Engine", "Trans", "21:89")
|
||||
.set("Engine", "WindingRes", 0.084)
|
||||
.set("Engine", "nmax", 1870)
|
||||
.set("Circuit", "CircuitRes", 0.01)
|
||||
.set("Circuit", "ImaxLo", 550)
|
||||
.set("Circuit", "ImaxHi", 550)
|
||||
.set("Circuit", "IminLo", 307)
|
||||
.set("Circuit", "IminHi", 332)
|
||||
.set("Cntrl", "MCPN", 43)
|
||||
.set("Cntrl", "SCPN", 3)
|
||||
.set("Cntrl", "CoupledCtrl", "No")
|
||||
.set("Cntrl", "IniCDelay", 0.2)
|
||||
.set("Cntrl", "SCDelay", 0.18)
|
||||
.set("Cntrl", "SCDDelay", 0.18)
|
||||
.set("Cntrl", "Camshaft", "Yes")
|
||||
.set("MotorParamTable0", "rows",
|
||||
nlohmann::ordered_json::array({nlohmann::ordered_json::array({0, 33.75, 57, 0.4, 225.70, 57, 0.4}), nlohmann::ordered_json::array({1, 31.66, 69, 0.4, 217.10, 69, 0.4}),
|
||||
nlohmann::ordered_json::array({2, 30.52, 90, 0.4, 212.80, 90, 0.4}), nlohmann::ordered_json::array({3, 28.74, 107, 0.4, 199.55, 107, 0.4})}))
|
||||
.set("RList", "Size", 43)
|
||||
.set("RList", "rows", skoda_rlist())};
|
||||
return result;
|
||||
}
|
||||
|
||||
// the locomotive running with the line contactors closed and the camshaft at Position, the master controller moved
|
||||
// to Controller, in the given direction; the time since the last step of the camshaft long enough for the next one
|
||||
void running(TMoverParameters &Locomotive, int const Direction, int const Position, int const Controller) {
|
||||
Locomotive.CabActive = 1;
|
||||
Locomotive.DirActive = Direction;
|
||||
Locomotive.Mains = true;
|
||||
Locomotive.PipePress = 5.0; // bar, the pressure switch lets the line contactors close
|
||||
Locomotive.BrakePress = 0.0;
|
||||
Locomotive.StLinFlag = true;
|
||||
Locomotive.MainCtrlActualPos = Position;
|
||||
Locomotive.MainCtrlPos = Controller;
|
||||
Locomotive.LastRelayTime = 10.0;
|
||||
}
|
||||
|
||||
// steps the camshaft as the physics does, each step once the delay since the previous one passed; returns where it
|
||||
// ended up
|
||||
int run_camshaft(TMoverParameters &Locomotive, int const Steps) {
|
||||
for (int step = 0; step < Steps; ++step) {
|
||||
Locomotive.LastRelayTime = 10.0;
|
||||
Locomotive.AutoRelayCheck();
|
||||
}
|
||||
return Locomotive.MainCtrlActualPos;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("camshaft: running backwards, the camshaft goes back down from the last series position (eu07/maszyna#393)") {
|
||||
vehicle locomotive{skoda()};
|
||||
auto &mover{locomotive.mover()};
|
||||
REQUIRE(mover.HasCamshaft);
|
||||
REQUIRE(mover.RlistSize == 43);
|
||||
REQUIRE(mover.RList[22].Bn == 1);
|
||||
REQUIRE(mover.RList[23].Bn == 2);
|
||||
|
||||
SUBCASE("the controller turned back a few positions") {
|
||||
running(mover, -1, 22, 15);
|
||||
CHECK(run_camshaft(mover, 1) == 21); // it used to stay at 22
|
||||
CHECK(run_camshaft(mover, 10) == 15);
|
||||
}
|
||||
SUBCASE("the controller turned back to zero: the camshaft runs down and the line contactors open") {
|
||||
running(mover, -1, 22, 0);
|
||||
run_camshaft(mover, 30);
|
||||
CHECK(mover.MainCtrlActualPos == 0);
|
||||
CHECK_FALSE(mover.StLinFlag); // the motors don't pull any more
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("camshaft: running backwards, the camshaft still doesn't go past the series connection") {
|
||||
vehicle locomotive{skoda()};
|
||||
auto &mover{locomotive.mover()};
|
||||
running(mover, -1, 20, 43);
|
||||
CHECK(run_camshaft(mover, 10) == 22);
|
||||
|
||||
SUBCASE("unless more branches are allowed backwards") {
|
||||
mover.BackwardsBranchesAllowed = 2;
|
||||
CHECK(run_camshaft(mover, 20) == 34);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("camshaft: running forwards, the camshaft goes through all the connections and back") {
|
||||
vehicle locomotive{skoda()};
|
||||
auto &mover{locomotive.mover()};
|
||||
running(mover, 1, 20, 43);
|
||||
CHECK(run_camshaft(mover, 30) == 43);
|
||||
|
||||
mover.MainCtrlPos = 10;
|
||||
CHECK(run_camshaft(mover, 40) == 10);
|
||||
}
|
||||
39
tests/unit/test_cntrl.cpp
Normal file
39
tests/unit/test_cntrl.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
// the Cntrl. section of the vehicle definition, as read by TMoverParameters::LoadFIZ_Cntrl()
|
||||
|
||||
TEST_CASE("cntrl: the brake delays of the settings come from BDelay1 to BDelay4") {
|
||||
vehicle wagon{definition::load("wagon").set("Cntrl", "BDelay1", 10.0).set("Cntrl", "BDelay2", 20.0).set("Cntrl", "BDelay3", 30.0).set("Cntrl", "BDelay4", 40.0)};
|
||||
CHECK(wagon->BrakeDelay[0] == doctest::Approx(10.0));
|
||||
// the vehicle varies the others a little, by 0.83 to 0.9 (CheckLocomotiveParameters())
|
||||
for (auto setting{1}; setting < 4; ++setting) {
|
||||
CAPTURE(setting);
|
||||
auto const given{10.0 * (setting + 1)};
|
||||
CHECK(wagon->BrakeDelay[setting] >= 0.83 * given);
|
||||
CHECK(wagon->BrakeDelay[setting] <= 0.9 * given);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("cntrl: the relays of a multiple unit start on their own, of other vehicles by hand") {
|
||||
SUBCASE("multiple unit") {
|
||||
vehicle unit{definition::load("wagon").set("Param", "Type", "ezt")};
|
||||
REQUIRE(unit->TrainType == dt_EZT);
|
||||
CHECK(unit->GroundRelayStart == start_t::automatic);
|
||||
CHECK(unit->ConverterOverloadRelayStart == start_t::converter); // activates when the converter is switched off
|
||||
}
|
||||
SUBCASE("other vehicle") {
|
||||
vehicle wagon{definition::load("wagon")};
|
||||
CHECK(wagon->GroundRelayStart == start_t::manual);
|
||||
CHECK(wagon->ConverterOverloadRelayStart == start_t::manual);
|
||||
}
|
||||
SUBCASE("given in the definition") {
|
||||
vehicle unit{definition::load("wagon").set("Param", "Type", "ezt").set("Cntrl", "GroundRelayStart", "Manual").set("Cntrl", "ConverterOverloadRelayStart", "Automatic")};
|
||||
CHECK(unit->GroundRelayStart == start_t::manual);
|
||||
CHECK(unit->ConverterOverloadRelayStart == start_t::automatic);
|
||||
}
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
115
tests/unit/test_compressor.cpp
Normal file
115
tests/unit/test_compressor.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
// the compressor waiting a while after getting its power before it starts (CompressorStartDelay,
|
||||
// MaSzyna-EU07/maszyna#67): in a diesel it starts some time after the engine, rather than with it
|
||||
|
||||
namespace {
|
||||
|
||||
double const step{0.01};
|
||||
|
||||
// a compressor which starts on its own, fed from the main circuit unless given another Power, its pressure
|
||||
// switch between MinCP and MaxCP, and an empty main reservoir for it to fill
|
||||
vehicle compressor_vehicle(double const Delay, std::string const &Power = "Main", double const MinCP = 6.5) {
|
||||
auto definition{definition::load("wagon")};
|
||||
definition.set("Brake", "Vv", 1.0).set("Brake", "MinCP", MinCP).set("Brake", "MaxCP", 8.0);
|
||||
definition.set("Brake", "CompressorSpeed", 0.01);
|
||||
if (false == Power.empty()) {
|
||||
definition.set("Brake", "CompressorPower", Power);
|
||||
}
|
||||
definition.set("Cntrl", "CompressorStart", "Automatic");
|
||||
if (Delay > 0.0) {
|
||||
definition.set("Brake", "CompressorStartDelay", Delay);
|
||||
}
|
||||
vehicle vehicle{definition};
|
||||
vehicle->CompressedVolume = 0.0;
|
||||
vehicle->LastSwitchingTime = 10.0; // nothing was switched lately
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
// runs the compressor for Seconds, the main circuit as it is, the time since the last switching going on as in
|
||||
// ComputeTotalForce()
|
||||
void run_compressor(vehicle &Vehicle, double const Seconds) {
|
||||
for (auto i{std::lround(Seconds / step)}; i > 0; --i) {
|
||||
Vehicle->LastSwitchingTime += step;
|
||||
Vehicle->CompressorCheck(step);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("compressor: without a start delay the compressor starts with its power") {
|
||||
auto vehicle{compressor_vehicle(0.0)};
|
||||
run_compressor(vehicle, 1.0);
|
||||
REQUIRE_FALSE(vehicle->CompressorFlag); // no power, no compressor
|
||||
|
||||
vehicle->Mains = true;
|
||||
run_compressor(vehicle, step);
|
||||
CHECK(vehicle->CompressorFlag);
|
||||
}
|
||||
|
||||
TEST_CASE("compressor: the compressor starts the delay after getting its power") {
|
||||
auto vehicle{compressor_vehicle(5.0)};
|
||||
vehicle->Mains = true;
|
||||
|
||||
run_compressor(vehicle, 4.9);
|
||||
CHECK_FALSE(vehicle->CompressorFlag);
|
||||
CHECK(vehicle->Compressor == doctest::Approx(0.0));
|
||||
|
||||
run_compressor(vehicle, 0.2);
|
||||
CHECK(vehicle->CompressorFlag);
|
||||
run_compressor(vehicle, 10.0);
|
||||
CHECK(vehicle->Compressor > 0.0); // and fills the reservoir
|
||||
}
|
||||
|
||||
TEST_CASE("compressor: the delay starts over once the power is gone") {
|
||||
auto vehicle{compressor_vehicle(5.0)};
|
||||
vehicle->Mains = true;
|
||||
run_compressor(vehicle, 10.0);
|
||||
REQUIRE(vehicle->CompressorFlag);
|
||||
|
||||
vehicle->Mains = false; // the engine stopped
|
||||
run_compressor(vehicle, 1.0);
|
||||
CHECK_FALSE(vehicle->CompressorFlag);
|
||||
|
||||
vehicle->Mains = true; // and started again
|
||||
run_compressor(vehicle, 4.9);
|
||||
CHECK_FALSE(vehicle->CompressorFlag);
|
||||
run_compressor(vehicle, 0.2);
|
||||
CHECK(vehicle->CompressorFlag);
|
||||
}
|
||||
|
||||
TEST_CASE("compressor: a compressor fed from the low voltage waits from the low voltage coming on") {
|
||||
auto vehicle{compressor_vehicle(5.0, "")}; // the default supply: the converter, the 110 V
|
||||
vehicle->Mains = true; // which alone doesn't feed it
|
||||
run_compressor(vehicle, 10.0);
|
||||
REQUIRE_FALSE(vehicle->CompressorFlag);
|
||||
|
||||
vehicle->Power110vIsAvailable = true;
|
||||
run_compressor(vehicle, 4.9);
|
||||
CHECK_FALSE(vehicle->CompressorFlag);
|
||||
run_compressor(vehicle, 0.2);
|
||||
CHECK(vehicle->CompressorFlag);
|
||||
}
|
||||
|
||||
TEST_CASE("compressor: the pressure switch stops the compressor above the cut-out pressure") {
|
||||
auto vehicle{compressor_vehicle(0.0)};
|
||||
vehicle->Mains = true;
|
||||
vehicle->CompressedVolume = 8.5; // over MaxCP, in the reservoir of 1 m3
|
||||
run_compressor(vehicle, step);
|
||||
CHECK(vehicle->CompressorGovernorLock);
|
||||
CHECK_FALSE(vehicle->CompressorFlag);
|
||||
}
|
||||
|
||||
TEST_CASE("compressor: without a pressure switch the air over the cut-out pressure is vented") {
|
||||
auto vehicle{compressor_vehicle(0.0, "Main", 8.0)}; // MinCP the same as MaxCP: no pressure switch
|
||||
vehicle->Mains = true;
|
||||
vehicle->CompressedVolume = 8.5;
|
||||
run_compressor(vehicle, step);
|
||||
REQUIRE(vehicle->CompressorFlag); // nothing stops it
|
||||
CHECK(vehicle->CompressedVolume < 8.5 * 0.81); // a fifth of the air let out
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
527
tests/unit/test_couplers.cpp
Normal file
527
tests/unit/test_couplers.cpp
Normal file
@@ -0,0 +1,527 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
#include "vehicle.h"
|
||||
#include "utilities/Globals.h"
|
||||
|
||||
using test::definition;
|
||||
using test::vehicle;
|
||||
|
||||
namespace {
|
||||
|
||||
// the wagon from data/wagon.json with automatic couplers at both ends, which couple the given connections
|
||||
definition automatic_definition(int Flag = coupling::coupler | coupling::brakehose) {
|
||||
return definition::load("wagon").set("BuffCoupl", "CType", "Automatic").set("BuffCoupl", "AutomaticFlag", Flag);
|
||||
}
|
||||
|
||||
// the wagon from data/wagon.json with automatic couplers at both ends, running at the given speed [km/h]
|
||||
vehicle automatic_wagon(double Velocity, std::string const &Name) {
|
||||
return vehicle{automatic_definition(), Velocity, Name};
|
||||
}
|
||||
|
||||
// the same wagon, twice as heavy
|
||||
vehicle heavy_automatic_wagon(double Velocity, std::string const &Name) {
|
||||
return vehicle{automatic_definition().set("Param", "M", 2 * 42200), Velocity, Name};
|
||||
}
|
||||
|
||||
bool derailed(vehicle &Vehicle) {
|
||||
return TestFlag(Vehicle->DamageFlag, dtrain_out);
|
||||
}
|
||||
|
||||
// runs the pair for Seconds, returns whether the vehicles were coupled at any point
|
||||
bool couple_during(test::pair &Pair, double Seconds) {
|
||||
auto coupled{false};
|
||||
for (auto i{std::lround(Seconds / 0.01)}; i > 0; --i) {
|
||||
Pair.step();
|
||||
coupled = coupled || Pair.coupled();
|
||||
}
|
||||
return coupled;
|
||||
}
|
||||
|
||||
// sets the crash damage setting for the test, restores it after
|
||||
class crash_damage_setting {
|
||||
public:
|
||||
explicit crash_damage_setting(bool Enabled) { Global.crash_damage = Enabled; }
|
||||
~crash_damage_setting() { Global.crash_damage = m_previous; }
|
||||
crash_damage_setting(crash_damage_setting const &) = delete;
|
||||
crash_damage_setting &operator=(crash_damage_setting const &) = delete;
|
||||
|
||||
private:
|
||||
bool m_previous{Global.crash_damage};
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// issue #86: automatic couplers used to catch at any closing speed, so the vehicles never collided nor derailed
|
||||
|
||||
TEST_CASE("couplers: automatic couplers catch a standing wagon hit at a walking pace") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto moving{automatic_wagon(10.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
REQUIRE(moving->Couplers[end::front].type() == TCouplerType::Automatic);
|
||||
REQUIRE(moving.speed() == doctest::Approx(10.0));
|
||||
|
||||
// the front of the moving wagon runs into the rear of the standing one
|
||||
CHECK(moving->CollisionVelocity(end::front, standing.mover(), end::rear) == doctest::Approx(10.0));
|
||||
CHECK(moving->AutomaticCouplingSafe(end::front, standing.mover(), end::rear));
|
||||
CHECK(standing->AutomaticCouplingSafe(end::rear, moving.mover(), end::front));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: automatic couplers don't catch a wagon hit too fast, the wagons collide instead") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto moving{automatic_wagon(30.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
REQUIRE(moving.speed() == doctest::Approx(30.0));
|
||||
|
||||
CHECK(moving->CollisionVelocity(end::front, standing.mover(), end::rear) > TMoverParameters::SafeCollisionVelocity);
|
||||
CHECK_FALSE(moving->AutomaticCouplingSafe(end::front, standing.mover(), end::rear));
|
||||
CHECK_FALSE(standing->AutomaticCouplingSafe(end::rear, moving.mover(), end::front));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: automatic couplers catch a wagon running ahead only a little slower") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto faster{automatic_wagon(60.0, "faster")};
|
||||
auto slower{automatic_wagon(50.0, "slower")};
|
||||
|
||||
CHECK(faster->CollisionVelocity(end::front, slower.mover(), end::rear) == doctest::Approx(10.0));
|
||||
CHECK(slower->CollisionVelocity(end::rear, faster.mover(), end::front) == doctest::Approx(10.0));
|
||||
CHECK(faster->AutomaticCouplingSafe(end::front, slower.mover(), end::rear));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: without crash damage automatic couplers catch at any speed") {
|
||||
crash_damage_setting const crashdamage{false};
|
||||
auto moving{automatic_wagon(30.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
|
||||
CHECK(moving->AutomaticCouplingSafe(end::front, standing.mover(), end::rear));
|
||||
}
|
||||
|
||||
// the closing speed used to treat the speed of each vehicle as a vector turned by half its heading, so for vehicles
|
||||
// facing each other it came out as the root of the sum of the squares of their speeds, rather than the sum
|
||||
|
||||
TEST_CASE("couplers: the closing speed of a rear-end collision is the difference of the speeds") {
|
||||
auto faster{automatic_wagon(40.0, "faster")};
|
||||
auto slower{automatic_wagon(25.0, "slower")};
|
||||
|
||||
// running forwards, the front of the faster wagon hits the rear of the slower one
|
||||
CHECK(faster->CollisionVelocity(end::front, slower.mover(), end::rear) == doctest::Approx(15.0));
|
||||
CHECK(slower->CollisionVelocity(end::rear, faster.mover(), end::front) == doctest::Approx(15.0));
|
||||
// the wagons running ahead of each other are parting
|
||||
CHECK(slower->CollisionVelocity(end::front, faster.mover(), end::rear) == doctest::Approx(-15.0));
|
||||
|
||||
// backing up, the rear of the faster wagon hits the front of the slower one
|
||||
auto backingfaster{automatic_wagon(-40.0, "backing faster")};
|
||||
auto backingslower{automatic_wagon(-25.0, "backing slower")};
|
||||
CHECK(backingfaster->CollisionVelocity(end::rear, backingslower.mover(), end::front) == doctest::Approx(15.0));
|
||||
CHECK(backingslower->CollisionVelocity(end::front, backingfaster.mover(), end::rear) == doctest::Approx(15.0));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: the closing speed of a head-on collision is the sum of the speeds") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto first{automatic_wagon(10.0, "first")};
|
||||
auto second{automatic_wagon(10.0, "second")};
|
||||
|
||||
// both wagons run forwards, their fronts meet
|
||||
CHECK(first->CollisionVelocity(end::front, second.mover(), end::front) == doctest::Approx(20.0));
|
||||
CHECK(second->CollisionVelocity(end::front, first.mover(), end::front) == doctest::Approx(20.0));
|
||||
// 20 km/h is above the limit, the couplers don't catch (the old formula gave 14.1 km/h and coupled them)
|
||||
CHECK(first->CollisionVelocity(end::front, second.mover(), end::front) > TMoverParameters::SafeCollisionVelocity);
|
||||
CHECK_FALSE(first->AutomaticCouplingSafe(end::front, second.mover(), end::front));
|
||||
CHECK_FALSE(second->AutomaticCouplingSafe(end::front, first.mover(), end::front));
|
||||
|
||||
// both wagons back up, their rears meet
|
||||
auto firstbacking{automatic_wagon(-10.0, "first backing")};
|
||||
auto secondbacking{automatic_wagon(-10.0, "second backing")};
|
||||
CHECK(firstbacking->CollisionVelocity(end::rear, secondbacking.mover(), end::rear) == doctest::Approx(20.0));
|
||||
|
||||
// running back to back, the wagons part
|
||||
CHECK(first->CollisionVelocity(end::rear, second.mover(), end::rear) == doctest::Approx(-20.0));
|
||||
CHECK(first->AutomaticCouplingSafe(end::rear, second.mover(), end::rear));
|
||||
|
||||
// slow enough, the couplers catch
|
||||
auto slowfirst{automatic_wagon(5.0, "slow first")};
|
||||
auto slowsecond{automatic_wagon(5.0, "slow second")};
|
||||
CHECK(slowfirst->CollisionVelocity(end::front, slowsecond.mover(), end::front) == doctest::Approx(10.0));
|
||||
CHECK(slowfirst->AutomaticCouplingSafe(end::front, slowsecond.mover(), end::front));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: the closing speed of a hit on a standing vehicle is the speed of the moving one, whichever way it faces") {
|
||||
auto moving{automatic_wagon(20.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
|
||||
// the standing wagon faces away from the moving one
|
||||
CHECK(moving->CollisionVelocity(end::front, standing.mover(), end::rear) == doctest::Approx(20.0));
|
||||
CHECK(standing->CollisionVelocity(end::rear, moving.mover(), end::front) == doctest::Approx(20.0));
|
||||
// the standing wagon faces the moving one
|
||||
CHECK(moving->CollisionVelocity(end::front, standing.mover(), end::front) == doctest::Approx(20.0));
|
||||
CHECK(standing->CollisionVelocity(end::front, moving.mover(), end::front) == doctest::Approx(20.0));
|
||||
// the moving wagon backs up into the standing one
|
||||
auto backing{automatic_wagon(-20.0, "backing")};
|
||||
CHECK(backing->CollisionVelocity(end::rear, standing.mover(), end::front) == doctest::Approx(20.0));
|
||||
CHECK(backing->CollisionVelocity(end::rear, standing.mover(), end::rear) == doctest::Approx(20.0));
|
||||
// the moving wagon runs away from the standing one
|
||||
CHECK(moving->CollisionVelocity(end::rear, standing.mover(), end::front) == doctest::Approx(-20.0));
|
||||
}
|
||||
|
||||
// the coupling as the simulation runs it: two vehicles on a track, closing in on each other until the couplers (or
|
||||
// buffers) meet, the coupler forces and the collision computed by the physics, step by step
|
||||
|
||||
TEST_CASE("couplers: automatic couplers catch right up to the safe closing speed") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
|
||||
auto below{automatic_wagon(14.9, "below")};
|
||||
CHECK(below->CollisionVelocity(end::front, standing.mover(), end::rear) == doctest::Approx(14.9));
|
||||
CHECK(below->AutomaticCouplingSafe(end::front, standing.mover(), end::rear));
|
||||
|
||||
auto above{automatic_wagon(15.1, "above")};
|
||||
CHECK(above->CollisionVelocity(end::front, standing.mover(), end::rear) == doctest::Approx(15.1));
|
||||
CHECK_FALSE(above->AutomaticCouplingSafe(end::front, standing.mover(), end::rear));
|
||||
auto faster{automatic_wagon(15.5, "faster")};
|
||||
CHECK_FALSE(faster->AutomaticCouplingSafe(end::front, standing.mover(), end::rear));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: a wagon rolling slowly into a standing one couples with it") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto moving{automatic_wagon(5.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
test::pair pair{moving, end::front, standing, end::rear, 1.0};
|
||||
|
||||
pair.run(3.0);
|
||||
|
||||
REQUIRE(pair.coupled());
|
||||
CHECK(moving->Couplers[end::front].CouplingFlag == (coupling::coupler | coupling::brakehose));
|
||||
CHECK(standing->Couplers[end::rear].CouplingFlag == (coupling::coupler | coupling::brakehose));
|
||||
CHECK(moving->Couplers[end::front].Connected == &standing.mover());
|
||||
CHECK_FALSE(derailed(moving));
|
||||
CHECK_FALSE(derailed(standing));
|
||||
// coupled, they run on together
|
||||
pair.run(2.0);
|
||||
CHECK(moving.speed() == doctest::Approx(standing.speed()).epsilon(0.05));
|
||||
CHECK(pair.gap() < 0.2);
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: a wagon hitting a standing one too fast doesn't couple, nor once the hit has slowed it down") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto moving{automatic_wagon(30.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
test::pair pair{moving, end::front, standing, end::rear, 1.0};
|
||||
|
||||
auto touched{false};
|
||||
auto parted{false};
|
||||
auto coupled{false};
|
||||
auto locked{true};
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
pair.step();
|
||||
// as far as the couplers know: the distance between them at the start of the step
|
||||
auto const distance{moving->Neighbours[end::front].distance};
|
||||
touched = touched || distance < 0.0;
|
||||
parted = parted || (touched && distance > 0.05);
|
||||
coupled = coupled || pair.coupled();
|
||||
if (touched && false == parted) {
|
||||
locked = locked && false == moving->Couplers[end::front].AutomaticCouplingAllowed && false == standing->Couplers[end::rear].AutomaticCouplingAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(touched);
|
||||
CHECK_FALSE(coupled);
|
||||
// the hit derailed and stopped them, the couplers next to each other, the automatic coupling locked all along
|
||||
CHECK_FALSE(parted);
|
||||
CHECK(locked);
|
||||
CHECK(derailed(moving));
|
||||
CHECK(derailed(standing));
|
||||
CHECK(std::abs(moving.speed()) < 3.0);
|
||||
CHECK(std::abs(standing.speed()) < 3.0);
|
||||
CHECK_FALSE(couple_during(pair, 5.0));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: the automatic coupling locked by a hit is unlocked once the vehicles part") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto moving{automatic_wagon(3.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
// as a hit too fast or manual uncoupling leaves them
|
||||
moving->Couplers[end::front].AutomaticCouplingAllowed = false;
|
||||
standing->Couplers[end::rear].AutomaticCouplingAllowed = false;
|
||||
|
||||
SUBCASE("parted by more than 5 cm, they couple on the next approach") {
|
||||
test::pair pair{moving, end::front, standing, end::rear, 0.5};
|
||||
pair.step();
|
||||
CHECK(moving->Couplers[end::front].AutomaticCouplingAllowed);
|
||||
CHECK(couple_during(pair, 3.0));
|
||||
}
|
||||
SUBCASE("kept together, they don't") {
|
||||
test::pair pair{moving, end::front, standing, end::rear, 0.0};
|
||||
auto coupled{false};
|
||||
for (int i = 0; i < 300; ++i) {
|
||||
pair.step();
|
||||
if (pair.gap() > 0.05) {
|
||||
break; // parted
|
||||
}
|
||||
coupled = coupled || pair.coupled();
|
||||
}
|
||||
CHECK_FALSE(coupled);
|
||||
}
|
||||
}
|
||||
|
||||
// the couplers refuse a hit by the closing speed when they meet, the derail check (CollisionDetect()) takes the one
|
||||
// left when the buffers are pressed in all the way, after their springs have slowed the hit down: for the wagons here
|
||||
// by about 7 km/h. so a hit a little over the safe closing speed only bounces the vehicles apart
|
||||
|
||||
TEST_CASE("couplers: a hit a little too fast for the couplers bounces the vehicles apart, uncoupled and on the rails") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto moving{automatic_wagon(20.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
test::pair pair{moving, end::front, standing, end::rear, 1.0};
|
||||
|
||||
CHECK_FALSE(couple_during(pair, 3.0));
|
||||
CHECK_FALSE(derailed(moving));
|
||||
CHECK_FALSE(derailed(standing));
|
||||
CHECK(pair.gap() > 0.5);
|
||||
CHECK(standing.speed() > moving.speed());
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: a hit too fast for the couplers derails the vehicles over the limit adjusted for their mass ratio") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
|
||||
SUBCASE("equal masses: both derail") {
|
||||
auto moving{automatic_wagon(30.0, "moving")};
|
||||
auto standing{automatic_wagon(0.0, "standing")};
|
||||
test::pair pair{moving, end::front, standing, end::rear, 1.0};
|
||||
CHECK_FALSE(couple_during(pair, 5.0));
|
||||
CHECK(derailed(moving));
|
||||
CHECK(derailed(standing));
|
||||
}
|
||||
SUBCASE("half the mass: between the safe closing speed and twice that, only the lighter one derails") {
|
||||
auto light{automatic_wagon(27.0, "light")};
|
||||
auto heavy{heavy_automatic_wagon(0.0, "heavy")};
|
||||
test::pair pair{light, end::front, heavy, end::rear, 1.0};
|
||||
CHECK_FALSE(couple_during(pair, 5.0));
|
||||
CHECK(derailed(light));
|
||||
CHECK_FALSE(derailed(heavy));
|
||||
}
|
||||
SUBCASE("half the mass: above twice the safe closing speed both derail") {
|
||||
auto light{automatic_wagon(45.0, "light")};
|
||||
auto heavy{heavy_automatic_wagon(0.0, "heavy")};
|
||||
test::pair pair{light, end::front, heavy, end::rear, 1.0};
|
||||
CHECK_FALSE(couple_during(pair, 5.0));
|
||||
CHECK(derailed(light));
|
||||
CHECK(derailed(heavy));
|
||||
}
|
||||
SUBCASE("half the mass: below the safe closing speed the couplers catch, nothing derails") {
|
||||
auto light{automatic_wagon(12.0, "light")};
|
||||
auto heavy{heavy_automatic_wagon(0.0, "heavy")};
|
||||
test::pair pair{light, end::front, heavy, end::rear, 1.0};
|
||||
CHECK(couple_during(pair, 5.0));
|
||||
CHECK_FALSE(derailed(light));
|
||||
CHECK_FALSE(derailed(heavy));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: wagons running head-on into each other couple only up to the safe closing speed") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
|
||||
SUBCASE("7 + 7 km/h, the couplers catch") {
|
||||
auto first{automatic_wagon(7.0, "first")};
|
||||
auto second{automatic_wagon(7.0, "second")};
|
||||
test::pair pair{first, end::front, second, end::front, 1.0};
|
||||
CHECK(couple_during(pair, 3.0));
|
||||
CHECK_FALSE(derailed(first));
|
||||
CHECK_FALSE(derailed(second));
|
||||
}
|
||||
SUBCASE("8 + 8 km/h, the wagons bounce apart") {
|
||||
auto first{automatic_wagon(8.0, "first")};
|
||||
auto second{automatic_wagon(8.0, "second")};
|
||||
test::pair pair{first, end::front, second, end::front, 1.0};
|
||||
CHECK_FALSE(couple_during(pair, 3.0));
|
||||
CHECK_FALSE(derailed(first));
|
||||
CHECK_FALSE(derailed(second));
|
||||
// both backwards, away from each other
|
||||
CHECK(first.speed() < 0.0);
|
||||
CHECK(second.speed() < 0.0);
|
||||
}
|
||||
SUBCASE("backing up, 8 + 8 km/h, the wagons bounce apart") {
|
||||
auto first{automatic_wagon(-8.0, "first")};
|
||||
auto second{automatic_wagon(-8.0, "second")};
|
||||
test::pair pair{first, end::rear, second, end::rear, 1.0};
|
||||
CHECK_FALSE(couple_during(pair, 3.0));
|
||||
CHECK(first.speed() > 0.0);
|
||||
CHECK(second.speed() > 0.0);
|
||||
}
|
||||
SUBCASE("15 + 15 km/h, both derail") {
|
||||
auto first{automatic_wagon(15.0, "first")};
|
||||
auto second{automatic_wagon(15.0, "second")};
|
||||
test::pair pair{first, end::front, second, end::front, 1.0};
|
||||
CHECK_FALSE(couple_during(pair, 5.0));
|
||||
CHECK(derailed(first));
|
||||
CHECK(derailed(second));
|
||||
}
|
||||
}
|
||||
|
||||
// the collision used to take the speed of a vehicle facing the other way as if it faced the same way, so a wagon
|
||||
// pushed away by the buffers of the vehicle hitting it head-on counted as running into it: the hit slowed it down,
|
||||
// and the hitter bounced back as from a wall
|
||||
|
||||
TEST_CASE("couplers: a wagon hit head-on runs off the same as one hit from behind") {
|
||||
// without automatic couplers or crash damage, the collision alone
|
||||
crash_damage_setting const crashdamage{false};
|
||||
auto speeds_after_hit = [](int StruckEnd) {
|
||||
auto moving{vehicle{definition::load("wagon"), 20.0, "moving"}};
|
||||
auto struck{vehicle{definition::load("wagon"), 0.0, "struck"}};
|
||||
test::pair pair{moving, end::front, struck, StruckEnd, 0.5};
|
||||
auto touched{false};
|
||||
for (int i = 0; i < 300; ++i) {
|
||||
pair.step();
|
||||
touched = touched || pair.gap() < 0.0;
|
||||
if (touched && pair.gap() > 0.3) {
|
||||
break; // bounced off
|
||||
}
|
||||
}
|
||||
REQUIRE(touched);
|
||||
REQUIRE(pair.gap() > 0.3);
|
||||
REQUIRE_FALSE(pair.coupled());
|
||||
return std::make_pair(moving.speed(), struck.speed());
|
||||
};
|
||||
|
||||
auto const [hitterfrombehind, struckfrombehind]{speeds_after_hit(end::rear)};
|
||||
auto const [hitterheadon, struckheadon]{speeds_after_hit(end::front)};
|
||||
|
||||
// hit from behind, the struck wagon runs off forwards, faster than the hitter
|
||||
CHECK(struckfrombehind > 10.0);
|
||||
CHECK(hitterfrombehind < struckfrombehind);
|
||||
// hit head-on, it runs off backwards, as fast
|
||||
CHECK(struckheadon == doctest::Approx(-struckfrombehind).epsilon(0.02));
|
||||
CHECK(hitterheadon == doctest::Approx(hitterfrombehind).epsilon(0.05));
|
||||
}
|
||||
|
||||
// the other conditions of automatic coupling
|
||||
|
||||
TEST_CASE("couplers: an automatic coupler doesn't catch a coupler of another type") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto moving{automatic_wagon(5.0, "moving")};
|
||||
auto standing{vehicle{definition::load("wagon"), 0.0, "standing"}};
|
||||
REQUIRE(standing->Couplers[end::rear].type() == TCouplerType::Screw);
|
||||
test::pair pair{moving, end::front, standing, end::rear, 1.0};
|
||||
|
||||
CHECK_FALSE(couple_during(pair, 3.0));
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: automatic couplers of different control systems couple without the control connection") {
|
||||
crash_damage_setting const crashdamage{true};
|
||||
auto const flag{coupling::coupler | coupling::brakehose | coupling::control};
|
||||
auto moving{vehicle{automatic_definition(flag).set("BuffCoupl", "ControlType", "first"), 5.0, "moving"}};
|
||||
|
||||
SUBCASE("the same control system") {
|
||||
auto standing{vehicle{automatic_definition(flag).set("BuffCoupl", "ControlType", "first"), 0.0, "standing"}};
|
||||
REQUIRE(standing->Couplers[end::rear].control_type == "first");
|
||||
test::pair pair{moving, end::front, standing, end::rear, 1.0};
|
||||
REQUIRE(couple_during(pair, 3.0));
|
||||
CHECK(pair.coupling() == flag);
|
||||
}
|
||||
SUBCASE("a different one") {
|
||||
auto standing{vehicle{automatic_definition(flag).set("BuffCoupl", "ControlType", "second"), 0.0, "standing"}};
|
||||
REQUIRE(standing->Couplers[end::rear].control_type == "second");
|
||||
test::pair pair{moving, end::front, standing, end::rear, 1.0};
|
||||
REQUIRE(couple_during(pair, 3.0));
|
||||
CHECK(pair.coupling() == (coupling::coupler | coupling::brakehose));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: the coupler force of vehicles facing each other lands on the couplers holding them") {
|
||||
// the force a vehicle takes from its coupler, the other one takes back on its own coupler of the pair, whichever
|
||||
// way the vehicles face; it used to land on the far end of the other vehicle when they faced each other.
|
||||
// CForce runs along the axis of its own vehicle, so the two forces of the pair are opposite along the track: of
|
||||
// opposite signs for vehicles facing the same way, of the same sign for vehicles facing each other
|
||||
auto first{automatic_wagon(5.0, "first")};
|
||||
auto second{automatic_wagon(0.0, "second")};
|
||||
|
||||
SUBCASE("facing each other") {
|
||||
test::pair pair{first, end::front, second, end::front, 1.0};
|
||||
pair.run(5.0);
|
||||
REQUIRE(pair.coupled());
|
||||
|
||||
pair.step();
|
||||
REQUIRE(second->Couplers[end::front].CForce != 0.0);
|
||||
CHECK(first->Couplers[end::front].CForce == doctest::Approx(second->Couplers[end::front].CForce));
|
||||
CHECK(first->Couplers[end::rear].CForce == 0.0); // nothing there
|
||||
CHECK(second->Couplers[end::rear].CForce == 0.0);
|
||||
}
|
||||
SUBCASE("facing the same way") {
|
||||
test::pair pair{first, end::front, second, end::rear, 1.0};
|
||||
pair.run(5.0);
|
||||
REQUIRE(pair.coupled());
|
||||
|
||||
pair.step();
|
||||
REQUIRE(second->Couplers[end::rear].CForce != 0.0);
|
||||
CHECK(first->Couplers[end::front].CForce == doctest::Approx(-second->Couplers[end::rear].CForce));
|
||||
CHECK(first->Couplers[end::rear].CForce == 0.0);
|
||||
CHECK(second->Couplers[end::front].CForce == 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// eu07/maszyna#553: articulated wagons (T3000e, N-234 and the like) set up with articulated couplers barely moved in a
|
||||
// freight train. the joint took the spring force up to 5 cm only, 225 kN, so it overstretched under the train and the
|
||||
// sections collided at every step; and each collision scaled the velocities of both vehicles down, rather than only
|
||||
// the velocity of one relative to the other, braking the whole train
|
||||
|
||||
namespace {
|
||||
|
||||
// the wagon from data/wagon.json, loaded, with articulated couplers at both ends
|
||||
vehicle articulated_wagon(double Velocity, std::string const &Name) {
|
||||
return vehicle{definition::load("wagon").set("Param", "M", 60000).set("BuffCoupl", "CType", "Articulated"), Velocity, Name};
|
||||
}
|
||||
|
||||
// couples the facing ends of the two vehicles for good, as the scenery does for an articulated set
|
||||
void join(vehicle &First, int FirstEnd, vehicle &Second, int SecondEnd) {
|
||||
REQUIRE(First->Attach(FirstEnd, SecondEnd, &Second.mover(), coupling::coupler, true, false));
|
||||
REQUIRE(Second->Attach(SecondEnd, FirstEnd, &First.mover(), coupling::coupler, true, false));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("couplers: an articulated joint takes its full tensile force within its travel") {
|
||||
auto wagon{articulated_wagon(0.0, "wagon")};
|
||||
auto const &joint{wagon->Couplers[end::front]};
|
||||
REQUIRE(joint.type() == TCouplerType::Articulated);
|
||||
|
||||
CHECK(joint.SpringKC * joint.DmaxC >= doctest::Approx(joint.FmaxC));
|
||||
CHECK(joint.SpringKB * joint.DmaxB >= doctest::Approx(joint.FmaxC));
|
||||
// and no less than it had before
|
||||
CHECK(joint.DmaxC >= 0.05);
|
||||
CHECK(joint.DmaxB >= 0.05);
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: an articulated set keeps its momentum when one section jerks the other") {
|
||||
// the front section moving, the rear one barely (so that its brakes are released), joined: the jerk overstretches the joint, the sections collide
|
||||
// and run on together at half the speed, as the momentum they have between them dictates
|
||||
auto front_section{articulated_wagon(20.0, "front")};
|
||||
auto rear_section{articulated_wagon(0.1, "rear")};
|
||||
join(rear_section, end::front, front_section, end::rear);
|
||||
test::pair pair{rear_section, end::front, front_section, end::rear, 0.0};
|
||||
REQUIRE(pair.coupled());
|
||||
// brakes released, as a locomotive keeps them
|
||||
front_section.hold_brake_pipe(5.0);
|
||||
rear_section.hold_brake_pipe(5.0);
|
||||
|
||||
pair.run(3.0, test::track{0.15, 0.0});
|
||||
|
||||
CHECK(front_section.speed() == doctest::Approx(rear_section.speed()).epsilon(0.1));
|
||||
// rolling resistance takes a little in the 3 s, the collisions used to take most of it
|
||||
CHECK(0.5 * (front_section.speed() + rear_section.speed()) > 9.0);
|
||||
CHECK(0.5 * (front_section.speed() + rear_section.speed()) < 10.05 + 1e-6);
|
||||
CHECK(pair.coupled());
|
||||
}
|
||||
|
||||
TEST_CASE("couplers: a collision of coupled vehicles keeps the momentum of the pair") {
|
||||
// the same jerk through screw couplers, which collide when stretched beyond their travel as well
|
||||
auto front_wagon{vehicle{definition::load("wagon"), 30.0, "front"}};
|
||||
auto rear_wagon{vehicle{definition::load("wagon"), 0.1, "rear"}};
|
||||
join(rear_wagon, end::front, front_wagon, end::rear);
|
||||
test::pair pair{rear_wagon, end::front, front_wagon, end::rear, 0.0};
|
||||
REQUIRE(pair.coupled());
|
||||
front_wagon.hold_brake_pipe(5.0);
|
||||
rear_wagon.hold_brake_pipe(5.0);
|
||||
|
||||
pair.run(3.0, test::track{0.15, 0.0});
|
||||
|
||||
CHECK(0.5 * (front_wagon.speed() + rear_wagon.speed()) > 13.5);
|
||||
CHECK(0.5 * (front_wagon.speed() + rear_wagon.speed()) < 15.05 + 1e-6);
|
||||
}
|
||||
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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
58
tests/unit/test_gauge_positions.cpp
Normal file
58
tests/unit/test_gauge_positions.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
|
||||
#include "vehicle/gaugepositions.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
// the sounds of the positions of a cab control (MaSzyna-EU07/maszyna#83): a brake lever moved smoothly (Num3/Num9)
|
||||
// passes its positions instead of stopping at them, and sounds each one it reaches, as it does when put there
|
||||
|
||||
namespace {
|
||||
|
||||
// a brake lever with sounds at positions 0, 2 and 5; values in hundredths of a position
|
||||
std::map<int, std::string> lever_sounds() {
|
||||
return {{0, "release"}, {2, "running"}, {5, "service"}};
|
||||
}
|
||||
|
||||
std::string reached(int const Previous, int const Desired) {
|
||||
auto positions{lever_sounds()};
|
||||
auto const position{gauge_positions::last_reached(positions, Previous, Desired)};
|
||||
return position != positions.end() ? position->second : "";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("gauge positions: a lever put at a position sounds it") {
|
||||
CHECK(reached(100, 200) == "running");
|
||||
CHECK(reached(600, 500) == "service");
|
||||
}
|
||||
|
||||
TEST_CASE("gauge positions: a lever moved smoothly past a position sounds it (MaSzyna-EU07/maszyna#83)") {
|
||||
CHECK(reached(190, 205) == "running"); // moving up
|
||||
CHECK(reached(510, 495) == "service"); // moving down
|
||||
}
|
||||
|
||||
TEST_CASE("gauge positions: of the positions passed in one go the last one reached sounds") {
|
||||
CHECK(reached(50, 520) == "service"); // up past 2 and 5
|
||||
CHECK(reached(520, 10) == "running"); // down past 5 and 2, short of 0
|
||||
CHECK(reached(520, 0) == "release");
|
||||
}
|
||||
|
||||
TEST_CASE("gauge positions: moving between the positions or off one sounds nothing") {
|
||||
CHECK(reached(210, 290) == "");
|
||||
CHECK(reached(200, 230) == ""); // leaving a position isn't reaching it
|
||||
CHECK(reached(200, 170) == "");
|
||||
}
|
||||
|
||||
TEST_CASE("gauge positions: positions below zero count the same way") {
|
||||
// a brake lever with the release position at -1
|
||||
std::map<int, std::string> positions{{-1, "release"}, {0, "running"}};
|
||||
CHECK(gauge_positions::last_reached(positions, 50, -120)->second == "release"); // down past 0 and -1
|
||||
CHECK(gauge_positions::last_reached(positions, -150, -90)->second == "release"); // up past -1
|
||||
}
|
||||
|
||||
TEST_CASE("gauge positions: a control without position sounds reaches none") {
|
||||
std::map<int, std::string> positions;
|
||||
CHECK(gauge_positions::last_reached(positions, 0, 500) == positions.end());
|
||||
}
|
||||
121
tests/unit/test_horn.cpp
Normal file
121
tests/unit/test_horn.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "stdafx.h"
|
||||
#include "doctest.h"
|
||||
|
||||
#include "vehicle.h"
|
||||
|
||||
#include "vehicle/horn.h"
|
||||
|
||||
// the horn keys of the cab: low tone (A) and high tone (shift+A), held to sound
|
||||
|
||||
TEST_CASE("horn: a single lever for both tones sounds one tone at a time (eu07/maszyna#392)") {
|
||||
auto signal{0};
|
||||
signal = horn::pressed(signal, horn::low, true);
|
||||
REQUIRE(signal == horn::low);
|
||||
|
||||
// the lever moved over to the high tone while the low tone key is still held
|
||||
signal = horn::pressed(signal, horn::high, true);
|
||||
CHECK(signal == horn::high);
|
||||
|
||||
// letting go of the low tone key leaves the high tone sounding
|
||||
signal = horn::released(signal, horn::low);
|
||||
CHECK(signal == horn::high);
|
||||
|
||||
signal = horn::released(signal, horn::high);
|
||||
CHECK(signal == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("horn: separate buttons for the tones can sound both at once") {
|
||||
auto signal{0};
|
||||
signal = horn::pressed(signal, horn::low, false);
|
||||
signal = horn::pressed(signal, horn::high, false);
|
||||
CHECK(signal == (horn::low | horn::high));
|
||||
|
||||
signal = horn::released(signal, horn::low);
|
||||
CHECK(signal == horn::high);
|
||||
}
|
||||
|
||||
TEST_CASE("horn: releasing a tone leaves the other bits of the signal alone") {
|
||||
auto const third{4}; // the third horn, operated separately
|
||||
CHECK(horn::released(horn::low | third, horn::low) == third);
|
||||
CHECK(horn::pressed(third, horn::high, true) == (horn::high | third));
|
||||
}
|
||||
|
||||
// what the horns need to sound (eu07/maszyna#290): a pneumatic horn the air of the main reservoir, an electric one
|
||||
// the low voltage. the horn lever stays where the driver put it, only the horn is silent
|
||||
namespace {
|
||||
|
||||
test::vehicle horn_vehicle(test::definition Definition) {
|
||||
// a main reservoir of its own
|
||||
return test::vehicle{Definition.set("Brake", "Vv", 1.0).set("Brake", "MinCP", 6.5).set("Brake", "MaxCP", 8.0)};
|
||||
}
|
||||
|
||||
int const allhorns{horn::low | horn::high | 4};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("horn: a pneumatic horn sounds on the air of the main reservoir only") {
|
||||
auto vehicle{horn_vehicle(test::definition::load("wagon"))};
|
||||
REQUIRE(vehicle->HornSupply == horn_supply::air); // the default
|
||||
|
||||
vehicle->Compressor = 6.5;
|
||||
CHECK(vehicle->SoundingHorns(allhorns) == allhorns);
|
||||
vehicle->Compressor = 0.0; // the reservoir is empty
|
||||
CHECK(vehicle->SoundingHorns(allhorns) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("horn: a vehicle without a main reservoir takes the horn air from the main pipe") {
|
||||
test::vehicle vehicle{test::definition::load("wagon")};
|
||||
REQUIRE(vehicle->VeselVolume == 0.0);
|
||||
|
||||
vehicle->ScndPipePress = 5.0;
|
||||
CHECK(vehicle->SoundingHorns(horn::low) == horn::low);
|
||||
vehicle->ScndPipePress = 0.0;
|
||||
CHECK(vehicle->SoundingHorns(horn::low) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("horn: an electric horn sounds on the low voltage, whatever the air") {
|
||||
auto vehicle{horn_vehicle(test::definition::load("wagon").set("Cntrl", "HornType", "Electric"))};
|
||||
REQUIRE(vehicle->HornSupply == horn_supply::electric);
|
||||
REQUIRE(vehicle->Horn3Supply == horn_supply::electric); // the third horn follows the others unless told otherwise
|
||||
|
||||
vehicle->Compressor = 0.0;
|
||||
vehicle->Power24vIsAvailable = true;
|
||||
CHECK(vehicle->SoundingHorns(allhorns) == allhorns);
|
||||
vehicle->Power24vIsAvailable = false;
|
||||
CHECK(vehicle->SoundingHorns(allhorns) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("horn: the third horn can have a supply of its own, an electric horn of a diesel say") {
|
||||
auto vehicle{horn_vehicle(test::definition::load("wagon").set("Cntrl", "Horn3Type", "Electric"))};
|
||||
REQUIRE(vehicle->HornSupply == horn_supply::air);
|
||||
REQUIRE(vehicle->Horn3Supply == horn_supply::electric);
|
||||
|
||||
vehicle->Compressor = 0.0;
|
||||
vehicle->Power24vIsAvailable = true;
|
||||
CHECK(vehicle->SoundingHorns(allhorns) == 4);
|
||||
vehicle->Compressor = 6.5;
|
||||
vehicle->Power24vIsAvailable = false;
|
||||
CHECK(vehicle->SoundingHorns(allhorns) == (horn::low | horn::high));
|
||||
}
|
||||
|
||||
TEST_CASE("horn: a vehicle without any air, a road vehicle say, sounds its pneumatic horn as before") {
|
||||
// no main reservoir and no main pipe connection at either end
|
||||
test::vehicle vehicle{test::definition::load("wagon").set("BuffCoupl", "AllowedFlag", 3)};
|
||||
REQUIRE(vehicle->VeselVolume == 0.0);
|
||||
vehicle->ScndPipePress = 0.0;
|
||||
CHECK(vehicle->SoundingHorns(allhorns) == allhorns);
|
||||
}
|
||||
|
||||
TEST_CASE("horn: a pneumatic horn sounds from the threshold pressure up") {
|
||||
auto vehicle{horn_vehicle(test::definition::load("wagon"))};
|
||||
vehicle->Compressor = TMoverParameters::HornMinPressure;
|
||||
CHECK(vehicle->SoundingHorns(horn::low) == horn::low);
|
||||
vehicle->Compressor = TMoverParameters::HornMinPressure - 0.01;
|
||||
CHECK(vehicle->SoundingHorns(horn::low) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("horn: an electric horn sounds on 110 V too") {
|
||||
auto vehicle{horn_vehicle(test::definition::load("wagon").set("Cntrl", "HornType", "Electric"))};
|
||||
vehicle->Power110vIsAvailable = true;
|
||||
CHECK(vehicle->SoundingHorns(horn::high) == horn::high);
|
||||
}
|
||||
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);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user