La conversion energie/SOC devient une courbe mesuree, pas une constante

576 paliers de SOC mesures sur 8 jours (tools/mesure-courbe-batterie.mjs,
ajoute) : pour chaque palier ou le SOC reste a une valeur puis descend d un
point, on integre la puissance batterie, en ecartant les paliers ou la batterie
a charge et ceux ou le reseau a apporte quoi que ce soit.

Resultat : plate a 0,169 kWh/point de 33 a 93 — six tranches independantes entre
0,163 et 0,171 — genou net a 32-33, puis 0,097 en dessous. Sous le genou un
point de SOC vaut 57 % de ce qu il vaut au-dessus, ce qui est coherent avec le
parc reel (un module en panne sur huit, un autre qui faiblit).

Energie utile totale de 100 a 22 % : 12,39 kWh mesures, contre 11,70 vus par le
bilan (15 kWh a plat) et 13,65 par INPUT_PARSE (17,5). Les deux constantes
etaient fausses, dans des sens opposes.

Comme 15 kWh se situe ENTRE les deux pentes, l erreur changeait de signe : SOC
requis trop bas de 3 a 4 points pour un petit deficit, trop haut de 4 a 6 pour
un gros. Cela corrige au passage une affirmation inexacte de la section 40, ou
j avais ecrit que required_soc etait systematiquement trop bas d un facteur
1,75 : ce facteur comparait la vitesse de descente du SOC a celle de la ligne,
deux grandeurs differentes, et l ecart venait surtout de la sous-estimation de
la consommation par le profil p50. La correction est posee en tete de la
section 40.

Trois fonctions remplacent les cinq conversions lineaires de BALANCE.js ;
requiredSocAtStartPct reste non ecrete au-dela de 100, l extrapolation utilisant
la pente haute. INPUT_PARSE passe de 17,5 a 16,9 avec la consigne explicite
qu un calcul traversant le genou doit lire la courbe et non cette constante.

Tests du bilan 42/42 apres mise a jour deliberee de six attendus, chacun verifie
a la main contre la courbe. Un libelle corrige : le seuil fixe de 30 % tombait
juste ce matin-la par coincidence, pas par construction. Deux mutations — pente
basse ramenee a la pente haute, puis genou ramene au plancher — font tomber les
six memes scenarios. Golden 78, hysteresis 7 et advisor inchanges.

Les trois nombres sont des resultats de mesure, pas des reglages, et vivent dans
le code avec l outil qui les produit ; a rejouer apres l extension du parc.

Principale erreur restante du bilan, desormais devant la conversion : le profil
de consommation p50 sous-estimait de 33 % les heures 03-06 de la nuit du
02-03/09. A instruire separement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
Tallagrand Thierry
2026-09-03 23:28:57 +02:00
parent 914ef021b2
commit 6603c5dfd2
8 changed files with 338 additions and 31 deletions

View File

