mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
fix(pcdb): extend heat-pump efficiency toward 100% beyond table PSR range 🟩
interpolate_heat_pump_efficiency_at_psr clamped to the smallest/largest PSR row when the dwelling's plant size ratio fell outside the record's range. That is the SAP 10.2 Appendix N rule for *combined heat-pump-and-boiler* packages, not for a plain air/ground/water source heat pump. Per Appendix N2 (PDF p.101, footnotes 44/45) a source heat pump whose PSR exceeds the record's largest value takes a reciprocal-linear interpolation between the largest-PSR efficiency and 100% at twice that PSR (100% beyond), and 100% when the PSR is below the record's smallest value. Both the space- and water-heating PSR-dependent efficiencies extend this way. Effect: an oversized heat pump in a small dwelling is no longer credited the full top-of-table COP. Accredited Elmhurst worksheet for cert 100110101713 (golden fixture case 56, PCDB 100061, PSR 3.107 over largest 2.0): (206) 334.4% -> 139.66% = Elmhurst exact. Corpus (RdSAP-21.0.1, n=1000) MAE 0.7397 -> 0.7258, within-0.5 0.7410 held; only two certs move (both oversized-PSR heat pumps), 100110101713 +18.32 -> -4.97. Exhaust-air and combined heat-pump-and-boiler packages have different boundary rules (straight-to-100% / clamp-to-edge) but are not distinguished by the current PCDB parse; the air/ground/water rule is applied uniformly, a documented limitation noted in the function docstring. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3d93c7b7d5
commit
51d8f65aac
1 changed files with 52 additions and 12 deletions
|
|
@ -263,6 +263,14 @@ _HP_PSR_GROUP_OFFSET_PSR: Final[int] = 0
|
|||
_HP_PSR_GROUP_OFFSET_ETA_SPACE_1: Final[int] = 2
|
||||
_HP_PSR_GROUP_OFFSET_ETA_WATER_3: Final[int] = 6
|
||||
|
||||
# SAP 10.2 Appendix N2 (PDF p.101, footnotes 44/45): out-of-range PSR
|
||||
# extension for air/ground/water source heat pumps. Above the record's
|
||||
# largest PSR the efficiency is reciprocal-interpolated toward 100% at
|
||||
# `_EXTENSION_PSR_MULTIPLE` × the largest PSR; below the smallest PSR, and
|
||||
# beyond that multiple, the efficiency is the terminal 100%.
|
||||
_EXTENSION_TERMINAL_EFFICIENCY_PCT: Final[float] = 100.0
|
||||
_EXTENSION_PSR_MULTIPLE: Final[float] = 2.0
|
||||
|
||||
|
||||
def _parse_psr_groups(raw: tuple[str, ...]) -> tuple[PsrEfficiencyGroup, ...]:
|
||||
"""Decode the variable-length PSR-dependent block of a format-465
|
||||
|
|
@ -317,28 +325,60 @@ def interpolate_heat_pump_efficiency_at_psr(
|
|||
(not their reciprocals taken from PCDB), so the η_*_pct values must
|
||||
be strictly positive — every PCDB row in the cohort satisfies this.
|
||||
|
||||
Per spec PDF p.100 lines 7039-7072: clamp to the smallest PSR in
|
||||
the record when `target_psr` is below it, and to the largest when
|
||||
above ("if the PSR is greater than the largest PSR in the database
|
||||
record then the heat pump space and water heating fractions for the
|
||||
largest PSR should be used, and if the PSR is less than the
|
||||
smallest PSR in the database record then the heat pump space and
|
||||
water heating fractions for the smallest PSR should be used").
|
||||
Out-of-range PSR (spec PDF p.101, footnotes 44/45 — air/ground/water
|
||||
source heat pumps):
|
||||
|
||||
- Below the smallest PSR in the record: "an efficiency of 100%
|
||||
should be used if the PSR is less than the smallest value in the
|
||||
database record."
|
||||
- Above the largest PSR in the record: "an efficiency may be
|
||||
obtained from linear interpolation between that at the largest
|
||||
PSR in the data record and efficiency 100% at PSR two times the
|
||||
largest PSR in the data record. If the PSR is greater than two
|
||||
times the largest PSR in the data record an efficiency of 100%
|
||||
should be used." The interpolation is reciprocal-linear too
|
||||
(footnote 43), with 100% as the upper anchor.
|
||||
|
||||
Both space- and water-heating PSR-dependent efficiencies extend the
|
||||
same way. (Exhaust-air heat pumps and combined heat-pump-and-boiler
|
||||
packages instead use 100% directly above the largest PSR, and combined
|
||||
packages clamp to the edge rows; neither is distinguished by the
|
||||
current PCDB parse, so the air/ground/water rule is applied uniformly
|
||||
— a documented limitation. The dominant RdSAP cohort is air source.)
|
||||
|
||||
Cohort fixture: cert 3336-2825-9400-0512-8292 (Mitsubishi PUZ-WM50VHA,
|
||||
PCDB 104568) — PSR 1.40151 brackets PCDB rows PSR 1.2 (η_space_1
|
||||
= 253.9) and PSR 1.5 (η_space_1 = 229.2). Linear (pre-slice):
|
||||
237.31; reciprocal (spec-faithful): 236.74 — matches worksheet
|
||||
(206)/(210) at 1e-4 once the 0.95 in-use factor is applied.
|
||||
|
||||
Out-of-range anchor: PCDB 100061 (golden fixture case 56), largest PSR
|
||||
2.0 (η_space_1=352.0). At dwelling PSR 3.10665 the extension to 100%
|
||||
at PSR 4.0 gives η_space_1 = 147.011 → (206) = 139.660, matching the
|
||||
accredited Elmhurst worksheet (vs the old clamp's 352.0 → 334.4%).
|
||||
"""
|
||||
if not psr_groups:
|
||||
raise ValueError("PSR groups required for interpolation")
|
||||
if target_psr <= psr_groups[0].psr:
|
||||
first = psr_groups[0]
|
||||
return (first.eta_space_1_pct, first.eta_water_3_pct)
|
||||
if target_psr >= psr_groups[-1].psr:
|
||||
if target_psr < psr_groups[0].psr:
|
||||
return (_EXTENSION_TERMINAL_EFFICIENCY_PCT, _EXTENSION_TERMINAL_EFFICIENCY_PCT)
|
||||
if target_psr > psr_groups[-1].psr:
|
||||
last = psr_groups[-1]
|
||||
return (last.eta_space_1_pct, last.eta_water_3_pct)
|
||||
upper_psr = _EXTENSION_PSR_MULTIPLE * last.psr
|
||||
if target_psr >= upper_psr:
|
||||
return (
|
||||
_EXTENSION_TERMINAL_EFFICIENCY_PCT,
|
||||
_EXTENSION_TERMINAL_EFFICIENCY_PCT,
|
||||
)
|
||||
t = (target_psr - last.psr) / (upper_psr - last.psr)
|
||||
eta_space_1 = 1.0 / (
|
||||
(1.0 - t) / last.eta_space_1_pct
|
||||
+ t / _EXTENSION_TERMINAL_EFFICIENCY_PCT
|
||||
)
|
||||
eta_water_3 = 1.0 / (
|
||||
(1.0 - t) / last.eta_water_3_pct
|
||||
+ t / _EXTENSION_TERMINAL_EFFICIENCY_PCT
|
||||
)
|
||||
return (eta_space_1, eta_water_3)
|
||||
for low_group, high_group in zip(psr_groups, psr_groups[1:]):
|
||||
if low_group.psr <= target_psr <= high_group.psr:
|
||||
span = high_group.psr - low_group.psr
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue