Batteries de CTA — chauffage et refroidissement

Le sous-paquet AHU.Coil regroupe les batteries d’une Centrale de Traitement d’Air (CTA) : composants qui réchauffent, refroidissent et, éventuellement, déshumidifient l’air. Chaque batterie s’insère en série dans la CTA — la sortie d’un composant alimente l’entrée du suivant via AHU.Connect.Air_connect.

Toutes les grandeurs psychrométriques (enthalpie h, humidité absolue w, température T, humidité relative RH, pression de vapeur saturante) sont calculées avec AHU.air_humide (voir Air humide — fonctions psychrométriques).

Modules disponibles

Module

Classe

Rôle

HeatingCoil

Object

Batterie chaude sensible : réchauffe l’air à humidité absolue constante jusqu’à une température de consigne.

HeatingCoilNUT

HeatingCoilNUT

Batterie chaude à eau, dimensionnée par la méthode NUT-ε (efficacité d’échangeur) avec un port fluide caloporteur.

CoolingCoil

Object

Batterie froide avec déshumidification (droite de saturation + facteur de bypass).

CoolingCoil_Tc

Object

Batterie froide sensible : refroidit jusqu’à une température de consigne, sans condensation.

CoolingCoil_Sensible

Object

Transformation sensible (chauffage ou refroidissement) à w constant vers une température cible.

CoolingCoil_Expert

Object

Variante « Expert » : état de sortie résolu numériquement pour une humidité relative de sortie imposée.

Connecteurs communs

Chaque batterie expose deux ports air AirPort :

  • Inlet — air entrant (h, w, P, F, F_dry) ;

  • Outlet — air traité, calculé par calculate().

HeatingCoilNUT ajoute deux ports fluide caloporteur FluidPort (eau) : Water_Inlet et Water_Outlet.

La perte de charge côté air P_drop [Pa] est retranchée à la pression : Outlet.P = Inlet.P - P_drop (nulle par défaut). Le débit d’air sec est conservé : F_dry = F / (1 + w/1000) [kg air sec/s]. Après calcul, chaque batterie remplit un DataFrame df récapitulant l’état de sortie et la puissance thermique.

Note

Convention de signe de Q_th : Q_th = (h_out - h_in) · F_dry. Elle est positive pour un chauffage (apport de chaleur) et négative pour un refroidissement (chaleur extraite).

Batterie chaude sensible — HeatingCoil

Rôle — réchauffe l’air jusqu’à To_target sans modifier son humidité absolue (chauffage sensible, w constant). Si l’air entre déjà plus chaud que la consigne, la batterie reste inactive (Q_th = 0).

Équations :

\[w_{out} = w_{in}, \qquad h_{out} = h(T_{o,target},\, w_{in})\]
\[Q_{th} = (h_{out} - h_{in}) \cdot \dot m_{dry}, \qquad RH_{out} = f\big(P_{v,sat}(T_{o,target}),\, w_{in},\, P_{out}\big)\]

Si To_target <= T_in : h_out = h_in et Q_th = 0.

Paramètres (__init__) :

Attribut

Défaut

Description

To_target

20

Température de consigne en sortie [°C]

P_drop

0

Perte de charge air [Pa]

Inlet / Outlet

AirPort()

Ports air (connectés via Air_connect)

Exemple :

from AHU.FreshAir import FreshAir
from AHU.Coil import HeatingCoil
from AHU.Connect import Air_connect

AN = FreshAir.Object()
AN.T = 5; AN.RH = 80; AN.F_m3h = 3000
AN.calculate()

HC = HeatingCoil.Object()
HC.To_target = 20
Air_connect(HC.Inlet, AN.Outlet)
HC.calculate()
print(HC.df)

Sortie réelle (air neuf 5 °C / 80 % HR, 3000 m³/h) :

Outlet.T (C)              20.000
Outlet.RH (%)             29.800
Outlet.h (kJ/kg)          31.000
Outlet.w (g/kgdry)         4.314
Q_th (kW)                 15.900

