mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 102f-prep.4: Equation N5 zone-mean blending leaf
SAP 10.2 Appendix N3.5 Equation N5 (PDF p.107):
T = [N24,9 × Th + N16,9 × T_uni + (Nm − N16,9 − N24,9) × T_bi] / Nm
`extended_zone_mean_temperature_c` is the pure-math leaf: takes
pre-computed bimodal (9-hour heating, two off periods) and unimodal
(16-hour heating, one 8-hour off period per Table N7 footnote b)
zone temperatures and the per-month day allocations, blends across
the three heating patterns (Th for 24-hour days, T_uni for 16-hour,
T_bi for the standard 9-hour SAP schedule).
Pinned against cert 0380's January living-area MIT: Th=21, T_bi
=18.5551 (worksheet "Living" row), T_uni back-solved from (87)
= 19.6153, N24=3, N16=28, Nm=31 → 19.7493 (worksheet (87) Jan).
Collapses cleanly: N24=N16=0 → T_bi (warm months / non-HP certs);
N24=Nm → Th (full 24-hour heating).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
80d3b9efd6
commit
a486e97d06
2 changed files with 107 additions and 0 deletions
|
|
@ -146,6 +146,45 @@ def allocate_extended_heating_days_to_months(
|
|||
return tuple(allocations)
|
||||
|
||||
|
||||
def extended_zone_mean_temperature_c(
|
||||
*,
|
||||
heating_temperature_c: float,
|
||||
t_bimodal_c: float,
|
||||
t_unimodal_c: float,
|
||||
n24_9_m: int,
|
||||
n16_9_m: int,
|
||||
days_in_month: int,
|
||||
) -> float:
|
||||
"""SAP 10.2 Appendix N3.5 Equation N5 (PDF p.107) — blend a zone's
|
||||
monthly mean temperature across three heating patterns:
|
||||
|
||||
T = [N24,9 × Th + N16,9 × T_uni + (Nm − N16,9 − N24,9) × T_bi] / Nm
|
||||
|
||||
The three patterns differ in their daily off-period structure:
|
||||
- 24-hour day: zero off periods → T = Th
|
||||
- Unimodal (16-hour day): one off period of 8h (0700-2300 heating
|
||||
period per Table N7 footnote b) → T = Th − u1(8h)
|
||||
- Bimodal (9-hour day): two off periods (7+8h for living-area and
|
||||
elsewhere control-type 1/2; 9+8h for elsewhere control-type 3
|
||||
per Table N7) → T = Th − u1 − u2
|
||||
|
||||
The caller passes the pre-computed `t_bimodal_c` and `t_unimodal_c`
|
||||
(already reduced from Th by the relevant Table 9b u terms); this
|
||||
helper just does the day-weighted blend.
|
||||
|
||||
When `n24_9_m = n16_9_m = 0` the formula collapses to `t_bimodal_c`,
|
||||
so non-HP certs and warm months flow through unchanged.
|
||||
"""
|
||||
if days_in_month <= 0:
|
||||
return t_bimodal_c
|
||||
bimodal_days = days_in_month - n16_9_m - n24_9_m
|
||||
return (
|
||||
n24_9_m * heating_temperature_c
|
||||
+ n16_9_m * t_unimodal_c
|
||||
+ bimodal_days * t_bimodal_c
|
||||
) / days_in_month
|
||||
|
||||
|
||||
def elsewhere_heating_temperature_c(
|
||||
*,
|
||||
heat_loss_parameter: float,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ from domain.sap10_calculator.worksheet.mean_internal_temperature import (
|
|||
allocate_extended_heating_days_to_months,
|
||||
elsewhere_heating_temperature_c,
|
||||
extended_heating_days_from_psr_variable,
|
||||
extended_zone_mean_temperature_c,
|
||||
mean_internal_temperature_monthly,
|
||||
off_period_temperature_reduction_c,
|
||||
)
|
||||
|
|
@ -431,6 +432,73 @@ def test_allocate_extended_heating_days_zero_is_all_zero() -> None:
|
|||
assert monthly == ((0, 0),) * 12
|
||||
|
||||
|
||||
def test_extended_zone_mean_temperature_matches_cert_0380_january_living() -> None:
|
||||
"""SAP 10.2 Appendix N3.5 Equation N5 (PDF p.107):
|
||||
|
||||
T = [N24,9 × Th + N16,9 × T_uni + (Nm − N16,9 − N24,9) × T_bi] / Nm
|
||||
|
||||
Cert 0380 January (Mitsubishi PUZ-WM50VHA, PSR 1.43):
|
||||
Living-area bimodal "Living" row = 18.5551 (worksheet)
|
||||
N24,9 = 3, N16,9 = 28 (Jan), Nm = 31, Th = 21
|
||||
|
||||
Back-solving the worksheet's MIT_living(87) = 19.7493:
|
||||
31 × 19.7493 = 612.228
|
||||
612.228 = 3 × 21 + 28 × T_uni + 0 × 18.5551
|
||||
T_uni = (612.228 − 63) / 28 = 19.6153
|
||||
|
||||
So this leaf, given Th=21, T_bi=18.5551, T_uni=19.6153, N24=3,
|
||||
N16=28, Nm=31, must return 19.7493.
|
||||
"""
|
||||
# Arrange / Act
|
||||
t = extended_zone_mean_temperature_c(
|
||||
heating_temperature_c=21.0,
|
||||
t_bimodal_c=18.5551,
|
||||
t_unimodal_c=19.6153,
|
||||
n24_9_m=3,
|
||||
n16_9_m=28,
|
||||
days_in_month=31,
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert abs(t - 19.7493) < 1e-4
|
||||
|
||||
|
||||
def test_extended_zone_mean_temperature_collapses_to_bimodal_when_zero_extension() -> None:
|
||||
"""When N24,9_m = N16,9_m = 0, Equation N5 reduces to T_bi — i.e.
|
||||
the standard SAP heating schedule is unchanged. This guards the
|
||||
"no extended heating" path so that warm months (Jun..Sep) and
|
||||
non-HP certs flow through the legacy bimodal calculation."""
|
||||
# Arrange / Act
|
||||
t = extended_zone_mean_temperature_c(
|
||||
heating_temperature_c=21.0,
|
||||
t_bimodal_c=18.0,
|
||||
t_unimodal_c=19.5, # Should be ignored when n16_9_m = 0
|
||||
n24_9_m=0,
|
||||
n16_9_m=0,
|
||||
days_in_month=30,
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert t == 18.0
|
||||
|
||||
|
||||
def test_extended_zone_mean_temperature_collapses_to_th_for_full_24h_month() -> None:
|
||||
"""When N24,9_m = days_in_month, Equation N5 reduces to Th — every
|
||||
day operates at the heating temperature with no off period."""
|
||||
# Arrange / Act
|
||||
t = extended_zone_mean_temperature_c(
|
||||
heating_temperature_c=21.0,
|
||||
t_bimodal_c=18.0,
|
||||
t_unimodal_c=19.5,
|
||||
n24_9_m=31,
|
||||
n16_9_m=0,
|
||||
days_in_month=31,
|
||||
)
|
||||
|
||||
# Assert
|
||||
assert t == 21.0
|
||||
|
||||
|
||||
def test_allocate_extended_heating_days_variable_year_totals_are_preserved() -> None:
|
||||
"""The helper's invariant for the Variable case: every input
|
||||
(N24,9, N16,9) day from Table N5 must land in some cold month
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue