lsa-planer
LSA-Planer Professional – Planungssoftware für Lichtsignalanlagen nach RiLSA 2015 und § 45 StVO. EUPL-1.2.
/ tests domain zeitschritt.test.ts
| 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 | }); |