IA et Énergie : Optimiser la Consommation avec le Prédictif

IA et Énergie : Optimiser la Consommation avec le Prédictif

Les factures d’énergie ont augmenté de 40 à 80 % pour les entreprises françaises entre 2021 et 2024. Dans ce contexte, l’optimisation énergétique n’est plus un sujet RSE — c’est une urgence de compétitivité. Une étude McKinsey de 2024 estime que l’IA prédictive peut réduire la consommation énergétique des bâtiments commerciaux de 15 à 30 % et de l’industrie de 10 à 20 %, sans investissement majeur en infrastructure. Voici comment mettre cette technologie au service de votre PME.

Comprendre les Leviers de l’Optimisation Énergétique par IA

L’IA n’agit pas sur la physique des équipements — elle agit sur le timing et le niveau de leur utilisation. Les trois leviers principaux sont :

  1. Prédiction de la demande : anticiper le besoin énergétique pour éviter les pics
  2. Optimisation du pilotage : ajuster en temps réel les consignes CVC, éclairage, process
  3. Détection d’anomalies : repérer les équipements dégradés qui consomment inutilement

Modéliser la Consommation Énergétique

Collecte des Données — Le Socle de Tout

Un bon modèle prédictif nécessite des données historiques riches. Les compteurs communicants (Linky pour l’électricité, compteurs gaz/eau connectés) fournissent des relevés au pas de 30 minutes — c’est votre point de départ.

import pandas as pd
import numpy as np
from pathlib import Path

def charger_donnees_energie(fichier_csv: str) -> pd.DataFrame:
    """Charger et préparer les données Linky ou compteur industriel."""
    df = pd.read_csv(fichier_csv, parse_dates=["horodatage"])
    df = df.sort_values("horodatage").reset_index(drop=True)

    # Compléter les créneaux manquants (Linky peut avoir des lacunes)
    index_complet = pd.date_range(
        start=df["horodatage"].min(),
        end=df["horodatage"].max(),
        freq="30T"
    )
    df = df.set_index("horodatage").reindex(index_complet)
    df["consommation_kwh"] = df["consommation_kwh"].interpolate(method="time")
    df.index.name = "horodatage"

    return df.reset_index()

def enrichir_features_temporelles(df: pd.DataFrame) -> pd.DataFrame:
    """Ajouter les variables temporelles et météo."""
    df = df.copy()
    ts = df["horodatage"]

    df["heure"] = ts.dt.hour
    df["jour_semaine"] = ts.dt.dayofweek
    df["mois"] = ts.dt.month
    df["est_weekend"] = (df["jour_semaine"] >= 5).astype(int)
    df["est_ferie"] = ts.dt.date.apply(est_jour_ferie_fr).astype(int)  # Calendrier jours fériés FR
    df["trimestre"] = ts.dt.quarter

    # Variables cycliques pour capturer la périodicité
    df["heure_sin"] = np.sin(2 * np.pi * df["heure"] / 24)
    df["heure_cos"] = np.cos(2 * np.pi * df["heure"] / 24)
    df["mois_sin"] = np.sin(2 * np.pi * df["mois"] / 12)
    df["mois_cos"] = np.cos(2 * np.pi * df["mois"] / 12)

    # Lag features (consommation passée = signal fort)
    df["conso_lag_1h"] = df["consommation_kwh"].shift(2)    # 1h avant
    df["conso_lag_24h"] = df["consommation_kwh"].shift(48)  # 24h avant
    df["conso_lag_1sem"] = df["consommation_kwh"].shift(336) # 1 semaine avant

    # Moyenne glissante
    df["conso_moy_7j"] = df["consommation_kwh"].rolling(336, min_periods=1).mean()

    return df.dropna()

Intégrer les Données Météo

La température extérieure est le premier prédicteur de consommation énergétique dans les bâtiments tertiaires (CVC représente 40 à 60 % de la consommation).

import httpx
from datetime import datetime, timedelta

