lsa-planer

LSA-Planer Professional – Planungssoftware für Lichtsignalanlagen nach RiLSA 2015 und § 45 StVO. EUPL-1.2.

/ tests domain zeitschritt.test.ts

3,4 KB Rohdatei
tests/domain/zeitschritt.test.ts — 84 Zeilen
1 import { describe, expect, it } from 'vitest';
2 import { buildSignalPlan } from '@/domain/plan/signalPlan';
3 import { createStandardIntersectionProject } from '@/domain/model/factory';
4 import { TrafficSimulation, type SimulationSnapshot } from '@/domain/simulation/simulation';
5
6 /**
7 * Die Simulation muss in Schritten von `timeStep` rechnen, gleich in welchen
8 * Teilstuecken die Zeit uebergeben wird (Befund 27, behoben in Fassung 5.9.0).
9 *
10 * Was der Anwender sonst erlebt: Die Ansicht uebergibt je Einzelbild die
11 * verstrichene Zeit mal Ablaufgeschwindigkeit. Bei "Echtzeit" und 60 Bildern je
12 * Sekunde rechnete das Modell deshalb mit 0,017 s statt der vorgegebenen 0,5 s.
13 * Dieselbe Anlage lieferte je nach Ablaufgeschwindigkeit und Bildwiederholrate
14 * andere Werte fuer Abgeflossen, Rueckstau und mittlere Wartezeit - waehrend der
15 * Hinweis am Ankreuzfeld "dieselbe Einstellung liefert dasselbe Ergebnis"
16 * zusagt.
17 */
18
19 const FESTES_DATUM = new Date('2026-01-01T00:00:00Z');
20
21 function laufen(teilstueck: number, gesamt: number, stochastisch = false): SimulationSnapshot {
22 const project = createStandardIntersectionProject('Zeitschritt', FESTES_DATUM);
23 const plan = buildSignalPlan(project);
24 const sim = new TrafficSimulation(plan, project, {
25 timeStep: 0.5,
26 stochastic: stochastisch,
27 });
28 for (let i = 0; i < Math.round(gesamt / teilstueck); i += 1) sim.advance(teilstueck);
29 return sim.snapshot();
30 }
31
32 /** Die Groessen, die in der Ansicht abgelesen werden. */
33 function kennzahlen(snapshot: SimulationSnapshot): unknown {
34 return {
35 time: snapshot.time,
36 overallDelay: snapshot.overallDelay,
37 totalArrived: snapshot.totalArrived,
38 totalDeparted: snapshot.totalDeparted,
39 totalQueue: snapshot.totalQueue,
40 groups: snapshot.groups.map((g) => ({
41 name: g.name,
42 queue: g.queue,
43 maxQueue: g.maxQueue,
44 arrived: g.arrived,
45 departed: g.departed,
46 averageDelay: g.averageDelay,
47 grade: g.serviceLevel.grade,
48 })),
49 };
50 }
51
52 describe('Zeitschritt der Simulation', () => {
53 // Teilstuecke, wie sie die Bildschleife bei 64 Bildern je Sekunde und
54 // Echtzeit, 8-fach, 16-fach und 32-fach uebergibt.
55 it.each([1 / 64, 0.125, 0.25, 0.5])(
56 'liefert bei %s s je Aufruf dasselbe Ergebnis wie in Bloecken zu 60 s',
57 (teilstueck) => {
58 expect(kennzahlen(laufen(teilstueck, 600))).toEqual(kennzahlen(laufen(60, 600)));
59 },
60 );
61
62 it('haengt auch mit Ankunftsschwankungen nicht an der Groesse der Teilstuecke', () => {
63 // Bei gesetztem Haken zog das Modell je Zeitschritt einmal; mit feinen
64 // Schritten kam so ein Vielfaches der erfassten Verkehrsstaerke an.
65 const inBloecken = laufen(60, 600, true);
66 const inEinzelbildern = laufen(0.125, 600, true);
67 expect(kennzahlen(inEinzelbildern)).toEqual(kennzahlen(inBloecken));
68 });
69
70 it('rechnet keinen Bruchteil eines Zeitschritts vorzeitig ab', () => {
71 // Vier Aufrufe zu 0,125 s ergeben genau einen Schritt zu 0,5 s - vorher
72 // rechnete jeder Aufruf einen eigenen, kleineren Schritt.
73 const project = createStandardIntersectionProject('Zeitschritt', FESTES_DATUM);
74 const plan = buildSignalPlan(project);
75 const sim = new TrafficSimulation(plan, project, { timeStep: 0.5 });
76 sim.advance(0.125);
77 expect(sim.snapshot().time).toBe(0);
78 sim.advance(0.125);
79 sim.advance(0.125);
80 expect(sim.snapshot().time).toBe(0);
81 sim.advance(0.125);
82 expect(sim.snapshot().time).toBe(0.5);
83 });
84 });