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