moteur : le tirage d'une borne non mesurée par phase est rendu à ses phases (V2C)
Une borne qui ne publie pas ses courants par phase (V2C Trydan : currentL1..3) avait meteredPhases() vide, et le plafond d'heures creuses ne lui rendait rien de ce qu'elle tire : il la lisait comme une charge de la maison sur sa phase, et la consigne alternait chaque nuit (16, 6, 13, 6 A sous 25 A et 10 % de marge ; 6 A tenus avec 8 A de plus sur A). evAttributableDraw() : le currentPower de la borne est attribué aux phases que le moteur lui suppose déjà (phasesForCount(), la phase A en monophasé, comme chargerPhaseKey() pour L4), un tiers par phase en triphasé. Seulement si c'est sûr : aucun état par phase publié, autant de phases annoncées que visées (pas de triphasée avec voiture monophasée, pas de bascule), une ou trois phases. Sinon rien, comme avant. Question 5 du lot délestage triphasé : hors heures creuses, evPhaseAllowanceW() rend aussi ce tirage, moins 1 A, hors dépassement (16, 9, 16, 9 A → 16 A tenus). En dépassement, la place libre reste la règle. Le calcul est mis en commun avec evOffPeakAllowanceW() (evCeilingGivingBackDraw()). run : le scénario 1 phase 32 A alternait 19/20 A sous la limite de phase et tient 20-21 A ; ses points de charge passent de 80/85/87 à 81/86/88 % (88 est la valeur de l'amont), 100 % à l'échéance inchangé. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3084b885d8
commit
70cdaed481
@ -1581,7 +1581,20 @@ double EnergyArbitrator::evPhaseAllowanceW(EvCharger *ev, uint phaseCount) const
|
||||
// marge PORTE le dépassement (elle vaut -1200 quand on dépasse de 1200 W) parce que
|
||||
// l'étape 4 en a besoin pour dire de combien délester. Ce qu'une borne peut prendre
|
||||
// n'est jamais négatif ; ce qu'il faut retirer à la maison, si.
|
||||
return qMax(0.0, marge.watts) * phaseCount;
|
||||
const double libreW = qMax(0.0, marge.watts) * phaseCount;
|
||||
|
||||
// Lot délestage V2C (question 5 du lot délestage triphasé) — HORS DÉPASSEMENT, la place libre
|
||||
// seule fait alterner une borne qui tient une bonne part de sa phase : pleine, la place tombe ;
|
||||
// au plancher, elle remonte (16, 9, 16, 9 A sous 25 A et 10 % de marge, maison à 4 A). Le
|
||||
// plafond qui lui rend son tirage, moins 1 A, se pose en un cycle — c'est la règle des heures
|
||||
// creuses (lot e2, D8). EN DÉPASSEMENT, la place libre reste la règle, et la raison de sécurité
|
||||
// ci-dessus avec elle : on ne rend rien à une borne sur une phase au-dessus du seuil.
|
||||
// Le MAXIMUM des deux garde la règle d'avant quand le tirage n'est pas attribuable (le plafond
|
||||
// rendu vaut alors la place libre moins 1 A) ou quand la borne tire moins d'un ampère.
|
||||
const PlafondRendu rendu = evCeilingGivingBackDraw(ev, phaseCount);
|
||||
if (!rendu.attribuable || rendu.depasse || rendu.watts < 0)
|
||||
return libreW;
|
||||
return qMax(libreW, rendu.watts);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -1593,38 +1606,90 @@ constexpr double MargeHeuresCreusesA = 1.0;
|
||||
|
||||
double EnergyArbitrator::evOffPeakAllowanceW(EvCharger *ev, uint phaseCount) const
|
||||
{
|
||||
return evCeilingGivingBackDraw(ev, phaseCount).watts;
|
||||
}
|
||||
|
||||
EnergyArbitrator::TirageBorne EnergyArbitrator::evAttributableDraw(EvCharger *ev, uint phaseCount) const
|
||||
{
|
||||
TirageBorne tirage;
|
||||
if (!ev || phaseCount == 0)
|
||||
return tirage;
|
||||
|
||||
// Ce que la borne tire, MESURÉ. Pas la consigne : une voiture qui prend 8 A d'une borne
|
||||
// commandée à 16 n'occupe que 8 A de la phase, et lui rendre 16 ouvrirait 8 A qu'elle peut
|
||||
// prendre d'un coup. Une borne sans mesure ne rend rien.
|
||||
if (ev->thing()->thingClass().stateTypes().findByName("currentPower").id().isNull())
|
||||
return tirage;
|
||||
|
||||
const Electricity::Phases mesurees = ev->meteredPhases();
|
||||
if (mesurees != Electricity::PhaseNone) {
|
||||
// Rendre sur une phase que la borne n'occupe pas créerait de la place qui n'existe pas —
|
||||
// et la borne, en la prenant ailleurs, ne la refermerait jamais. Pendant une bascule
|
||||
// (phases mesurées ≠ phases visées), on ne rend donc rien.
|
||||
if (Electricity::getPhaseCount(mesurees) != phaseCount)
|
||||
return tirage;
|
||||
tirage.phases = mesurees;
|
||||
} else {
|
||||
// Lot délestage V2C — une borne qui ne publie PAS ses courants par phase (le V2C Trydan
|
||||
// publie `currentL1..3`, que l'interface ne connaît pas). meteredPhases() est vide, et
|
||||
// jusqu'ici rien n'était rendu : le plafond lisait la borne comme une charge de la maison
|
||||
// sur sa phase, et la consigne alternait chaque nuit (16, 6, 13, 6 A sous 25 A).
|
||||
//
|
||||
// Ses phases sont celles que le moteur lui suppose DÉJÀ — phasesForCount(), la phase A en
|
||||
// monophasé : c'est le masque de ce plafond, celui de L4 (chargerPhaseKey()) et celui de
|
||||
// l'amont (prepareInformation()). Attribuer son tirage ailleurs ferait deux hypothèses.
|
||||
//
|
||||
// Seulement quand c'est sûr :
|
||||
// - une borne qui publie des états par phase, tous nuls alors qu'elle tire, a une mesure
|
||||
// qui se contredit — elle n'est pas « non mesurée » ;
|
||||
// - elle doit annoncer autant de phases que le cycle en vise. Une triphasée qui charge
|
||||
// une voiture monophasée (le cycle vise 1, elle annonce 3), ou une borne en cours de
|
||||
// bascule, tire sur des phases que rien ne dit ;
|
||||
// - une ou trois phases : la monophasée sur sa phase, la triphasée un tiers par phase.
|
||||
// En biphasé, le masque A+B est une convention de l'amont, pas une observation : rien
|
||||
// n'est rendu (décision du 2026-10-27 : mono et tri seulement).
|
||||
for (const char *etat : {"currentPhaseA", "currentPhaseB", "currentPhaseC",
|
||||
"currentPowerPhaseA", "currentPowerPhaseB", "currentPowerPhaseC"}) {
|
||||
if (ev->thing()->hasState(etat))
|
||||
return tirage;
|
||||
}
|
||||
if ((phaseCount != 1 && phaseCount != 3) || ev->phaseCount() != phaseCount)
|
||||
return tirage;
|
||||
tirage.phases = const_cast<EnergyArbitrator *>(this)->phasesForCount(phaseCount);
|
||||
}
|
||||
tirage.watts = qMax(0.0, ev->currentPower());
|
||||
return tirage;
|
||||
}
|
||||
|
||||
EnergyArbitrator::PlafondRendu EnergyArbitrator::evCeilingGivingBackDraw(EvCharger *ev, uint phaseCount) const
|
||||
{
|
||||
PlafondRendu plafond;
|
||||
RootMeter *meter = internalRootMeter();
|
||||
if (!ev || phaseCount == 0 || !meter)
|
||||
return -1;
|
||||
return plafond;
|
||||
|
||||
const QList<DrawCap> plafonds = drawCaps();
|
||||
if (plafonds.isEmpty())
|
||||
return -1;
|
||||
return plafond;
|
||||
|
||||
// Ce que la borne tire, MESURÉ, et sur quelles phases. Pas la consigne : une voiture qui
|
||||
// prend 8 A d'une borne commandée à 16 n'occupe que 8 A de la phase, et lui rendre 16
|
||||
// ouvrirait 8 A qu'elle peut prendre d'un coup. Une borne sans mesure ne rend rien.
|
||||
const bool mesuree = !ev->thing()->thingClass().stateTypes().findByName("currentPower").id().isNull();
|
||||
const Electricity::Phases tirees = mesuree ? ev->meteredPhases() : Electricity::PhaseNone;
|
||||
// Rendre sur une phase que la borne n'occupe pas créerait de la place qui n'existe pas — et
|
||||
// la borne, en la prenant ailleurs, ne la refermerait jamais. Pendant une bascule (phases
|
||||
// mesurées ≠ phases visées), on ne rend donc rien.
|
||||
const bool attribuable = tirees != Electricity::PhaseNone
|
||||
&& Electricity::getPhaseCount(tirees) == phaseCount;
|
||||
const Electricity::Phases masque = attribuable
|
||||
? tirees : const_cast<EnergyArbitrator *>(this)->phasesForCount(phaseCount);
|
||||
const double tireW = attribuable ? qMax(0.0, ev->currentPower()) : 0.0;
|
||||
const TirageBorne tirage = evAttributableDraw(ev, phaseCount);
|
||||
plafond.attribuable = tirage.phases != Electricity::PhaseNone;
|
||||
const Electricity::Phases masque = plafond.attribuable
|
||||
? tirage.phases : const_cast<EnergyArbitrator *>(this)->phasesForCount(phaseCount);
|
||||
const double tireW = plafond.attribuable ? tirage.watts : 0.0;
|
||||
|
||||
// Le tirage de la maison SANS la borne, phase par phase, écrêté à zéro : une borne qui
|
||||
// annoncerait plus que ce que le compteur voit ne se fabrique pas de place au-delà de la
|
||||
// limite. Au mieux, une phase vaut sa limite.
|
||||
QList<double> sansLaBorne = phaseDrawW(masque, phasePowerLimit());
|
||||
const QList<double> avecLaBorne = phaseDrawW(masque, phasePowerLimit());
|
||||
plafond.depasse = resolveDrawMargin(plafonds, avecLaBorne, meter->currentPower()).watts < 0;
|
||||
QList<double> sansLaBorne = avecLaBorne;
|
||||
for (double &w : sansLaBorne)
|
||||
w = qMax(0.0, w - tireW / phaseCount);
|
||||
const DrawMargin marge = resolveDrawMargin(plafonds, sansLaBorne,
|
||||
qMax(0.0, meter->currentPower() - tireW));
|
||||
if (!marge.borne)
|
||||
return -1;
|
||||
return plafond;
|
||||
|
||||
// Moins la marge, à l'ampère INFÉRIEUR : l'adaptateur arrondit la consigne au plus proche,
|
||||
// et un plafond de 13,6 A deviendrait 14 A — la marge serait mangée de moitié.
|
||||
@ -1634,7 +1699,8 @@ double EnergyArbitrator::evOffPeakAllowanceW(EvCharger *ev, uint phaseCount) con
|
||||
// vaut limite − (I − E) − 1 < E − 1. La consigne descend d'au moins 1 A par cycle, jusqu'à
|
||||
// sortir du dépassement ou jusqu'au plancher, où L4 décide.
|
||||
const double parPhaseA = std::floor(marge.watts / 230.0 - MargeHeuresCreusesA);
|
||||
return qMax(0.0, parPhaseA) * 230.0 * phaseCount;
|
||||
plafond.watts = qMax(0.0, parPhaseA) * 230.0 * phaseCount;
|
||||
return plafond;
|
||||
}
|
||||
|
||||
bool EnergyArbitrator::evCommandedByWaterfall(EvCharger *evCharger) const
|
||||
|
||||
@ -917,12 +917,17 @@ public:
|
||||
* waterfall pourrait allouer un surplus que le branchement ne supporte pas, et la seule
|
||||
* chose qui rattraperait serait \c verifyOverloadProtection() **après coup**.
|
||||
*
|
||||
* \note Le plafond est la place LIBRE, et on n'y rend **pas** ce que la borne tire déjà.
|
||||
* C'est délibéré et c'est de sécurité : sur une phase en dépassement la marge est
|
||||
* négative, et c'est ce signe qui ramène la borne à son minimum. Rendre sa propre
|
||||
* \note EN DÉPASSEMENT, le plafond est la place LIBRE, et on n'y rend **pas** ce que la
|
||||
* borne tire déjà. C'est délibéré et c'est de sécurité : sur une phase en dépassement la
|
||||
* marge est négative, et c'est ce signe qui ramène la borne à son minimum. Rendre sa propre
|
||||
* consommation lui rendrait exactement la puissance qui cause le dépassement
|
||||
* (`testOverloadProtectionEcoMode`). La formulation inverse figurait ici et était
|
||||
* fausse : le code ne l'a jamais fait.
|
||||
* (`testOverloadProtectionEcoMode`, dont le compteur ne voit pas la borne baisser).
|
||||
* \note HORS DÉPASSEMENT (lot délestage V2C, question 5), le plafond vaut au moins celui qui
|
||||
* rend à la borne son tirage attribuable, moins 1 A (\c evCeilingGivingBackDraw()). Sans
|
||||
* lui, une borne qui tient une bonne part de sa phase alternait : pleine, la place libre
|
||||
* tombait ; au plancher, elle remontait (16, 9, 16, 9 A sous 25 A et 10 % de marge). Le
|
||||
* maximum des deux garde la règle d'avant quand rien n'est attribuable, ou quand la borne
|
||||
* tire moins d'un ampère.
|
||||
* \note Valeur de CYCLE : elle dépend de ce que le reste de la maison consomme à cet
|
||||
* instant. Elle est donc relue à chaque \c toLoadContext(), jamais mémorisée.
|
||||
*/
|
||||
@ -945,9 +950,11 @@ public:
|
||||
*
|
||||
* \par Contrat
|
||||
* - Le courant rendu est MESURÉ sur la borne (état \c currentPower de sa classe), jamais
|
||||
* déduit de sa consigne. Il n'est rendu que sur les phases où la borne le mesure, et
|
||||
* seulement si elles sont aussi nombreuses que les phases visées. Sinon — borne sans
|
||||
* mesure, à l'arrêt, ou qui bascule — rien n'est rendu, et la marge s'applique quand même.
|
||||
* déduit de sa consigne. Il n'est rendu que sur les phases où la borne le tire, quand c'est
|
||||
* sûr (\c evAttributableDraw()) : mesurées, et aussi nombreuses que les phases visées ; ou,
|
||||
* pour une borne qui ne publie pas ses phases, celles que le moteur lui suppose (lot
|
||||
* délestage V2C). Sinon — borne sans mesure, à l'arrêt, ou qui bascule — rien n'est rendu,
|
||||
* et la marge s'applique quand même.
|
||||
* - Une phase ne peut pas valoir plus que sa limite, moins la marge : ce que la maison tire
|
||||
* sans la borne est écrêté à zéro. Une borne qui annoncerait plus que ce que le compteur
|
||||
* voit ne se fabrique donc pas de place au-delà de la limite.
|
||||
@ -960,7 +967,8 @@ public:
|
||||
* mange jamais la marge.
|
||||
*
|
||||
* \note Réservée aux heures creuses et à la pleine puissance du lot e2. Hors de là,
|
||||
* \c evPhaseAllowanceW() reste la règle, et les décisions sans tarif ne changent pas.
|
||||
* \c evPhaseAllowanceW() reste la règle ; depuis le lot délestage V2C, elle rend elle aussi
|
||||
* le tirage hors dépassement.
|
||||
*/
|
||||
double evOffPeakAllowanceW(EvCharger *ev, uint phaseCount) const;
|
||||
|
||||
@ -1043,6 +1051,53 @@ protected:
|
||||
const QDateTime ¤tDateTime) override;
|
||||
|
||||
private:
|
||||
//! Lot délestage V2C — ce qu'une borne tire, et sur quelles phases. \c phases vaut
|
||||
//! \c PhaseNone quand l'attribution n'est pas sûre : rien n'est alors rendu.
|
||||
struct TirageBorne {
|
||||
Electricity::Phases phases = Electricity::PhaseNone;
|
||||
double watts = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Lot délestage V2C — le tirage MESURÉ d'une borne, attribué à ses phases quand c'est sûr.
|
||||
*
|
||||
* \param ev Borne. \param phaseCount Nombre de phases VISÉ par le cycle.
|
||||
* \return Les phases et la puissance (\c currentPower de la borne, jamais sa consigne) ; un
|
||||
* tirage vide si la borne n'a pas de \c currentPower ou si l'attribution n'est pas sûre.
|
||||
*
|
||||
* \par Deux cas
|
||||
* - Borne MESURÉE par phase (\c meteredPhases() non vide) : ses phases mesurées, si elles
|
||||
* sont aussi nombreuses que les phases visées. Sinon elle bascule, et rien n'est attribué.
|
||||
* C'est la règle du lot e2, inchangée.
|
||||
* - Borne NON MESURÉE par phase (aucun état \c currentPhaseX ni \c currentPowerPhaseX : le
|
||||
* V2C Trydan publie \c currentL1..3) : les phases que le moteur lui suppose déjà
|
||||
* (\c phasesForCount() — la phase A en monophasé, comme \c chargerPhaseKey() pour L4 et
|
||||
* \c prepareInformation() pour l'amont), à condition que la borne annonce autant de phases
|
||||
* que le cycle en vise (\c EvCharger::phaseCount()), et que ce soit une ou trois. Une
|
||||
* triphasée qui charge une voiture monophasée, ou une borne en cours de bascule, n'est donc
|
||||
* pas attribuée.
|
||||
* \note Une borne qui PUBLIE des courants par phase, tous nuls alors qu'elle tire, n'est pas
|
||||
* « non mesurée » : sa mesure se contredit, et rien n'est attribué.
|
||||
* \note L'hypothèse de la phase A est celle de tout le moteur. Une monophasée câblée sur une
|
||||
* autre phase la met en défaut, ici comme dans L4 : c'est le plugin qui peut la lever, en
|
||||
* publiant ses courants par phase.
|
||||
*/
|
||||
TirageBorne evAttributableDraw(EvCharger *ev, uint phaseCount) const;
|
||||
|
||||
//! Lot délestage V2C — le plafond d'une borne qui lui rend ce qu'elle tire (règle du lot e2).
|
||||
struct PlafondRendu {
|
||||
double watts = -1; //!< Plafond en W, multiple de 230 W par phase ; −1 sans limite.
|
||||
bool depasse = false; //!< Une phase de la borne, borne comprise, est au-dessus du seuil.
|
||||
bool attribuable = false;//!< Le tirage de la borne a été rendu (\c evAttributableDraw()).
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Lot délestage V2C — limite − (tirage de la phase − tirage attribué à la borne) − 1 A,
|
||||
* à l'ampère inférieur, × phases. Le calcul d'\c evOffPeakAllowanceW(), mis en commun avec
|
||||
* \c evPhaseAllowanceW() ; son contrat est écrit sur la première.
|
||||
*/
|
||||
PlafondRendu evCeilingGivingBackDraw(EvCharger *ev, uint phaseCount) const;
|
||||
|
||||
/*!
|
||||
* \brief Construit le SurplusContext §5 : meter brut + loads EV + SG-Ready.
|
||||
*
|
||||
|
||||
@ -2560,16 +2560,22 @@ void Simulation::run_data()
|
||||
},
|
||||
{
|
||||
520, {
|
||||
// [ETM lot délestage V2C] 80 % → 81 % (et 85 → 86 au pas 700, 87 → 88
|
||||
// au pas 900). Vers 10:10 UTC la borne est bornée par la limite de
|
||||
// phase (32 A) et le compteur la voit : sa place libre alternait 19 et
|
||||
// 20 A d'un cycle à l'autre. Le plafond lui rend désormais son tirage
|
||||
// mesuré hors dépassement (evPhaseAllowanceW()) ; elle tient 20-21 A,
|
||||
// borné par le surplus, et la voiture prend un point d'avance.
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6) ,
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 80)
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 81)
|
||||
}
|
||||
},
|
||||
{
|
||||
700, {
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6) ,
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 85)
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 86)
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -2579,8 +2585,10 @@ void Simulation::run_data()
|
||||
// l'écart s'accumule sur 900 pas de rétroaction. Ce qui compte est
|
||||
// au pas 960, et c'est inchangé : la voiture est à 100 % à
|
||||
// l'échéance. Les 14 autres scénarios sont identiques au bit près.
|
||||
// [ETM lot délestage V2C] 87 % → 88 %, la valeur de l'amont : le point
|
||||
// gagné vers 10:10 (cf. pas 520) se retrouve ici.
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 87)
|
||||
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 88)
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -12866,19 +12874,27 @@ void Simulation::testWaterfallChargerSettlesUnderThePhaseLimit()
|
||||
// (déjà net du solaire de A). Limite 25 A, marge 10 % (seuil 22,5 A). Le surplus offert à la
|
||||
// borne vaut 2E − H ≥ 16 A : c'est la phase qui borne, jamais le surplus.
|
||||
// Attendu : 22,5 − H − 1 à l'ampère inférieur, plafonné à 16 A.
|
||||
//
|
||||
// La maison chargée tire 10,3 A, et non 10 : au premier cycle la borne est à l'arrêt, rien ne
|
||||
// lui est rendu, et son plafond est la place libre ARRONDIE AU PLUS PROCHE par l'adaptateur
|
||||
// (règle d'avant ce lot). À 10 A, 12,5 A deviennent 13 A, la phase passe à 23 A pour un seuil
|
||||
// de 22,5 A, et L4 rabaisse d'un ampère. En production, la consigne se pose ensuite à 11 A ;
|
||||
// ici, le harnais rappelle la protection sur le MÊME compteur (simulationCallUpdate()) et
|
||||
// coupe la borne déjà au plancher, qui repart au cycle suivant — une boucle du harnais, pas
|
||||
// du moteur. À 10,3 A, 12,2 A deviennent 12 A, sous le seuil, et la règle se lit seule.
|
||||
FuseauDeTest fuseau("Europe/Paris");
|
||||
struct Cas { const char *quoi; BorneHc borne; double maisonA; double exportA; int attenduA; };
|
||||
const QList<Cas> cas = {
|
||||
{"mesurée, maison légère", BorneHc::Monophasee, 4, 12, 16},
|
||||
{"mesurée, maison chargée", BorneHc::Monophasee, 10, 14, 11},
|
||||
{"non mesurée, maison chargée", BorneHc::MonophaseeNonMesuree, 10, 14, 11},
|
||||
{"mesurée, maison légère", BorneHc::Monophasee, 4, 12, 16},
|
||||
{"mesurée, maison chargée", BorneHc::Monophasee, 10.3, 14, 11},
|
||||
{"non mesurée, maison chargée", BorneHc::MonophaseeNonMesuree, 10.3, 14, 11},
|
||||
};
|
||||
constexpr int Cycles = 10;
|
||||
QList<QList<int>> toutesConsignes;
|
||||
QList<QList<double>> toutesPires;
|
||||
QStringList traces;
|
||||
for (const Cas &c : cas) {
|
||||
ScenarioHc s = preparerScenarioHc(QStringLiteral("jour-phase-%1-%2").arg(static_cast<int>(c.borne)).arg(c.maisonA),
|
||||
ScenarioHc s = preparerScenarioHc(QStringLiteral("jour-phase-%1-%2").arg(static_cast<int>(c.borne)).arg(qRound(c.maisonA * 10)),
|
||||
BatterieHc::Aucune, QVariantList(), c.borne);
|
||||
QVERIFY2(s.arb && s.borne, c.quoi);
|
||||
QCOMPARE(injectAndWait("NymeaEnergy.SetPhasePowerLimit", QVariantMap({{"phasePowerLimit", 25}, {"phaseSafetyMarginPercent", 10}}))
|
||||
@ -12906,9 +12922,8 @@ void Simulation::testWaterfallChargerSettlesUnderThePhaseLimit()
|
||||
}
|
||||
|
||||
for (int i = 0; i < cas.size(); ++i) {
|
||||
// Les deux premiers cycles posent la borne (le premier juge une borne à l'arrêt, et
|
||||
// l'arrondi au plus proche de la place libre peut franchir le seuil d'un demi-ampère, que
|
||||
// L4 reprend). Ensuite la consigne TIENT, sous le seuil moins 1 A.
|
||||
// Les deux premiers cycles posent la borne : le premier juge une borne à l'arrêt, qui
|
||||
// n'a rien à se voir rendre. Ensuite la consigne TIENT, sous le seuil moins 1 A.
|
||||
for (int k = 2; k < Cycles; ++k) {
|
||||
const QByteArray ctx = QStringLiteral("%1 — cycle %2 : %3").arg(cas.at(i).quoi).arg(k).arg(traces.at(i)).toUtf8();
|
||||
QVERIFY2(toutesConsignes.at(i).at(k) == cas.at(i).attenduA, ctx.constData());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user