Weitere Berechnungen

This commit is contained in:
Jens Cornelsen
2025-01-10 18:12:59 +01:00
parent fcc12f5a3c
commit d492045429
7 changed files with 128 additions and 269 deletions

View File

@@ -1,132 +0,0 @@
import { BedarfsausweisWohnenClient, GebaeudeAufnahmeClient } from "#components/Ausweis/types.js";
/**
* Berechnung des monatlichen Belastungsgrades aus Tabelle 9 EFH (Zeitkonstante 90,130)
* @see 18599-Tabellenverfahren-Wohngebaeude.pdf
* @export
* @param {BedarfsausweisWohnenClient} ausweis
* @param {GebaeudeAufnahmeClient} gebaeude_aufnahme
*/
export function BerechnungMonatlicherBelastungsgradT9() {
let Zeitkonstante = 40;
let heizlastGebaeude = 5;
type MonthData = {
month: string;
values: number[];
};
// Zeitkonstante bis 50
const datasetZeitkonstante50: MonthData[] = [
{ month: "Januar", values: [0.557, 0.554, 0.550, 0.543, 0.536, 0.533, 0.531, 0.530] },
{ month: "Februar", values: [0.531, 0.527, 0.524, 0.517, 0.510, 0.507, 0.505, 0.504] },
{ month: "März", values: [0.448, 0.445, 0.443, 0.437, 0.431, 0.427, 0.427, 0.426] },
{ month: "April", values: [0.317, 0.314, 0.313, 0.308, 0.305, 0.303, 0.302, 0.301] },
{ month: "Mai", values: [0.173, 0.172, 0.171, 0.169, 0.166, 0.165, 0.165, 0.164] },
{ month: "Juni", values: [0.097, 0.096, 0.096, 0.094, 0.093, 0.092, 0.092, 0.092] },
{ month: "Juli", values: [0.029, 0.029, 0.029, 0.029, 0.028, 0.028, 0.028, 0.028] },
{ month: "August", values: [0.041, 0.041, 0.041, 0.040, 0.040, 0.040, 0.039, 0.039] },
{ month: "September", values: [0.167, 0.166, 0.165, 0.164, 0.162, 0.161, 0.161, 0.161] },
{ month: "Oktober", values: [0.308, 0.306, 0.304, 0.300, 0.296, 0.293, 0.293, 0.293] },
{ month: "November", values: [0.466, 0.463, 0.460, 0.454, 0.448, 0.445, 0.444, 0.443] },
{ month: "Dezember", values: [0.560, 0.557, 0.553, 0.546, 0.539, 0.536, 0.534, 0.533] }
];
// Zeitkonstante 90
const datasetZeitkonstante90: MonthData[] = [
{ month: "Januar", values: [0.562, 0.559, 0.555, 0.548, 0.541, 0.538, 0.536, 0.535] },
{ month: "Februar", values: [0.536, 0.532, 0.529, 0.522, 0.515, 0.512, 0.510, 0.510] },
{ month: "März", values: [0.453, 0.450, 0.447, 0.441, 0.436, 0.433, 0.431, 0.431] },
{ month: "April", values: [0.320, 0.318, 0.316, 0.311, 0.307, 0.306, 0.305, 0.304] },
{ month: "Mai", values: [0.175, 0.173, 0.172, 0.170, 0.168, 0.167, 0.166, 0.166] },
{ month: "Juni", values: [0.098, 0.097, 0.096, 0.095, 0.094, 0.093, 0.093, 0.093] },
{ month: "Juli", values: [0.030, 0.029, 0.029, 0.029, 0.028, 0.028, 0.028, 0.028] },
{ month: "August", values: [0.041, 0.041, 0.041, 0.040, 0.040, 0.040, 0.040, 0.040] },
{ month: "September", values: [0.169, 0.168, 0.167, 0.164, 0.162, 0.161, 0.161, 0.161] },
{ month: "Oktober", values: [0.311, 0.309, 0.307, 0.303, 0.299, 0.297, 0.296, 0.296] },
{ month: "November", values: [0.471, 0.467, 0.465, 0.459, 0.453, 0.450, 0.448, 0.448] },
{ month: "Dezember", values: [0.565, 0.562, 0.558, 0.551, 0.544, 0.540, 0.539, 0.538] }
];
// Zeitkonstante größer oder gleich 130
const datasetZeitkonstante130: MonthData[] = [
{ month: "Januar", values: [0.567, 0.563, 0.560, 0.553, 0.545, 0.542, 0.540, 0.539, 0.539] },
{ month: "Februar", values: [0.540, 0.537, 0.533, 0.526, 0.520, 0.516, 0.515, 0.514, 0.513] },
{ month: "März", values: [0.457, 0.454, 0.451, 0.445, 0.439, 0.435, 0.435, 0.434, 0.434] },
{ month: "April", values: [0.322, 0.320, 0.318, 0.314, 0.310, 0.308, 0.307, 0.307, 0.306] },
{ month: "Mai", values: [0.176, 0.175, 0.174, 0.172, 0.169, 0.168, 0.168, 0.168, 0.167] },
{ month: "Juni", values: [0.098, 0.097, 0.096, 0.095, 0.094, 0.094, 0.094, 0.094, 0.094] },
{ month: "Juli", values: [0.030, 0.030, 0.029, 0.029, 0.028, 0.028, 0.028, 0.028, 0.028] },
{ month: "August", values: [0.042, 0.041, 0.041, 0.040, 0.040, 0.040, 0.040, 0.040, 0.040] },
{ month: "September", values: [0.170, 0.169, 0.168, 0.166, 0.164, 0.163, 0.162, 0.162, 0.162] },
{ month: "Oktober", values: [0.313, 0.311, 0.309, 0.305, 0.301, 0.300, 0.299, 0.298, 0.298] },
{ month: "November", values: [0.474, 0.471, 0.469, 0.462, 0.456, 0.454, 0.453, 0.451, 0.451] },
{ month: "Dezember", values: [0.570, 0.566, 0.563, 0.555, 0.548, 0.545, 0.543, 0.542, 0.542] },
];
// Für "Ohne Teilbeheizung" habe ich hier einfach 0 genommen. Prakmatisch würde ich sagen.
const HeizLastTabelle = [0, 5, 10, 25, 50, 75, 100, 125, 150];
/**
* Linearly interpolates a value for the given x.
* @param x The x value to interpolate.
* @param xValues The array of x-values.
* @param yValues The array of y-values corresponding to x-values.
* @returns The interpolated value.
*/
function interpolate(x: number, xValues: number[], yValues: number[]): number {
if (x <= xValues[0]) return yValues[0];
if (x >= xValues[xValues.length - 1]) return yValues[yValues.length - 1];
for (let i = 0; i < xValues.length - 1; i++) {
if (x >= xValues[i] && x <= xValues[i + 1]) {
const x1 = xValues[i];
const x2 = xValues[i + 1];
const y1 = yValues[i];
const y2 = yValues[i + 1];
return y1 + ((x - x1) * (y2 - y1)) / (x2 - x1);
}
}
throw new Error("Interpolation error: Value is out of bounds.");
}
let interpolatedValues: { month: string, interpolatedValue: number }[] = [];
if (Zeitkonstante < 50) {
interpolatedValues = datasetZeitkonstante50.map(data => ({
month: data.month,
interpolatedValue: interpolate(heizlastGebaeude, HeizLastTabelle, data.values)
}));
} else if (Zeitkonstante < 90) {
interpolatedValues = datasetZeitkonstante50.map((data, index) => {
if (datasetZeitkonstante90[index] && datasetZeitkonstante90[index].values) {
const interpolatedValue = interpolate(Zeitkonstante, [50, 90], [datasetZeitkonstante50[index].values[0], datasetZeitkonstante90[index].values[0]]);
return {
month: data.month,
interpolatedValue: interpolate(heizlastGebaeude, HeizLastTabelle, [data.values[0], interpolatedValue])
};
} else {
throw new Error(`Data for index ${index} is undefined in datasetZeitkonstante90.`);
}
});
} else if (Zeitkonstante < 130) {
interpolatedValues = datasetZeitkonstante90.map((data, index) => {
if (datasetZeitkonstante130[index] && datasetZeitkonstante130[index].values) {
const interpolatedValue = interpolate(Zeitkonstante, [90, 130], [datasetZeitkonstante90[index].values[0], datasetZeitkonstante130[index].values[0]]);
return {
month: data.month,
interpolatedValue: interpolate(heizlastGebaeude, HeizLastTabelle, [data.values[0], interpolatedValue])
};
} else {
throw new Error(`Data for index ${index} is undefined in datasetZeitkonstante130.`);
}
});
} else {
interpolatedValues = datasetZeitkonstante130.map(data => ({
month: data.month,
interpolatedValue: interpolate(heizlastGebaeude, HeizLastTabelle, data.values)
}));
}
return interpolatedValues;
}