L’humidité absolue reste à 4,314 g/kg (chauffage sensible) ; la HR chute de 80 % à 29,8 % et la batterie fournit 15,9 kW.

Batterie chaude à eau (NUT-ε) — HeatingCoilNUT

Rôle — batterie chaude alimentée par un fluide caloporteur (eau). La puissance n’est pas imposée par une consigne d’air mais dimensionnée par la méthode du Nombre d’Unités de Transfert (NUT-ε), à partir de la surface d’échange S et du coefficient global U. Le chauffage reste sensible (w constant).

Connecteurs : ports air Inlet / Outlet et ports eau Water_Inlet / Water_Outlet (FluidPort(fluid='Water')). Les propriétés de l’eau (cp, ρ) sont évaluées via CoolProp.

Équations — débits calorifiques et efficacité :

\[C_{eau} = \dot m_{eau}\, c_{p,eau}, \qquad C_{air} = \dot m_{dry}\, \cdot 1006\]
\[C_{min} = \min(C_{eau}, C_{air}), \qquad C_r = \frac{C_{min}}{C_{max}}, \qquad NUT = \frac{U\,S}{C_{min}}\]

Efficacité (formule codée, échangeur à courants croisés non brassés) :

\[\varepsilon = 1 - \exp\!\left[-\,\frac{NUT\,\big(1 - e^{-C_r\,NUT}\big)}{C_r}\right]\]

Puissance échangée puis état de sortie de l’air :

\[Q_{max} = C_{min}\,(T_{eau,in} - T_{in}), \qquad Q_{th} = \frac{\varepsilon\, Q_{max}}{1000}\ \text{[kW]}\]
\[\Delta T = \frac{Q_{th}\cdot 1000}{\dot m_{dry}\cdot 1006}, \qquad T_{out} = T_{in} + \Delta T, \qquad h_{out} = h(T_{out},\, w_{in})\]

Côté eau, l’enthalpie de sortie est mise à jour par bilan (h_water_out = h_water_in - Q_th·1000 / ṁ_eau) et T_water_out en est déduite. Si To_target <= T_in, Q_th = 0.

Paramètres (__init__) :

Attribut

Défaut

Description

S

10

Surface d’échange [m²]

U

50

Coefficient d’échange global [W/m².K]

To_target

20

Consigne max de sortie air [°C] (garde-fou : au-delà, Q_th conservé)

P_drop

0

Perte de charge air [Pa]

T_water_in / T_water_out

80 / 60

Températures eau [°C] (recalculées depuis Water_Inlet / le bilan)

P_water

3e5

Pression eau [Pa] (lue sur Water_Inlet)

m_water

0

Débit eau [kg/s] (lu sur Water_Inlet)

Exemple (source d’eau chaude ThermodynamicCycles.Source) :

from AHU.FreshAir import FreshAir
from AHU.Connect import Air_connect
from AHU.Coil.HeatingCoilNUT import HeatingCoilNUT
from ThermodynamicCycles.Source import Source

# Source d'eau chaude (fluide caloporteur)
water = Source.Object()
water.fluid = "Water"; water.Ti_degC = 80; water.Pi_bar = 3; water.F_m3h = 1.0
water.calculate()

# Air neuf
AN = FreshAir.Object()
AN.T = 5; AN.RH = 90; AN.F_m3h = 5000
AN.calculate()

# Batterie NUT-ε
HC = HeatingCoilNUT()
HC.S = 10; HC.U = 50; HC.To_target = 20
Air_connect(HC.Inlet, AN.Outlet)     # côté air
HC.Water_Inlet = water.Outlet        # côté eau
HC.calculate()
print(HC.df)

Sortie réelle (air 5 °C / 90 % HR, 5000 m³/h ; eau 80 °C, 1 m³/h ; S=10, U=50) :

