Air-source heat pump (ASHP — space conditioning)¶
ASHP conditions a building zone (heating + cooling) rather than charging a DHW tank. The refrigerant cycle and outdoor-coil source side are shared with the air-source boiler family; what differs is the demand side — a zone energy balance instead of a tank.
Overview¶
The class is tmhp.AirSourceHeatPump. Use it when the heat
pump’s job is space conditioning rather than DHW production.
Base usage¶
from tmhp import AirSourceHeatPump
ashp = AirSourceHeatPump(ref="R32")
# See API reference below for the full constructor and
# analyze_steady / analyze_dynamic signatures.
Source-side mechanics¶
Outdoor coil with variable-speed fan and an ε-NTU air-side heat exchanger — the shared air-source environmental-side model.
Sink-side mechanics¶
A zone temperature / load proxy stands in for the building. The
caller supplies indoor-unit load as Q_r_iu: positive values
select cooling, negative values select heating, and zero values
represent off operation. There is no tank energy balance.
API reference¶
Air source heat pump — physics-based cycle model with indoor unit.
Resolves a vapour-compression refrigerant cycle coupled to
an outdoor-air heat exchanger and an indoor-air heat exchanger.
Supports both cooling (Q_r_iu > 0) and heating (Q_r_iu < 0)
modes. The indoor load Q_r_iu is imposed externally each timestep.
At each time step the model finds the minimum-power operating point (compressor + indoor fan + outdoor fan) via bounded 2-D optimisation over the evaporator and condenser approach temperature differences.
Architecture mirrors AirSourceHeatPumpBoiler — uses the same
shared utility functions (calc_ref_state, calc_HX_perf_for_target_heat,
calc_fan_power_from_dV_fan) and the same postprocess_exergy()
pattern, but replaces the tank energy balance with direct air-side
heat exchange at the indoor unit.
- class tmhp.air_source_heat_pump.AirSourceHeatPump(ref='R32', V_cmp_ref=None, eta_cmp_isen=None, eta_cmp_vol=None, eta_cmp=None, dT_superheat=3.0, dT_subcool=3.0, UA_ou_rated=None, UA_iu_rated=None, n_ou=0.65, n_iu=0.65, dV_ou_fan_a_rated=None, dP_ou_fan_rated=None, A_cross_ou=None, eta_ou_fan_rated=None, dV_iu_fan_a_rated=None, dP_iu_fan_rated=None, A_cross_iu=None, eta_iu_fan_rated=None, hp_capacity=4000.0, T_a_room=27.0, dT_hx_min=0.5, PR_cycle_min=1.5, PR_cycle_max=5.0, rps_min=10.0, rps_max=150.0, vsd_coeffs_ou=None, vsd_coeffs_iu=None, V_disp_cmp=None, eta_cmp_mech=None, UA_cond_rated=None, UA_evap_rated=None, n_cond=None, n_evap=None, UA_cond_design=None, UA_evap_design=None, dV_ou_fan_a_design=None, dP_ou_fan_design=None, eta_ou_fan_design=None, dV_iu_fan_a_design=None, dP_iu_fan_design=None, eta_iu_fan_design=None)[source]¶
Bases:
objectAir source heat pump with indoor-unit air heat exchange.
The refrigerant cycle is resolved via CoolProp with user-specified superheat / subcool margins. A bounded 2-D optimiser minimises total electrical input (
E_cmp + E_iu_fan + E_ou_fan) over the evaporator and condenser approach temperatures.- Parameters:
ref (
str)V_cmp_ref (
Optional[float])eta_cmp_isen (
Union[float,Callable,None])eta_cmp_vol (
Union[float,Callable,None])eta_cmp (
Union[float,Callable,None])dT_superheat (
float)dT_subcool (
float)UA_ou_rated (
Optional[float])UA_iu_rated (
Optional[float])n_ou (
float)n_iu (
float)dV_ou_fan_a_rated (
Optional[float])dP_ou_fan_rated (
Optional[float])A_cross_ou (
Optional[float])eta_ou_fan_rated (
Optional[float])dV_iu_fan_a_rated (
Optional[float])dP_iu_fan_rated (
Optional[float])A_cross_iu (
Optional[float])eta_iu_fan_rated (
Optional[float])hp_capacity (
float)T_a_room (
float)dT_hx_min (
float)PR_cycle_min (
float)PR_cycle_max (
float)rps_min (
float)rps_max (
float)vsd_coeffs_ou (
Optional[dict])vsd_coeffs_iu (
Optional[dict])V_disp_cmp (
Optional[float])eta_cmp_mech (
Union[float,Callable,None])UA_cond_rated (
Optional[float])UA_evap_rated (
Optional[float])n_cond (
Optional[float])n_evap (
Optional[float])UA_cond_design (
Optional[float])UA_evap_design (
Optional[float])dV_ou_fan_a_design (
Optional[float])dP_ou_fan_design (
Optional[float])eta_ou_fan_design (
Optional[float])dV_iu_fan_a_design (
Optional[float])dP_iu_fan_design (
Optional[float])eta_iu_fan_design (
Optional[float])
- __init__(ref='R32', V_cmp_ref=None, eta_cmp_isen=None, eta_cmp_vol=None, eta_cmp=None, dT_superheat=3.0, dT_subcool=3.0, UA_ou_rated=None, UA_iu_rated=None, n_ou=0.65, n_iu=0.65, dV_ou_fan_a_rated=None, dP_ou_fan_rated=None, A_cross_ou=None, eta_ou_fan_rated=None, dV_iu_fan_a_rated=None, dP_iu_fan_rated=None, A_cross_iu=None, eta_iu_fan_rated=None, hp_capacity=4000.0, T_a_room=27.0, dT_hx_min=0.5, PR_cycle_min=1.5, PR_cycle_max=5.0, rps_min=10.0, rps_max=150.0, vsd_coeffs_ou=None, vsd_coeffs_iu=None, V_disp_cmp=None, eta_cmp_mech=None, UA_cond_rated=None, UA_evap_rated=None, n_cond=None, n_evap=None, UA_cond_design=None, UA_evap_design=None, dV_ou_fan_a_design=None, dP_ou_fan_design=None, eta_ou_fan_design=None, dV_iu_fan_a_design=None, dP_iu_fan_design=None, eta_iu_fan_design=None)[source]¶
- Parameters:
ref (
str)V_cmp_ref (
Optional[float])eta_cmp_isen (
Union[float,Callable,None])eta_cmp_vol (
Union[float,Callable,None])eta_cmp (
Union[float,Callable,None])dT_superheat (
float)dT_subcool (
float)UA_ou_rated (
Optional[float])UA_iu_rated (
Optional[float])n_ou (
float)n_iu (
float)dV_ou_fan_a_rated (
Optional[float])dP_ou_fan_rated (
Optional[float])A_cross_ou (
Optional[float])eta_ou_fan_rated (
Optional[float])dV_iu_fan_a_rated (
Optional[float])dP_iu_fan_rated (
Optional[float])A_cross_iu (
Optional[float])eta_iu_fan_rated (
Optional[float])hp_capacity (
float)T_a_room (
float)dT_hx_min (
float)PR_cycle_min (
float)PR_cycle_max (
float)rps_min (
float)rps_max (
float)vsd_coeffs_ou (
Optional[dict])vsd_coeffs_iu (
Optional[dict])V_disp_cmp (
Optional[float])eta_cmp_mech (
Union[float,Callable,None])UA_cond_rated (
Optional[float])UA_evap_rated (
Optional[float])n_cond (
Optional[float])n_evap (
Optional[float])UA_cond_design (
Optional[float])UA_evap_design (
Optional[float])dV_ou_fan_a_design (
Optional[float])dP_ou_fan_design (
Optional[float])eta_ou_fan_design (
Optional[float])dV_iu_fan_a_design (
Optional[float])dP_iu_fan_design (
Optional[float])eta_iu_fan_design (
Optional[float])
- analyze_steady(Q_r_iu, T0, T_a_room=None, *, return_dict=True, postprocess=True, verbose=True)[source]¶
Run a steady-state performance snapshot.
- Parameters:
Q_r_iu (float) – Indoor thermal load [W]. >0 cooling, <0 heating, 0 off.
T0 (float) – Dead-state / outdoor-air temperature [°C].
T_a_room (float | None) – Room air temperature [°C]. Uses constructor default if None.
return_dict (bool) – If True return dict; else single-row DataFrame.
postprocess (bool) – If True, apply postprocess_exergy to the output.
verbose (bool) – If True, print warnings upon convergence failure.
- Returns:
Cycle state plus diagnostic flags.
Two keys are useful for branching:
"converged"(bool) — True only when the inner HX optimisation and the SciPy optimiser both succeeded."failure_reason"(str) — one of"none","cycle_invalid"(the refrigerant cycle itself was infeasible),"hx_not_converged"(cycle OK but the HX residual exceeded tolerance), or"optimizer_failed"(SciPy reportedsuccess=False).
ASHP triggers an off-mode fallback for any of the non-
"none"reasons —E_cmp [W]will be 0 and the COP keys will be NaN in that case. Treatfailure_reason != "none"as “do not trust the numbers”.- Return type:
dict | pd.DataFrame
- analyze_dynamic(simulation_period_sec, dt_s, Q_r_iu_schedule, T0_schedule, T_a_room_schedule=None, result_save_csv_path=None)[source]¶
Run a time-stepping dynamic simulation.
- Parameters:
simulation_period_sec (int) – Total simulation duration [s].
dt_s (int) – Time step size [s].
Q_r_iu_schedule (array-like) – Indoor thermal load per step [W].
T0_schedule (array-like) – Outdoor temperature per step [°C].
T_a_room_schedule (array-like | None) – Room air temperature per step [°C]. If None, uses constructor default.
result_save_csv_path (str | None) – Optional CSV output path.
- Returns:
Per-timestep result DataFrame.
- Return type:
pd.DataFrame
- postprocess_exergy(df)[source]¶
Compute ASHP-specific exergy variables.
Mirrors
AirSourceHeatPumpBoiler.postprocess_exergy()with adaptations for indoor-unit air exchange.Pipeline:
Refrigerant state-point exergy (CoolProp)
Electricity = exergy (compressor, IU fan, OU fan)
Air exergy (outdoor unit + indoor unit)
HX Carnot exergy (condenser, evaporator)
Component-level exergy destruction
Exergetic efficiency metrics
- Parameters:
df (
DataFrame)- Return type:
DataFrame