From e7b631d9bcfef6dc8f509131cbd83ac2dfbbeed4 Mon Sep 17 00:00:00 2001 From: Simon Garnier Date: Tue, 3 Mar 2026 14:10:24 +0100 Subject: [PATCH] fix: linear interpolation for thresholds of <40m2 --- src/conso.js | 5 +++-- src/interpolateLimitTable.js | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/interpolateLimitTable.js diff --git a/src/conso.js b/src/conso.js index e2e4b0c..32b9597 100644 --- a/src/conso.js +++ b/src/conso.js @@ -2,6 +2,7 @@ import enums from './enums.js'; import calc_conso_eclairage from './16_conso_eclairage.js'; import tvs from './tv.js'; import { tv } from './utils.js'; +import { interpolateLimitTable } from './interpolateLimitTable.js'; export const COEFF_EP_2_3 = 2.3; export const COEFF_EP_1_9 = 1.9; @@ -340,7 +341,7 @@ export default function calc_conso( export function classe_bilan_dpe(ep_conso_5_usages_m2, zc_id, ca_id, Sh) { const ca = enums.classe_altitude[ca_id]; - const cut = tvs.dpe_class_limit[ca][Math.round(Sh)] ?? []; + const cut = interpolateLimitTable(tvs.dpe_class_limit[ca], Sh); if (ep_conso_5_usages_m2 == null) return null; if (ep_conso_5_usages_m2 < (cut['A'] ?? 70)) return 'A'; @@ -363,7 +364,7 @@ export function classe_bilan_dpe(ep_conso_5_usages_m2, zc_id, ca_id, Sh) { export function classe_emission_ges(emission_ges_5_usages_m2, zc_id, ca_id, Sh) { const ca = enums.classe_altitude[ca_id]; - const cut = tvs.ges_class_limit[ca][Math.round(Sh)] ?? []; + const cut = interpolateLimitTable(tvs.ges_class_limit[ca], Sh); if (emission_ges_5_usages_m2 == null) return null; if (emission_ges_5_usages_m2 < (cut['A'] ?? 6)) return 'A'; diff --git a/src/interpolateLimitTable.js b/src/interpolateLimitTable.js new file mode 100644 index 0000000..4d26ada --- /dev/null +++ b/src/interpolateLimitTable.js @@ -0,0 +1,35 @@ +export function interpolateLimitTable(table, Sh) { + const keys = Object.keys(table) + .map(Number) + .sort((a, b) => a - b); + + const minKey = keys[0]; + const maxKey = keys[keys.length - 1]; + + if (Sh <= minKey) return table[minKey]; + if (Sh >= maxKey) return table[maxKey]; + + if (table[Sh]) return table[Sh]; + + const lo = keys.filter((k) => k <= Sh).pop(); + const hi = keys.filter((k) => k >= Sh).shift(); + + const loRow = table[lo]; + const hiRow = table[hi]; + const t = (Sh - lo) / (hi - lo); + + const result = {}; + const allLetters = new Set([...Object.keys(loRow), ...Object.keys(hiRow)]); + for (const letter of allLetters) { + const vLo = loRow[letter]; + const vHi = hiRow[letter]; + if (vLo !== undefined && vHi !== undefined) { + result[letter] = vLo + (vHi - vLo) * t; + } else if (vLo !== undefined) { + result[letter] = vLo; + } else if (vHi !== undefined) { + result[letter] = vHi; + } + } + return result; +}