Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Multisinus le paradoxe
#14
Bonjour,

  la première étape, c'est la répartition nombre de demi-onde passante / nombre de demi onde pour obtenir le % de routage,

  en y regardant de prés, la routine André se contente d’arrêter les estimations quand la valeur est dans la tolérance 0.4%

  cette procédure arrive a dire que pour obtenir 8% le ratio 2/24 est acceptable (erreur 0.3333)  si on pousse le ratio à 2/25 c'est parfait avec écart de 0%

  c'est valable pour d'autres situations

  pour corriger la situation, j'ai ajouté une boucle supplémentaire qui commence par remplir le tableau avec tolérance 0 puis pour les cas pas encore couvert tolérance 0.1% et ainsi de suite jusque 0.4%, je fini par un tour qui patch les cas non couvert en utilisant la valeur du % précédent

Code :
  // dans setup()
  #define MINSEQLEN 2               //++MS
  #define MAXSEQLEN 64              //++MS
  #define BASEPRECIS 0              //++MS
  #define FINPRECIS 4               //++MS
  for (int I = 0; I <= 50; I++) {   // on ne traite que la moitié, l’autre partie c’est symétrique //++MS
    tabPulseSinusTotal[I] = 0xFF;
    tabPulseSinusOn[I] = 0xFF;
    target = float(I) / 100.0f;
    float tolerance = 0.001f;       //++MS
    for (int K =  BASEPRECIS ; K <=  FINPRECIS ; K++) {  // on fait plusieurs passe en augmentant la tolérance a l'erreur (premier tour recherche la correspondance parfaite) //++MS
      if (tabPulseSinusTotal[I] < 0xFF ) break;  // on a déjà trouver une solution avec une tolérance plus faible
      tolerance = 0.001f * K;         
      for (int T = MINSEQLEN; T < MAXSEQLEN; T++) {
        for (int N = max(0, (int)(T * target) - 1); N <= T; N++) {  // démarre la recherche d'une cohérence juste avant la cible théorique
          if (T % 2 == 1 || N % 2 == 0) {  // Valeurs impaires du total [le cycle suivant rétablira la neutralité électrique] ou pulses pairs pour éviter courant continu
            vrai = float(N) / float(T);
            erreur = fabs(vrai - target);
            if (erreur <= tolerance) {
              tabPulseSinusTotal[I] = T;
              tabPulseSinusOn[I] = N;
              break; // sort de la boucle for N  //++MS
            }
          }
        }  // for N
        if (erreur <= tolerance) break;  // sort de la boucle for T //++MS
      }  // for T
      if (erreur <= tolerance) break;  // sort de la boucle for K //++MS
    }  // for K
  }  // for I
  // patch pour solutions non trouvées (on utilise la valeur précédente s'il n'y a pas de solution)  //++MS
  for (int I = 1; I <= 50; I++) { 
    if (tabPulseSinusTotal[I] == 0xFF) {  // pas trouver de solution
       tabPulseSinusTotal[I] = tabPulseSinusTotal[I - 1];          // on prend la valeur précédente
       tabPulseSinusOn[I] = tabPulseSinusOn[I - 1];
    }
  }
  // double la durée pour les cas impair 'court' ça devient un cas pair
  for (int i = 0; i <= 50; i++) {
      if ((tabPulseSinusOn[i] % 2 || tabPulseSinusTotal[i] % 2) && tabPulseSinusTotal[i] <= 32) {  // avec 32, en doublant, on sait encoder la séquence sur 64 bits
          tabPulseSinusOn[i] *= 2;
          tabPulseSinusTotal[i] *= 2;
      }
  }
  // propage la table de 51 a 100
  for (int I = 51; I <= 100; I++) {
      tabPulseSinusTotal[I] = tabPulseSinusTotal[100 - I];
      tabPulseSinusOn[I] = tabPulseSinusTotal[I] - tabPulseSinusOn[100-I];
  }
  // cas particuliers 1 et 99 on force à 1/64
  tabPulseSinusOn[1] = 1;
  tabPulseSinusTotal[1] = 64;
  tabPulseSinusOn[99] = 63;
  tabPulseSinusTotal[99] = 64;