def recuperer_meteo_historique(
    latitude: float,
    longitude: float,
    date_debut: str,
    date_fin: str
) -> pd.DataFrame:
    """API Open-Meteo — gratuite jusqu'à 10 000 appels/jour."""
    url = "https://archive-api.open-meteo.com/v1/archive"
    params = {
        "latitude": latitude,
        "longitude": longitude,
        "start_date": date_debut,
        "end_date": date_fin,
        "hourly": "temperature_2m,relative_humidity_2m,wind_speed_10m,cloud_cover,direct_radiation",
        "timezone": "Europe/Paris"
    }
    response = httpx.get(url, params=params, timeout=30)
    data = response.json()

    df_meteo = pd.DataFrame({
        "horodatage": pd.to_datetime(data["hourly"]["time"]),
        "temperature_c": data["hourly"]["temperature_2m"],
        "humidite_pct": data["hourly"]["relative_humidity_2m"],
        "vent_kmh": data["hourly"]["wind_speed_10m"],
        "couverture_nuageuse": data["hourly"]["cloud_cover"],
        "rayonnement_wm2": data["hourly"]["direct_radiation"]
    })

    # Degree Days de Chauffe (DJC) — indicateur clé pour chauffage
    df_meteo["djc"] = (18 - df_meteo["temperature_c"]).clip(lower=0)
    # Degree Days de Refroidissement (DJR)
    df_meteo["djr"] = (df_meteo["temperature_c"] - 26).clip(lower=0)

    return df_meteo

Prédire la Consommation — Modèle LSTM

Les séries temporelles de consommation présentent des motifs multi-échelles (heure, jour, semaine, saison) que les réseaux LSTM capturent mieux que les modèles classiques.

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader

class DatasetConsommation(Dataset):
    def __init__(self, df: pd.DataFrame, sequence_len: int = 48, horizon: int = 24):
        """
        sequence_len : historique en entrée (48 = 24h à pas 30 min)
        horizon : horizon de prédiction (24 = 12h)
        """
        self.X = []
        self.y = []

        features = df.drop("consommation_kwh", axis=1).values
        target = df["consommation_kwh"].values

        for i in range(len(df) - sequence_len - horizon):
            self.X.append(features[i:i+sequence_len])
            self.y.append(target[i+sequence_len:i+sequence_len+horizon])

        self.X = torch.FloatTensor(np.array(self.X))
        self.y = torch.FloatTensor(np.array(self.y))

    def __len__(self): return len(self.X)
    def __getitem__(self, idx): return self.X[idx], self.y[idx]

class LSTMConsommation(nn.Module):
    def __init__(self, n_features: int, hidden_size: int = 128, horizon: int = 24):
        super().__init__()
        self.lstm = nn.LSTM(
            input_size=n_features,
            hidden_size=hidden_size,
            num_layers=2,
            dropout=0.2,
            batch_first=True
        )
        self.attention = nn.MultiheadAttention(hidden_size, num_heads=4, batch_first=True)
        self.fc = nn.Sequential(
            nn.Linear(hidden_size, 64),
            nn.ReLU(),
            nn.Dropout(0.1),
            nn.Linear(64, horizon)
        )

    def forward(self, x):
        lstm_out, _ = self.lstm(x)
        attn_out, _ = self.attention(lstm_out, lstm_out, lstm_out)
        # Prendre le dernier pas de temps
        return self.fc(attn_out[:, -1, :])

# Entraînement
n_features = X_train.shape[2]
model = LSTMConsommation(n_features=n_features, hidden_size=128, horizon=24)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-4)
criterion = nn.HuberLoss()  # Robuste aux outliers

for epoch in range(50):
    model.train()
    for X_batch, y_batch in loader_train:
        optimizer.zero_grad()
        pred = model(X_batch)
        loss = criterion(pred, y_batch)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
        optimizer.step()

Optimisation CVC — Smart Building

Le Problème du Préchauffage Optimal