View File

@@ -10,8 +10,7 @@ import { linearInterpolation } from "js-interpolate"
* @param {BedarfsausweisWohnenClient} ausweis
* @param {GebaeudeAufnahmeClient} gebaeude_aufnahme
*/
export function berechnungTrinkwarmwasserWaermebedarf(ausweis: BedarfsausweisWohnenClient, gebaeude_aufnahme: GebaeudeAufnahmeClient) {
export function berechnungNutzenergiebedarfTrinkwasser(ausweis: BedarfsausweisWohnenClient, gebaeude_aufnahme: GebaeudeAufnahmeClient) {
// A_NGF
const bezugsflaeche = gebaeude_aufnahme.nutzflaeche ?? 0;

View File

@@ -0,0 +1,28 @@
import { BedarfsausweisWohnenClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { FixedLengthArray } from "./types.js";
export function berechnungRechnerischeLauzeitHeizung(ausweis: VerbrauchsausweisWohnenClient) {
// TODO Tabelle A.12 (Berechnung Nutzenergiebedarf)
const zeitkonstanteHeizung;
const faktorWochenendAbschaltung = 0.042;
const zeitkonstanteRechnerischeLaufzeitEinfamilienhaus: FixedLengthArray<number, 12> = [17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17];
const zeitkonstanteRechnerischeLaufzeitMehrfamilienhaus: FixedLengthArray<number, 12> = [19.86, 18.58, 18.69, 17.25, 17, 17, 17, 17, 17, 17.16, 18.88, 19.9];
let rechnerischeLaufzeiten = new Array(12).fill(0) as unknown as FixedLengthArray<number, 12>
if (ausweis.gebaeude_aufnahme_allgemein.gebaeudetyp === "Einfamilienhaus") {
for (let i = 0; i < 12; i++) {
rechnerischeLaufzeiten[i] = zeitkonstanteHeizung * faktorWochenendAbschaltung * zeitkonstanteRechnerischeLaufzeitEinfamilienhaus[i]
}
} else {
for (let i = 0; i < 12; i++) {
rechnerischeLaufzeiten[i] = zeitkonstanteHeizung * faktorWochenendAbschaltung * zeitkonstanteRechnerischeLaufzeitMehrfamilienhaus[i]
}
}
return {
rechnerischeLaufzeitGesamt: rechnerischeLaufzeiten.reduce((acc, curr) => acc + curr, 0),
rechnerischeLaufzeiten
}
}

View File

@@ -0,0 +1,5 @@
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
export function berechnungWaermequellenAusAnlagentechnikTrinkwasser(ausweis: VerbrauchsausweisWohnenClient) {
}

View File

@@ -1,154 +1,105 @@
// Funktion zur Berechnung des monatlichen Belastungsgrades aus Tabelle 9 EFH (Januar, Zeitkonstante 90)
import { nevillePolynomialInterpolation, lagrangeInterpolation } from "js-interpolate";
import { nevillePolynomialInterpolation } from "js-interpolate";
// Funktion zur Berechnung des monatlichen Belastungsgrades aus Tabelle 9 EFH (Zeitkonstante 90,130)
type MonthData = {
month: string;
values: number[];
};
const datasetZeitkonstante90: MonthData[] = [
{
month: "Januar",
values: [0.562, 0.559, 0.555, 0.548, 0.541, 0.538, 0.536, 0.535, 0.535],
},
{
month: "Februar",
values: [0.536, 0.532, 0.529, 0.522, 0.515, 0.512, 0.51, 0.51, 0.509],
},
{
month: "März",
values: [0.453, 0.45, 0.447, 0.441, 0.436, 0.433, 0.431, 0.431, 0.43],
},
{
month: "April",
values: [0.32, 0.318, 0.316, 0.311, 0.307, 0.306, 0.305, 0.304, 0.304],
},
{
month: "Mai",
values: [0.175, 0.173, 0.172, 0.17, 0.168, 0.167, 0.166, 0.166, 0.166],
},
{
month: "Juni",
values: [0.098, 0.097, 0.096, 0.095, 0.094, 0.093, 0.093, 0.093, 0.093],
},
{
month: "Juli",
values: [0.03, 0.029, 0.029, 0.029, 0.028, 0.028, 0.028, 0.028, 0.028],
},
{
month: "August",
values: [0.041, 0.041, 0.041, 0.04, 0.04, 0.04, 0.039, 0.039, 0.039],
},
{
month: "September",
values: [0.169, 0.168, 0.167, 0.164, 0.162, 0.161, 0.161, 0.161, 0.16],
},
{
month: "Oktober",
values: [0.311, 0.309, 0.307, 0.303, 0.299, 0.297, 0.296, 0.296, 0.295],
},
{
month: "November",
values: [0.471, 0.467, 0.465, 0.459, 0.453, 0.45, 0.448, 0.448, 0.447],
},
{
month: "Dezember",
values: [0.565, 0.562, 0.558, 0.551, 0.544, 0.54, 0.539, 0.538, 0.537],
},
];
const datasetZeitkonstante130: MonthData[] = [
{
month: "Januar",
values: [0.567, 0.563, 0.56, 0.553, 0.545, 0.542, 0.54, 0.539, 0.539],
},
{
month: "Februar",
values: [0.54, 0.537, 0.533, 0.526, 0.52, 0.516, 0.515, 0.514, 0.513],
},
{
month: "März",
values: [0.457, 0.454, 0.451, 0.445, 0.439, 0.435, 0.435, 0.434, 0.434],
},
{
month: "April",
values: [0.322, 0.32, 0.318, 0.314, 0.31, 0.308, 0.307, 0.307, 0.306],
},
{
month: "Mai",
values: [0.176, 0.175, 0.174, 0.172, 0.169, 0.168, 0.168, 0.168, 0.167],
},
{
month: "Juni",
values: [0.098, 0.097, 0.096, 0.095, 0.094, 0.094, 0.094, 0.094, 0.094],
},
{
month: "Juli",
values: [0.03, 0.03, 0.029, 0.029, 0.028, 0.028, 0.028, 0.028, 0.028],
},
{
month: "August",
values: [0.042, 0.041, 0.041, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04],
},
{
month: "September",
values: [0.17, 0.169, 0.168, 0.166, 0.164, 0.163, 0.162, 0.162, 0.162],
},
{
month: "Oktober",
values: [0.313, 0.311, 0.309, 0.305, 0.301, 0.3, 0.299, 0.298, 0.298],
},
{
month: "November",
values: [0.474, 0.471, 0.469, 0.462, 0.456, 0.454, 0.453, 0.451, 0.451],
},
{
month: "Dezember",
values: [0.57, 0.566, 0.563, 0.555, 0.548, 0.545, 0.543, 0.542, 0.542],
},
];
const dataset = {
Januar: {
50: [ 0.557, 0.554, 0.55, 0.543, 0.536, 0.533, 0.531, 0.53, 0.53 ],
90: [ 0.562, 0.559, 0.555, 0.548, 0.541, 0.538, 0.536, 0.535, 0.535 ],
130: [ 0.567, 0.563, 0.56, 0.553, 0.545, 0.542, 0.54, 0.539, 0.539 ],
},
Februar: {
50: [ 0.531, 0.527, 0.524, 0.517, 0.51, 0.507, 0.505, 0.504, 0.505 ],
90: [ 0.536, 0.532, 0.529, 0.522, 0.515, 0.512, 0.51, 0.51, 0.509 ],
130: [ 0.54, 0.537, 0.533, 0.526, 0.52, 0.516, 0.515, 0.514, 0.513 ],
},
"März": {
50: [ 0.448, 0.445, 0.443, 0.437, 0.431, 0.427, 0.427, 0.426, 0.426 ],
90: [ 0.453, 0.45, 0.447, 0.441, 0.436, 0.433, 0.431, 0.431, 0.43 ],
130: [ 0.457, 0.454, 0.451, 0.445, 0.439, 0.435, 0.435, 0.434, 0.434 ],
},
April: {
50: [ 0.317, 0.314, 0.313, 0.308, 0.305, 0.303, 0.302, 0.301, 0.301 ],
90: [ 0.32, 0.318, 0.316, 0.311, 0.307, 0.306, 0.305, 0.304, 0.304 ],
130: [ 0.322, 0.32, 0.318, 0.314, 0.31, 0.308, 0.307, 0.307, 0.306 ],
},
Mai: {
50: [ 0.173, 0.172, 0.171, 0.169, 0.166, 0.165, 0.165, 0.165, 0.164 ],
90: [ 0.175, 0.173, 0.172, 0.17, 0.168, 0.167, 0.166, 0.166, 0.166 ],
130: [ 0.176, 0.175, 0.174, 0.172, 0.169, 0.168, 0.168, 0.168, 0.167 ],
},
Juni: {
50: [ 0.097, 0.096, 0.096, 0.094, 0.093, 0.092, 0.092, 0.092, 0.092 ],
90: [ 0.098, 0.097, 0.096, 0.095, 0.094, 0.093, 0.093, 0.093, 0.093 ],
130: [ 0.098, 0.097, 0.096, 0.095, 0.094, 0.094, 0.094, 0.094, 0.094 ],
},
Juli: {
50: [ 0.029, 0.029, 0.029, 0.029, 0.028, 0.028, 0.028, 0.028, 0.028 ],
90: [ 0.03, 0.029, 0.029, 0.029, 0.028, 0.028, 0.028, 0.028, 0.028 ],
130: [ 0.03, 0.03, 0.029, 0.029, 0.028, 0.028, 0.028, 0.028, 0.028 ],
},
August: {
50: [ 0.041, 0.041, 0.041, 0.04, 0.04, 0.04, 0.039, 0.039, 0.039 ],
90: [ 0.041, 0.041, 0.041, 0.04, 0.04, 0.04, 0.039, 0.039, 0.039 ],
130: [ 0.042, 0.041, 0.041, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04 ],
},
September: {
50: [ 0.167, 0.166, 0.165, 0.163, 0.161, 0.16, 0.159, 0.159, 0.159 ],
90: [ 0.169, 0.168, 0.167, 0.164, 0.162, 0.161, 0.161, 0.161, 0.16 ],
130: [ 0.17, 0.169, 0.168, 0.166, 0.164, 0.163, 0.162, 0.162, 0.162 ],
},
Oktober: {
50: [ 0.308, 0.306, 0.304, 0.3, 0.296, 0.294, 0.293, 0.293, 0.293 ],
90: [ 0.311, 0.309, 0.307, 0.303, 0.299, 0.297, 0.296, 0.296, 0.295 ],
130: [ 0.313, 0.311, 0.309, 0.305, 0.301, 0.3, 0.299, 0.298, 0.298 ],
},
November: {
50: [ 0.466, 0.463, 0.46, 0.454, 0.448, 0.445, 0.444, 0.443, 0.443 ],
90: [ 0.471, 0.467, 0.465, 0.459, 0.453, 0.45, 0.448, 0.448, 0.447 ],
130: [ 0.474, 0.471, 0.469, 0.462, 0.456, 0.454, 0.453, 0.451, 0.451 ],
},
Dezember: {
50: [ 0.56, 0.557, 0.553, 0.546, 0.539, 0.536, 0.534, 0.533, 0.533 ],
90: [ 0.565, 0.562, 0.558, 0.551, 0.544, 0.54, 0.539, 0.538, 0.537 ],
130: [ 0.57, 0.566, 0.563, 0.555, 0.548, 0.545, 0.543, 0.542, 0.542 ],
},
}
// Für "Ohne Teilbeheizung" habe ich hier einfach 0 eingesetzt:
const HeizLast = [0, 5, 10, 25, 50, 75, 100, 125, 150];
// Um über die beiden Tabellen zu interpolieren können wir einfach zuerst über
// jede einzeln interpolieren und dann zwischen den Tabellen interpolieren.
// Falls wir also den Wert an Stelle Heizlast: 120, Zeitkonstante 100, Monat:
// Januar haben wollen:
function crossInterpolate(heizlast: number, zeitkonstane: number, monat: keyof typeof dataset) {
const data = dataset[monat]
const interpolations: number[] = []
// Um über die beiden Tabellen zu interpolieren können wir einfach zuerst über jede einzeln interpolieren und dann zwischen den Tabellen interpolieren.
// Falls wir also den Wert an Stelle Heizlast: 120, Zeitkonstante 100, Monat: Januar haben wollen:
for (const key in data) {
const values = data[key as unknown as keyof typeof data]
function crossInterpolate(heizlast: number, zeitkonstane: number, monat: string) {
const interpolatedValuesZeitkonstante90 = datasetZeitkonstante90.filter(data => data.month === monat).map((data) => {
const interpolate = nevillePolynomialInterpolation(
data.values.map((value, i) => ({ x: HeizLast[i], y: value })),
data.values.length
);
return interpolate(heizlast)
});
const interpolatedValuesZeitkonstante130 = datasetZeitkonstante130.filter(data => data.month === monat).map((data) => {
const interpolate = nevillePolynomialInterpolation(
data.values.map((value, i) => ({ x: HeizLast[i], y: value })),
data.values.length
);
return interpolate(heizlast)
});
values.map((value, i) => ({ x: HeizLast[i], y: value })),
values.length
)
interpolations.push(interpolate(heizlast))
}
const interpolate = nevillePolynomialInterpolation(
[{
x: 90,
y: interpolatedValuesZeitkonstante90
}, {
x: 130,
y: interpolatedValuesZeitkonstante130
}],
2
interpolations.map((interpolation, i) => {
return {
x: Object.keys(data)[i],
y: interpolation
}
}),
interpolations.length
)
return interpolate(zeitkonstane)
}
console.log(crossInterpolate(25, 90, "Januar"));
console.log(crossInterpolate(120, 100, "Januar"));

View File

@@ -0,0 +1,8 @@
type ArrayLengthMutationKeys = 'splice' | 'push' | 'pop' | 'shift' | 'unshift'
export type FixedLengthArray<T, L extends number, TObj = [T, ...Array<T>]> =
Pick<TObj, Exclude<keyof TObj, ArrayLengthMutationKeys>>
& {
readonly length: L
[ I : number ] : T
[Symbol.iterator]: () => IterableIterator<T>
}