l'étape suivant c'est la répartition des demi-onde passante ou bloqué
La logique utilisé par André c'est de mettre toute les demi-onde passante au début du cycle
  l'inconvénient c'est de potentiel clignotement (quand c'est de longue séquence, ça devient visible pour l’œil humain) [++++et perturbation système de mesure sur courte période]

La logique LoLo69 c'est une répartition à la volée en utilisant la formule : ((pos * on_count) % total < on_count)
  c'est beaucoup mieux, avec quelques situations non appréciable 
   => cas 50%, on ne laisse passer que les demi- ondes d'une seul polarité (même sur enchainement de plusieurs séquence à 50%)
   => cas 17,26,47,48,49,51,52,53,74,83 majorité de demi-onde de même polarité (compensé par les demi ondes inverses lors de la séquence suivante)

Je propose de répartir des moments de conduction en onde complète (demi positive suivi de demi négative) séparé par des tempos régulièrement espacées (et placer une demi-onde isolé dans les cas impaires), ça commence a se compliquer pour trouver une formule qui fait ça à la volée

Avec un nombre sur 64 bits, 
Code :
uint64_t tabsequenceMultiSinus[101]; // en multisinus représentation binaire des moments passant et des moments bloqués (nombre de bits utiles dans PulseTotal[])

je code les bits a 1 quand ça doit être passant et 0 quand c'est bloqué / utilisation du nombre de bit correspondant la tabPulseSinusTotal[] (qui ne doit pas être plus que 64 !)  => c'est pour ça que les cas 1% et 99% qui était sur 73 demi onde se trouve avec les valeurs de 0% et 100% respectivement [comme on est dans des cas extrêmes, l'impact devrait être faible]

Code :
  // réparti les demi ondes passantes ou bloquées de manière ~équilibré en faisant des groupes demi-alternance+ et demi-alternance- associés //++MS
  for (int i = 0; i <= 50; i++) {  // premiere moitié de la table avec majorité de OFF  //++MS
    uint64_t tmp = 0ull;
    char shift = 0;
    uint8_t nbActif =  tabPulseSinusOn[i];
    if (((nbActif + 1) / 2) != 0)  // anti division par zero
      shift = ((tabPulseSinusTotal[i] + 1) - nbActif) / ((nbActif + 1) / 2);
    else
      shift = tabPulseSinusTotal[i] - 1;
    char nbON = 0;
    char p = 0;  // position
    switch (nbActif) {
      case 0 :
        tmp = 0;  // pas de ON tout est a zéro
        nbON = 0;
        p = 0;
        break;
      case 1 :
        tmp = 0b1;  // une seule demi alternance a ON
        nbON = 1;
        p = 1;
        break;
      case 2 :
        tmp = 0b11;  // Un alternance complete a ON
        nbON = 2;
        p = 2;
        break;
      default:  // jusque 50 on commence par 2 demi onde activées puis on shift xx demi onde en OFF
        tmp = 0b11;
        char nbON = 2;
        char p = 2;
        while ((p + shift + 2) < tabPulseSinusTotal[i]) {
          tmp <<= (shift + 1);              // decale vers la gauche avec des 0
          p += shift + 1;                   // nombre de bit vers la gauche
          if (nbON < nbActif) {             // si on a pas encore injecté tous les bits a mettre a 1
            tmp |= 0b1;                     // met le dernier bit a 1 si on a pas encore le compte
            nbON++;
          }
          tmp <<= 1;                        // decale de 1 a gauche en inserant un zero
          p++;
          if (nbON < nbActif) {             // si on a pas encore injecté tous les bits a mettre a 1
            tmp |= 0b1;                     // met le dernier bit a 1 si on a pas encore le compte
            nbON++;
          }
        }
    }
    tabsequenceMultiSinus[i] = 0ull;
    for (int j = 0; j < tabPulseSinusTotal[i]; j++) { // traduit la sequence sur 64 bits (uniquement les tabPulseSinusTotal[i] bits de faible poids sont utilisés)
      tabsequenceMultiSinus[i] <<= 1;
      tabsequenceMultiSinus[i] |= uint64_t((tmp >> j) & 0b1);
    }
  }  //++MS

  for (int i = 51; i <= 100; i++) {  // seconde partie de la table, avec une majorité de passant
    uint64_t tmp = 0ull;
    char shift = 0;
    uint8_t nbInActif =  tabPulseSinusOn[i];
    if (((nbInActif + 1) / 2) != 0 )  // anti division par zero
      shift = ((tabPulseSinusTotal[i] + 1) - nbInActif) / ((nbInActif + 1) / 2);
    else
      shift = tabPulseSinusTotal[i] - 1;
    char nbOFF = 0;
    char p = 0;  // position

    tmp = 0b11;// au dela de 50 on commence par 2 demi onde activées puis on shift xx demi onde en OFF
    nbOFF = 2;
    p = 2;
    while ((p + shift + 1) < tabPulseSinusTotal[i]) {
      tmp <<= (shift + 1);              // decale vers la gauche avec des 0
      p += shift + 1;                   // nombre de bit vers la gauche
      if (nbOFF < nbInActif) {          // si on a pas encore injecté tous les bits a mettre a 1
        tmp |= 0b1;                     // met le dernier bit a 1 si on a pas encore le compte
        nbOFF++;
      }
      tmp <<= 1;                        // decale de 1 a gauche en inserant un zero
      p++;
      if (nbOFF < nbInActif) {          // si on a pas encore injecté tous les bits a mettre a 1
        tmp |= 0b1;                     // met le dernier bit a 1 si on a pas encore le compte
        nbOFF++;
      }
    }
    tabsequenceMultiSinus[i] = 0ull;
    for (int j = 0; j < tabPulseSinusTotal[i]; j++) { // traduit la sequence sur 64 bits (uniquement les tabPulseSinusTotal[i] bits de faible poids sont utilisés)
      tabsequenceMultiSinus[i] <<= 1;
      tabsequenceMultiSinus[i] |= uint64_t((tmp >> j) & 0b1);
    }
  }

reste a utiliser les tables  tabPulseSinusTotal[] et  tabsequenceMultiSinus[] pour charge la séquence a utiliser en multisinus pour l'action adéquate (différentiation de traitement pour multisinus et train de sinus)
Code :
void GestionOverproduction() { // chaque 200ms (soit adaptation 5 fois par seconde)
  static uint8_t prevpercent[NBACTIONMAX];  // 0 a 100

Code :
        case 2 : //ACT_MULTISIN:   // 2:Multi Sinus
          int tmp = 100 - Retard[i];
          if (tmp == prevpercent[i]) {  // on continu la même séquence si le % de contrôle n’a pas changer,
            break;
          }
          PulseComptage[i] = 0;         // sinon on arrête la séquence en cours et on redémarre a début de la nouvelle séquence avec un nouveau % d'ouverture
          PulseOn[i] = tabPulseSinusOn[tmp];
          PulseTotal[i] = tabPulseSinusTotal[tmp];
          sequenceHalfWave[i] = tabsequenceMultiSinus[tmp] ;
          prevpercent[i] = tmp;
          break;
        case 3: //ACT_TRAINSIN:   // 3:Train de Sinus
          PulseOn[i] = 100 - Retard[i];
          PulseTotal[i] = 99;  //Nombre impair pour éviter courant continu
          break;
        case 4: //ACT_PWM:        //  4:PWM
          Vout = int32_t(RetardF[i] * 2.55);
          if (OutOn[i] == 1) Vout = 255 - Vout;
          ledcWrite(Gpio[i], Vout);
          break;

pour activer ou pas le SSR par période de 10ms ça se passe dans GestionIT_10ms, où il faut différencier le traitement multisinus et train de sinus
Code :
void IRAM_ATTR GestionIT_10ms() {  // en IRAM, (c'est appelé depuis une ISR), les variables modifiées doivent être volatile

Code :
      case 2: // ACT_MULTISIN: // 2:MultiSinus -> répartition des demi-onde passante et bloqué sur la durée nécessaire pour obtenir le % d'ouverture requis
        if (Gpio[i] >= 0) {
          if (PulseComptage[i] <= PulseTotal[i]) {
            if ((sequenceHalfWave[i] >> PulseComptage[i]) & 0b1) {
              digitalWrite(Gpio[i], OutOn[i]);
            } else {
              digitalWrite(Gpio[i], OutOff[i]);  //Stop
            }
            PulseComptage[i] = PulseComptage[i] + 1;
          }
          if (PulseComptage[i] >= PulseTotal[i]) {
            PulseComptage[i] = 0;  // relance une nouvelle séquence
          }
        }                              
        break;
      case 3: // ACT_TRAINSIN: // 3:Train de sinus  -> le bloc de demi onde passante au début complétés par une séquence de demi onde bloqués
        if (Gpio[i] >= 0) {  //Gpio valide
          if (PulseComptage[i] < PulseOn[i]) {
            digitalWrite(Gpio[i], OutOn[i]);
          } else {
            digitalWrite(Gpio[i], OutOff[i]);  //Stop
          }
          PulseComptage[i] = PulseComptage[i] + 1;
          if (PulseComptage[i] >= PulseTotal[i]) {
            PulseComptage[i] = 0;  // relance une nouvelle séquence
          }
        }
        break;
      case 4: // ACT_PWM:      // 4:PWM ne dépend pas IT 10ms
        break;

Je n'ai pas encore tout testé, il y a peut être quelques coquilles ...
Merci André Smile ,
Routeur V15.09b (since V2.01) / 1xESP32 (IP fixe) / Source UxI / 5 actions
Panneaux 1680Wc
1 Triac : ECS 2000W
1 SSR (multi) : ECS 1800W
1 SSR (On-Off) : Circulateur plancher chauffant eau 50W
1 SSR (multi) : circuit d'eau 1500W
1 SSR (multi) : Ultime 2000W
Répondre



Messages dans ce sujet
Multisinus le paradoxe - par Lolo69 - 27-09-2025, 02:44 PM
RE: Multisinus le paradoxe - par grostoto - 27-09-2025, 03:24 PM
RE: Multisinus le paradoxe - par Lolo69 - 27-09-2025, 04:22 PM
RE: Multisinus le paradoxe - par Ludovic35 - 27-09-2025, 04:50 PM
RE: Multisinus le paradoxe - par Lolo69 - 27-09-2025, 05:46 PM
RE: Multisinus le paradoxe - par Ludovic35 - 30-09-2025, 08:50 AM
RE: Multisinus le paradoxe - par Lolo69 - 30-09-2025, 02:00 PM
RE: Multisinus le paradoxe - par Lolo69 - 30-09-2025, 02:21 PM
RE: Multisinus le paradoxe - par Juju67 - 04-10-2025, 11:39 AM
RE: Multisinus le paradoxe - par grostoto - 30-09-2025, 02:05 PM
RE: Multisinus le paradoxe - par Lolo69 - 04-10-2025, 12:11 PM
RE: Multisinus le paradoxe - par Oliv' - 08-10-2025, 02:30 PM
RE: Multisinus le paradoxe - par Lolo69 - 08-10-2025, 08:50 PM
RE: Multisinus le paradoxe - par michy - 10-10-2025, 01:07 PM
RE: Multisinus le paradoxe - par Lolo69 - 10-10-2025, 01:49 PM
RE: Multisinus le paradoxe - par michy - 10-10-2025, 02:40 PM
RE: Multisinus le paradoxe - par F1ATB - 10-10-2025, 04:40 PM
RE: Multisinus le paradoxe - par michy - 10-10-2025, 05:29 PM
RE: Multisinus le paradoxe - par Lolo69 - 11-10-2025, 01:27 PM
RE: Multisinus le paradoxe - par michy - 12-10-2025, 12:11 AM
RE: Multisinus le paradoxe - par F1ATB - 12-10-2025, 06:41 AM
RE: Multisinus le paradoxe - par Lolo69 - 12-10-2025, 07:21 AM
RE: Multisinus le paradoxe - par michy - 12-10-2025, 10:26 PM
RE: Multisinus le paradoxe - par Lolo69 - 13-10-2025, 07:34 AM
RE: Multisinus le paradoxe - par memz - 13-10-2025, 08:35 AM
RE: Multisinus le paradoxe - par Lolo69 - 13-10-2025, 09:31 PM
RE: Multisinus le paradoxe - par F1ATB - 13-10-2025, 09:08 AM
RE: Multisinus le paradoxe - par F1ATB - 14-10-2025, 03:16 AM
RE: Multisinus le paradoxe - par F1ATB - 14-10-2025, 04:19 AM
RE: Multisinus le paradoxe - par Lolo69 - 14-10-2025, 07:40 AM
RE: Multisinus le paradoxe - par clyon44 - 15-10-2025, 09:02 AM
RE: Multisinus le paradoxe - par Lolo69 - 15-10-2025, 04:24 PM
RE: Multisinus le paradoxe - par F1ATB - 16-10-2025, 09:03 AM
RE: Multisinus le paradoxe - par Lolo69 - 16-10-2025, 10:12 AM
RE: Multisinus le paradoxe - par clyon44 - 16-10-2025, 01:26 PM
RE: Multisinus le paradoxe - par Lolo69 - 16-10-2025, 05:43 PM
RE: Multisinus le paradoxe - par F1ATB - 16-10-2025, 02:02 PM
RE: Multisinus le paradoxe - par michy - 17-10-2025, 11:36 PM
RE: Multisinus le paradoxe - par Juju67 - 18-10-2025, 10:18 AM
RE: Multisinus le paradoxe - par Ludovic35 - 18-10-2025, 03:46 PM
RE: Multisinus le paradoxe - par F1ATB - 18-10-2025, 04:05 PM
RE: Multisinus le paradoxe - par F1ATB - 18-10-2025, 04:16 PM
RE: Multisinus le paradoxe - par michy - 18-10-2025, 05:57 PM
RE: Multisinus le paradoxe - par Lolo69 - 18-10-2025, 04:20 PM
RE: Multisinus le paradoxe - par Sgb31 - 18-10-2025, 05:07 PM

Atteindre :


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

Moteur MyBB, © 2002-2025 Melroy van den Berg.