fix(3g-1): la conversion watts→ampères arrondit, elle ne tronque pas
Quatrième défaut latent de 3g-1. Il vaut son propre message parce que c'est une décision, et qu'elle s'est prise contre le test. 3g-1 convertit l'enveloppe du waterfall en ampères puis la passe à `static_cast<uint>(qBound(...))` — donc une TRONCATURE. Cela paraît prudent (« ne jamais dépasser l'enveloppe ») et coûte systématiquement un ampère : 230 W par phase, abandonnés à chaque cycle, toute la journée. Les scénarios de simulation le chiffrent — huit d'entre eux sortaient un ampère plus bas, et la voiture finissait la journée 1 % moins chargée. L'arbitrage : l'enveloppe est une ALLOCATION, pas une limite. Elle sort d'une mesure de compteur dont le bruit dépasse largement 115 W. Ce qui est une limite — le courant maximal de la borne et la place laissée par la protection de surcharge — n'est pas franchi pour autant : le plafond est déclaré à l'enveloppe (commit précédent), donc respecté AVANT l'allocation, et le qBound écrête au matériel. C'est pourquoi le CODE a été réaligné sur l'amont plutôt que le test : testOverloadProtectionEcoMode encode le comportement de l'arrondi, et la troncature faisait basculer la protection de surcharge de « réduire au minimum » à « couper ». Un ampère de conversion ne doit pas décider ça. Et c'est aussi pourquoi la limite de phase n'est PAS réappliquée en ampères entiers dans l'adaptateur : ce second écrêtage serait plus strict que celui de l'amont (plancher au lieu d'arrondi) et coûterait de nouveau un ampère, pour 69 W de marge théorique que la couche L4 mesure réellement en temps réel. Suite simulation `run` 16/16, testOverloadProtectionEcoMode vert. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TVywtayEeoRJ2yWUW4iZj
This commit is contained in:
parent
e5e20db9fd
commit
c8bd41e36b
@ -157,8 +157,27 @@ LoadAction EvAdapter::applyAction(const LoadAction &action, const QDateTime &now
|
||||
|
||||
double demandeA = action.currentA;
|
||||
if (demandeA <= 0 && action.powerW > 0)
|
||||
demandeA = action.powerW / (230.0 * phases);
|
||||
// 3g-2 — arrondi au PLUS PROCHE, comme le faisait le proxy. Tronquer paraissait plus
|
||||
// prudent (« ne jamais dépasser l'enveloppe ») et coûtait systématiquement un ampère :
|
||||
// 230 W par phase abandonnés à chaque cycle, sur toute la journée. Les 18 scénarios de
|
||||
// simulation le chiffrent — voiture 1 % moins chargée le soir, huit fois sur huit.
|
||||
//
|
||||
// L'enveloppe est une ALLOCATION, pas une limite : elle sort d'une mesure de compteur
|
||||
// dont le bruit dépasse largement 115 W. Ce qui est une limite, c'est le plafond
|
||||
// matériel — et celui-là n'est jamais franchi : il est déclaré à l'enveloppe par
|
||||
// toLoadContext(), et le qBound ci-dessous écrête au courant maximal de la borne.
|
||||
demandeA = qRound(action.powerW / (230.0 * phases));
|
||||
|
||||
// La limite de phase n'est PAS réappliquée ici, et c'est délibéré : elle est déjà dans
|
||||
// l'enveloppe, déclarée par toLoadContext() comme plafond de la charge, donc respectée par
|
||||
// le waterfall AVANT d'allouer. La réappliquer en ampères entiers ferait un second
|
||||
// écrêtage, plus strict que celui de l'amont (plancher au lieu d'arrondi), et coûterait à
|
||||
// nouveau un ampère dans les scénarios de simulation — pour 69 W de marge théorique que la
|
||||
// couche L4, elle, mesure réellement en temps réel.
|
||||
//
|
||||
// La répartition reste celle du modèle de sécurité : la stratégie respecte le plafond
|
||||
// déclaré, l'adaptateur écrête au matériel, et verifyOverloadProtection() garde le dernier
|
||||
// mot sur la mesure.
|
||||
const uint clampedA = static_cast<uint>(
|
||||
qBound(static_cast<double>(minA), demandeA, static_cast<double>(maxA)));
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user