Outlet.T (C)                 17.400
Outlet.RH (%)                39.600
Outlet.h (kJ/kg)             29.700
Outlet.w (g/kgdry)            4.858
Q_th (kW)                    21.700
NUT (-)                       0.980
Effectiveness (-)             0.570
T_water_out (C)              60.800

L’efficacité de l’échangeur (0,57) limite l’air soufflé à 17,4 °C (la consigne de 20 °C n’est pas atteinte), pour 21,7 kW, et l’eau ressort à 60,8 °C.

Batterie froide avec déshumidification — CoolingCoil

Rôle — batterie froide qui refroidit et déshumidifie. Le modèle repose sur la droite de saturation : l’air non traité (bypass) se mélange à l’air saturé au contact de la batterie (point de rosée T_sat), pondéré par l’efficacité Eff et son complément le facteur de bypass FB = 1 - Eff.

État de la batterie :

\[w_{sat} = w(T_{sat}, RH{=}100\%,\, P), \qquad h_{sat} = h(T_{sat},\, w_{sat})\]

Le calcul distingue plusieurs cas selon la position de l’air d’entrée :

  • Déshumidification (w_in >= w_target >= w_sat) :

    \[Eff = \frac{w_{in} - w_{target}}{w_{in} - w_{sat}}, \qquad h_{out} = h_{in} - Eff\,(h_{in} - h_{sat})\]
  • Cas intermédiaire (w_sat < w_in <= w_target et T_in >= T_target) :

    \[Eff = \frac{T_{target} - T_{sat}}{T_{in} - T_{sat}}, \quad h_{out} = h_{sat} + Eff\,(h_{in} - h_{sat}), \quad w_{out} = w_{sat} + Eff\,(w_{target} - w_{sat})\]
  • Refroidissement sensible (w_in <= w_sat et T_in >= T_target) : w_out = w_in, sortie amenée à T_target (pas de condensation).

  • Sinon : aucune action (Eff = 0, h_out = h_in).

Puis Q_th = (h_out - h_in) · F_dry (négatif).

Paramètres (__init__) :

Attribut

Défaut

Description

w_target

8

Humidité absolue de consigne en sortie [g/kg air sec]

T_target

0

Température de consigne en sortie [°C]

T_sat

7

Température de surface (point de rosée) de la batterie froide [°C]

Déshutype

"Droite_sat"

Type de déshumidification (droite de saturation)

Eff / FB

0.8 / 0.2

Efficacité / facteur de bypass (recalculés)

P_drop

0

Perte de charge air [Pa]

Exemple (air estival 30 °C / 60 % HR) :

from AHU.FreshAir import FreshAir
from AHU.Coil import CoolingCoil
from AHU.Connect import Air_connect

AN = FreshAir.Object()
AN.T = 30; AN.RH = 60; AN.F_m3h = 5000
AN.calculate()          # w_in ≈ 16.0 g/kg

CC = CoolingCoil.Object()
CC.w_target = 8      # consigne humidité absolue [g/kg]
CC.T_target = 14     # consigne température [°C]
CC.T_sat    = 7      # point de rosée de la batterie [°C]
Air_connect(CC.Inlet, AN.Outlet)
CC.calculate()
print(CC.df)

Sortie réelle :

Outlet.T (C)              11.200
Outlet.RH (%)             96.600
Outlet.h (kJ/kg)          31.400
Outlet.w (g/kgdry)         8.000
Q_th (kW)                -62.000
Eff                        0.818
FB                         0.182

L’humidité passe de 16,0 à 8,0 g/kg (déshumidification), l’air ressort à 11,2 °C proche de la saturation (96,6 % HR) ; la batterie extrait 62 kW pour une efficacité de 0,818 (facteur de bypass 0,182).

Batterie froide sensible (consigne T) — CoolingCoil_Tc

Rôle — refroidissement sensible (w constant) jusqu’à une consigne de température T_target, sans condensation. Efficacité et facteur de bypass sont calculés relativement à la température de surface T_sat.

Équations (si T_in >= T_target) :