Dans un bâtiment de bureaux, le chauffage doit atteindre la consigne à 8h00. Mais le temps de montée en température dépend de la température extérieure, de l’inertie thermique du bâtiment et de l’occupation prévue. L’IA calcule l’heure de démarrage optimale chaque jour.

from scipy.optimize import minimize_scalar
import numpy as np

class OptimiseurCVC:
    def __init__(self, modele_thermique, meteo_prevision):
        self.modele = modele_thermique
        self.meteo = meteo_prevision

    def calculer_heure_demarrage(
        self,
        temperature_actuelle: float,
        consigne_confort: float,
        heure_occupation: int = 8
    ) -> int:
        """
        Retourne l'heure optimale de démarrage du chauffage (0-7h).
        Minimise la consommation tout en garantissant T_confort à T_occupation.
        """
        def cout_total(heure_start):
            # Simuler la montée en température
            temp_finale = self.modele.simuler(
                temperature_actuelle,
                heure_start,
                heure_occupation,
                self.meteo.temperature_prevue
            )
            # Pénalité si consigne non atteinte
            penalite = max(0, consigne_confort - temp_finale) * 1000
            # Coût énergie = durée × puissance × tarif heure creuse/pleine
            tarif = self.meteo.tarif_heure(heure_start)
            duree_h = heure_occupation - heure_start
            cout_energie = duree_h * 10 * tarif  # 10 kW de puissance exemple

            return cout_energie + penalite

        # Optimiser entre 4h et 7h30
        result = minimize_scalar(cout_total, bounds=(4, 7.5), method="bounded")
        return result.x

    def ajuster_consigne_temps_reel(
        self,
        temperature_actuelle: float,
        occupation_prevue: float,  # 0 à 1
        heure_actuelle: int
    ) -> float:
        """Consigne CVC dynamique selon l'occupation réelle."""
        # Sans occupation → mode Hors-Gel (8°C)
        if occupation_prevue < 0.1:
            return 8.0
        # Occupation partielle → consigne réduite
        elif occupation_prevue < 0.5:
            return 18.0
        # Pleine occupation → consigne confort
        else:
            return 20.0

Détection des Équipements Énergivores

Un équipement défectueux (compresseur avec fuite de frigorigène, moteur avec roulement usé) peut consommer 20 à 50 % de plus que la normale. La détection d’anomalie le signale avant la panne.

from sklearn.ensemble import IsolationForest
import pandas as pd

class DetecteurEquipementEnergivore:
    def __init__(self, contamination: float = 0.05):
        self.modele = IsolationForest(
            n_estimators=200,
            contamination=contamination,  # 5% de points anormaux attendus
            random_state=42
        )
        self.seuil_alerte = None

    def entrainer(self, df_normal: pd.DataFrame, cols_features: list):
        """Entraîner sur des données de fonctionnement normal."""
        X = df_normal[cols_features].values
        self.modele.fit(X)
        scores = -self.modele.score_samples(X)
        self.seuil_alerte = np.percentile(scores, 95)
        print(f"Seuil d'anomalie calibré : {self.seuil_alerte:.3f}")

    def detecter(self, df_courant: pd.DataFrame, cols_features: list) -> pd.DataFrame:
        X = df_courant[cols_features].values
        scores = -self.modele.score_samples(X)
        df_courant = df_courant.copy()
        df_courant["score_anomalie"] = scores
        df_courant["est_anomalie"] = scores > self.seuil_alerte

        anomalies = df_courant[df_courant["est_anomalie"]]
        if len(anomalies) > 0:
            print(f"⚠️  {len(anomalies)} créneaux anormaux détectés !")
            print(f"Consommation anormale moyenne : {anomalies['consommation_kwh'].mean():.1f} kWh")

        return df_courant

# Usage
detecteur = DetecteurEquipementEnergivore()
detecteur.entrainer(df_normal, ["consommation_kwh", "temperature_c", "occupation"])

# Analyser la semaine courante
df_analyse = detecteur.detecter(df_semaine_courante, ["consommation_kwh", "temperature_c", "occupation"])