@@ -2938,13 +2938,26 @@ par point de SOC, sur cinq fenetres et trois nuits :
| 02-03/09 03:00-06:00 (zero reseau) | 45 → 22 | 0,121 | **12,1 kWh** |
| 01-02/09 03:00-06:00 | 33 → 20 | 0,082 | **8,2 kWh** |
Au-dessus de ~42 % la jauge est lineaire et coherente (~17 kWh, ce qui valide
le `batteryUsableCapacityKwh: 17.5` code en dur). **En dessous elle s'effondre :
un point de SOC y vaut moitie moins.** Or `BALANCE.js` convertit avec une
constante unique : `socNeeded = energyToCover / usable_capacity_kwh * 100`, avec
le helper a 15 kWh. `required_soc` est donc systematiquement TROP BAS dans la
bande ou la nuit se termine — c'est le facteur 1,75 mesure la nuit du 02-03/09,
ou le SOC descendait bien plus vite que la ligne.
Au-dessus de ~42 % la jauge est lineaire et coherente (~17 kWh). **En dessous
elle s'effondre : un point de SOC y vaut moitie moins.** Or `BALANCE.js`
convertit avec une constante unique (helper a 15 kWh).
> ⚠️ **CORRECTION apportee le 03/09 au soir (§41).** La phrase qui figurait ici
> — « `required_soc` est donc systematiquement TROP BAS ... c'est le facteur
> 1,75 » — etait FAUSSE, sur les deux points.
> 1. 15 kWh se situe ENTRE les deux pentes reelles (0,097 et 0,169), donc
> l'erreur CHANGE DE SIGNE : trop bas de 3 a 4 points pour un petit deficit
> (fin de nuit), trop haut de 4 a 6 points pour un gros (debut de nuit).
> 2. Le facteur 1,75 comparait la vitesse de descente du SOC a celle de la
> ligne. Ces deux grandeurs ne mesurent pas la meme chose : la ligne descend
> parce que le temps passe. L'ecart venait donc surtout de la
> **sous-estimation de la consommation** par le profil p50 (2,1 kWh annonces
> pour 03:00-06:00, 2,79 kWh mesures), et non de la conversion.
>
> La conception de la session (relachement sur la fenetre et non sur un seuil de
> SOC) reste juste : elle ne dependait pas de l'ampleur de l'erreur, seulement
> du fait que le relachement ne doit pas porter sur une grandeur approximative
> ni rouvrir l'oscillateur du 27/08.
**Conclusion de conception, et elle est structurante : le relachement de la
session reseau ne peut PAS etre un seuil de SOC.** Il porterait sur une grandeur
@@ -3042,3 +3055,106 @@ distinct.
---
*Document mis a jour le : 03/09/2026 (~23:20) — session reseau unique de la nuit, golden 78/78, deploye*
## 41. Session du 03/09/2026 (suite) — La conversion energie ↔ SOC devient une courbe mesuree
### La mesure
`tools/mesure-courbe-batterie.mjs` (nouveau, rejouable). Methode : pour chaque
palier ou le SOC reste a une valeur puis **descend d'un point**, integrer la
puissance batterie sur ce palier — en ecartant les paliers ou la batterie a
charge et ceux ou le reseau a apporte quoi que ce soit (> 20 Wh). Chaque palier
donne donc directement une mesure de « kWh par point de SOC », attribuee a ce
point.
**576 paliers retenus sur 8 jours** (105 ecartes) :
| tranche | paliers | kWh/point | capacite implicite |
|---|---:|---:|---:|
| 21-31 | 88 | **0,097** | 9,7 kWh |
| 35-44 | 78 | 0,171 | 17,1 kWh |
| 45-54 | 76 | 0,169 | 16,9 kWh |
| 55-64 | 85 | 0,163 | 16,3 kWh |
| 65-74 | 80 | 0,171 | 17,1 kWh |
| 75-84 | 81 | 0,170 | 17,0 kWh |
| 85-94 | 62 | 0,169 | 16,9 kWh |
Plate a **0,169** de 33 a 93 — remarquablement stable sur six tranches
independantes — **genou net a 32-33**, puis **0,097** en dessous. Sous le genou,
un point de SOC vaut **57 %** de ce qu'il vaut au-dessus. Coherent avec §0 (un
module en panne sur huit, un autre qui faiblit) et avec l'effondrement de la
jauge signale au §28 : ceci lui donne enfin sa courbe.
### Ce que la constante faisait vraiment
15 kWh se situe ENTRE les deux pentes, donc **l'erreur change de signe** :
| energie a couvrir | SOC requis annonce | reel | ecart |
|---:|---:|---:|---:|
| 1 kWh | 28,7 | 32,3 | **−3,6** |
| 4,3 kWh | 50,7 | 52,1 | −1,4 |
| 8 kWh | 75,3 | 74,0 | +1,3 |
| 11,7 kWh | 99,7 | 95,7 | **+4,1** |
Trop bas en fin de nuit — la direction dangereuse — et trop haut en debut de
nuit. Ce n'est pas le facteur 1,75 annonce au §40, qui est corrige en tete de
cette section.
**Energie utile totale de 100 a 22 % : 12,39 kWh mesures**, contre 11,70 vus par
le bilan (15 kWh a plat) et 13,65 par `INPUT_PARSE` (17,5). **Les deux
constantes existantes etaient fausses, dans des sens opposes.** Chiffre a
retenir pour le dimensionnement du parc prevu cet hiver.
### Le correctif (deploye 03/09 23:27)
- **`src/energy-balance/BALANCE.js`** : trois fonctions —
`energyBetweenSoc(lo, hi)`, `socForEnergy(kWh, floor)`, `socAfterEnergy(soc, kWh)`
— remplacent les **cinq** conversions lineaires : `requiredSocPct`,
`gridEnergyNeededKwh`, `requiredSocAtStartPct`, `storageShortfallKwh` +
`reachable`, et le manque de la reserve d'orage.
`requiredSocAtStartPct` reste **NON ecrete** au-dela de 100 (§26 : signal de
dimensionnement) ; l'extrapolation y utilise la pente haute.
- **`src/nodes/INPUT_PARSE.js`** : `batteryUsableCapacityKwh` 17,5 → **16,9**
(valeur mesuree). Cette constante ne sert qu'a des ecarts SOC → cible, tous
deux au-dessus du genou. **Un calcul qui traverserait le genou doit lire la
COURBE, pas cette constante** — commentaire pose sur place.
- `usable_capacity_kwh` reste exige en entree (garde de completude du snapshot)
et publie, mais ne pilote plus aucune conversion.
### Tests : 42/42 apres mise a jour deliberee de 6 attendus
Les six valeurs ont ete **verifiees a la main** contre la courbe avant d'etre
figees (0,82 kWh → 30,5 ; 2,42 → 41,0 ; 12,77 → 102,2 ; manque 100→102,2 = 0,37 ;
orage 21→41 = 2,52 ; orage 95→102,2 = 1,22). Un libelle a ete corrige :
`bilan-rejeu-24-08-matin` affirmait « SOC requis 27,5 % au lieu du seuil fixe de
30 % » ; la courbe donne 30,5 %, donc **le seuil fixe tombait juste ce matin-la —
par coincidence, pas par construction**. Le dire ainsi est plus honnete que de
laisser croire a un ecart.
Mutation, deux directions : pente basse ramenee a la pente haute, puis genou
ramene au plancher — **6 echecs a chaque fois**, les memes six. Restauration →
42/42. Les trois autres suites (golden 78, hysteresis 7, advisor) sont
inchangees.
### ⚠️ A RE-MESURER apres l'extension du parc
Les trois nombres (`kneePct`, `kwhPerPointAbove`, `kwhPerPointBelow`) sont des
**resultats de mesure**, pas des reglages : `node tools/mesure-courbe-batterie.mjs 8`
puis mise a jour. C'est aussi la raison pour laquelle ils vivent dans le code
avec l'outil qui les produit, plutot que dans trois helpers de plus.
### Ce que ce correctif NE corrige pas
Le profil de consommation p50 sous-estimait de ~33 % les heures 03-06 la nuit du
02-03/09 (2,1 kWh annonces, 2,79 mesures). **C'est desormais la principale
source d'erreur du bilan**, devant la conversion. Les profils sont recalcules
quotidiennement par `evcs-energy-profiles-daily-v1` sur l'historique — a
instruire separement : fenetre d'apprentissage, saisonnalite, et le fait que
l'historique HA ne remonte qu'a ~7 jours (§28).
### Etat du cablage du bilan
| consommateur | statut |
|---|---|
| plancher de demarrage du soir | ✅ §38 |
| cible du matin | ✅ §39 |
| session reseau unique de la nuit | ✅ §40 |
| conversion kWh ↔ SOC | ✅ §41 (courbe mesuree) |
| profil de consommation p50 | ⚠️ sous-estime, principale erreur restante |
| hysteresis `grid_soc_on`/`off` (20/30) | ❌ niveaux fixes |
---
*Document mis a jour le : 03/09/2026 (~23:35) — conversion energie/SOC mesuree (576 paliers), bilan 42/42, golden 78/78, deploye*