Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Minuscule bug sur les mesures U & I
#1
Je suis en UxI en v12.03

Il y a un tout petit bug sur les mesures U et I toutes les 1 heure 11 minutes et 35 secondes (soit 4295 secondes, soit 2^32 µs)

Rien de très important ni d'urgent, cela peut juste déclencher de façon très brève les actions sans raison, ça a eu cet effet chez moi ce matin
(Et l'échelle du graph sur Home Assistant est plus grande que nécessaire.)

Désolé pour les petits bugs trouvés, André, je vais essayer de chercher de mon côté s'il est possible de mitiger ou d'éviter ça dans le code simplement.

[Image: Mesure-Tension.png]

Une piste (peut-être complètement fausse) :

-> La valeur retournée par la fonction micros() déborde toutes les 2^32µs
-> Concernant la ligne iStore = (micros() % 20000) / 200; : 2^32 a un reste quand on le divise par 20000, du coup je suppose que des échantillons sont stockés dans le tableau à des index erronés pendant 1 appel (ou 2?) de MeasurePower()
Micros() = 4294967295 implique que iStore = 36
Micros() = 0 implique que iStore = 0
et on ne va pas jusqu'au bout du tableau ?

A l'occasion, j'essayerai de compiler une version avec des tableaux de 128 mesures, voir si ça passe niveau timing sur le core0 (128*150µs = 19.2ms, presque pas d'aliasing)
Répondre
#2
Ok, on se trompe toutes les 71 min. C'est tolérable.
Répondre
#3
Certes... voici néanmoins une solution clé en main, André :

void MeasurePower() {  //Lecture Tension et courants pendant 20ms
  int iStore;
  value0 = analogRead(AnalogIn0);  //Mean value. Should be at 3.3v/2
  static unsigned long OverflowOffset = 0;
  static unsigned long PrevMicros = 0;
  unsigned long NowMicros;
  unsigned long MeasureMillis = millis();
 
  while (millis() - MeasureMillis < 21) {  //Read values in continuous during 20ms. One loop is around 150 micro seconds
    NowMicros = micros();
    if(NowMicros < PrevMicros) {
      OverflowOffset += 7296;
    }
    iStore = ((NowMicros + OverflowOffset) % 20000) / 200;    //We have more results that we need during 20ms to fill the tables of 100 samples
    volt[iStore] = analogRead(AnalogIn1) - value0;
    amp[iStore] = analogRead(AnalogIn2) - value0;
    PrevMicros = NowMicros;
  }
}

...pas forcément la plus élégante, mais fonctionnelle et rapide, un copier-coller et c'est bon.
Répondre
#4
OK je note pour une prochaine version. Avez vous testé si cela ne prend pas trop de temps pour avoir au moins les 100 mesures.

Cdlt
André
Répondre
#5
Je n'ai pas testé, mais j'en suis persuadé !

J'ai ajouté en gros:

- Deux affectations
- Une comparaison
- Une addition d'entiers
 
Si cela prends les 50µs de marge moyenne par cycle de mesures UI, je mange mon chapeau Big Grin
on doit plutôt être sous les 50ns

Bon, on est à plus de 100 mesures par cycle, par contre ce n'est pas parfait sur le long terme, mieux mais pas parfait
(on voit la différence entre sans et avec la modif avec le changement à partir de 15h au milieu du graph) :
[Image: Modif.png]
Répondre
#6
Bonjour, 
YA t-il un impact lorsque les mesures se font via un Shelly EM ?
Répondre
#7
Non pas d'impact avec Shelly Em uniquement pour UxI ou le compteur des microsecondes n'est pas un multiple de 200. La version 12 . 05, sortie ce jour, corrige ce petit souci.
Cordialement, André.
Répondre
#8
Bonsoir André,
voici une meilleure solution, belle, propre et qui fonctionne enfin à 100%, testée sur 24h, plus aucune mauvaise mesure de V et de I (enfin... à part les valeurs au démarrage, mais c'est un autre problème) :

typedef union {
  uint64_t U64;
  struct {
    unsigned long Lower;
    unsigned long Upper;
  } U32;
} uint64_32;

void MeasurePower() {  //Lecture Tension et courants pendant 20ms
  int iStore;
  value0 = analogRead(AnalogIn0);  //Mean value. Should be at 3.3v/2
  static uint64_32 Micros64 = {0};
  unsigned long Micros32;
  unsigned long MeasureMillis = millis();

  while (millis() - MeasureMillis < 21) {  //Read values in continuous during 20ms. One loop is around 150 micro seconds
    Micros32 = micros();
    if(Micros32 < Micros64.U32.Lower) {
      Micros64.U32.Upper ++;
    }
    Micros64.U32.Lower = Micros32;
    iStore = (Micros64.U64 % 20000) / 200;    //We have more results that we need during 20ms to fill the tables of 100 samples
    volt[iStore] = analogRead(AnalogIn1) - value0;
    amp[iStore] = analogRead(AnalogIn2) - value0;
  }
}

Bonne soirée à vous, et si besoin d'explications je reste disponible.
Répondre
#9
Là, il faut que je révise pour tout comprendre. Je n'ai pas l'habitude d'utiliser ces structures.
Je mettrai ce code dans une prochaine révision.

Cela fonctionne, je vous fais confiance.

@+
André
Répondre


Atteindre :


Utilisateur(s) parcourant ce sujet : 2 visiteur(s)