Green AI — Réduire l’Empreinte Carbone de l’IA Elle-Même

L’IA consomme elle-même de l’énergie. Un modèle GPT-4 consomme environ 10 Wh par requête. À l’échelle d’une organisation faisant 10 000 requêtes par jour, cela représente 36 MWh/an — équivalent à la consommation annuelle d’un appartement. Quelques bonnes pratiques :

OptimisationÉconomie estimée
Utiliser Haiku/Mistral 7B au lieu de GPT-4 quand possible80-95 % de l’énergie par requête
Mettre en cache les réponses identiques30-60 % du volume de requêtes
Quantifier les modèles locaux (INT8)50-70 % énergie inference
Entraîner en heures creuses (énergie renouvelable)20-40 % émissions CO2
Utiliser des régions cloud à énergie verte50-90 % émissions CO2
import anthropic
import hashlib
import json
from pathlib import Path

class CacheRequetesLLM:
    """Cache disque pour éviter les appels LLM redondants."""
    def __init__(self, dossier_cache: str = ".llm_cache"):
        self.dossier = Path(dossier_cache)
        self.dossier.mkdir(exist_ok=True)
        self.client = anthropic.Anthropic()
        self.hits = 0
        self.misses = 0

    def _cle_cache(self, prompt: str, modele: str) -> str:
        return hashlib.sha256(f"{modele}:{prompt}".encode()).hexdigest()

    def generer(self, prompt: str, modele: str = "claude-3-5-haiku-20241022") -> str:
        cle = self._cle_cache(prompt, modele)
        fichier_cache = self.dossier / f"{cle}.json"

        if fichier_cache.exists():
            self.hits += 1
            return json.loads(fichier_cache.read_text())["reponse"]

        self.misses += 1
        response = self.client.messages.create(
            model=modele,
            max_tokens=512,
            messages=[{"role": "user", "content": prompt}]
        )
        reponse = response.content[0].text
        fichier_cache.write_text(json.dumps({"reponse": reponse, "modele": modele}))
        return reponse

    def stats(self):
        total = self.hits + self.misses
        print(f"Taux de cache : {self.hits/total:.0%} ({self.hits} hits / {self.misses} misses)")
        print(f"Économie estimée : {self.hits * 0.01:.2f} € (à 0,01€/requête)")

ROI — Chiffrer les Gains pour une PME

Exemple : Immeuble de Bureaux 3 000 m²

Action IAÉconomie estiméeInvestissementRetour
Prédiction CVC + pilotage optimal18 000 €/an8 000 €5 mois
Détection équipements énergivores6 000 €/an3 000 €6 mois
Optimisation éclairage (présence)4 000 €/an2 500 €7 mois
Total28 000 €/an13 500 €6 mois

Exemple : Atelier Industriel 500 kW installés

Un process industriel avec 500 kW de puissance installée et 4 000 heures/an de fonctionnement consomme environ 2 000 MWh/an. À 0,15 €/kWh, la facture annuelle atteint 300 000 €. Une réduction de 15 % par optimisation IA = 45 000 €/an d’économie.

Conclusion

L’IA prédictive appliquée à l’énergie est l’un des retours sur investissement les plus rapides dans le domaine de l’intelligence artificielle : les modèles s’appuient sur des données déjà disponibles (compteurs communicants, capteurs existants), les gains sont mesurables immédiatement, et les retours sur investissement s’atteignent en 6 à 12 mois dans la plupart des cas.

La démarche recommandée : commencer par la modélisation de la consommation sur 12 mois d’historique, identifier les 3 postes les plus énergivores, déployer un premier modèle prédictif sur ces postes, mesurer les gains sur 3 mois, puis étendre.

Vos factures d’énergie explosent et vous cherchez des leviers d’action concrets ? Contactez-nous à contact@brio-novia.eu — nous réalisons un audit énergétique augmenté par IA et identifions avec vous les économies atteignables dès les 6 prochains mois.