forked from jappel/leistungsbilanz-ts
Align cable sizing with DIN VDE 0298-4
This commit is contained in:
parent
598003554a
commit
5cbbd3a84a
9 changed files with 262 additions and 244 deletions
11
AGENTS.md
11
AGENTS.md
|
|
@ -607,10 +607,13 @@ circuit list (see `docs/cable-sizing-module.md`). Rules:
|
||||||
by clicking a grid cell; cable cells keep the normal spreadsheet behavior.
|
by clicking a grid cell; cable cells keep the normal spreadsheet behavior.
|
||||||
- It has no database table and no migration; `/api/cable-sizing/*` is
|
- It has no database table and no migration; `/api/cable-sizing/*` is
|
||||||
stateless.
|
stateless.
|
||||||
- Reference data is IEC 60364-5-52:2009 Annex B. Change table values only with
|
- Current-carrying capacities and correction factors use
|
||||||
a documented source in `docs/cable-sizing-module.md`; where sources differ,
|
DIN VDE 0298-4:2023-06 with Berichtigung 1:2023-10; the exact scope and the
|
||||||
use the lower value. Inputs outside the tables return no result instead of
|
separate basis of voltage-drop and protection checks are documented in
|
||||||
assuming a factor of 1.
|
`docs/cable-sizing-module.md`. Inputs outside the supported tables return no
|
||||||
|
result instead of assuming a factor of 1. Direct burial, grouped method E,
|
||||||
|
aluminium below 25 mm² and neutral-current sizing above 33 % third harmonic
|
||||||
|
remain unsupported until their required inputs or normative basis exist.
|
||||||
- Inputs are prefilled from the circuit (power, phase, voltage, weighted cos φ,
|
- Inputs are prefilled from the circuit (power, phase, voltage, weighted cos φ,
|
||||||
length, protective device) and remain editable; manual cable entry without
|
length, protective device) and remain editable; manual cable entry without
|
||||||
a calculation stays possible.
|
a calculation stays possible.
|
||||||
|
|
|
||||||
|
|
@ -1,159 +1,109 @@
|
||||||
# Leitungsberechnung (Cable-Sizing-Modul)
|
# Leitungsberechnung
|
||||||
|
|
||||||
Optionales, abgegrenztes Rechenmodul für die Querschnittsempfehlung eines
|
Das optionale Modul gibt für einen einzelnen Stromkreis eine prüfbare
|
||||||
Stromkreises. Es wurde als eigenständiges Modul vereinbart, das an die
|
Querschnittsempfehlung aus. Es schreibt selbst keine Projektdaten. Erst die
|
||||||
Stromkreisliste angedockt ist. Es **schreibt keine Projektdaten selbst**: Ein
|
ausdrückliche Aktion **Übernehmen** aktualisiert `cableCrossSection`,
|
||||||
Ergebnis wird erst durch ausdrückliches „Übernehmen“ über den bestehenden
|
`cableType` und `cableLength` über den vorhandenen Befehl `circuit.update`.
|
||||||
Befehl `circuit.update` in den Stromkreis geschrieben. Revisionen und
|
Revisionen sowie Undo/Redo bleiben dadurch erhalten.
|
||||||
Undo/Redo bleiben damit unverändert gültig.
|
|
||||||
|
|
||||||
Die vollständige, automatische Bemessung aller Stromkreise (siehe
|
Eine automatische Bemessung aller Stromkreise ist weiterhin nicht Bestandteil
|
||||||
`docs/spec/06-future-sizing-and-calculations.md`) ist weiterhin **nicht**
|
des Moduls.
|
||||||
Teil dieses Moduls.
|
|
||||||
|
|
||||||
## Aufbau und Andockpunkte
|
## Aufbau
|
||||||
|
|
||||||
```
|
```text
|
||||||
src/cable-sizing/domain/cable-sizing-calculation.ts reine Berechnung + Tabellen
|
src/cable-sizing/domain/cable-sizing-calculation.ts Berechnung und Tabellen
|
||||||
src/cable-sizing/domain/cable-sizing-contracts.ts Zod-Schema der API
|
src/cable-sizing/domain/cable-sizing-contracts.ts API-Validierung
|
||||||
src/server/controllers/cable-sizing.controller.ts zustandslose Endpunkte
|
src/server/controllers/cable-sizing.controller.ts zustandslose Endpunkte
|
||||||
src/server/routes/cable-sizing.routes.ts Router unter /api/cable-sizing
|
src/server/routes/cable-sizing.routes.ts Router
|
||||||
src/frontend/components/cable-sizing-api.ts Fetch-Client
|
src/frontend/components/cable-sizing-api.ts Fetch-Client
|
||||||
src/frontend/components/cable-sizing-defaults.ts Vorbelegung aus dem Stromkreis
|
src/frontend/components/cable-sizing-defaults.ts Vorbelegung
|
||||||
src/frontend/components/cable-sizing-modal.tsx Dialog
|
src/frontend/components/cable-sizing-modal.tsx Dialog
|
||||||
tests/cable-sizing-calculation.test.ts Tabellen, Rechnung, Vorbelegung
|
tests/cable-sizing-calculation.test.ts Tabellen und Grenzfälle
|
||||||
```
|
```
|
||||||
|
|
||||||
Das Domänenmodul importiert nichts aus `db/`, `server/` oder `frontend/`.
|
Das Domänenmodul hängt weder von Datenbank, Server noch React ab. Die API ist
|
||||||
Außerhalb dieser Dateien gibt es genau zwei Andockpunkte:
|
zustandslos. Im Stromkreis-Editor öffnet ein Rechner-Symbol den Dialog; die
|
||||||
|
Kabelzellen behalten ihr übliches Spreadsheet-Verhalten.
|
||||||
|
|
||||||
1. `src/server/index.ts`: `app.use("/api/cable-sizing", cableSizingRouter)`.
|
## Eingaben
|
||||||
2. `src/frontend/components/circuit-tree-editor.tsx`: Zustand für den
|
|
||||||
geöffneten Dialog, ein Button **Leitungsberechnung** (Rechner-Icon) in der
|
|
||||||
Aktionsspalte jeder Stromkreiszeile, der Dialog selbst und
|
|
||||||
`handleApplyCableSizing`, das über `updateCircuitById` den regulären
|
|
||||||
`circuit.update`-Befehl ausführt.
|
|
||||||
|
|
||||||
Der Aufruf liegt bewusst **nicht** auf einer Tabellenzelle: Klick, Doppelklick,
|
Aus dem Stromkreis werden Leistung, Phasen, Spannung, leistungsgewichtetes
|
||||||
Enter, F2 und Tippen in den Kabelspalten verhalten sich wie in jeder anderen
|
cos φ, Leitungslänge und ein vorhandenes Überstromschutzorgan vorbelegt. Der
|
||||||
Zelle (Spreadsheet-Regel in `AGENTS.md`). Es gibt keine eigene Datenbanktabelle
|
Planer wählt Verlegeart, Isolierstoff, Leitermaterial, Temperatur, Häufung,
|
||||||
und keine Migration.
|
zulässigen Spannungsfall und bei Drehstrom den Anteil der dritten Harmonischen.
|
||||||
|
|
||||||
## Eingaben und Vorbelegung
|
Eine Leitungslänge von `0 m` ist zulässig. Der Dialog weist sichtbar darauf
|
||||||
|
hin, dass dann kein Spannungsfall angesetzt wird.
|
||||||
|
|
||||||
| Eingabe | Vorbelegung |
|
## Normative Grundlage und Grenzen
|
||||||
|---|---|
|
|
||||||
| Leistung | `circuitTotalPower` des Stromkreises (mit Geräte-GZF), nicht editierbar |
|
|
||||||
| Phasen | 3~, wenn die Stromkreisgruppe 3-phasig ist oder eine Gerätezeile `three_phase` hat, sonst 1~ |
|
|
||||||
| Spannung | `circuit.voltage` (aus den Projekteinstellungen abgeleitet); bei manuell abweichender Phasenzahl die jeweilige Projektspannung |
|
|
||||||
| cos φ | leistungsgewichtet aus den Gerätezeilen: P / Σ(P_Zeile / cos φ_Zeile), fehlendes cos φ = 1; änderbar |
|
|
||||||
| Länge | `cableLength` des Stromkreises |
|
|
||||||
| Schutzorgan | Schutzgerät des Stromkreises: LS, FI/LS, AFDD = Leitungsschutzschalter; D0/NH = Sicherung gG; FI ohne Überstromauslöser wird nicht berücksichtigt |
|
|
||||||
| Verlegeart, Isolierstoff, Leitermaterial, Temperatur, Häufung, max. ΔU, Oberschwingungen | Planereingaben |
|
|
||||||
|
|
||||||
Kabeltyp und Querschnitt lassen sich im Dialog auch ohne Berechnung direkt
|
Die Strombelastbarkeiten und Korrekturfaktoren wurden gegen
|
||||||
eintragen. Weicht der Eintrag von der Empfehlung oder dem
|
**DIN VDE 0298-4 (VDE 0298-4):2023-06** einschließlich
|
||||||
Praxis-Mindestquerschnitt ab, erscheint nur ein Hinweis.
|
**Berichtigung 1:2023-10** geprüft:
|
||||||
|
|
||||||
|
- Strombelastbarkeit: Tabellen 3 bis 6.
|
||||||
|
- Temperaturfaktoren: Tabellen 17 und 20.
|
||||||
|
- Häufung A1 bis C: Tabelle 22 nach der korrigierten Zuordnung.
|
||||||
|
- Häufung D: Tabelle 26 für sich berührende Rohre oder Kanäle im Erdreich.
|
||||||
|
- Oberschwingungen: Anhang B, insbesondere Tabelle B.1.
|
||||||
|
|
||||||
|
Unterstützt werden A1, A2, B1, B2, C, D und E. D bezeichnet ausschließlich
|
||||||
|
mehradrige Kabel oder Mantelleitungen im Rohr beziehungsweise Kanal im
|
||||||
|
Erdreich. Direkte Erdverlegung wird nicht angeboten, weil DIN VDE 0298-4 dafür
|
||||||
|
auf die Kabel-Produktnorm DIN VDE 0276-603 verweist.
|
||||||
|
|
||||||
|
Für Verlegeart E hängen Häufungsfaktoren von Trägerart, Abstand und Anzahl der
|
||||||
|
Kabelpritschen ab. Diese Angaben gehören noch nicht zum Eingabemodell. Daher
|
||||||
|
ist E nur für einen einzelnen Stromkreis berechenbar. Für D sind höchstens
|
||||||
|
sechs gehäufte Stromkreise durch die verwendete Tabellenzeile abgedeckt.
|
||||||
|
|
||||||
|
Aluminium wird erst ab 25 mm² angeboten, weil die verwendeten Tabellen keine
|
||||||
|
kleineren Aluminiumquerschnitte enthalten. Bei mehr als 33 % dritter
|
||||||
|
Harmonischer ist der Neutralleiterstrom Bemessungsgrundlage. Solange dieser
|
||||||
|
nicht als Zahlenwert eingegeben und berechnet wird, liefert das Modul keine
|
||||||
|
Empfehlung.
|
||||||
|
|
||||||
|
Die Berechnung des Spannungsfalls ist eine vereinfachte Ergänzung mit
|
||||||
|
Leitfähigkeit bei Betriebstemperatur; Reaktanz wird vernachlässigt. Ihre
|
||||||
|
Planungsgrenzen folgen nicht allein aus DIN VDE 0298-4. Auch die Koordination
|
||||||
|
mit Leitungsschutzschaltern und gG-Sicherungen gehört zur
|
||||||
|
Überstromschutzbemessung und ist getrennt von der Strombelastbarkeit zu
|
||||||
|
beurteilen. Der Dialog bezeichnet diese Ergebnisse deshalb nicht als vollständig
|
||||||
|
normative Leitungsbemessung.
|
||||||
|
|
||||||
## Rechenweg
|
## Rechenweg
|
||||||
|
|
||||||
1. Betriebsstrom I_B aus Leistung, Spannung, cos φ und Phasenzahl.
|
1. Betriebsstrom `I_B` aus Leistung, Spannung, cos φ und Phasenzahl.
|
||||||
2. Erforderliche Belastbarkeit: ohne Schutzorgan I_B; mit Schutzorgan
|
2. Erforderliche Belastbarkeit aus `I_B` und gegebenenfalls dem vorhandenen
|
||||||
max(I_B, I_n, I₂/1,45) nach IEC 60364-4-43 (I_n ≤ I_z und I₂ ≤ 1,45 · I_z).
|
Schutzorgan.
|
||||||
I₂/I_n: Leitungsschutzschalter 1,45; Sicherung gG 2,1 (I_n ≤ 4 A),
|
3. Tabellenwert `I_z` multipliziert mit Temperatur-, Häufungs- und gegebenenfalls
|
||||||
1,9 (4 A < I_n < 16 A), 1,6 (I_n ≥ 16 A).
|
Oberschwingungsfaktor.
|
||||||
3. Tabellenwert I_z je Querschnitt × Temperaturfaktor × Häufungsfaktor
|
4. Vereinfachter Spannungsfall für jeden verfügbaren Querschnitt.
|
||||||
(× 0,86 bei 15–33 % 3. Harmonischer im Drehstromkreis).
|
5. Empfehlung als größerer Querschnitt aus Belastbarkeit und Spannungsfall.
|
||||||
4. Spannungsfall ΔU = k · L · I_B · cos φ / (κ · A · U) mit k = 2 (1~) bzw.
|
6. Bei einphasigen Stromkreisen Anhebung auf den vereinbarten praktischen
|
||||||
√3 (3~), κ = 48 (Cu) bzw. 30 (Al) m/(Ω·mm²) bei Betriebstemperatur;
|
Mindestquerschnitt von 2,5 mm².
|
||||||
Reaktanz wird vernachlässigt.
|
|
||||||
5. Empfehlung = größerer Querschnitt aus Belastbarkeit und Spannungsfall;
|
|
||||||
1-phasige Stromkreise werden auf den Praxis-Mindestquerschnitt 2,5 mm²
|
|
||||||
angehoben (Planungskonvention aus `docs/spec/06-…`, keine Rechenanforderung).
|
|
||||||
6. Zusätzlich: maximale Länge für den zulässigen Spannungsfall.
|
|
||||||
|
|
||||||
Temperaturen und Häufungen **zwischen** Tabellenwerten werden auf den nächsten
|
Temperaturen und Häufungen zwischen Tabellenwerten werden zum nächsten
|
||||||
ungünstigeren Tabellenwert gerundet (höhere Temperatur, mehr Stromkreise).
|
ungünstigeren Tabellenwert gerundet. Außerhalb des belegten Tabellenbereichs
|
||||||
Werte **außerhalb** der Tabellen liefern kein Ergebnis und eine Meldung – es
|
wird keine Empfehlung ausgegeben. Ein abweichender Querschnitt kann weiterhin
|
||||||
wird nie stillschweigend mit Faktor 1 gerechnet.
|
manuell eingetragen und bewusst übernommen werden.
|
||||||
|
|
||||||
## Datenbasis und Prüfnachweis
|
|
||||||
|
|
||||||
Grundlage ist **IEC 60364-5-52:2009, Anhang B**. Alle Werte wurden am
|
|
||||||
26.09.2026 zeilenweise mit öffentlich zugänglichen Wiedergaben abgeglichen:
|
|
||||||
TiSoft ElectricalDesign-Hilfe zu IEC 60364-5-52
|
|
||||||
(`ti-soft.com/en/support/help/electricaldesign/standards/iec-60364-5-52/…`)
|
|
||||||
und ECalPro (`ecalpro.com/standards/iec-60364/…`). Wo die Quellen voneinander
|
|
||||||
abweichen, ist der kleinere, sichere Wert eingetragen.
|
|
||||||
|
|
||||||
| Tabelle | Inhalt | Abgleich | Abweichungen |
|
|
||||||
|---|---|---|---|
|
|
||||||
| B.52.2 | PVC, 2 belastete Adern, Cu/Al, A1–D2 | TiSoft; Cu A1–C zusätzlich ECalPro | Cu A1 240 mm²: 321 / 320 → 320 |
|
|
||||||
| B.52.3 | VPE, 2 belastete Adern, Cu/Al, A1–D2 | TiSoft | – |
|
|
||||||
| B.52.4 | PVC, 3 belastete Adern, Cu/Al, A1–D2 | TiSoft | – |
|
|
||||||
| B.52.5 | VPE, 3 belastete Adern, Cu/Al, A1–D2 | TiSoft | – |
|
|
||||||
| B.52.10 / .11 | PVC, Verlegeart E, mehradrig, Cu / Al | TiSoft; Cu 2 Adern zusätzlich ECalPro | Cu 3 Adern 70 / 120 mm²: 198 / 278 bzw. 196 / 276 → 196 / 276 |
|
|
||||||
| B.52.12 / .13 | VPE, Verlegeart E, mehradrig, Cu / Al | TiSoft | – |
|
|
||||||
| B.52.14 | Temperatur Luft, PVC / VPE | TiSoft, ECalPro | – |
|
|
||||||
| B.52.15 | Temperatur Erde, PVC / VPE | TiSoft | – |
|
|
||||||
| B.52.17 | Häufung Luft, Zeile 1 (gebündelt) | TiSoft, ECalPro | – |
|
|
||||||
| B.52.18 | Häufung Erde direkt, Kabel berührend | TiSoft | – |
|
|
||||||
| B.52.19 A | Häufung mehradrige Kabel in berührenden Rohren im Erdreich | TiSoft | – |
|
|
||||||
|
|
||||||
Anwendung der Tabellen:
|
|
||||||
|
|
||||||
- Verlegearten A1, A2, B1, B2, C, E in Luft (Bezug 30 °C), D1 und D2 im
|
|
||||||
Erdreich (Bezug 20 °C, Bodenwärmewiderstand 2,5 K·m/W). Nach Tabelle B.52.1
|
|
||||||
ist **D1 = Leitung im Rohr/Kabelschutzrohr im Erdreich** und **D2 = Kabel
|
|
||||||
direkt im Erdreich**.
|
|
||||||
- Häufung in Luft immer nach B.52.17 Zeile 1, auch für Verlegeart E; das ist
|
|
||||||
die ungünstigste Anordnung (einlagig auf Pritschen wären höhere Faktoren
|
|
||||||
zulässig). D1 nach B.52.19 A, D2 nach B.52.18 jeweils „berührend“.
|
|
||||||
- Aluminium nur mit den echten Aluminiumwerten (ab 2,5 mm², D2 ab 16 mm²);
|
|
||||||
Querschnitte ohne Tabellenwert werden nie empfohlen.
|
|
||||||
- Die Verlegearten F und G (Einzeladern mit Abstand) sind nicht enthalten.
|
|
||||||
|
|
||||||
**Vor produktivem Einsatz:** Die nationalen Tabellen der DIN VDE 0298-4
|
|
||||||
können in einzelnen Werten abweichen. Der Planer muss die Tabellen gegen den
|
|
||||||
Normtext prüfen. Die Prüfung ist in `tests/cable-sizing-calculation.test.ts`
|
|
||||||
über Stichwerte und eine Monotonieprüfung jeder Tabellenzeile abgesichert.
|
|
||||||
|
|
||||||
## Nicht enthalten
|
## Nicht enthalten
|
||||||
|
|
||||||
- Kurzschlussfestigkeit, Abschaltbedingungen (Schleifenimpedanz) und
|
- direkte Erdverlegung
|
||||||
Selektivität
|
- detaillierte Anordnung mehrerer Kabel bei Verlegeart E
|
||||||
- Bodenwärmewiderstand ≠ 2,5 K·m/W, Häufung mit Abstand, Verlegearten F/G
|
- Neutralleiterbemessung bei mehr als 33 % dritter Harmonischer
|
||||||
- Bemessung des Neutralleiters bei > 33 % 3. Harmonischer (nur Hinweis)
|
- Kurzschlussfestigkeit, Schleifenimpedanz, Abschaltbedingungen und Selektivität
|
||||||
- automatische Bemessung oder Prüfung aller Stromkreise
|
- abweichender Bodenwärmewiderstand sowie Verlegearten F und G
|
||||||
|
- automatische Berechnung oder Änderung mehrerer Stromkreise
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
`POST /api/cable-sizing/calculate` – zustandslos, liest und schreibt keine
|
`POST /api/cable-sizing/calculate` berechnet zustandslos. Die Verlegeart ist
|
||||||
Projektdaten.
|
`A1 | A2 | B1 | B2 | C | D | E`; `lengthM` darf `0` sein. Das Ergebnis enthält
|
||||||
|
`supported: false` und einen der Gründe `temperature`, `grouping` oder
|
||||||
|
`harmonics`, wenn keine belastbare Empfehlung möglich ist.
|
||||||
|
|
||||||
```jsonc
|
`GET /api/cable-sizing/laying-methods` und
|
||||||
{
|
`GET /api/cable-sizing/insulation-materials` liefern die Auswahllisten.
|
||||||
"phase": 1, // 1 | 3
|
|
||||||
"mode": "power", // "power" | "current"
|
|
||||||
"powerKw": 4.2, // bei mode "power"
|
|
||||||
"currentA": 18.3, // bei mode "current"
|
|
||||||
"cosPhi": 0.95, // 0,1 … 1
|
|
||||||
"voltage": 230,
|
|
||||||
"lengthM": 23.5,
|
|
||||||
"layingMethod": "C", // A1 | A2 | B1 | B2 | C | D1 | D2 | E
|
|
||||||
"conductorMaterial": "copper", // copper | aluminum
|
|
||||||
"insulation": "pvc", // pvc | xlpe
|
|
||||||
"ambientTemperatureC": 30, // Luft; bei D1/D2 Bodentemperatur
|
|
||||||
"groupingCircuits": 1, // 1 … 100, Tabellen bis 20
|
|
||||||
"maxVoltageDropPercent": 3,
|
|
||||||
"harmonicNeutralLoad": "none", // none | 15to33Percent | over33Percent
|
|
||||||
"existingProtection": { "ratedCurrentA": 16, "kind": "breaker" }, // optional; kind: breaker | fuse
|
|
||||||
"circuitCategory": "single_phase" // optional
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Antwort: `{ "result": CableSizingResult, "alerts": CableSizingAlert[] }`.
|
|
||||||
`result.supported = false` mit `unsupportedReason` (`temperature` oder
|
|
||||||
`grouping`), wenn die Eingaben außerhalb der Tabellen liegen.
|
|
||||||
`GET /api/cable-sizing/laying-methods` und `GET /api/cable-sizing/insulation-materials`
|
|
||||||
liefern die Auswahllisten.
|
|
||||||
|
|
|
||||||
|
|
@ -433,14 +433,15 @@ read nor write project data; applying a result uses `circuit.update` through
|
||||||
|
|
||||||
- `POST /cable-sizing/calculate`
|
- `POST /cable-sizing/calculate`
|
||||||
- request: phase, mode (`power` | `current`), powerKw or currentA, cosPhi,
|
- request: phase, mode (`power` | `current`), powerKw or currentA, cosPhi,
|
||||||
voltage, lengthM, layingMethod (`A1` | `A2` | `B1` | `B2` | `C` | `D1` |
|
voltage, lengthM, layingMethod (`A1` | `A2` | `B1` | `B2` | `C` | `D` |
|
||||||
`D2` | `E`), conductorMaterial, insulation (`pvc` | `xlpe`),
|
`E`), conductorMaterial, insulation (`pvc` | `xlpe`),
|
||||||
ambientTemperatureC, groupingCircuits, maxVoltageDropPercent,
|
ambientTemperatureC, groupingCircuits, maxVoltageDropPercent,
|
||||||
harmonicNeutralLoad, optional `existingProtection`
|
harmonicNeutralLoad, optional `existingProtection`
|
||||||
(`{ ratedCurrentA, kind: "breaker" | "fuse" }`) and circuitCategory
|
(`{ ratedCurrentA, kind: "breaker" | "fuse" }`) and circuitCategory
|
||||||
- returns `{ "result": { ... }, "alerts": [ ... ] }`; `result.supported`
|
- returns `{ "result": { ... }, "alerts": [ ... ] }`; `result.supported`
|
||||||
is `false` with `unsupportedReason` when temperature or grouping lie
|
is `false` with `unsupportedReason` when temperature or grouping lie
|
||||||
outside the tables
|
outside the tables or the neutral current needed above 33 % third
|
||||||
|
harmonic is unavailable
|
||||||
- unknown fields are rejected (`400`)
|
- unknown fields are rejected (`400`)
|
||||||
- `GET /cable-sizing/laying-methods`
|
- `GET /cable-sizing/laying-methods`
|
||||||
- `GET /cable-sizing/insulation-materials`
|
- `GET /cable-sizing/insulation-materials`
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,11 @@
|
||||||
- The global device library supports basic CRUD and copy operations, but has no
|
- The global device library supports basic CRUD and copy operations, but has no
|
||||||
versioning, permissions or controlled synchronization model.
|
versioning, permissions or controlled synchronization model.
|
||||||
- There is no automatic sizing of all circuits. The optional cable sizing
|
- There is no automatic sizing of all circuits. The optional cable sizing
|
||||||
module suggests a cross-section for one circuit on demand (IEC 60364-5-52
|
module suggests a cross-section for one circuit on demand using
|
||||||
Annex B tables; no short-circuit, disconnection-time or selectivity checks,
|
DIN VDE 0298-4:2023-06 with Berichtigung 1:2023-10. It excludes direct
|
||||||
no methods F/G, soil resistivity fixed at 2.5 K·m/W) and does not validate
|
burial, grouped method E and neutral-current sizing above 33 % third
|
||||||
manually entered cable values. National tables (DIN VDE 0298-4) must be
|
harmonic, and it does not check short-circuit withstand, disconnection time
|
||||||
checked by the planner; see `docs/cable-sizing-module.md`.
|
or selectivity. See `docs/cable-sizing-module.md`.
|
||||||
- Sorting is view-only until users explicitly apply sorted order.
|
- Sorting is view-only until users explicitly apply sorted order.
|
||||||
- Complete-circuit drag supports one circuit at a time between groups of the
|
- Complete-circuit drag supports one circuit at a time between groups of the
|
||||||
same category. Cross-category moves and multi-circuit moves across group
|
same category. Cross-category moves and multi-circuit moves across group
|
||||||
|
|
|
||||||
|
|
@ -507,8 +507,10 @@ Kopieren in ein Projekt erzeugt ein eigenständiges Projektgerät.
|
||||||
## Leitungsberechnung
|
## Leitungsberechnung
|
||||||
|
|
||||||
Das optionale Modul `src/cable-sizing` berechnet auf Anforderung eine
|
Das optionale Modul `src/cable-sizing` berechnet auf Anforderung eine
|
||||||
Querschnittsempfehlung für einen Stromkreis (IEC 60364-5-52 Anhang B:
|
Querschnittsempfehlung für einen Stromkreis. Strombelastbarkeit, Temperatur
|
||||||
Belastbarkeit, Temperatur, Häufung, Spannungsfall, Schutzorgan). Die
|
und Häufung beruhen auf DIN VDE 0298-4:2023-06 einschließlich
|
||||||
|
Berichtigung 1:2023-10; Spannungsfall und Schutzorgan werden ergänzend und mit
|
||||||
|
den in der Moduldokumentation beschriebenen Grenzen geprüft. Die
|
||||||
Domänenlogik ist rein, `POST /api/cable-sizing/calculate` ist zustandslos und
|
Domänenlogik ist rein, `POST /api/cable-sizing/calculate` ist zustandslos und
|
||||||
es gibt keine eigene Tabelle. Der Editor öffnet den Dialog über den Button
|
es gibt keine eigene Tabelle. Der Editor öffnet den Dialog über den Button
|
||||||
„Leitungsberechnung“ in der Aktionsspalte; „Übernehmen“ schreibt Kabeltyp,
|
„Leitungsberechnung“ in der Aktionsspalte; „Übernehmen“ schreibt Kabeltyp,
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,9 @@ requirements and intended sequencing, not proof of implementation.
|
||||||
- [x] Phase F: documentation and full GUI verification.
|
- [x] Phase F: documentation and full GUI verification.
|
||||||
- [ ] Keep full electrical sizing and cable-dimensioning rules separate until
|
- [ ] Keep full electrical sizing and cable-dimensioning rules separate until
|
||||||
the planner supplies the calculation requirements. The optional per-circuit
|
the planner supplies the calculation requirements. The optional per-circuit
|
||||||
cable sizing module (`docs/cable-sizing-module.md`) exists; its tables must
|
cable sizing module (`docs/cable-sizing-module.md`) exists; its supported
|
||||||
be confirmed by the planner against DIN VDE 0298-4.
|
tables were confirmed against DIN VDE 0298-4:2023-06 with
|
||||||
|
Berichtigung 1:2023-10. Unsupported arrangements stay explicitly blocked.
|
||||||
- Detailed specification:
|
- Detailed specification:
|
||||||
`docs/spec/09-distribution-board-components-and-protection-groups.md`
|
`docs/spec/09-distribution-board-components-and-protection-groups.md`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,14 @@
|
||||||
// the module is an optional calculator attached to the circuit list and never
|
// the module is an optional calculator attached to the circuit list and never
|
||||||
// writes project data itself (see docs/cable-sizing-module.md).
|
// writes project data itself (see docs/cable-sizing-module.md).
|
||||||
//
|
//
|
||||||
// Reference data: IEC 60364-5-52:2009, Annex B (tables B.52.2 to B.52.5,
|
// Reference data: DIN VDE 0298-4 (VDE 0298-4):2023-06 together with
|
||||||
// B.52.10 to B.52.19). Every value was cross-checked against publicly
|
// Berichtigung 1:2023-10. The table-by-table scope and the separate sources
|
||||||
// available reproductions of these tables; where sources disagreed the lower,
|
// required for voltage drop and protection coordination are documented in
|
||||||
// i.e. safer, value is used. The table-by-table verification record is in
|
// docs/cable-sizing-module.md.
|
||||||
// docs/cable-sizing-module.md. National tables (DIN VDE 0298-4) may differ in
|
|
||||||
// individual values and must be checked by the planner against the norm text.
|
|
||||||
|
|
||||||
// -- Reference installation methods (IEC 60364-5-52, Table B.52.1) ----------
|
// -- Reference installation methods (DIN VDE 0298-4, Table 2) ---------------
|
||||||
|
|
||||||
export const LAYING_METHODS = ["A1", "A2", "B1", "B2", "C", "D1", "D2", "E"] as const;
|
export const LAYING_METHODS = ["A1", "A2", "B1", "B2", "C", "D", "E"] as const;
|
||||||
export type LayingMethod = (typeof LAYING_METHODS)[number];
|
export type LayingMethod = (typeof LAYING_METHODS)[number];
|
||||||
|
|
||||||
export const LAYING_METHOD_GROUP: Record<LayingMethod, "air" | "ground"> = {
|
export const LAYING_METHOD_GROUP: Record<LayingMethod, "air" | "ground"> = {
|
||||||
|
|
@ -21,8 +19,7 @@ export const LAYING_METHOD_GROUP: Record<LayingMethod, "air" | "ground"> = {
|
||||||
B2: "air",
|
B2: "air",
|
||||||
C: "air",
|
C: "air",
|
||||||
E: "air",
|
E: "air",
|
||||||
D1: "ground",
|
D: "ground",
|
||||||
D2: "ground",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LAYING_METHOD_LABELS: Record<LayingMethod, string> = {
|
export const LAYING_METHOD_LABELS: Record<LayingMethod, string> = {
|
||||||
|
|
@ -31,8 +28,7 @@ export const LAYING_METHOD_LABELS: Record<LayingMethod, string> = {
|
||||||
B1: "B1 – Einzeladern im Rohr auf oder in der Wand",
|
B1: "B1 – Einzeladern im Rohr auf oder in der Wand",
|
||||||
B2: "B2 – Mehradrige Leitung im Rohr auf oder in der Wand",
|
B2: "B2 – Mehradrige Leitung im Rohr auf oder in der Wand",
|
||||||
C: "C – Mehradrige Leitung direkt auf oder in der Wand",
|
C: "C – Mehradrige Leitung direkt auf oder in der Wand",
|
||||||
D1: "D1 – Leitung im Rohr oder Kabelschutzrohr im Erdreich",
|
D: "D – Mehradriges Kabel im Rohr oder Kanal im Erdreich",
|
||||||
D2: "D2 – Kabel direkt im Erdreich",
|
|
||||||
E: "E – Mehradrige Leitung frei in Luft",
|
E: "E – Mehradrige Leitung frei in Luft",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -49,7 +45,7 @@ export const INSULATION_MATERIAL_LABELS: Record<InsulationMaterial, string> = {
|
||||||
export const CONDUCTOR_MATERIALS = ["copper", "aluminum"] as const;
|
export const CONDUCTOR_MATERIALS = ["copper", "aluminum"] as const;
|
||||||
export type ConductorMaterial = (typeof CONDUCTOR_MATERIALS)[number];
|
export type ConductorMaterial = (typeof CONDUCTOR_MATERIALS)[number];
|
||||||
|
|
||||||
// -- Harmonic neutral loading (IEC 60364-5-52, Annex E, three-phase only) ---
|
// -- Harmonic neutral loading (DIN VDE 0298-4, Annex B, three-phase only) ---
|
||||||
|
|
||||||
export const HARMONIC_NEUTRAL_LOAD_OPTIONS = [
|
export const HARMONIC_NEUTRAL_LOAD_OPTIONS = [
|
||||||
"none",
|
"none",
|
||||||
|
|
@ -61,7 +57,7 @@ export type HarmonicNeutralLoad = (typeof HARMONIC_NEUTRAL_LOAD_OPTIONS)[number]
|
||||||
export const HARMONIC_NEUTRAL_LOAD_LABELS: Record<HarmonicNeutralLoad, string> = {
|
export const HARMONIC_NEUTRAL_LOAD_LABELS: Record<HarmonicNeutralLoad, string> = {
|
||||||
none: "Keine nennenswerte 3. Harmonische (< 15 %) – Standardfall",
|
none: "Keine nennenswerte 3. Harmonische (< 15 %) – Standardfall",
|
||||||
"15to33Percent": "3. Harmonische 15–33 % – Reduktionsfaktor 0,86",
|
"15to33Percent": "3. Harmonische 15–33 % – Reduktionsfaktor 0,86",
|
||||||
over33Percent: "3. Harmonische > 33 % – Neutralleiter wie Außenleiter dimensionieren",
|
over33Percent: "3. Harmonische > 33 % – ohne Neutralleiterstrom keine Empfehlung",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const HARMONIC_REDUCTION_FACTOR = 0.86;
|
export const HARMONIC_REDUCTION_FACTOR = 0.86;
|
||||||
|
|
@ -85,14 +81,13 @@ export const CURRENT_CAPACITY_A: Record<
|
||||||
> = {
|
> = {
|
||||||
pvc: {
|
pvc: {
|
||||||
copper: {
|
copper: {
|
||||||
// B.52.2 / B.52.4; E: B.52.10 multi-core. A1 2L 240 mm²: sources 320/321 → 320.
|
// DIN VDE 0298-4, tables 3 and 4.
|
||||||
// E 3L 70/120 mm²: sources 196/198 and 276/278 → 196 and 276.
|
|
||||||
A1: {
|
A1: {
|
||||||
2: [14.5, 19.5, 26, 34, 46, 61, 80, 99, 119, 151, 182, 210, 240, 273, 320],
|
2: [15.5, 19.5, 26, 34, 46, 61, 80, 99, 119, 151, 182, 210, 240, 273, 321],
|
||||||
3: [13.5, 18, 24, 31, 42, 56, 73, 89, 108, 136, 164, 188, 216, 245, 286],
|
3: [13.5, 18, 24, 31, 42, 56, 73, 89, 108, 136, 164, 188, 216, 245, 286],
|
||||||
},
|
},
|
||||||
A2: {
|
A2: {
|
||||||
2: [14, 18.5, 25, 32, 43, 57, 75, 92, 110, 139, 167, 192, 219, 248, 291],
|
2: [15.5, 18.5, 25, 32, 43, 57, 75, 92, 110, 139, 167, 192, 219, 248, 291],
|
||||||
3: [13, 17.5, 23, 29, 39, 52, 68, 83, 99, 125, 150, 172, 196, 223, 261],
|
3: [13, 17.5, 23, 29, 39, 52, 68, 83, 99, 125, 150, 172, 196, 223, 261],
|
||||||
},
|
},
|
||||||
B1: {
|
B1: {
|
||||||
|
|
@ -107,22 +102,18 @@ export const CURRENT_CAPACITY_A: Record<
|
||||||
2: [19.5, 27, 36, 46, 63, 85, 112, 138, 168, 213, 258, 299, 344, 392, 461],
|
2: [19.5, 27, 36, 46, 63, 85, 112, 138, 168, 213, 258, 299, 344, 392, 461],
|
||||||
3: [17.5, 24, 32, 41, 57, 76, 96, 119, 144, 184, 223, 259, 299, 341, 403],
|
3: [17.5, 24, 32, 41, 57, 76, 96, 119, 144, 184, 223, 259, 299, 341, 403],
|
||||||
},
|
},
|
||||||
D1: {
|
D: {
|
||||||
2: [22, 29, 37, 46, 60, 78, 99, 119, 140, 173, 204, 231, 261, 292, 336],
|
2: [22, 29, 37, 46, 60, 78, 99, 119, 140, 173, 204, 231, 261, 292, 336],
|
||||||
3: [18, 24, 30, 38, 50, 64, 82, 98, 116, 143, 169, 192, 217, 243, 280],
|
3: [18, 24, 30, 38, 50, 64, 82, 98, 116, 143, 169, 192, 217, 243, 280],
|
||||||
},
|
},
|
||||||
D2: {
|
|
||||||
2: [22, 28, 38, 48, 64, 83, 110, 132, 156, 192, 230, 261, 293, 331, 382],
|
|
||||||
3: [19, 24, 33, 41, 54, 70, 92, 110, 130, 162, 193, 220, 246, 278, 320],
|
|
||||||
},
|
|
||||||
E: {
|
E: {
|
||||||
2: [22, 30, 40, 51, 70, 94, 119, 148, 180, 232, 282, 328, 379, 434, 514],
|
2: [22, 30, 40, 51, 70, 94, 119, 148, 180, 232, 282, 328, 379, 434, 514],
|
||||||
3: [18.5, 25, 34, 43, 60, 80, 101, 126, 153, 196, 238, 276, 319, 364, 430],
|
3: [18.5, 25, 34, 43, 60, 80, 101, 126, 153, 196, 238, 276, 319, 364, 430],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
aluminum: {
|
aluminum: {
|
||||||
// B.52.2 / B.52.4 aluminium; E: B.52.11. No values below 2.5 mm²
|
// DIN VDE 0298-4 aluminium values; the normalization below removes all
|
||||||
// (D2 below 16 mm²).
|
// entries below the first tabulated aluminium size of 25 mm².
|
||||||
A1: {
|
A1: {
|
||||||
2: [n, 15, 20, 26, 36, 48, 63, 77, 93, 118, 142, 164, 189, 215, 252],
|
2: [n, 15, 20, 26, 36, 48, 63, 77, 93, 118, 142, 164, 189, 215, 252],
|
||||||
3: [n, 14, 18.5, 24, 32, 43, 57, 70, 84, 107, 129, 149, 170, 194, 227],
|
3: [n, 14, 18.5, 24, 32, 43, 57, 70, 84, 107, 129, 149, 170, 194, 227],
|
||||||
|
|
@ -143,14 +134,10 @@ export const CURRENT_CAPACITY_A: Record<
|
||||||
2: [n, 21, 28, 36, 49, 66, 83, 103, 125, 160, 195, 226, 261, 298, 352],
|
2: [n, 21, 28, 36, 49, 66, 83, 103, 125, 160, 195, 226, 261, 298, 352],
|
||||||
3: [n, 18.5, 25, 32, 44, 59, 73, 90, 110, 140, 170, 197, 227, 259, 305],
|
3: [n, 18.5, 25, 32, 44, 59, 73, 90, 110, 140, 170, 197, 227, 259, 305],
|
||||||
},
|
},
|
||||||
D1: {
|
D: {
|
||||||
2: [n, 22, 29, 36, 47, 61, 77, 93, 109, 135, 159, 180, 204, 228, 262],
|
2: [n, 22, 29, 36, 47, 61, 77, 93, 109, 135, 159, 180, 204, 228, 262],
|
||||||
3: [n, 18.5, 24, 30, 39, 50, 64, 77, 91, 112, 132, 150, 169, 190, 218],
|
3: [n, 18.5, 24, 30, 39, 50, 64, 77, 91, 112, 132, 150, 169, 190, 218],
|
||||||
},
|
},
|
||||||
D2: {
|
|
||||||
2: [n, n, n, n, n, 63, 82, 98, 117, 145, 173, 200, 224, 255, 298],
|
|
||||||
3: [n, n, n, n, n, 53, 69, 83, 99, 122, 148, 169, 189, 214, 250],
|
|
||||||
},
|
|
||||||
E: {
|
E: {
|
||||||
2: [n, 23, 31, 39, 54, 73, 89, 111, 135, 173, 210, 244, 282, 322, 380],
|
2: [n, 23, 31, 39, 54, 73, 89, 111, 135, 173, 210, 244, 282, 322, 380],
|
||||||
3: [n, 19.5, 26, 33, 46, 61, 78, 96, 117, 150, 183, 212, 245, 280, 330],
|
3: [n, 19.5, 26, 33, 46, 61, 78, 96, 117, 150, 183, 212, 245, 280, 330],
|
||||||
|
|
@ -180,14 +167,10 @@ export const CURRENT_CAPACITY_A: Record<
|
||||||
2: [24, 33, 45, 58, 80, 107, 138, 171, 209, 269, 328, 382, 441, 506, 599],
|
2: [24, 33, 45, 58, 80, 107, 138, 171, 209, 269, 328, 382, 441, 506, 599],
|
||||||
3: [22, 30, 40, 52, 71, 96, 119, 147, 179, 229, 278, 322, 371, 424, 500],
|
3: [22, 30, 40, 52, 71, 96, 119, 147, 179, 229, 278, 322, 371, 424, 500],
|
||||||
},
|
},
|
||||||
D1: {
|
D: {
|
||||||
2: [25, 33, 43, 53, 71, 91, 116, 139, 164, 203, 239, 271, 306, 343, 395],
|
2: [25, 33, 43, 53, 71, 91, 116, 139, 164, 203, 239, 271, 306, 343, 395],
|
||||||
3: [21, 28, 36, 44, 58, 75, 96, 115, 135, 167, 197, 223, 251, 281, 324],
|
3: [21, 28, 36, 44, 58, 75, 96, 115, 135, 167, 197, 223, 251, 281, 324],
|
||||||
},
|
},
|
||||||
D2: {
|
|
||||||
2: [27, 35, 46, 58, 77, 100, 129, 155, 183, 225, 270, 306, 343, 387, 448],
|
|
||||||
3: [23, 30, 39, 49, 65, 84, 107, 129, 153, 188, 226, 257, 287, 324, 375],
|
|
||||||
},
|
|
||||||
E: {
|
E: {
|
||||||
2: [26, 36, 49, 63, 86, 115, 149, 185, 225, 289, 352, 410, 473, 542, 641],
|
2: [26, 36, 49, 63, 86, 115, 149, 185, 225, 289, 352, 410, 473, 542, 641],
|
||||||
3: [23, 32, 42, 54, 75, 100, 127, 158, 192, 246, 298, 346, 399, 456, 538],
|
3: [23, 32, 42, 54, 75, 100, 127, 158, 192, 246, 298, 346, 399, 456, 538],
|
||||||
|
|
@ -215,14 +198,10 @@ export const CURRENT_CAPACITY_A: Record<
|
||||||
2: [n, 26, 35, 45, 62, 84, 101, 126, 154, 198, 241, 280, 324, 371, 439],
|
2: [n, 26, 35, 45, 62, 84, 101, 126, 154, 198, 241, 280, 324, 371, 439],
|
||||||
3: [n, 24, 32, 41, 57, 76, 90, 112, 136, 174, 211, 245, 283, 323, 382],
|
3: [n, 24, 32, 41, 57, 76, 90, 112, 136, 174, 211, 245, 283, 323, 382],
|
||||||
},
|
},
|
||||||
D1: {
|
D: {
|
||||||
2: [n, 26, 33, 42, 55, 71, 90, 108, 128, 158, 186, 211, 238, 267, 307],
|
2: [n, 26, 33, 42, 55, 71, 90, 108, 128, 158, 186, 211, 238, 267, 307],
|
||||||
3: [n, 22, 28, 35, 46, 59, 75, 90, 106, 130, 154, 174, 197, 220, 253],
|
3: [n, 22, 28, 35, 46, 59, 75, 90, 106, 130, 154, 174, 197, 220, 253],
|
||||||
},
|
},
|
||||||
D2: {
|
|
||||||
2: [n, n, n, n, n, 76, 98, 117, 139, 170, 204, 233, 261, 296, 343],
|
|
||||||
3: [n, n, n, n, n, 64, 82, 98, 117, 144, 172, 197, 220, 250, 290],
|
|
||||||
},
|
|
||||||
E: {
|
E: {
|
||||||
2: [n, 28, 38, 49, 67, 91, 108, 135, 164, 211, 257, 300, 346, 397, 470],
|
2: [n, 28, 38, 49, 67, 91, 108, 135, 164, 211, 257, 300, 346, 397, 470],
|
||||||
3: [n, 24, 32, 42, 58, 77, 97, 120, 146, 187, 227, 263, 304, 347, 409],
|
3: [n, 24, 32, 42, 58, 77, 97, 120, 146, 187, 227, 263, 304, 347, 409],
|
||||||
|
|
@ -231,9 +210,25 @@ export const CURRENT_CAPACITY_A: Record<
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DIN VDE 0298-4 only supplies aluminium current-carrying capacities from
|
||||||
|
// 25 mm² onward. Smaller values from the former IEC data set must therefore
|
||||||
|
// never participate in a recommendation.
|
||||||
|
for (const insulation of INSULATION_MATERIALS) {
|
||||||
|
for (const method of LAYING_METHODS) {
|
||||||
|
for (const coreCount of [2, 3] as const) {
|
||||||
|
const row = CURRENT_CAPACITY_A[insulation].aluminum[method][coreCount] as (number | null)[];
|
||||||
|
CROSS_SECTIONS_MM2.forEach((crossSection, index) => {
|
||||||
|
if (crossSection < 25) {
|
||||||
|
row[index] = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -- Correction factors ------------------------------------------------------
|
// -- Correction factors ------------------------------------------------------
|
||||||
|
|
||||||
/** B.52.14 (air, reference 30 °C) and B.52.15 (ground, reference 20 °C). */
|
/** DIN VDE 0298-4 tables 17 (air) and 20 (ground). */
|
||||||
export const TEMPERATURE_FACTORS: Record<
|
export const TEMPERATURE_FACTORS: Record<
|
||||||
"air" | "ground",
|
"air" | "ground",
|
||||||
Record<InsulationMaterial, Record<number, number>>
|
Record<InsulationMaterial, Record<number, number>>
|
||||||
|
|
@ -260,26 +255,32 @@ export const REFERENCE_TEMPERATURE_C: Record<"air" | "ground", number> = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grouping reduction factors for touching circuits/cables:
|
* Grouping reduction factors according to the corrected references in
|
||||||
* air (A1–C, E): B.52.17 item 1 "bunched in air, on a surface, embedded or
|
* DIN VDE 0298-4 Berichtigung 1:2023-10:
|
||||||
* enclosed" – the most restrictive arrangement, also used for E (single
|
* A1–C use table 22, row 1 (bundled/touching), D uses table 26 for touching
|
||||||
* layers on trays would allow higher factors);
|
* conduits/ducts in earth. Method E needs details about support, spacing and
|
||||||
* D1: B.52.19 A (multi-core cables in touching ducts);
|
* number of trays from table 23, which the current input model does not carry;
|
||||||
* D2: B.52.18 (cables direct in ground, touching).
|
* it is therefore supported only for one circuit.
|
||||||
*/
|
*/
|
||||||
export const GROUPING_FACTORS: Record<"air" | "D1" | "D2", Record<number, number>> = {
|
export const GROUPING_FACTORS: Record<"A1_TO_C" | "D" | "E", Record<number, number>> = {
|
||||||
air: { 1: 1.0, 2: 0.8, 3: 0.7, 4: 0.65, 5: 0.6, 6: 0.57, 7: 0.54, 8: 0.52, 9: 0.5, 12: 0.45, 16: 0.41, 20: 0.38 },
|
A1_TO_C: {
|
||||||
D1: {
|
1: 1.0, 2: 0.8, 3: 0.7, 4: 0.65, 5: 0.6, 6: 0.57, 7: 0.54, 8: 0.52,
|
||||||
1: 1.0, 2: 0.85, 3: 0.75, 4: 0.7, 5: 0.65, 6: 0.6, 7: 0.57, 8: 0.54, 9: 0.52, 10: 0.49,
|
9: 0.5, 10: 0.48, 12: 0.45, 14: 0.43, 16: 0.41, 18: 0.39, 20: 0.38,
|
||||||
11: 0.47, 12: 0.45, 13: 0.44, 14: 0.42, 15: 0.41, 16: 0.39, 17: 0.38, 18: 0.37, 19: 0.35, 20: 0.34,
|
|
||||||
},
|
},
|
||||||
D2: { 1: 1.0, 2: 0.75, 3: 0.65, 4: 0.6, 5: 0.55, 6: 0.5, 7: 0.45, 8: 0.43, 9: 0.41, 12: 0.36, 16: 0.32, 20: 0.29 },
|
D: { 1: 1.0, 2: 0.85, 3: 0.75, 4: 0.7, 5: 0.65, 6: 0.6 },
|
||||||
|
E: { 1: 1.0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MAX_GROUPING_CIRCUITS = 20;
|
|
||||||
|
|
||||||
function groupingTableFor(method: LayingMethod) {
|
function groupingTableFor(method: LayingMethod) {
|
||||||
return method === "D1" ? GROUPING_FACTORS.D1 : method === "D2" ? GROUPING_FACTORS.D2 : GROUPING_FACTORS.air;
|
return method === "D"
|
||||||
|
? GROUPING_FACTORS.D
|
||||||
|
: method === "E"
|
||||||
|
? GROUPING_FACTORS.E
|
||||||
|
: GROUPING_FACTORS.A1_TO_C;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function maxGroupingCircuits(method: LayingMethod): number {
|
||||||
|
return Math.max(...Object.keys(groupingTableFor(method)).map(Number));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -373,7 +374,7 @@ export interface CableSizingInput {
|
||||||
layingMethod: LayingMethod;
|
layingMethod: LayingMethod;
|
||||||
conductorMaterial: ConductorMaterial;
|
conductorMaterial: ConductorMaterial;
|
||||||
insulation: InsulationMaterial;
|
insulation: InsulationMaterial;
|
||||||
/** Ambient air temperature, or ground temperature for D1/D2. */
|
/** Ambient air temperature, or ground temperature for D. */
|
||||||
ambientTemperatureC: number;
|
ambientTemperatureC: number;
|
||||||
/** Number of grouped circuits or multi-core cables, including this one. */
|
/** Number of grouped circuits or multi-core cables, including this one. */
|
||||||
groupingCircuits: number;
|
groupingCircuits: number;
|
||||||
|
|
@ -405,7 +406,7 @@ export interface ProtectionCoordinationResult {
|
||||||
coordinated: boolean;
|
coordinated: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UnsupportedReason = "temperature" | "grouping";
|
export type UnsupportedReason = "temperature" | "grouping" | "harmonics";
|
||||||
|
|
||||||
export interface CableSizingResult {
|
export interface CableSizingResult {
|
||||||
/** false: the inputs are outside the tabulated range – no numeric result. */
|
/** false: the inputs are outside the tabulated range – no numeric result. */
|
||||||
|
|
@ -454,13 +455,23 @@ export function calculateCableSizing(input: CableSizingInput): CableSizingResult
|
||||||
input.ambientTemperatureC
|
input.ambientTemperatureC
|
||||||
);
|
);
|
||||||
const grouping =
|
const grouping =
|
||||||
input.groupingCircuits <= MAX_GROUPING_CIRCUITS
|
input.groupingCircuits <= maxGroupingCircuits(input.layingMethod)
|
||||||
? lookupConservative(groupingTableFor(input.layingMethod), Math.max(1, input.groupingCircuits))
|
? lookupConservative(groupingTableFor(input.layingMethod), Math.max(1, input.groupingCircuits))
|
||||||
: null;
|
: null;
|
||||||
|
const harmonicsSupported = !(
|
||||||
|
input.phase === 3 && input.harmonicNeutralLoad === "over33Percent"
|
||||||
|
);
|
||||||
|
const unsupportedReason: UnsupportedReason | null = !temperature
|
||||||
|
? "temperature"
|
||||||
|
: !grouping
|
||||||
|
? "grouping"
|
||||||
|
: !harmonicsSupported
|
||||||
|
? "harmonics"
|
||||||
|
: null;
|
||||||
|
|
||||||
const empty: CableSizingResult = {
|
const empty: CableSizingResult = {
|
||||||
supported: false,
|
supported: false,
|
||||||
unsupportedReason: !temperature ? "temperature" : "grouping",
|
unsupportedReason,
|
||||||
operatingCurrentA: ib,
|
operatingCurrentA: ib,
|
||||||
designCurrentA,
|
designCurrentA,
|
||||||
temperatureUsedC: temperature?.key ?? null,
|
temperatureUsedC: temperature?.key ?? null,
|
||||||
|
|
@ -477,7 +488,7 @@ export function calculateCableSizing(input: CableSizingInput): CableSizingResult
|
||||||
rows: [],
|
rows: [],
|
||||||
protectionCoordination: null,
|
protectionCoordination: null,
|
||||||
};
|
};
|
||||||
if (!temperature || !grouping) {
|
if (unsupportedReason || !temperature || !grouping) {
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -586,12 +597,17 @@ export function buildCableSizingAlerts(input: CableSizingInput, result: CableSiz
|
||||||
const group = LAYING_METHOD_GROUP[input.layingMethod];
|
const group = LAYING_METHOD_GROUP[input.layingMethod];
|
||||||
|
|
||||||
if (!result.supported) {
|
if (!result.supported) {
|
||||||
|
const groupingMaximum = maxGroupingCircuits(input.layingMethod);
|
||||||
alerts.push({
|
alerts.push({
|
||||||
kind: "critical",
|
kind: "critical",
|
||||||
text:
|
text:
|
||||||
result.unsupportedReason === "temperature"
|
result.unsupportedReason === "temperature"
|
||||||
? `${group === "air" ? "Umgebungstemperatur" : "Bodentemperatur"} ${input.ambientTemperatureC} °C liegt außerhalb der Tabelle für ${input.insulation === "pvc" ? "PVC" : "VPE"} – keine Berechnung möglich.`
|
? `${group === "air" ? "Umgebungstemperatur" : "Bodentemperatur"} ${input.ambientTemperatureC} °C liegt außerhalb der Tabelle für ${input.insulation === "pvc" ? "PVC" : "VPE"} – keine Berechnung möglich.`
|
||||||
: `Häufung mit ${input.groupingCircuits} Stromkreisen liegt außerhalb der Tabelle (max. ${MAX_GROUPING_CIRCUITS}) – keine Berechnung möglich.`,
|
: result.unsupportedReason === "harmonics"
|
||||||
|
? "Bei mehr als 33 % dritter Harmonischer muss nach dem Neutralleiterstrom bemessen werden. Ohne diesen Wert wird keine Querschnittsempfehlung ausgegeben."
|
||||||
|
: input.layingMethod === "E"
|
||||||
|
? "Für Verlegeart E benötigt die Norm bei Häufung Angaben zu Trägerart, Abstand und Anzahl der Kabelpritschen. Ohne diese Angaben ist nur ein einzelner Stromkreis berechenbar."
|
||||||
|
: `Häufung mit ${input.groupingCircuits} Stromkreisen liegt für Verlegeart ${input.layingMethod} außerhalb der verwendeten Tabelle (max. ${groupingMaximum}) – keine Berechnung möglich.`,
|
||||||
});
|
});
|
||||||
return alerts;
|
return alerts;
|
||||||
}
|
}
|
||||||
|
|
@ -637,10 +653,10 @@ export function buildCableSizingAlerts(input: CableSizingInput, result: CableSiz
|
||||||
text: "Reduktionsfaktor 0,86 wegen 15–33 % 3. Harmonischer im Neutralleiter angewendet.",
|
text: "Reduktionsfaktor 0,86 wegen 15–33 % 3. Harmonischer im Neutralleiter angewendet.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (input.phase === 3 && input.harmonicNeutralLoad === "over33Percent") {
|
if (input.lengthM === 0) {
|
||||||
alerts.push({
|
alerts.push({
|
||||||
kind: "warn",
|
kind: "info",
|
||||||
text: "3. Harmonische > 33 %: Der Neutralleiter ist nach dem Neutralleiterstrom zu bemessen – hier nicht berücksichtigt.",
|
text: "Leitungslänge 0 m: Für diese Berechnung wird kein Spannungsfall angesetzt.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (group === "ground") {
|
if (group === "ground") {
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ import {
|
||||||
LAYING_METHODS,
|
LAYING_METHODS,
|
||||||
LAYING_METHOD_GROUP,
|
LAYING_METHOD_GROUP,
|
||||||
LAYING_METHOD_LABELS,
|
LAYING_METHOD_LABELS,
|
||||||
MAX_GROUPING_CIRCUITS,
|
|
||||||
PRACTICAL_MINIMUM_CROSS_SECTION_MM2,
|
PRACTICAL_MINIMUM_CROSS_SECTION_MM2,
|
||||||
REFERENCE_TEMPERATURE_C,
|
REFERENCE_TEMPERATURE_C,
|
||||||
|
maxGroupingCircuits,
|
||||||
temperatureOptions,
|
temperatureOptions,
|
||||||
type CableSizingAlert,
|
type CableSizingAlert,
|
||||||
type CableSizingInput,
|
type CableSizingInput,
|
||||||
|
|
@ -100,6 +100,7 @@ export function CableSizingModal({
|
||||||
? threePhaseVoltageV
|
? threePhaseVoltageV
|
||||||
: singlePhaseVoltageV;
|
: singlePhaseVoltageV;
|
||||||
const group = LAYING_METHOD_GROUP[layingMethod];
|
const group = LAYING_METHOD_GROUP[layingMethod];
|
||||||
|
const groupingMaximum = maxGroupingCircuits(layingMethod);
|
||||||
const availableTemperatures = temperatureOptions(layingMethod, insulation);
|
const availableTemperatures = temperatureOptions(layingMethod, insulation);
|
||||||
|
|
||||||
const input: CableSizingInput = useMemo(
|
const input: CableSizingInput = useMemo(
|
||||||
|
|
@ -208,7 +209,7 @@ export function CableSizingModal({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormModal
|
<FormModal
|
||||||
description="Querschnittsempfehlung nach IEC 60364-5-52 Anhang B (Belastbarkeit, Temperatur, Häufung, Spannungsfall, Schutzorgan) oder direkte Eingabe. Die Empfehlung vor der Übernahme fachlich prüfen; nationale Tabellen (DIN VDE 0298-4) können abweichen."
|
description="Querschnittsempfehlung mit Strombelastbarkeit, Temperatur- und Häufungsfaktoren nach DIN VDE 0298-4:2023-06 einschließlich Berichtigung 1:2023-10. Spannungsfall und Schutzorgan werden ergänzend geprüft. Die Empfehlung vor der Übernahme fachlich prüfen."
|
||||||
isSaving={isSaving}
|
isSaving={isSaving}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
|
@ -234,6 +235,11 @@ export function CableSizingModal({
|
||||||
type="number"
|
type="number"
|
||||||
value={lengthM}
|
value={lengthM}
|
||||||
/>
|
/>
|
||||||
|
{lengthM === 0 ? (
|
||||||
|
<div className="form-text text-warning">
|
||||||
|
Bei 0 m wird kein Spannungsfall angesetzt.
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-md-4">
|
<div className="col-12 col-md-4">
|
||||||
<label className="form-label" htmlFor="cable-sizing-phase">
|
<label className="form-label" htmlFor="cable-sizing-phase">
|
||||||
|
|
@ -279,6 +285,7 @@ export function CableSizingModal({
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
const method = event.target.value as LayingMethod;
|
const method = event.target.value as LayingMethod;
|
||||||
setLayingMethod(method);
|
setLayingMethod(method);
|
||||||
|
setGroupingCircuits((current) => Math.min(current, maxGroupingCircuits(method)));
|
||||||
applyReferenceTemperature(method, insulation);
|
applyReferenceTemperature(method, insulation);
|
||||||
resetResult();
|
resetResult();
|
||||||
}}
|
}}
|
||||||
|
|
@ -362,7 +369,7 @@ export function CableSizingModal({
|
||||||
<input
|
<input
|
||||||
className="form-control"
|
className="form-control"
|
||||||
id="cable-sizing-grouping"
|
id="cable-sizing-grouping"
|
||||||
max={MAX_GROUPING_CIRCUITS}
|
max={groupingMaximum}
|
||||||
min={1}
|
min={1}
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
setGroupingCircuits(Math.max(1, Math.round(Number(event.target.value) || 1)));
|
setGroupingCircuits(Math.max(1, Math.round(Number(event.target.value) || 1)));
|
||||||
|
|
@ -373,7 +380,10 @@ export function CableSizingModal({
|
||||||
value={groupingCircuits}
|
value={groupingCircuits}
|
||||||
/>
|
/>
|
||||||
<div className="form-text">
|
<div className="form-text">
|
||||||
Anzahl gemeinsam verlegter Stromkreise, einschließlich dieses.
|
Anzahl gemeinsam verlegter Stromkreise, einschließlich dieses
|
||||||
|
{layingMethod === "E"
|
||||||
|
? "; ohne Angaben zur Kabelpritsche ist nur 1 zulässig."
|
||||||
|
: `; für diese Verlegeart sind bis ${groupingMaximum} tabelliert.`}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{phase === 3 ? (
|
{phase === 3 ? (
|
||||||
|
|
|
||||||
|
|
@ -45,28 +45,34 @@ const capacity = (
|
||||||
CROSS_SECTIONS_MM2.indexOf(crossSection as (typeof CROSS_SECTIONS_MM2)[number])
|
CROSS_SECTIONS_MM2.indexOf(crossSection as (typeof CROSS_SECTIONS_MM2)[number])
|
||||||
];
|
];
|
||||||
|
|
||||||
describe("cable sizing reference tables (IEC 60364-5-52 Annex B)", () => {
|
describe("cable sizing reference tables (DIN VDE 0298-4:2023-06)", () => {
|
||||||
it("contains the checked PVC copper values", () => {
|
it("contains the checked PVC copper values", () => {
|
||||||
// B.52.2: A1 two loaded conductors (the previously wrong row)
|
assert.equal(capacity("pvc", "copper", "A1", 2, 1.5), 15.5);
|
||||||
|
assert.equal(capacity("pvc", "copper", "A2", 2, 1.5), 15.5);
|
||||||
assert.equal(capacity("pvc", "copper", "A1", 2, 2.5), 19.5);
|
assert.equal(capacity("pvc", "copper", "A1", 2, 2.5), 19.5);
|
||||||
assert.equal(capacity("pvc", "copper", "A1", 2, 16), 61);
|
assert.equal(capacity("pvc", "copper", "A1", 2, 16), 61);
|
||||||
assert.equal(capacity("pvc", "copper", "A1", 2, 120), 210);
|
assert.equal(capacity("pvc", "copper", "A1", 2, 120), 210);
|
||||||
// B.52.2: B2 from 50 mm² (previously copied from B1)
|
// DIN table 3: B2 from 50 mm² (previously copied from B1)
|
||||||
assert.equal(capacity("pvc", "copper", "B2", 2, 50), 133);
|
assert.equal(capacity("pvc", "copper", "B2", 2, 50), 133);
|
||||||
assert.equal(capacity("pvc", "copper", "B2", 2, 120), 232);
|
assert.equal(capacity("pvc", "copper", "B2", 2, 120), 232);
|
||||||
// B.52.4 and D1/D2
|
// Tables 3 and 4, including reference method D in conduits/ducts.
|
||||||
assert.equal(capacity("pvc", "copper", "C", 3, 6), 41);
|
assert.equal(capacity("pvc", "copper", "C", 3, 6), 41);
|
||||||
assert.equal(capacity("pvc", "copper", "D1", 2, 2.5), 29);
|
assert.equal(capacity("pvc", "copper", "D", 2, 2.5), 29);
|
||||||
assert.equal(capacity("pvc", "copper", "D2", 3, 16), 70);
|
assert.equal(capacity("pvc", "copper", "A1", 2, 240), 321);
|
||||||
// Conflicting sources resolved to the lower value
|
|
||||||
assert.equal(capacity("pvc", "copper", "A1", 2, 240), 320);
|
|
||||||
assert.equal(capacity("pvc", "copper", "E", 3, 70), 196);
|
assert.equal(capacity("pvc", "copper", "E", 3, 70), 196);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses the aluminium and XLPE tables instead of flat factors", () => {
|
it("uses aluminium only from the first DIN-tabulated size of 25 mm²", () => {
|
||||||
assert.equal(capacity("pvc", "aluminum", "A1", 2, 1.5), null);
|
for (const insulation of ["pvc", "xlpe"] as const) {
|
||||||
assert.equal(capacity("pvc", "aluminum", "C", 3, 16), 59);
|
for (const method of ["A1", "A2", "B1", "B2", "C", "D", "E"] as const) {
|
||||||
assert.equal(capacity("pvc", "aluminum", "D2", 2, 10), null);
|
for (const cores of [2, 3] as const) {
|
||||||
|
for (const crossSection of CROSS_SECTIONS_MM2.filter((value) => value < 25)) {
|
||||||
|
assert.equal(capacity(insulation, "aluminum", method, cores, crossSection), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.equal(capacity("pvc", "aluminum", "C", 3, 25), 73);
|
||||||
assert.equal(capacity("xlpe", "copper", "C", 2, 2.5), 33);
|
assert.equal(capacity("xlpe", "copper", "C", 2, 2.5), 33);
|
||||||
assert.equal(capacity("xlpe", "aluminum", "E", 3, 25), 97);
|
assert.equal(capacity("xlpe", "aluminum", "E", 3, 25), 97);
|
||||||
});
|
});
|
||||||
|
|
@ -113,10 +119,15 @@ describe("calculateCableSizing", () => {
|
||||||
const cold = calculateCableSizing({ ...BASE_INPUT, ambientTemperatureC: 5 });
|
const cold = calculateCableSizing({ ...BASE_INPUT, ambientTemperatureC: 5 });
|
||||||
assert.equal(cold.temperatureUsedC, 10);
|
assert.equal(cold.temperatureUsedC, 10);
|
||||||
assert.equal(cold.temperatureFactor, 1.22);
|
assert.equal(cold.temperatureFactor, 1.22);
|
||||||
const grouped = calculateCableSizing({ ...BASE_INPUT, groupingCircuits: 10 });
|
const exact = calculateCableSizing({ ...BASE_INPUT, groupingCircuits: 10 });
|
||||||
|
assert.equal(exact.groupingUsed, 10);
|
||||||
|
assert.equal(exact.groupingFactor, 0.48);
|
||||||
|
assert.equal(calculateCableSizing({ ...BASE_INPUT, groupingCircuits: 14 }).groupingFactor, 0.43);
|
||||||
|
assert.equal(calculateCableSizing({ ...BASE_INPUT, groupingCircuits: 18 }).groupingFactor, 0.39);
|
||||||
|
const grouped = calculateCableSizing({ ...BASE_INPUT, groupingCircuits: 11 });
|
||||||
assert.equal(grouped.groupingUsed, 12);
|
assert.equal(grouped.groupingUsed, 12);
|
||||||
assert.equal(grouped.groupingFactor, 0.45);
|
assert.equal(grouped.groupingFactor, 0.45);
|
||||||
const alerts = buildCableSizingAlerts({ ...BASE_INPUT, groupingCircuits: 10 }, grouped);
|
const alerts = buildCableSizingAlerts({ ...BASE_INPUT, groupingCircuits: 11 }, grouped);
|
||||||
assert.ok(alerts.some((alert) => alert.text.includes("12 Stromkreise gerundet")));
|
assert.ok(alerts.some((alert) => alert.text.includes("12 Stromkreise gerundet")));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -129,13 +140,15 @@ describe("calculateCableSizing", () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses the ground tables for D1 (ducts) and D2 (direct)", () => {
|
it("limits grouping to the corrected DIN tables for D and E", () => {
|
||||||
const d1 = calculateCableSizing({ ...BASE_INPUT, layingMethod: "D1", ambientTemperatureC: 20, groupingCircuits: 10 });
|
const d = calculateCableSizing({ ...BASE_INPUT, layingMethod: "D", ambientTemperatureC: 20, groupingCircuits: 6 });
|
||||||
assert.equal(d1.groupingFactor, 0.49);
|
assert.equal(d.groupingFactor, 0.6);
|
||||||
const d2 = calculateCableSizing({ ...BASE_INPUT, layingMethod: "D2", ambientTemperatureC: 20, groupingCircuits: 10 });
|
assert.equal(calculateCableSizing({ ...BASE_INPUT, layingMethod: "D", ambientTemperatureC: 20, groupingCircuits: 7 }).supported, false);
|
||||||
assert.equal(d2.groupingUsed, 12);
|
const e = calculateCableSizing({ ...BASE_INPUT, layingMethod: "E", groupingCircuits: 2 });
|
||||||
assert.equal(d2.groupingFactor, 0.36);
|
assert.equal(e.supported, false);
|
||||||
assert.equal(calculateCableSizing({ ...BASE_INPUT, layingMethod: "D2", ambientTemperatureC: 30 }).temperatureFactor, 0.89);
|
assert.equal(e.unsupportedReason, "grouping");
|
||||||
|
assert.ok(buildCableSizingAlerts({ ...BASE_INPUT, layingMethod: "E", groupingCircuits: 2 }, e)[0]?.text.includes("Kabelpritsche"));
|
||||||
|
assert.equal(calculateCableSizing({ ...BASE_INPUT, layingMethod: "D", ambientTemperatureC: 30 }).temperatureFactor, 0.89);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("refuses inputs outside the tables instead of assuming a factor of 1", () => {
|
it("refuses inputs outside the tables instead of assuming a factor of 1", () => {
|
||||||
|
|
@ -156,9 +169,11 @@ describe("calculateCableSizing", () => {
|
||||||
lengthM: 5,
|
lengthM: 5,
|
||||||
conductorMaterial: "aluminum",
|
conductorMaterial: "aluminum",
|
||||||
});
|
});
|
||||||
assert.equal(result.recommendedCrossSectionMm2, 2.5);
|
assert.equal(result.recommendedCrossSectionMm2, 25);
|
||||||
assert.equal(result.rows[0].ratedCurrentA, null);
|
for (const row of result.rows.filter((row) => row.crossSectionMm2 < 25)) {
|
||||||
assert.equal(result.rows[0].recommended, false);
|
assert.equal(row.ratedCurrentA, null);
|
||||||
|
assert.equal(row.recommended, false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks gG fuses with I2 = 1.6 In and circuit-breakers with In ≤ Iz", () => {
|
it("checks gG fuses with I2 = 1.6 In and circuit-breakers with In ≤ Iz", () => {
|
||||||
|
|
@ -186,6 +201,23 @@ describe("calculateCableSizing", () => {
|
||||||
assert.equal(single.harmonicReductionApplied, false);
|
assert.equal(single.harmonicReductionApplied, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not recommend a cross-section above 33 % third harmonic without neutral current", () => {
|
||||||
|
const input = { ...BASE_INPUT, phase: 3 as const, voltage: 400, harmonicNeutralLoad: "over33Percent" as const };
|
||||||
|
const result = calculateCableSizing(input);
|
||||||
|
assert.equal(result.supported, false);
|
||||||
|
assert.equal(result.unsupportedReason, "harmonics");
|
||||||
|
assert.equal(result.recommendedCrossSectionMm2, null);
|
||||||
|
assert.equal(buildCableSizingAlerts(input, result)[0]?.kind, "critical");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows zero length and states that no voltage drop is applied", () => {
|
||||||
|
const input = { ...BASE_INPUT, lengthM: 0 };
|
||||||
|
const result = calculateCableSizing(input);
|
||||||
|
assert.equal(result.supported, true);
|
||||||
|
assert.equal(result.voltageDropAtRecommendedPercent, 0);
|
||||||
|
assert.ok(buildCableSizingAlerts(input, result).some((alert) => alert.text.includes("kein Spannungsfall")));
|
||||||
|
});
|
||||||
|
|
||||||
it("raises single-phase circuits to the 2.5 mm² practical minimum", () => {
|
it("raises single-phase circuits to the 2.5 mm² practical minimum", () => {
|
||||||
const result = calculateCableSizing({
|
const result = calculateCableSizing({
|
||||||
...BASE_INPUT,
|
...BASE_INPUT,
|
||||||
|
|
@ -203,7 +235,7 @@ describe("calculateCableSizing", () => {
|
||||||
it("offers only tabulated temperatures", () => {
|
it("offers only tabulated temperatures", () => {
|
||||||
assert.deepEqual(temperatureOptions("C", "pvc").at(-1), 60);
|
assert.deepEqual(temperatureOptions("C", "pvc").at(-1), 60);
|
||||||
assert.deepEqual(temperatureOptions("C", "xlpe").at(-1), 80);
|
assert.deepEqual(temperatureOptions("C", "xlpe").at(-1), 80);
|
||||||
assert.deepEqual(temperatureOptions("D1", "pvc")[2], 20);
|
assert.deepEqual(temperatureOptions("D", "pvc")[2], 20);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -219,6 +251,9 @@ describe("cable sizing request schema", () => {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
assert.equal(cableSizingRequestSchema.safeParse({ ...BASE_INPUT, layingMethod: "F" }).success, false);
|
assert.equal(cableSizingRequestSchema.safeParse({ ...BASE_INPUT, layingMethod: "F" }).success, false);
|
||||||
|
assert.equal(cableSizingRequestSchema.safeParse({ ...BASE_INPUT, layingMethod: "D1" }).success, false);
|
||||||
|
assert.equal(cableSizingRequestSchema.safeParse({ ...BASE_INPUT, layingMethod: "D2" }).success, false);
|
||||||
|
assert.equal(cableSizingRequestSchema.safeParse({ ...BASE_INPUT, layingMethod: "D" }).success, true);
|
||||||
assert.equal(cableSizingRequestSchema.safeParse({ ...BASE_INPUT, mode: "current" }).success, false);
|
assert.equal(cableSizingRequestSchema.safeParse({ ...BASE_INPUT, mode: "current" }).success, false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue