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
|
|
@ -45,28 +45,34 @@ const capacity = (
|
|||
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", () => {
|
||||
// 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, 16), 61);
|
||||
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, 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", "D1", 2, 2.5), 29);
|
||||
assert.equal(capacity("pvc", "copper", "D2", 3, 16), 70);
|
||||
// Conflicting sources resolved to the lower value
|
||||
assert.equal(capacity("pvc", "copper", "A1", 2, 240), 320);
|
||||
assert.equal(capacity("pvc", "copper", "D", 2, 2.5), 29);
|
||||
assert.equal(capacity("pvc", "copper", "A1", 2, 240), 321);
|
||||
assert.equal(capacity("pvc", "copper", "E", 3, 70), 196);
|
||||
});
|
||||
|
||||
it("uses the aluminium and XLPE tables instead of flat factors", () => {
|
||||
assert.equal(capacity("pvc", "aluminum", "A1", 2, 1.5), null);
|
||||
assert.equal(capacity("pvc", "aluminum", "C", 3, 16), 59);
|
||||
assert.equal(capacity("pvc", "aluminum", "D2", 2, 10), null);
|
||||
it("uses aluminium only from the first DIN-tabulated size of 25 mm²", () => {
|
||||
for (const insulation of ["pvc", "xlpe"] as const) {
|
||||
for (const method of ["A1", "A2", "B1", "B2", "C", "D", "E"] as const) {
|
||||
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", "aluminum", "E", 3, 25), 97);
|
||||
});
|
||||
|
|
@ -113,10 +119,15 @@ describe("calculateCableSizing", () => {
|
|||
const cold = calculateCableSizing({ ...BASE_INPUT, ambientTemperatureC: 5 });
|
||||
assert.equal(cold.temperatureUsedC, 10);
|
||||
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.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")));
|
||||
});
|
||||
|
||||
|
|
@ -129,13 +140,15 @@ describe("calculateCableSizing", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("uses the ground tables for D1 (ducts) and D2 (direct)", () => {
|
||||
const d1 = calculateCableSizing({ ...BASE_INPUT, layingMethod: "D1", ambientTemperatureC: 20, groupingCircuits: 10 });
|
||||
assert.equal(d1.groupingFactor, 0.49);
|
||||
const d2 = calculateCableSizing({ ...BASE_INPUT, layingMethod: "D2", ambientTemperatureC: 20, groupingCircuits: 10 });
|
||||
assert.equal(d2.groupingUsed, 12);
|
||||
assert.equal(d2.groupingFactor, 0.36);
|
||||
assert.equal(calculateCableSizing({ ...BASE_INPUT, layingMethod: "D2", ambientTemperatureC: 30 }).temperatureFactor, 0.89);
|
||||
it("limits grouping to the corrected DIN tables for D and E", () => {
|
||||
const d = calculateCableSizing({ ...BASE_INPUT, layingMethod: "D", ambientTemperatureC: 20, groupingCircuits: 6 });
|
||||
assert.equal(d.groupingFactor, 0.6);
|
||||
assert.equal(calculateCableSizing({ ...BASE_INPUT, layingMethod: "D", ambientTemperatureC: 20, groupingCircuits: 7 }).supported, false);
|
||||
const e = calculateCableSizing({ ...BASE_INPUT, layingMethod: "E", groupingCircuits: 2 });
|
||||
assert.equal(e.supported, false);
|
||||
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", () => {
|
||||
|
|
@ -156,9 +169,11 @@ describe("calculateCableSizing", () => {
|
|||
lengthM: 5,
|
||||
conductorMaterial: "aluminum",
|
||||
});
|
||||
assert.equal(result.recommendedCrossSectionMm2, 2.5);
|
||||
assert.equal(result.rows[0].ratedCurrentA, null);
|
||||
assert.equal(result.rows[0].recommended, false);
|
||||
assert.equal(result.recommendedCrossSectionMm2, 25);
|
||||
for (const row of result.rows.filter((row) => row.crossSectionMm2 < 25)) {
|
||||
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", () => {
|
||||
|
|
@ -186,6 +201,23 @@ describe("calculateCableSizing", () => {
|
|||
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", () => {
|
||||
const result = calculateCableSizing({
|
||||
...BASE_INPUT,
|
||||
|
|
@ -203,7 +235,7 @@ describe("calculateCableSizing", () => {
|
|||
it("offers only tabulated temperatures", () => {
|
||||
assert.deepEqual(temperatureOptions("C", "pvc").at(-1), 60);
|
||||
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
|
||||
);
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue