lsa-planer

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

/ tests domain ankunftsschwankungen.test.ts

3,4 KB Rohdatei
tests/domain/ankunftsschwankungen.test.ts — 77 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 * Ankunftsschwankungen duerfen um die erfasste Verkehrsstaerke streuen, sie
8 * duerfen sie nicht anheben (Befund 25, behoben in Fassung 5.9.0).
9 *
10 * Was der Anwender sonst erlebt: Er setzt den Haken "Ankunftsschwankungen
11 * berücksichtigen", laesst eine Stunde laufen und liest in der Spalte
12 * "Angekommen" fuer eine Gruppe mit 620 Fz/h rund 1800 Fahrzeuge ab. Rueckstau,
13 * Laenge, mittlere Wartezeit und Qualitaetsstufe sind damit unbrauchbar, und der
14 * Rueckstau waechst auch dort unbegrenzt, wo die Leistungsfaehigkeit desselben
15 * Plans die Gruppe als deutlich unterausgelastet fuehrt.
16 *
17 * Ursache: Der Bruchteil eines Fahrzeugs wurde beim Feuern der Ziehung
18 * verworfen, statt verbraucht zu werden - je Zeitschritt ein
19 * Erwartungswert-Ueberschuss von rem * (1 - rem).
20 */
21
22 const FESTES_DATUM = new Date('2026-01-01T00:00:00Z');
23
24 const PROJEKT = createStandardIntersectionProject('Ankunftsschwankungen', FESTES_DATUM);
25 const PLAN = buildSignalPlan(PROJEKT);
26
27 function laufen(sekunden: number, seed?: number): SimulationSnapshot {
28 const sim = new TrafficSimulation(PLAN, PROJEKT, {
29 timeStep: 0.5,
30 stochastic: true,
31 ...(seed === undefined ? {} : { seed }),
32 });
33 for (let i = 0; i < sekunden / 60; i += 1) sim.advance(60);
34 return sim.snapshot();
35 }
36
37 describe('Simulation mit Ankunftsschwankungen', () => {
38 it('laesst in einer Stunde etwa so viele Fahrzeuge ankommen wie die Verkehrsstaerke angibt', () => {
39 const snapshot = laufen(3600);
40 for (const group of snapshot.groups) {
41 // Vor der Behebung kamen bei 620 Fz/h 1814 Fahrzeuge an - das Dreifache.
42 const meldung = `${group.name}: ${group.arrived} statt ${group.demand}`;
43 expect(group.arrived, meldung).toBeGreaterThan(group.demand * 0.9);
44 expect(group.arrived, meldung).toBeLessThan(group.demand * 1.1);
45 }
46 });
47
48 it('haelt den Erwartungswert ueber mehrere Startwerte bei der erfassten Verkehrsstaerke', () => {
49 // Eine Schwankung streut um den Mittelwert; ueber viele Startwerte gemittelt
50 // muss die erfasste Verkehrsstaerke herauskommen. Vor der Behebung lag der
51 // Mittelwert systematisch um ein Mehrfaches darueber - unabhaengig vom
52 // Startwert, denn der Ueberschuss rem * (1 - rem) ist nie negativ.
53 const startwerte = [1, 2, 3, 5, 8, 13, 21, 34];
54 const summe = new Map<string, number>();
55 for (const seed of startwerte) {
56 for (const group of laufen(1800, seed).groups) {
57 summe.set(group.groupId, (summe.get(group.groupId) ?? 0) + group.arrived);
58 }
59 }
60 for (const group of laufen(1800).groups) {
61 const mittel = (summe.get(group.groupId) ?? 0) / startwerte.length;
62 // Eine halbe Stunde: die halbe stuendliche Verkehrsstaerke.
63 const soll = group.demand / 2;
64 expect(Math.abs(mittel - soll), `${group.name}: ${mittel} statt ${soll}`).toBeLessThan(
65 soll * 0.05,
66 );
67 }
68 });
69
70 it('erzeugt nie mehr Fahrzeuge, als die Fahrzeugbilanz traegt', () => {
71 const snapshot = laufen(1800);
72 for (const group of snapshot.groups) {
73 expect(group.arrived).toBe(group.departed + group.queue);
74 expect(group.queue).toBeGreaterThanOrEqual(0);
75 }
76 });
77 });