lsa-planer

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

/ tests domain grundwartezeit.test.ts

4,4 KB Rohdatei
tests/domain/grundwartezeit.test.ts — 102 Zeilen
1 import { describe, expect, it } from 'vitest';
2 import { computeDelay, sperrzeitenAusFenstern } from '@/domain/rilsa/delay';
3
4 /*
5 * Fassung 5.10.0 - die Grundwartezeit.
6 *
7 * `computeDelay` bildet den Zaehler der Grundwartezeit seit Befund 26 aus
8 * Summe(r_j^2) / tU ueber die Sperrzeiten des Umlaufs
9 * (`summeSperrzeitenQuadrate` in src/domain/rilsa/delay.ts); ein Nachtrag hat
10 * die Uebergabe der Sperrzeiten aus dem Planaufbau nachgezogen, seitdem kommt
11 * die allgemeine Form auch im laufenden Programm an.
12 *
13 * Die Unterlagen fuehrten die Groesse weiter ausschliesslich in der
14 * geschlossenen Einfensterform tW,G = tU * (1 - fA)^2 / (2 * (1 - min(1; x) * fA)).
15 * Wer damit nachrechnet, was das Programm bei mehreren Freigabezeitfenstern
16 * ausweist, kommt auf das Doppelte und haelt die Zahl des Programms fuer
17 * falsch. Die Faelle hier messen an `computeDelay` nach, dass die allgemeine
18 * Form gilt - und dass die Einfensterform genau der Sonderfall ist.
19 *
20 * NACHTRAG: Die r_j der Formel sind nicht die Rot-Abschnitte,
21 * die `sperrzeitenAusFenstern` liefert - deren Summe ist tU - tF. Erst nachdem
22 * `summeSperrzeitenQuadrate` je Freigabezeitfenster den Zeitzuschlag der
23 * Abflusszeit abgezogen hat, gilt Summe(r_j) = tU - tA. Der letzte Fall misst
24 * diesen Unterschied.
25 *
26 * Die beiden Rechenfaelle sind der Beleg, dass die allgemeine Form stimmt, und
27 * werden rot, sobald jemand die Rechnung wieder auf die Einfensterform
28 * zurueckdreht.
29 */
30
31 /**
32 * Umlauf mit zwei gleich langen Sperrzeiten.
33 *
34 * tU = 100 s, tA = 20 s: Die wirksame Sperrzeit betraegt 80 s. Uebergeben
35 * werden 45 s + 45 s - die Sperrzeiten aus den Freigabezeitfenstern tragen den
36 * Zeitzuschlag der Abflusszeit noch; `summeSperrzeitenQuadrate` zieht ihn je
37 * Fenster ab und rechnet mit 40 s + 40 s.
38 *
39 * Zaehler allgemein: (40² + 40²) / 100 = 32 s. Zaehler geschlossen: 100 · (1 −
40 * 0,2)² = 64 s - genau das Doppelte.
41 */
42 const ZWEI_FENSTER = {
43 cycleTime: 100,
44 greenTime: 19,
45 abflusszeit: 20,
46 capacity: 1000,
47 demand: 500,
48 verfahren: 'HBS',
49 mode: 'kfz',
50 } as const;
51
52 describe('Die Grundwartezeit rechnet in der allgemeinen Form', () => {
53 it('rechnet bei zwei Fenstern nach der allgemeinen Form', () => {
54 const zwei = computeDelay({ ...ZWEI_FENSTER, sperrzeiten: [45, 45] });
55
56 // 32 s / (2 · (1 − 0,5 · 0,2)) = 32 / 1,8 = 17,78 s
57 expect(zwei.rechenweg.abflussanteil).toBeCloseTo(0.2, 6);
58 expect(zwei.degreeOfSaturation).toBeCloseTo(0.5, 6);
59 expect(zwei.uniformDelay).toBeCloseTo(32 / 1.8, 1);
60 });
61
62 it('fällt ohne brauchbare Sperrzeiten auf die Einfensterform zurück', () => {
63 // Genau der Sonderfall der Einfensterform: 64 s / 1,8 = 35,56 s,
64 // das Doppelte des Wertes darueber.
65 const ohne = computeDelay(ZWEI_FENSTER);
66 const unbrauchbar = computeDelay({ ...ZWEI_FENSTER, sperrzeiten: [0, Number.NaN] });
67
68 expect(ohne.uniformDelay).toBeCloseTo(64 / 1.8, 1);
69 expect(unbrauchbar.uniformDelay).toBe(ohne.uniformDelay);
70 // Ein Fenster: Die allgemeine Form ergibt denselben Wert wie der Rueckfall.
71 expect(computeDelay({ ...ZWEI_FENSTER, sperrzeiten: [81] }).uniformDelay).toBeCloseTo(
72 ohne.uniformDelay,
73 1,
74 );
75 });
76
77 it('unterscheidet in der Rechnung die Rot-Abschnitte von den wirksamen r_j', () => {
78 // Zwei Freigabezeitfenster von je 5 s im 100-s-Umlauf: tF = 10 s.
79 const rotAbschnitte = sperrzeitenAusFenstern(
80 [
81 { start: 0, duration: 5 },
82 { start: 50, duration: 5 },
83 ],
84 100,
85 );
86 expect(rotAbschnitte).toEqual([45, 45]);
87 // Die Summe der gelieferten Abschnitte ist tU - tF, nicht tU - tA.
88 const summeRot = rotAbschnitte.reduce((wert, r) => wert + r, 0);
89 expect(summeRot).toBeCloseTo(100 - 10, 6);
90 expect(summeRot).not.toBeCloseTo(100 - 12, 6);
91
92 // tA = tF + 1 s je Fenster = 12 s. Erst die wirksamen Sperrzeiten
93 // 44 s + 44 s summieren sich zu tU - tA = 88 s.
94 const ergebnis = computeDelay({ ...ZWEI_FENSTER, abflusszeit: 12, sperrzeiten: rotAbschnitte });
95 expect(ergebnis.rechenweg.abflussanteil).toBeCloseTo(0.12, 6);
96 // Zaehler (44² + 44²) / 100 = 38,72 s, Nenner 2 · (1 − 0,5 · 0,12) = 1,88.
97 expect(ergebnis.uniformDelay).toBeCloseTo(38.72 / 1.88, 1);
98 // Mit den Rot-Abschnitten selbst waeren es (45² + 45²) / 100 = 40,5 s -
99 // genau der Nachrechenfehler, den die alte Gleichsetzung ausloeste.
100 expect(ergebnis.uniformDelay).not.toBeCloseTo(40.5 / 1.88, 1);
101 });
102 });