Bilan : une heure de nuit n'a aucune forme a minorer

Le drapeau « degrade » introduit la veille s'allumait de 20 h a 07 h toutes les
nuits. La qualite de forme d'une heure vient du taux de censure ; les heures
sans soleil portent un taux de 1 faute d'avoir quoi que ce soit a observer, pas
parce que la mesure serait douteuse. Comme les heures de deficit sont justement
les heures sans soleil, le drapeau se declenchait exactement quand le bilan
sert.

Une heure dont l'enveloppe demontree est nulle recoit desormais la qualite
'nuit'. Scenario epingle sur l'enveloppe et le taux de censure releves en
production, pas sur le fixture — dont la nuit valait 0 et qui ne reproduisait
donc pas le defaut. Preuve par mutation : avant 'minoree', apres 'nuit'.

Suite 37 -> 38. Documente la nuit du 25-26/08 : profil corrige verifie a
0,2 kWh/h pres, bilan qui predit le point bas a un point pres, et non-linearite
du SOC mesuree (huit points en dix-sept minutes pour 0,16 kWh).
This commit is contained in:
Tallagrand Thierry
2026-08-26 12:14:35 +02:00
parent 08c072d781
commit 8ad34f8c93
5 changed files with 189 additions and 2 deletions

View File

@@ -425,6 +425,151 @@ l'utilisateur. C'est voulu pour un câblage réel en période d'essai, mais il f
le savoir — et le retirer le jour où le câblage sera adopté.
## 26/08/2026 — La nuit qui valide le bilan, et le défaut du mètre
### Déroulé (véhicule débranché à 03:01, donc hors mécanique de nuit EVCS)
| Heure | Événement |
|---|---|
| 01:24:03 | Fenêtre HC → EDF ON, charge du véhicule dès 01:25:30 |
| 02:52:30 | Fin de charge détectée → `night_recovery_done_idle` |
| 02:53:03 | EDF coupé **3 secondes** plus tard |
| 03:01 | Débranchement |
| 05:10 | SOC affiché 20 % → EDF ON (branche « SOC bas » de l'hystérésis) |
| 06:18 | SOC affiché 30 % → EDF OFF |
| 09:06 | Point bas de la nuit : 23 % affichés, puis le PV prend le relais |
Réseau importé : 5,70 kWh pour le véhicule (01 h et 02 h, mesurés sur
`energy_from_ac_in_1_to_ac_out`) et 1,71 kWh pour la batterie (05:10-06:19,
intégration de `battery_power`). **Aucun yoyo** : une seule session, 69 minutes,
20 → 30 %. L'hystérésis a fait exactement ce pour quoi elle est écrite.
### Le profil de consommation corrigé colle à la mesure
Le correctif d'attribution horaire de la veille se vérifie sur une nuit
complète — profil publié contre consommation réellement mesurée :
| Heure | p50 publié | Mesuré | Heure | p50 publié | Mesuré |
|---|---:|---:|---|---:|---:|
| 21 h | 1,60 | 1,50 | 03 h | 0,70 | 0,80 |
| 22 h | 1,40 | 1,40 | 04 h | 0,70 | 0,70 |
| 23 h | 1,30 | 1,20 | 07 h | 0,70 | 0,70 |
| 00 h | 1,10 | 1,00 | 08 h | 0,80 | 0,70 |
Écart maximal 0,2 kWh/h. Le matin ne porte plus l'import réseau de la nuit
suivante.
### Le bilan a prédit le point bas de la nuit à un point près
`required_soc` publié heure par heure, contre le SOC réellement observé :
| Heure | Requis | Réel | Marge |
|---|---:|---:|---:|
| 21 h | 90,5 | 69 | −21,5 |
| 00 h | 62,7 | 45 | −17,7 |
| 03 h | 46,2 | 36 | −10,2 |
| 06 h | 32,1 | 29 | −3,1 |
| 07 h | 27,5 | 27 | −0,5 |
| 08 h | 23,3 | 24 | **+0,7** |
| 09 h | 22,0 | 23 | **+1,0** |
Le bilan annonçait le croisement à 09 h : le point bas est tombé à 09:06. Il
annonçait 22 % nécessaires à 09 h : la batterie a touché 23 %. C'est la
première validation quantitative du modèle sur une nuit entière.
Deux conséquences immédiates :
1. **Le seuil fixe a coupé une fois de trop tôt.** À 06:00 le bilan demandait
32,1 %, `grid_soc_off` a coupé à 30 %. La batterie est ensuite descendue à
23 %, soit **un point au-dessus du plancher dur**. Le seuil fixe n'était pas
grossièrement faux — il était court de 2 points, et c'est le lever du jour
qui a payé la différence. Une matinée couverte aurait traversé le plancher.
2. **La cible SOC du matin n'a joué aucun rôle cette nuit.** Le véhicule est
parti à 03:01, donc `nightSessionActive` est retombé à faux et toute la
mécanique de nuit EVCS avec lui. Ce sont `grid_soc_on`/`grid_soc_off`
(20/30, dans le workflow d'hystérésis) qui ont gouverné — et **le conseiller
IA ne peut pas les toucher**, même toggle activé.
### Le défaut du mètre : le SOC n'est pas linéaire dans la bande qui décide
Énergie réellement échangée par point de SOC, mesurée par intégration de
`sensor.victron_battery_power` :
| Fenêtre | ΔSOC | Énergie | kWh / point | Capacité implicite |
|---|---:|---:|---:|---:|
| 69 → 39 % (décharge) | 30 | 5,11 kWh | 0,170 | 17,0 kWh |
| **35 → 20 % (décharge)** | **15** | **1,07 kWh** | **0,071** | **7,1 kWh** |
| 20 → 30 % (charge) | 10 | 1,71 kWh | 0,171 | 17,1 kWh |
| 30 → 23 % (décharge) | 7 | 1,19 kWh | 0,170 | 17,0 kWh |
| 23 → 80 % (charge) | 57 | 9,06 kWh | 0,159 | 15,9 kWh |
Tout vaut 0,16-0,17 kWh par point — sauf la descente 35 → 20 %, qui n'en vaut
que 0,071. En regardant de plus près, la chute est concentrée : **de 04:17 à
04:34, le SOC affiché passe de 32 % à 24 %, huit points en dix-sept minutes**,
sous une décharge parfaitement stable de 560 W. Huit points « coûtent » 0,16 kWh
là où ils devraient en coûter 1,3.
La tension tranche : 48,81 V à 04:17, 48,75 V à 04:34, soit 60 mV pour huit
points, quand les six points précédents en avaient consommé 200. **Le pack n'a
pas perdu cette énergie ; c'est l'estimateur qui a décroché.** Comportement
classique d'un BMS Pylontech dont un module est plus faible que les autres — et
le parc en compte un mort isolé et un second qui faiblit (§0 du manuel).
Conséquence directe : la session réseau de 05:10 a été déclenchée par un « 20 % »
qui valait physiquement 26 à 28 %. Elle restait justifiée au fond — le bilan
demandait 36,9 % à 05:00 — mais elle a été **déclenchée par le mauvais
instrument, pour la bonne raison, par hasard**.
### Le drapeau « dégradé » criait au loup toutes les nuits
Introduit la veille, il a affiché `degrade` de 20:00 à 07:00. Cause : dans
`RESOURCE_ESTIMATE.js`, la qualité de forme d'une heure vient du taux de
censure, et les heures de nuit portent un taux de 1 — non pas parce que la
mesure serait douteuse, mais parce qu'il n'y a jamais eu de soleil à observer.
Or les heures de déficit *sont* les heures sans soleil : le drapeau se
déclenchait donc **toutes les nuits, c'est-à-dire exactement quand le bilan
sert**. Le commentaire du code disait déjà la bonne règle ; le code ne
l'appliquait pas.
Correctif : une heure dont l'enveloppe démontrée est nulle reçoit la qualité
`'nuit'` et non `'minoree'` — elle n'a aucune forme à minorer. Scénario
`ressource-nuit-forme-non-minoree`, épinglé sur l'enveloppe et le taux de
censure **relevés en production**, pas sur le fixture (dont la nuit valait 0 et
qui ne reproduisait donc pas le défaut — le piège du 24/08, à nouveau). Preuve
par mutation : code d'avant → `minoree`, après → `nuit`. Suite 37 → 38.
### Conclusion sur la cible SOC du matin
Trois arguments convergent, et ils déplacent la cible du chantier :
1. **La bonne grandeur n'est pas un SOC, c'est une énergie.** Le bilan calcule
déjà l'énergie à couvrir jusqu'au croisement, et il vient de le faire à un
point près sur douze heures. La cible de 35 % est une valeur de table ; la
valeur physique de cette nuit-là était 32,1 % à 06:00.
2. **Convertir une énergie en points de SOC réimporte le défaut du mètre.**
`usable_capacity_kwh = 15` appliqué linéairement suppose que tous les points
se valent ; les mesures ci-dessus montrent que ceux de la bande 24-32 %,
celle où se prennent toutes les décisions de nuit, peuvent ne rien valoir.
Tant que la conversion reste linéaire, câbler l'advisor sur la cible ne fait
que déplacer un nombre arbitraire vers un nombre calculé sur une règle
graduée fausse.
3. **La cible du matin n'est pas le seuil qui gouverne le plus souvent.** Elle
ne s'applique qu'avec un véhicule branché pendant la fenêtre HC. Les nuits
sans véhicule — celle-ci — sont gouvernées par `grid_soc_off`, que personne
n'arbitre et que le conseiller ne voit même pas.
Ordre de travail qui en découle, avant tout câblage :
- **a.** Rendre la conversion énergie ↔ SOC honnête : soit une courbe de
capacité par bande de SOC construite sur l'historique (la donnée existe, elle
vient d'être mesurée), soit un drapeau qui signale que le SOC vient de
décrocher et qu'il ne faut pas décider dessus pendant N minutes.
- **b.** Donner au bilan le seuil qui gouverne réellement : `grid_soc_off`,
côté hystérésis. C'est le chiffre qui a manqué de 2 points cette nuit, et
c'est le seul que le conseiller ne peut pas atteindre aujourd'hui.
- **c.** Ensuite seulement, la cible SOC du matin — qui deviendra un
sous-produit du bilan plutôt qu'un réglage indépendant.
## Backlog
- [ ] **Doublon `unique_id: victron_vebus_dc_power`** — déclaré deux fois, avec