lsa-planer

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

/ src domain rilsa signalTimes.ts

6,8 KB Rohdatei
src/domain/rilsa/signalTimes.ts — 176 Zeilen
1 import type { KilometersPerHour, Meters, MetersPerSecond, Seconds } from '../units';
2 import { isFiniteNumber } from '../units';
3 import { OEPNV_UEBERGANGSZEIT_STAFFEL, RILSA_DEFAULTS, type RilsaDefaults } from './constants';
4 import type { SignalGroupTimes, TrafficMode } from './types';
5
6 /**
7 * Gelbzeit einer Signalgruppe.
8 *
9 * KORREKTUR gegenueber dem Altbestand: Dort lieferte die Funktion fuer
10 * Fussgaenger die Gelbzeit des Radverkehrs (3 s), weil der Fussgaenger-Fall
11 * durch den Sammelzweig am Ende fiel. Fussgaengersignale haben kein Gelb.
12 */
13 export function yellowTime(
14 mode: TrafficMode,
15 vZul: KilometersPerHour,
16 defaults: RilsaDefaults = RILSA_DEFAULTS,
17 ): Seconds {
18 switch (mode) {
19 case 'fuss':
20 return 0;
21 case 'rad':
22 return defaults.yellowRad;
23 case 'oepnv':
24 /*
25 * KORREKTUR (Fassung 5.27.0): Hier stand 0 s mit dem Vermerk
26 * "Sondersignale (Balkensignale) kennen kein Gelb". Sie kennen kein
27 * GELB, aber sehr wohl eine Uebergangszeit: das Uebergangssignal nach
28 * Par. 51 BOStrab, dessen Dauer die RiLSA 2015 in Abschnitt 2.4 nach der
29 * betrieblich zugelassenen Hoechstgeschwindigkeit staffelt (4 s bis
30 * 30 km/h bis 8 s bei 70 km/h). Begruendung und die beiden nicht
31 * abgebildeten Ausnahmen stehen bei OEPNV_UEBERGANGSZEIT_STAFFEL.
32 */
33 return oepnvUebergangszeit(vZul);
34 case 'kfz': {
35 if (!isFiniteNumber(vZul) || vZul <= 0) {
36 // Ohne belastbare Geschwindigkeitsangabe wird die laengste Gelbzeit
37 // angesetzt. Das ist die sichere Seite; die Validierung meldet die
38 // fehlende Angabe zusaetzlich als Fehler.
39 return lastYellowStep(defaults);
40 }
41 for (const step of defaults.yellowBySpeed) {
42 if (vZul <= step.upToKmh) return step.yellow;
43 }
44 return lastYellowStep(defaults);
45 }
46 }
47 }
48
49 /**
50 * Dauer des Uebergangssignals eines gesondert signalisierten
51 * OePNV-Fahrzeugs nach der Staffel der RiLSA 2015 (Abschnitt 2.4).
52 *
53 * Ohne Vmax und oberhalb des Staffelendes von 70 km/h gilt die oberste Stufe -
54 * die laengere Uebergangszeit ist die sichere Seite, und oberhalb 70 km/h
55 * sollen Lichtsignalanlagen ohnehin nicht betrieben werden.
56 */
57 function oepnvUebergangszeit(vZul: KilometersPerHour): Seconds {
58 const oberste = OEPNV_UEBERGANGSZEIT_STAFFEL.at(-1)?.uebergang ?? 8;
59 if (!isFiniteNumber(vZul) || vZul <= 0) return oberste;
60 for (const stufe of OEPNV_UEBERGANGSZEIT_STAFFEL) {
61 if (vZul <= stufe.upToKmh) return stufe.uebergang;
62 }
63 return oberste;
64 }
65
66 function lastYellowStep(defaults: RilsaDefaults): Seconds {
67 const last = defaults.yellowBySpeed[defaults.yellowBySpeed.length - 1];
68 return last ? last.yellow : 5;
69 }
70
71 /**
72 * Rot-Gelb-Zeit einer Signalgruppe.
73 * Fussgaenger- und OePNV-Sondersignale haben kein Rot-Gelb.
74 */
75 export function redYellowTime(
76 mode: TrafficMode,
77 defaults: RilsaDefaults = RILSA_DEFAULTS,
78 ): Seconds {
79 return mode === 'fuss' || mode === 'oepnv' ? 0 : defaults.redYellow;
80 }
81
82 /**
83 * Mindestfreigabezeit einer Signalgruppe - der REGELWERT je Verkehrsart.
84 *
85 * Fuer Fussgaengergruppen ist das nur die Untergrenze: Daneben gilt die
86 * Furtregel (`furtFreigabebedarf`), und massgebend ist der groessere Wert.
87 * Beides zusammen rechnet `mindestfreigabezeitDerGruppe` in
88 * src/domain/plan/signalPlan.ts, weil dafuer die Konfliktbeziehungen des
89 * Projekts gebraucht werden.
90 */
91 export function minGreenTime(mode: TrafficMode, defaults: RilsaDefaults = RILSA_DEFAULTS): Seconds {
92 return defaults.minGreen[mode];
93 }
94
95 /**
96 * Freigabezeitbedarf einer Fussgaengerfurt nach der Furtregel der RiLSA 2015.
97 *
98 * Ein Fussgaenger, der zu Beginn der Freigabezeit die Furt betritt, muss
99 * waehrend der Freigabe die HALBE Furt zuruecklegen koennen; mit einer
100 * Zusatzeinrichtung fuer Blinde und Sehbehinderte (DIN 32981) die GANZE Furt.
101 * Zeitbedarf = Furtweg / vr, mit der Raeumgeschwindigkeit der Gruppe
102 * (Regelwert 1,2 m/s; 1,0 m/s bei erhoehtem Zeitbedarf).
103 *
104 * NEU (Fassung 5.4.0, Befund C1): Bis dahin galt fuer jede
105 * Fussgaengergruppe allein die feste Mindestfreigabezeit von 5 s. Eine 20 m
106 * lange Furt erhielt damit 5 s Freigabe, obwohl schon die halbe Furt 8,3 s
107 * verlangt - der Fussgaenger stand nach Freigabeende noch 3,3 s vor der Mitte.
108 *
109 * Alle Groessen stehen im Ergebnis, damit die Meldung den Rechenweg nennen kann
110 * und ein Pruefer ihn nachrechnet. `zeitbedarf` ist ungerundet;
111 * `zeitbedarfGerundet` ist der Wert, mit dem der Plan rechnet (ganze Sekunden,
112 * aufgerundet) - HIER gerundet und nicht beim Aufrufer, weil die Rundungsregel
113 * sonst an jeder Ausgabestelle noch einmal stand (signalPlan.ts zweimal, pdf.ts
114 * einmal) und beim naechsten Aufrufer auseinanderliefe.
115 */
116 export interface FurtFreigabebedarf {
117 /** Furtlaenge in Metern. */
118 readonly furtlaenge: Meters;
119 /** Ganze Furt (Zusatzeinrichtung fuer Blinde und Sehbehinderte) oder halbe Furt. */
120 readonly ganzeFurt: boolean;
121 /** Angesetzter Furtweg: Furtlaenge bzw. Furtlaenge / 2. */
122 readonly furtweg: Meters;
123 /** Angesetzte Raeumgeschwindigkeit vr in m/s. */
124 readonly vr: MetersPerSecond;
125 /** Zeitbedarf furtweg / vr in Sekunden, ungerundet. */
126 readonly zeitbedarf: Seconds;
127 /**
128 * Zeitbedarf auf ganze Sekunden AUFGERUNDET - der Wert, der in den Plan
129 * eingeht. Aufgerundet, nie abgerundet: Signalzeiten werden in ganzen
130 * Sekunden geschaltet, und 5,83 s Bedarf sind mit 5 s nicht gedeckt.
131 */
132 readonly zeitbedarfGerundet: Seconds;
133 }
134
135 /**
136 * Toleranz gegen Gleitkommarauschen beim Aufrunden: 8,4 m / 1,2 m/s ist
137 * rechnerisch 7,000000000000001 s und darf nicht 8 s ergeben. Eine echte
138 * Ueberschreitung um weniger als eine Mikrosekunde gibt es bei Wegen in
139 * Metern (zwei Nachkommastellen) und Geschwindigkeiten mit einer
140 * Nachkommastelle nicht.
141 */
142 const RUNDUNGSTOLERANZ: Seconds = 1e-6;
143
144 export function furtFreigabebedarf(
145 furtlaenge: Meters,
146 vr: MetersPerSecond,
147 ganzeFurt: boolean,
148 ): FurtFreigabebedarf {
149 const furtweg = ganzeFurt ? furtlaenge : furtlaenge / 2;
150 // vr <= 0 kann aus den Vorgaben nicht kommen (Schranken in settings.ts);
151 // hier trotzdem abgesichert, damit nie "Infinity s" entsteht.
152 const zeitbedarf = vr > 0 ? furtweg / vr : 0;
153 const zeitbedarfGerundet = Math.max(0, Math.ceil(zeitbedarf - RUNDUNGSTOLERANZ));
154 return { furtlaenge, ganzeFurt, furtweg, vr, zeitbedarf, zeitbedarfGerundet };
155 }
156
157 /** Alle Signalzeiten einer Signalgruppe in einem Zug. */
158 export function signalGroupTimes(
159 mode: TrafficMode,
160 vZul: KilometersPerHour,
161 defaults: RilsaDefaults = RILSA_DEFAULTS,
162 ): SignalGroupTimes {
163 return {
164 minGreen: minGreenTime(mode, defaults),
165 yellow: yellowTime(mode, vZul, defaults),
166 redYellow: redYellowTime(mode, defaults),
167 };
168 }
169
170 /**
171 * Dauer eines vollstaendigen Signalwechsels von Rot nach Rot:
172 * Rot-Gelb + Freigabezeit + Gelb.
173 */
174 export function signalGroupCycleSpan(times: SignalGroupTimes, green: Seconds): Seconds {
175 return times.redYellow + green + times.yellow;
176 }