lsa-planer

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

/ src domain rilsa engstellensignalisierung.ts

9,8 KB Rohdatei
src/domain/rilsa/engstellensignalisierung.ts — 245 Zeilen
1 import type { KilometersPerHour, MetersPerSecond, Meters, Ratio, Seconds } from '../units';
2 import { ceilSeconds, isFiniteNumber, roundTo } from '../units';
3 import { RILSA_ENGSTELLE } from './constants';
4 import type { CalculationNote } from './types';
5
6 /**
7 * Das eigene Rechenverfahren der Engstellensignalisierung
8 * (RiLSA 2015, Abschnitt 5.2).
9 *
10 * WARUM DAS EIN ZWEITES VERFAHREN IST UND KEINE VARIANTE DES ERSTEN: Die RiLSA
11 * sagt in Abschnitt 5.2.1, die Ausfuehrungen gelten "primaer fuer die
12 * transportablen, das heisst voruebergehend eingesetzten Lichtsignalanlagen
13 * (Baustellenampeln) an Arbeitsstellen" - also genau fuer die Anlagenart
14 * `einstreifig` dieses Programms. Und sie rechnet dort anders als am
15 * Knotenpunkt, in fuenf Punkten:
16 *
17 * 1. Die Ueberfahrzeit betraegt 4 s, unabhaengig von allem uebrigen. Am
18 * Knotenpunkt sind es 3 s geradeaus bzw. 2 s abbiegend (Faelle 1 und 2)
19 * oder, im Ansatz dieses Programms, die Gelbzeit.
20 * 2. Die Raeumgeschwindigkeit haengt an der zulaessigen
21 * Hoechstgeschwindigkeit und wird in km/h angesetzt, nicht in m/s.
22 * 3. Der Raeumweg ist der Abstand der Haltlinien - OHNE Fahrzeuglaenge. Am
23 * Knotenpunkt kommen 6 m hinzu.
24 * 4. Eine Einfahrzeit wird NICHT abgezogen ("Die Zwischenzeit tz wird ohne
25 * Beruecksichtigung einer Einfahrzeit ermittelt").
26 * 5. Auch die Uebergangszeit GELB betraegt 4 s statt der 3/4/5 s der
27 * Gelbzeitstaffel.
28 *
29 * BIS ZUR FASSUNG 5.26.0 rechnete dieses Programm die einstreifige
30 * Verkehrsfuehrung nach den Knotenpunktregeln. Das war nicht durchweg falsch -
31 * fuer einen nachgerechneten angeordneten Plan (Raeumweg 40 m, zulaessig
32 * 50 km/h) kommen beide Wege auf dieselben 8 s -, aber es war eine andere
33 * Rechnung mit anderen Groessen, und bei anderer Geometrie laufen sie
34 * auseinander. Bei 40 km/h zulaessiger Hoechstgeschwindigkeit tut sie das in
35 * die VERKUERZENDE Richtung: 200 m Raeumweg ergeben nach Abschnitt 5.2
36 * 4 + 200/30 * 3,6 = 28 s, nach den Knotenpunktregeln 3 + 206/10 = 24 s.
37 *
38 * DIESES MODUL RECHNET NUR; es entscheidet nicht, wann es gilt. Das tut
39 * `resolveIntergreens` in plan/signalPlan.ts anhand der Anlagenart.
40 */
41
42 /** Woher die angesetzte Raeumgeschwindigkeit einer Engstelle kommt. */
43 export type EngstellenRaeumgrund =
44 /** Staffel nach der zulaessigen Hoechstgeschwindigkeit. */
45 | 'vzul'
46 /** Schlechte Fahrbahn oder regelmaessig landwirtschaftliche Fahrzeuge. */
47 | 'fahrbahn'
48 /** Der Radverkehr ist massgebend. */
49 | 'radverkehr'
50 /** Unterhalb der Staffel: die kleinste Stufe. */
51 | 'unter-staffel'
52 /** Auf die zulaessige Hoechstgeschwindigkeit gedeckelt. */
53 | 'vmax-deckel';
54
55 export interface EngstellenRaeumgeschwindigkeit {
56 /** Angesetzte Raeumgeschwindigkeit Vr in km/h - die Einheit des Abschnitts. */
57 readonly vrKmh: KilometersPerHour;
58 readonly grund: EngstellenRaeumgrund;
59 }
60
61 export interface EngstellenAnnahmen {
62 /**
63 * Schlechte Fahrbahn oder regelmaessig auftretende landwirtschaftliche
64 * Fahrzeuge: dann 30 km/h, unabhaengig von der zulaessigen
65 * Hoechstgeschwindigkeit.
66 */
67 readonly schlechteFahrbahn?: boolean;
68 /**
69 * Der Radverkehr ist massgebend - die Engstelle ist nicht so breit und
70 * uebersichtlich, dass sich Kraftfahrzeuge und Radfahrer unbedenklich
71 * begegnen koennen. Dann 18 km/h.
72 */
73 readonly radverkehrMassgebend?: boolean;
74 }
75
76 /**
77 * Raeumgeschwindigkeit einer Engstelle nach Abschnitt 5.2.2.
78 *
79 * Die Staffel nennt drei Stufen (50/40/30 km/h bei zulaessig 60/50/40 km/h).
80 * Unterhalb von 40 km/h endet sie; angesetzt wird dann die kleinste Stufe -
81 * eine kleinere Raeumgeschwindigkeit ergaebe eine laengere Zwischenzeit, und
82 * die RiLSA nennt fuer diesen Fall keinen Wert. Oberhalb von 60 km/h ebenso
83 * die oberste: Dort duerfte ohnehin keine Baustellenampel stehen (die RSA
84 * beschraenkt Arbeitsstellen laengerer Dauer in der Regel auf 50 km/h).
85 *
86 * DIE BEIDEN SONDERFAELLE GEHEN VOR, und der langsamere von beiden gewinnt:
87 * Beide setzen die Geschwindigkeit HERAB, und wo beide zutreffen, gilt die
88 * kleinere - eine Engstelle wird nicht dadurch schneller, dass zwei Gruende
89 * fuer Langsamkeit zusammentreffen.
90 */
91 export function engstellenRaeumgeschwindigkeit(
92 vZul: KilometersPerHour,
93 annahmen: EngstellenAnnahmen = {},
94 ): EngstellenRaeumgeschwindigkeit {
95 const sonderfaelle: EngstellenRaeumgeschwindigkeit[] = [];
96 if (annahmen.radverkehrMassgebend === true) {
97 sonderfaelle.push({ vrKmh: RILSA_ENGSTELLE.vrRadverkehr, grund: 'radverkehr' });
98 }
99 if (annahmen.schlechteFahrbahn === true) {
100 sonderfaelle.push({ vrKmh: RILSA_ENGSTELLE.vrSchlechteFahrbahn, grund: 'fahrbahn' });
101 }
102 if (sonderfaelle.length > 0) {
103 return sonderfaelle.reduce((a, b) => (b.vrKmh < a.vrKmh ? b : a));
104 }
105
106 const staffel = RILSA_ENGSTELLE.raeumgeschwindigkeit;
107 const kleinste = staffel[staffel.length - 1];
108 if (!isFiniteNumber(vZul) || vZul <= 0) {
109 // Ohne Angabe die kleinste Stufe: Sie ergibt die laengste Zwischenzeit.
110 return { vrKmh: kleinste?.vrKmh ?? 30, grund: 'unter-staffel' };
111 }
112 let gewaehlt: EngstellenRaeumgeschwindigkeit = {
113 vrKmh: kleinste?.vrKmh ?? 30,
114 grund: 'unter-staffel',
115 };
116 for (const stufe of staffel) {
117 if (vZul >= stufe.vZulAb) {
118 gewaehlt = { vrKmh: stufe.vrKmh, grund: 'vzul' };
119 break;
120 }
121 }
122 /*
123 * NICHT SCHNELLER RAEUMEN, ALS GEFAHREN WERDEN DARF - derselbe Deckel wie
124 * am Knotenpunkt (Fassung 5.22.0, `vmaxDeckel` in intergreen.ts).
125 *
126 * Er wird hier gebraucht, weil die Staffel bei 40 km/h endet: Unterhalb
127 * davon gilt ihre kleinste Stufe, 30 km/h - und die liegt bei einer
128 * Arbeitsstelle mit Tempo 20 ueber der zulaessigen Hoechstgeschwindigkeit.
129 * Ein Fahrzeug raeumte dann rechnerisch schneller, als es fahren darf. Der
130 * Deckel ist ein Ansatz DIESES Programms; die RiLSA nennt fuer diesen Fall
131 * keinen Wert. Er wirkt nur nach unten und verlaengert die Zwischenzeit.
132 */
133 if (vZul < gewaehlt.vrKmh) return { vrKmh: vZul, grund: 'vmax-deckel' };
134 return gewaehlt;
135 }
136
137 export interface EngstellenZwischenzeit {
138 /** Zwischenzeit in ganzen Sekunden, aufgerundet. */
139 readonly zwischenzeit: Seconds;
140 /** Ungerundetes Ergebnis tue + sr/Vr * 3,6. */
141 readonly roh: Seconds;
142 /** Angesetzte Ueberfahrzeit - nach Abschnitt 5.2.2 stets 4 s. */
143 readonly ueberfahrzeit: Seconds;
144 /** Raeumweg sr: Abstand der Haltlinien, OHNE Fahrzeuglaenge. */
145 readonly raeumweg: Meters;
146 /** Angesetzte Raeumgeschwindigkeit mit ihrer Begruendung. */
147 readonly raeumgeschwindigkeit: EngstellenRaeumgeschwindigkeit;
148 /** Raeumzeit sr/Vr * 3,6 in Sekunden. */
149 readonly raeumzeit: Seconds;
150 readonly notes: readonly CalculationNote[];
151 }
152
153 /**
154 * Zwischenzeit einer Engstelle nach Abschnitt 5.2.2:
155 *
156 * tz = tue + sr / Vr * 3,6 mit tue = 4 s und Vr in km/h
157 *
158 * OHNE EINFAHRZEIT - das steht dort ausdruecklich, und es ist der Grund, warum
159 * diese Funktion keinen einfahrenden Strom kennt. Wer hier eine Einfahrzeit
160 * abzoege, verkuerzte die Zwischenzeit gegenueber dem Regelwerk.
161 */
162 export function engstellenZwischenzeit(
163 raeumweg: Meters,
164 vZul: KilometersPerHour,
165 annahmen: EngstellenAnnahmen = {},
166 ): EngstellenZwischenzeit {
167 const notes: CalculationNote[] = [];
168 const sr = isFiniteNumber(raeumweg) && raeumweg > 0 ? raeumweg : 0;
169 if (sr === 0) {
170 notes.push({
171 severity: 'warnung',
172 code: 'engstelle-raeumweg-null',
173 message:
174 'Der Räumweg der Engstelle beträgt 0 m. Nach RiLSA 2015, Abschnitt 5.2.2 ist der Abstand ' +
175 'zwischen den Haltlinien anzusetzen - bei nicht markierten Haltlinien der Abstand der ' +
176 'Signalgeber.',
177 });
178 }
179
180 const raeumgeschwindigkeit = engstellenRaeumgeschwindigkeit(vZul, annahmen);
181 const raeumzeit = (sr / raeumgeschwindigkeit.vrKmh) * 3.6;
182 const roh = RILSA_ENGSTELLE.ueberfahrzeit + raeumzeit;
183
184 return {
185 zwischenzeit: ceilSeconds(roh),
186 roh: roundTo(roh, 3),
187 ueberfahrzeit: RILSA_ENGSTELLE.ueberfahrzeit,
188 raeumweg: sr,
189 raeumgeschwindigkeit,
190 raeumzeit: roundTo(raeumzeit, 3),
191 notes,
192 };
193 }
194
195 /** Die Raeumgeschwindigkeit einer Engstelle in SI-Einheiten. */
196 export function engstellenRaeumgeschwindigkeitMs(
197 vZul: KilometersPerHour,
198 annahmen: EngstellenAnnahmen = {},
199 ): MetersPerSecond {
200 return engstellenRaeumgeschwindigkeit(vZul, annahmen).vrKmh / 3.6;
201 }
202
203 /**
204 * Wartezeitminimale Umlaufzeit einer Engstelle nach Abschnitt 5.2.3:
205 *
206 * tU = (1,3 * TZ + 4) / (1 - (q1/qS1 + q2/qS2)) mit Summe < 1
207 *
208 * Dieselbe Bauart wie Webster, aber mit anderen Beiwerten UND einer anderen
209 * Bezugsgroesse: TZ ist die Summe der beiden ZWISCHENzeiten, nicht die
210 * Verlustzeit je Umlauf. Die Anfahrverluste, die dieses Programm am
211 * Knotenpunkt in L einrechnet, kommen hier nicht vor.
212 *
213 * Die Umlaufzeit soll nicht groesser als 300 s sein. Dass dieses Programm
214 * dieselbe Schranke bereits fuehrte, ist ein Zufall der Herleitung: Sie war
215 * bis 5.26.0 aus den uebrigen Schranken gerechnet und ausdruecklich als
216 * "kein Wert eines Regelwerks" ausgewiesen. Jetzt ist sie einer.
217 */
218 export function engstellenUmlaufzeit(zwischenzeitSumme: Seconds, auslastungssumme: Ratio): Seconds {
219 const nenner = 1 - auslastungssumme;
220 if (!(nenner > 0)) return Number.POSITIVE_INFINITY;
221 return (
222 (RILSA_ENGSTELLE.umlaufzeitFaktor * zwischenzeitSumme + RILSA_ENGSTELLE.umlaufzeitZuschlag) /
223 nenner
224 );
225 }
226
227 /**
228 * Freigabezeit einer Fahrtrichtung nach Abschnitt 5.2.3:
229 *
230 * tFi = (qi/qSi) / (q1/qS1 + q2/qS2) * (tU - TZ)
231 *
232 * Das ist dieselbe Aufteilung wie am Knotenpunkt (Abschnitt 2.7.1) - die
233 * verbleibende Zeit im Verhaeltnis der Auslastungsgrade. Sie steht hier
234 * gleichwohl eigens, weil die RiLSA sie eigens nennt und weil ein Pruefer sie
235 * an dieser Fundstelle sucht.
236 */
237 export function engstellenFreigabezeit(
238 auslastung: Ratio,
239 auslastungssumme: Ratio,
240 umlaufzeit: Seconds,
241 zwischenzeitSumme: Seconds,
242 ): Seconds {
243 if (!(auslastungssumme > 0)) return 0;
244 return (auslastung / auslastungssumme) * (umlaufzeit - zwischenzeitSumme);
245 }