\[Eff = \frac{T_{target} - T_{sat}}{T_{in} - T_{sat}}, \qquad FB = 1 - Eff\]
\[w_{out} = w_{in}, \qquad h_{out} = h_s(T_{target},\, P,\, w_{in}), \qquad Q_{th} = (h_{out} - h_{in})\, \dot m_{dry}\]

Sinon, aucune action. Paramètres identiques à CoolingCoil (w_target, T_target, T_sat, P_drop …).

Avertissement

Modèle purement sensible : aucune déshumidification n’est modélisée. Si T_target descend sous le point de rosée de l’air entrant, l’humidité absolue conservée conduit à une HR de sortie > 100 % (état non physique). Réserver ce modèle à l’air peu humide ou aux refroidissements restant au-dessus du point de rosée.

Exemple :

from AHU.Coil import CoolingCoil_Tc

CCt = CoolingCoil_Tc.Object()
CCt.T_target = 18; CCt.T_sat = 7
Air_connect(CCt.Inlet, AN.Outlet)   # AN : air neuf 30 °C / 60 %
CCt.calculate()
print(CCt.df)     # Outlet.w = 16.042 (constant), Q_th ≈ -19.0 kW, Eff ≈ 0.486

Batterie sensible à w constant — CoolingCoil_Sensible

Rôle — transformation sensible simple vers To_target à humidité absolue constante. Le sens est déterminé par To_target : refroidissement si To_target < T_in (Q_th négatif), chauffage sinon. Contrairement à HeatingCoil, aucune condition n’annule le calcul (la transformation est toujours appliquée).

Équations :

\[w_{out} = w_{in}, \quad h_{out} = h(T_{o,target},\, w_{in}), \quad Q_{th} = (h_{out} - h_{in})\,\dot m_{dry}\]

Paramètres : To_target (défaut 20), P_drop (0).

Note

Le code affecte Outlet.F = Inlet.F (annoté « à corriger » dans la source) ; le débit d’air sec Outlet.F_dry reste correct. Une trace de débogage (print) est émise à chaque appel de calculate().

Exemple (refroidissement sensible 30 → 24 °C) :

from AHU.Coil import CoolingCoil_Sensible

CS = CoolingCoil_Sensible.Object()
CS.To_target = 24
Air_connect(CS.Inlet, AN.Outlet)    # AN : air neuf 30 °C / 60 %
CS.calculate()
print(CS.df)     # Outlet.w = 16.042 (constant), Q_th ≈ -9.7 kW, RH_out ≈ 85.3 %

Batterie froide « Expert » — CoolingCoil_Expert

Rôle — variante avancée qui, en cas de déshumidification (w_in >= w_target >= w_sat), résout numériquement (scipy.optimize.fsolve) la température de sortie telle que l’air à w_target atteigne une humidité relative de sortie imposée Outlet_RH (90 % par défaut, ou 100 % si l’air entrant est déjà à plus de 90 % HR). L’enthalpie de sortie vaut alors h(T_out, w_target). Un cas de refroidissement sensible (w_in <= w_target et T_in >= T_target) et un cas « aucune action » sont également prévus.

Paramètres (__init__) : w_target (8), T_target (15), Outlet_RH (90), T_sat (7), P_drop (0).

Avertissement

La résolution fsolve est fragile : selon les conditions d’entrée et l’initialisation (x0 = 1341 Pa, T0 = 12 °C), elle peut diverger vers des températures négatives et lever une ValueError: math domain error dans Air_Pv_sat. Pour un usage robuste, préférer CoolingCoil (déshumidification par droite de saturation, sans résolution numérique).

Variantes historiques (old/)

Le dossier AHU/Coil/old/ conserve des versions antérieures (HeatingCoil.py, CoolingCoil.py, CoolingCoil_Sensible.py, CoolingCoil_Tc.py, CoolingCoil_Expert.py, helpers.py). Elles sont maintenues pour référence historique et remplacées par les modules décrits ci-dessus ; ne pas les utiliser dans un nouveau modèle.

Voir aussi