Section 5 : Usages finaux de l’énergie
5.1. Module AHU - Centrales de Traitement d’Air (CTA)
Le module AHU permet de modéliser les centrales de traitement d’air avec leurs différents composants.
5.1.1. FreshAir - Mélange d’air neuf et air recyclé
from energysystemmodels.AHU import FreshAir
# Configuration du mélange
fresh_air = FreshAir(
debit_air_neuf_m3_h=3000,
debit_air_recycle_m3_h=7000,
temperature_ext_C=5,
humidite_ext_pct=80,
temperature_reprise_C=22,
humidite_reprise_pct=45
)
# Calculer l'état du mélange
etat_melange = fresh_air.calculer_etat_melange()
print(f"Température du mélange : {etat_melange['temperature_C']:.1f}°C")
print(f"Humidité relative : {etat_melange['humidite_relative_pct']:.1f}%")
print(f"Humidité absolue : {etat_melange['humidite_absolue_g_kg']:.2f} g/kg")
print(f"Enthalpie : {etat_melange['enthalpie_kJ_kg']:.2f} kJ/kg")
Diagramme psychrométrique
from energysystemmodels.AHU import FreshAir
import matplotlib.pyplot as plt
fresh_air = FreshAir(
debit_air_neuf_m3_h=3000,
debit_air_recycle_m3_h=7000,
temperature_ext_C=5,
humidite_ext_pct=80,
temperature_reprise_C=22,
humidite_reprise_pct=45
)
# Tracer le diagramme psychrométrique
fig = fresh_air.plot_psychrometric_chart()
plt.show()
5.1.2. HeatingCoil - Batterie chaude
from energysystemmodels.AHU import HeatingCoil
# Batterie chaude à eau
batterie = HeatingCoil(
type_batterie="eau_chaude",
puissance_nominale_kW=50,
temperature_entree_eau_C=80,
temperature_sortie_eau_C=60,
efficacite=0.85
)
# Air à chauffer
debit_air = 10000 # m³/h
T_air_entree = 10 # °C
# Calculer le chauffage
resultats = batterie.calculer_chauffage(
debit_air_m3_h=debit_air,
temperature_air_entree_C=T_air_entree
)
print(f"Puissance de chauffage : {resultats['puissance_kW']:.2f} kW")
print(f"Température air sortie : {resultats['temperature_air_sortie_C']:.1f}°C")
print(f"Débit d'eau : {resultats['debit_eau_m3_h']:.2f} m³/h")
Exemple : Dimensionnement d’une batterie chaude
from energysystemmodels.AHU import HeatingCoil
# Conditions de dimensionnement
debit_air = 15000 # m³/h
T_air_entree = 5 # °C
T_air_sortie_voulue = 18 # °C
T_eau_aller = 80 # °C
T_eau_retour = 60 # °C
# Calculer la puissance nécessaire
rho_air = 1.2 # kg/m³
cp_air = 1.005 # kJ/kg.K
debit_massique_air = debit_air / 3600 * rho_air # kg/s
puissance_requise = debit_massique_air * cp_air * (T_air_sortie_voulue - T_air_entree)
print(f"Puissance requise : {puissance_requise:.2f} kW")
# Créer la batterie avec cette puissance
batterie = HeatingCoil(
type_batterie="eau_chaude",
puissance_nominale_kW=puissance_requise,
temperature_entree_eau_C=T_eau_aller,
temperature_sortie_eau_C=T_eau_retour,
efficacite=0.90
)
# Vérifier les performances
resultats = batterie.calculer_chauffage(debit_air, T_air_entree)
print(f"Température air sortie obtenue : {resultats['temperature_air_sortie_C']:.1f}°C")
5.1.3. Humidifier - Humidificateur
from energysystemmodels.AHU import Humidifier
# Humidificateur à vapeur
humidificateur = Humidifier(
type_humidificateur="vapeur",
capacite_kg_h=30,
efficacite=0.95
)
# Air à humidifier
debit_air = 10000 # m³/h
T_air = 20 # °C
HR_entree = 30 # %
HR_souhaitee = 50 # %
# Calculer l'humidification
resultats = humidificateur.calculer_humidification(
debit_air_m3_h=debit_air,
temperature_C=T_air,
humidite_relative_entree_pct=HR_entree,
humidite_relative_sortie_pct=HR_souhaitee
)
print(f"Débit de vapeur nécessaire : {resultats['debit_vapeur_kg_h']:.2f} kg/h")
print(f"Puissance consommée : {resultats['puissance_kW']:.2f} kW")
print(f"Humidité absolue entrée : {resultats['humidite_abs_entree_g_kg']:.2f} g/kg")
print(f"Humidité absolue sortie : {resultats['humidite_abs_sortie_g_kg']:.2f} g/kg")
Exemple complet : CTA complète
from energysystemmodels.AHU import FreshAir, HeatingCoil, CoolingCoil, Humidifier, Fan
# Conditions extérieures hiver
T_ext = 5 # °C
HR_ext = 80 # %
# Conditions intérieures
T_reprise = 22 # °C
HR_reprise = 45 # %
# Consigne soufflage
T_soufflage = 18 # °C
HR_soufflage = 50 # %
# Débits
debit_air_neuf = 3000 # m³/h
debit_air_recycle = 7000 # m³/h
debit_total = debit_air_neuf + debit_air_recycle
print("=== SIMULATION CTA HIVER ===\n")
# 1. Mélange air neuf / air recyclé
fresh_air = FreshAir(
debit_air_neuf_m3_h=debit_air_neuf,
debit_air_recycle_m3_h=debit_air_recycle,
temperature_ext_C=T_ext,
humidite_ext_pct=HR_ext,
temperature_reprise_C=T_reprise,
humidite_reprise_pct=HR_reprise
)
etat_melange = fresh_air.calculer_etat_melange()
print(f"1. Après mélange :")
print(f" T = {etat_melange['temperature_C']:.1f}°C")
print(f" HR = {etat_melange['humidite_relative_pct']:.1f}%\n")
# 2. Chauffage
batterie_chaude = HeatingCoil(
type_batterie="eau_chaude",
puissance_nominale_kW=80,
temperature_entree_eau_C=80,
temperature_sortie_eau_C=60,
efficacite=0.90
)
resultats_chauffage = batterie_chaude.calculer_chauffage(
debit_air_m3_h=debit_total,
temperature_air_entree_C=etat_melange['temperature_C']
)
print(f"2. Après batterie chaude :")
print(f" T = {resultats_chauffage['temperature_air_sortie_C']:.1f}°C")
print(f" Puissance = {resultats_chauffage['puissance_kW']:.2f} kW\n")
# 3. Humidification
humidificateur = Humidifier(
type_humidificateur="vapeur",
capacite_kg_h=50,
efficacite=0.95
)
# Calculer HR après chauffage (approximation)
HR_apres_chauffage = etat_melange['humidite_relative_pct'] * \
etat_melange['temperature_C'] / \
resultats_chauffage['temperature_air_sortie_C']
resultats_humidif = humidificateur.calculer_humidification(
debit_air_m3_h=debit_total,
temperature_C=resultats_chauffage['temperature_air_sortie_C'],
humidite_relative_entree_pct=HR_apres_chauffage,
humidite_relative_sortie_pct=HR_soufflage
)
print(f"3. Après humidification :")
print(f" HR = {HR_soufflage}%")
print(f" Vapeur = {resultats_humidif['debit_vapeur_kg_h']:.2f} kg/h")
print(f" Puissance = {resultats_humidif['puissance_kW']:.2f} kW\n")
# 4. Ventilateur
ventilateur = Fan(
type_ventilateur="centrifuge",
debit_nominal_m3_h=debit_total,
pression_statique_Pa=800,
rendement=0.75
)
puissance_ventilateur = ventilateur.calculer_puissance()
print(f"4. Ventilateur :")
print(f" Puissance = {puissance_ventilateur:.2f} kW\n")
# Bilan énergétique total
print("=== BILAN ÉNERGÉTIQUE ===")
puissance_totale = (resultats_chauffage['puissance_kW'] +
resultats_humidif['puissance_kW'] +
puissance_ventilateur)
print(f"Puissance totale CTA : {puissance_totale:.2f} kW")
Exemple issu des tests : GenericAHU (Recycling)
from AHU.GenericAHU import GenericAHU
ahu = GenericAHU()
results = ahu.run_simulation(
file_path='test/AHU/data/config_recycling.xlsx',
sheet_name='1. Air Recycling AHU Input',
output_file='test/AHU/data/results_recycling.xlsx'
)
print("Nombre de points simulés:", len(results))
print("Colonnes de sortie:", results.shape[1])
print("Puissance Chauffage moyenne:", results['HC_Q_th[kW]'].mean())
5.2. Module PinchAnalysis - Analyse Pinch
L’analyse Pinch permet d’optimiser les réseaux d’échangeurs de chaleur et de minimiser la consommation énergétique.
Exemple : Analyse Pinch simple
from energysystemmodels.PinchAnalysis import PinchAnalysis, Stream
# Définir les courants chauds
hot_streams = [
Stream(name="H1", T_in=180, T_out=60, heat_flow=300), # kW
Stream(name="H2", T_in=150, T_out=40, heat_flow=200)
]
# Définir les courants froids
cold_streams = [
Stream(name="C1", T_in=20, T_out=135, heat_flow=250),
Stream(name="C2", T_in=80, T_out=140, heat_flow=150)
]
# Créer l'analyse Pinch
pinch = PinchAnalysis(
hot_streams=hot_streams,
cold_streams=cold_streams,
delta_T_min=10 # Pincement minimal 10°C
)
# Calculer les résultats
resultats = pinch.analyze()
print(f"Température de pincement : {resultats['pinch_temperature']}°C")
print(f"Besoin minimum de chauffage : {resultats['hot_utility_min']:.0f} kW")
print(f"Besoin minimum de refroidissement : {resultats['cold_utility_min']:.0f} kW")
print(f"Récupération de chaleur possible : {resultats['heat_recovery']:.0f} kW")
print(f"Économie potentielle : {resultats['energy_savings_pct']:.1f}%")
Courbes composites
from energysystemmodels.PinchAnalysis import PinchAnalysis
import matplotlib.pyplot as plt
# Utiliser l'analyse précédente
fig = pinch.plot_composite_curves()
plt.show()
Exemple complet : Optimisation d’un procédé industriel
from energysystemmodels.PinchAnalysis import PinchAnalysis, Stream
# Procédé industriel avec 4 courants chauds et 3 courants froids
hot_streams = [
Stream(name="Reactor outlet", T_in=220, T_out=40, heat_flow=500),
Stream(name="Distillation", T_in=180, T_out=60, heat_flow=400),
Stream(name="Product cooling", T_in=150, T_out=80, heat_flow=300),
Stream(name="Exhaust gases", T_in=350, T_out=120, heat_flow=250)
]
cold_streams = [
Stream(name="Feed preheating", T_in=20, T_out=180, heat_flow=450),
Stream(name="Reboiler", T_in=140, T_out=145, heat_flow=350),
Stream(name="Process water", T_in=15, T_out=90, heat_flow=200)
]
# Analyse avec différents pincements
delta_T_values = [5, 10, 15, 20]
print("Analyse de sensibilité au pincement :")
print("-" * 80)
print(f"{'ΔTmin (°C)':<12} {'Chauffage (kW)':<18} {'Refroid. (kW)':<18} {'Récup. (%)':<15}")
print("-" * 80)
for delta_T in delta_T_values:
pinch = PinchAnalysis(hot_streams, cold_streams, delta_T_min=delta_T)
resultats = pinch.analyze()
print(f"{delta_T:<12.0f} {resultats['hot_utility_min']:<18.0f} "
f"{resultats['cold_utility_min']:<18.0f} "
f"{resultats['energy_savings_pct']:<15.1f}")
# Analyse détaillée avec ΔTmin = 10°C
print("\n=== Configuration optimale (ΔTmin = 10°C) ===")
pinch_optimal = PinchAnalysis(hot_streams, cold_streams, delta_T_min=10)
resultats_optimal = pinch_optimal.analyze()
print(f"\nBilan énergétique :")
print(f" Chaleur disponible : {resultats_optimal['total_hot_available']:.0f} kW")
print(f" Chaleur requise : {resultats_optimal['total_cold_required']:.0f} kW")
print(f" Récupération interne : {resultats_optimal['heat_recovery']:.0f} kW")
print(f" Utilité chaude nécessaire : {resultats_optimal['hot_utility_min']:.0f} kW")
print(f" Utilité froide nécessaire : {resultats_optimal['cold_utility_min']:.0f} kW")
# Tracer les courbes composites
fig = pinch_optimal.plot_composite_curves()
plt.show()
Exemple issu des tests : PinchAnalysis sur données réelles
from PinchAnalysis import PinchAnalysis
import pandas as pd
data = {
'id': [1, 2, 3, 4],
'name': ['C1', 'H1', 'C2', 'H2'],
'mCp': [2.0, 3.0, 4.0, 1.5],
'Ti': [20, 170, 80, 150],
'To': [135, 60, 140, 30],
'dTmin2': [5, 5, 5, 5],
}
liste_flux = pd.DataFrame(data)
Pinch_study = PinchAnalysis.Object(liste_flux)
print(Pinch_study.Pinch_Temperature)
print(Pinch_study.Heating_duty)
print(Pinch_study.Cooling_duty)
5.3. Module IPMVP - International Performance Measurement and Verification Protocol
Le module IPMVP mesure et vérifie les économies d’énergie (Option C). La
fonction Mathematical_Models ajuste un modèle de baseline puis quantifie les
économies ; elle retourne un tuple de 9 éléments (il n’existe pas de classe
IPMVPModel ni IPMVPReport).
import pandas as pd
from datetime import datetime
from IPMVP.IPMVP import Mathematical_Models, incertitude_savings
df = pd.read_excel("src/IPMVP/IPMVP_input.xlsx")
df["Mois"] = pd.to_datetime(df["Mois"])
df = df.set_index("Mois")
col_conso = [c for c in df.columns if c.lower().startswith("consommation")][0]
X, y = df[["DJU"]], df[col_conso]
(y_pred, df_bl, conformite, table_inc,
y_pred_report, df_report, conformite_report, table_inc_report,
df_savings) = Mathematical_Models(
y, X,
datetime(2016, 9, 1), datetime(2021, 5, 1), # période de référence
datetime(2021, 10, 1), datetime(2022, 10, 1), # période de suivi
degree=1, seuil_z_scores=3, site="exemple_site",
print_report=True, # rapport .docx + figures matplotlib
)
print(df_bl) # coefficients + indicateurs (r2, rmse, cv_rmse, stat_t…)
print(conformite) # verdict de conformité IPMVP
print(df_savings) # économies ANTE-POST / POST-ANTE
Sortie réelle (extrait) : r2 = 0,81, économie ANTE-POST = 18,15 %.
Chapitre détaillé : exemple complet, mesure des économies, incertitude propagée
(incertitude_savings), paramètres et théorie dans IPMVP - Mesure et Vérification.
5.4. Modèle RC de bâtiment
Le modèle RC (Résistance-Capacité) permet de simuler le comportement thermique dynamique d’un bâtiment.
Modèle RC simple (1R1C)
from energysystemmodels.BuildingModel import RC_Model
# Paramètres du bâtiment
modele_rc = RC_Model(
resistance_thermique=0.01, # K/W
capacite_thermique=50e6, # J/K
surface_vitree_m2=30,
orientation_vitrage=180, # Sud
apports_internes_W=500
)
# Conditions initiales
T_interieure_initiale = 20 # °C
# Simulation sur 24h
import numpy as np
heures = np.arange(0, 24, 1)
temperatures_ext = 10 + 5 * np.sin(2 * np.pi * (heures - 6) / 24)
temperatures_int = []
T_int = T_interieure_initiale
for h, T_ext in zip(heures, temperatures_ext):
T_int = modele_rc.simuler_pas_de_temps(
T_interieure=T_int,
T_exterieure=T_ext,
rayonnement_solaire_W_m2=max(0, 500 * np.sin(np.pi * (h - 6) / 12)),
dt_seconds=3600
)
temperatures_int.append(T_int)
# Affichage
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
plt.plot(heures, temperatures_ext, label='T° extérieure', linewidth=2)
plt.plot(heures, temperatures_int, label='T° intérieure', linewidth=2)
plt.xlabel('Heure')
plt.ylabel('Température (°C)')
plt.title('Modèle RC 1R1C - Évolution des températures')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
Modèle RC avancé (2R2C)
from energysystemmodels.BuildingModel import RC_Model_Advanced
# Modèle 2R2C avec inertie lourde et légère
modele_2r2c = RC_Model_Advanced(
R_envelope=0.005, # K/W - Résistance enveloppe
R_internal=0.003, # K/W - Résistance interne
C_light=10e6, # J/K - Capacité légère (air)
C_heavy=100e6, # J/K - Capacité lourde (structure)
surface_vitree_m2=40,
apports_internes_W=800
)
# Simulation avec chauffage
T_consigne = 20 # °C
resultats_simulation = modele_2r2c.simuler_periode(
T_ext_serie=temperatures_ext,
T_consigne=T_consigne,
puissance_chauffage_max_W=5000,
dt_seconds=3600
)
print(f"Consommation de chauffage : {resultats_simulation['energie_chauffage_kWh']:.1f} kWh")
print(f"Température moyenne : {np.mean(resultats_simulation['temperatures_int']):.1f}°C")