Messages : 136
Sujets : 9
Inscription : Oct 2024
(25-03-2026, 10:37 PM)Lolo69 a écrit : Et non dommage que tu sois aussi obstiné ça te rend aveugle .
Je rend aussi hommage à Mr Bresenham grand mathématicien et informaticien dont les travaux m’inspirent beaucoup
Réfléchis un peu à la précison et tu réviseras ce que c est qu un regulateur PID et que justement c est l accumulation interne qui déstabilise toutes la boucle . La commande ayant effectivement que 100 pas il ne faut pas les gaspiller avant …
Bref j’ attend ton code avec impatience pour comparer les courbes mais je suis serein , meme si je m’en fout je connais déjà le résultat.
En attendant mon esp32 passe 56 cycles pour calculer le polynôme avec des cycles max sur les 2 cœurs à 50ms.
Comme le cache est bien chaud pas de latence pour aller lire un tableau en dram.
Admettons 100 cycles ça fait jamais que 400nanoS sur des cycles PID à 200ms ça laisse de la marge
Tes tableaux lisent des indexes en float ? tu as raison j ai etait un peux simpliste ma fonctions donner avait encore trop d erreur mais j ai corriger.
par contre elle a besoin de plus de temps de calcul 20us mais sur 200ms ca ne fait que 0.01% du temps disponible, comme tu dit ca laisse de la marge.
ma fonction :
Code : float ouverturebis(float p) {
if (p <= 0) return 0; if (p >= 100) return 100;
bool m = p > 50; if (m) p = 100 - p;
float a = 1.5708f;
for (int i = 0; i < 3; i++) {
float s = sinf(a), c2 = 1 - s * s;
a -= ((PI - a - s * sqrtf(c2)) * INV_PI - p * 0.01f) / ((2 * c2 - 2) * INV_PI);
}
float o = 100 * (1 - a * INV_PI);
return m ? 100 - o : o;
}
avec #define INV_PI 0.318309886f
le mieux c est encore de tester en reel sur un esp32 le code de test:
Code : #include <Arduino.h>
#define INV_PI 0.318309886f
// =============================
// Polynôme degré 7 (Horner)
// =============================
float ouverturePoly(float x) {
return (((((((1.77247643e-10f * x
- 6.20366752e-08f) * x
+ 8.72516510e-06f) * x
- 6.30374389e-04f) * x
+ 2.48566569e-02f) * x
- 5.26588432e-01f) * x
+ 6.06926288e+00f) * x);
}
// ============================
float ouverturebis(float p) {
if (p <= 0) return 0; if (p >= 100) return 100;
bool m = p > 50; if (m) p = 100 - p;
float a = 1.5708f;
for (int i = 0; i < 3; i++) {
float s = sinf(a), c2 = 1 - s * s;
a -= ((PI - a - s * sqrtf(c2)) * INV_PI - p * 0.01f) / ((2 * c2 - 2) * INV_PI);
}
float o = 100 * (1 - a * INV_PI);
return m ? 100 - o : o;
}
// =============================
// Fonction inverse (vérification)
// =============================
float puissanceFromOuverture(float ouv) {
if (ouv <= 0) return 0;
if (ouv >= 100) return 100;
float alpha = PI * (1.0f - ouv / 100.0f);
return (PI - alpha + sinf(2.0f * alpha) * 0.5f) * INV_PI * 100.0f;
}
// =============================
// Benchmark vitesse
// =============================
void testVitesse() {
const int N = 1000;
Serial.println("\n===== TEST VITESSE =====");
// Polynôme
unsigned long t0 = micros();
for (int i = 0; i < N; i++) {
float x = random(0, 10000) / 100.0f;
ouverturePoly(x);
}
unsigned long t1 = micros();
//
unsigned long t2 = micros();
for (int i = 0; i < N; i++) {
float x = random(0, 10000) / 100.0f;
ouverturebis(x);
}
unsigned long t3 = micros();
float tPoly = (t1 - t0) / (float)N;
float tbis = (t3 - t2) / (float)N;
Serial.printf("Poly : %.3f us / appel\n", tPoly);
Serial.printf("bis : %.3f us / appel\n", tbis);
}
// =============================
// Test précision
// =============================
void testPrecision() {
Serial.println("\n===== TEST PRECISION =====");
Serial.println("\n--- Polynome ---");
Serial.println("Pw\tOuv\tPw_verif\tErreur");
for (int i = 0; i <= 100; i++) {
float pw = (float)i;
float ouv = ouverturePoly(pw);
float pw2 = puissanceFromOuverture(ouv);
float err = pw2 - pw;
Serial.printf("%3d\t%.2f\t%.2f\t\t%.3f\n", i, ouv, pw2, err);
}
Serial.println("\n--- bis ---");
Serial.println("Pw\tOuv\tPw_verif\tErreur");
for (int i = 0; i <= 100; i++) {
float pw = (float)i;
float ouv = ouverturebis(pw);
float pw2 = puissanceFromOuverture(ouv);
float err = pw2 - pw;
Serial.printf("%3d\t%.2f\t%.2f\t\t%.3f\n", i, ouv, pw2, err);
}
}
// =============================
// Setup
// =============================
void setup() {
Serial.begin(115200);
delay(2000);
randomSeed(esp_random());
testVitesse();
testPrecision();
}
void loop() {
}
le tester est en 2 parties
1/ envoi 1000 valeurs aleatoires entre 0.0 et 100 et calcule le temps moyen pour 1 calcul .
2/ calcul la précision du en verififiant le résultat en faisant le calcul inverse.
resultat moniteur serie
===== TEST VITESSE =====
Poly : 0.689 us / appel
bis : 19.387 us / appel
--- Polynome ---
Pw Ouv Pw_verif Erreur
0 0.00 0.00 0.000
1 5.57 0.11 -0.887
2 10.22 0.69 -1.312
3 14.09 1.77 -1.230
4 17.29 3.21 -0.794
5 19.92 4.81 -0.191
6 22.08 6.43 0.428
7 23.83 7.96 0.961
8 25.27 9.35 1.354
9 26.44 10.59 1.587
10 27.40 11.66 1.664
11 28.20 12.60 1.603
12 28.88 13.43 1.430
13 29.46 14.17 1.171
14 29.99 14.85 0.854
15 30.48 15.50 0.505
16 30.96 16.14 0.145
17 31.43 16.79 -0.206
18 31.91 17.47 -0.533
19 32.40 18.18 -0.822
20 32.92 18.94 -1.065
21 33.46 19.75 -1.254
22 34.03 20.61 -1.385
23 34.63 21.54 -1.457
24 35.26 22.53 -1.469
25 35.90 23.58 -1.423
26 36.57 24.67 -1.325
27 37.25 25.82 -1.179
28 37.94 27.01 -0.992
29 38.64 28.23 -0.771
30 39.35 29.47 -0.526
31 40.05 30.73 -0.266
32 40.74 32.00 0.001
33 41.43 33.27 0.266
34 42.10 34.52 0.519
35 42.75 35.75 0.754
36 43.39 36.96 0.963
37 44.00 38.14 1.139
38 44.59 39.28 1.279
39 45.15 40.38 1.378
40 45.69 41.44 1.435
41 46.21 42.45 1.448
42 46.70 43.42 1.418
43 47.17 44.35 1.346
44 47.61 45.23 1.235
45 48.04 46.09 1.087
46 48.45 46.91 0.909
47 48.85 47.71 0.705
48 49.24 48.48 0.481
49 49.62 49.24 0.244
50 50.00 50.00 -0.001
51 50.38 50.76 -0.245
52 50.76 51.52 -0.483
53 51.15 52.29 -0.707
54 51.55 53.09 -0.911
55 51.96 53.91 -1.089
56 52.39 54.76 -1.236
57 52.83 55.65 -1.348
58 53.30 56.58 -1.419
59 53.79 57.55 -1.450
60 54.31 58.56 -1.437
61 54.85 59.62 -1.380
62 55.41 60.72 -1.281
63 56.00 61.86 -1.141
64 56.61 63.04 -0.965
65 57.25 64.24 -0.755
66 57.90 65.48 -0.522
67 58.57 66.73 -0.268
68 59.25 68.00 -0.004
69 59.95 69.26 0.264
70 60.65 70.52 0.524
71 61.35 71.77 0.768
72 62.05 72.99 0.989
73 62.75 74.18 1.176
74 63.43 75.32 1.322
75 64.10 76.42 1.421
76 64.74 77.46 1.465
77 65.37 78.45 1.452
78 65.96 79.38 1.382
79 66.53 80.25 1.251
80 67.08 81.06 1.060
81 67.60 81.82 0.819
82 68.09 82.53 0.528
83 68.57 83.20 0.203
84 69.04 83.85 -0.150
85 69.51 84.49 -0.511
86 70.00 85.14 -0.858
87 70.53 85.82 -1.175
88 71.12 86.57 -1.434
89 71.80 87.39 -1.609
90 72.60 88.33 -1.670
91 73.56 89.41 -1.593
92 74.73 90.64 -1.359
93 76.16 92.03 -0.968
94 77.92 93.57 -0.433
95 80.07 95.19 0.188
96 82.70 96.79 0.791
97 85.90 98.23 1.228
98 89.77 99.31 1.310
99 94.43 99.89 0.887
100 99.99 100.00 -0.000
--- bis ---
Pw Ouv Pw_verif Erreur
0 0.00 0.00 0.000
1 13.11 1.43 0.433
2 15.32 2.26 0.258
3 17.19 3.15 0.155
4 18.83 4.09 0.093
5 20.28 5.06 0.056
6 21.58 6.03 0.034
7 22.78 7.02 0.021
8 23.89 8.01 0.013
9 24.92 9.01 0.008
10 25.90 10.00 0.005
11 26.82 11.00 0.003
12 27.69 12.00 0.002
13 28.53 13.00 0.001
14 29.33 14.00 0.001
15 30.10 15.00 0.000
16 30.85 16.00 0.000
17 31.58 17.00 0.000
18 32.28 18.00 0.000
19 32.96 19.00 0.000
20 33.63 20.00 0.000
21 34.28 21.00 0.000
22 34.92 22.00 0.000
23 35.55 23.00 0.000
24 36.16 24.00 0.000
25 36.76 25.00 0.000
26 37.36 26.00 0.000
27 37.94 27.00 0.000
28 38.51 28.00 0.000
29 39.08 29.00 0.000
30 39.64 30.00 0.000
31 40.20 31.00 0.000
32 40.74 32.00 0.000
33 41.29 33.00 0.000
34 41.82 34.00 0.000
35 42.35 35.00 0.000
36 42.88 36.00 0.000
37 43.41 37.00 0.000
38 43.93 38.00 0.000
39 44.44 39.00 0.000
40 44.96 40.00 0.000
41 45.47 41.00 0.000
42 45.98 42.00 0.000
43 46.49 43.00 0.000
44 46.99 44.00 0.000
45 47.49 45.00 0.000
46 48.00 46.00 0.000
47 48.50 47.00 0.000
48 49.00 48.00 0.000
49 49.50 49.00 0.000
50 50.00 50.00 0.000
51 50.50 51.00 0.000
52 51.00 52.00 0.000
53 51.50 53.00 0.000
54 52.00 54.00 0.000
55 52.51 55.00 0.000
56 53.01 56.00 0.000
57 53.51 57.00 0.000
58 54.02 58.00 0.000
59 54.53 59.00 0.000
60 55.04 60.00 0.000
61 55.56 61.00 0.000
62 56.07 62.00 0.000
63 56.59 63.00 0.000
64 57.12 64.00 0.000
65 57.65 65.00 0.000
66 58.18 66.00 0.000
67 58.71 67.00 0.000
68 59.26 68.00 0.000
69 59.80 69.00 0.000
70 60.36 70.00 0.000
71 60.92 71.00 0.000
72 61.49 72.00 0.000
73 62.06 73.00 0.000
74 62.64 74.00 0.000
75 63.24 75.00 0.000
76 63.84 76.00 0.000
77 64.45 77.00 0.000
78 65.08 78.00 0.000
79 65.72 79.00 0.000
80 66.37 80.00 0.000
81 67.04 81.00 0.000
82 67.72 82.00 0.000
83 68.42 83.00 0.000
84 69.15 84.00 0.000
85 69.90 85.00 0.000
86 70.67 86.00 -0.001
87 71.47 87.00 -0.001
88 72.31 88.00 -0.002
89 73.18 89.00 -0.003
90 74.10 90.00 -0.005
91 75.08 90.99 -0.008
92 76.11 91.99 -0.013
93 77.22 92.98 -0.021
94 78.42 93.97 -0.034
95 79.72 94.94 -0.056
96 81.17 95.91 -0.093
97 82.81 96.85 -0.155
98 84.68 97.74 -0.258
99 86.89 98.57 -0.433
100 100.00 100.00 -0.000
un graphique avec le resultat du moniteur serie est plus parlant.
Messages : 1,139
Sujets : 9
Inscription : Sep 2024
28-03-2026, 03:06 PM
(Modification du message : 28-03-2026, 03:22 PM par Lolo69.)
Ce serait mieux que tu ouvres une discussion plutôt que de polluer la mienne d autant plus que ta formule de base étant fausse tes comparaison le sont également. Moi j attend un programme pour le routeur que je puisse comparer les courbes de routages. C est étonnant qu une lecture d un tableau prends 30 fois plus de temps qu un polynôme , non ? Et tu es encore sur du pw entier , alors qu il faut intercaler la linéarisation en flottant avant la conversion en int sinon il n y a aucun intérêt
(27-03-2026, 04:40 PM)Lolo69 a écrit : En attendant la méthode de 59Jag, vous pouvez donc tester la méthode Polynôme qui fonctionne parfaitement chez moi sans engendrer aucun reset ESP depuis 1 semaine
Pour cela il suffit d'inserer les quelques lignes de code ci-dessous dans le fichier Solar_routeur_v17_06 , entre la ligne 1746 et 1748 (RetardF[i] = constrain(RetardF[i], 0.0, 100.0)
Code : //LBE Linearisation mode decoupe sinus uniquement faire un if mode decoupe sinus plus tard
// LBE Linearisation polynôme 7ème degré
if (Actif[i]==MODE_DECOUPE_ONOFF) {//Linearisation uniquement pour le mode découpe de sinus
float puissance_pid = 100.0f - RetardF[i]; // Sortie PID en puissance (0-100%)
//Polynome degré 7
// Merci Mike pour l'Optimisation methode Horner pour réduire les multiplications Estimations 90ns
// Merci Laurent53 pour le forcage en float poue eviter les calculs inutiles et gourmand en double
float puissance_corrigee =
(((((((
1.77247643e-10f * puissance_pid
- 6.20366752e-08f) * puissance_pid
+ 8.72516510e-06f) * puissance_pid
- 6.30374389e-04f) * puissance_pid
+ 2.48566569e-02f) * puissance_pid
- 5.26588432e-01f) * puissance_pid
+ 6.06926288e+00f) * puissance_pid
);
RetardF[i] = 100.0f - puissance_corrigee;
}
//fin linearisation
Pour expliquer un peu mieux comment cela fonctionne , avec l'image ci dessous prenons un exemple avec
Sortie PID = 20%
à 20 % de sortie si on ne linearise pas on va donc aller sur la courbe bleue, donc 5 % de puissance. , c est à dire un ratio de 20/5 = 4 à ce point de fonctionnenement
le probleme est que passe à 40% sur la courbe bleue on a 30% c est à dire un ratio de 40/30= 1.33 ce qui est très différent du point de fonctionnement précédent, donc le PID ne sait pas comment agir, et le reglage PID bon a un point sera mauvais à l'autre , entrainant une mauvaise performance
Avec la linearisation , on va aller sur la courbe violette ( Polynome simplfié ou la courbe Verte calcul par regression de Newton)
à 20% de sortie PID la courbe violette donne 5
à 5 la courbe violette donne 20
Donc 20 donne 20 Yessss c est lineaire ( ratio 20/20 =1)
Si vous faites l exercice à PID=40 % vous arriverez aussi 40% donne 40 Yessssss c est lineaire ( ratio 40/40 =1) et ca c est très bon pour regler le PID de façon très réactive sans partir en osclliation ( je vous laisse voir les messages au début de cette discussion pour voir les résultats)
Pour aller plus loin, l'interet du polynome par rapport à une table de correspondance c 'est que c est un calcul continu, sans arrondi
Exemple si PID OUT=10.5 % le polynome va piloter le triac à 28 % ( la valeur idéale) la où une table oscillerait en permanence entre 27 et 29 generant du flickering
On peut laisser les modifs de gain , même si c est moins nécessaires ça derange pas
Messages : 136
Sujets : 9
Inscription : Oct 2024
28-03-2026, 03:47 PM
(Modification du message : 28-03-2026, 03:50 PM par 59jag.)
(25-03-2026, 10:37 PM)Lolo69 a écrit : Réfléchis un peu à la précison et tu réviseras ce que c est qu un regulateur PID et que justement c est l accumulation interne qui déstabilise toutes la boucle . La commande ayant effectivement que 100 pas il ne faut pas les gaspiller avant …
Bref j’ attend ton code avec impatience pour comparer les courbes mais je suis serein , meme si je m’en fout je connais déjà le résultat.
(25-03-2026, 10:37 PM)Lolo69 a écrit : En attendant la méthode de 59Jag, vous pouvez donc tester la méthode Polynôme qui fonctionne parfaitement chez moi sans engendrer aucun reset ESP depuis 1 semaine
je répond juste a tes messages.
tu as meme âs pris le temps de regarder le code il y a pas de lecture de tableaux, pw est un float .
pour le code j ai mis la function dans le routeur faut l appeler comme ceci
Code : if (Actif[i]==MODE_DECOUPE_ONOFF) {
float puissance_pid = 100.0f - RetardF[i];
float puissance_corrigee = ouverturebis(puissance_pid);
RetardF[i] = 100.0f - puissance_corrigee;
}
le code esp32 ne ment pas c est le résultat réel des 2 fonctions , je pensais que tu voulais une bonne précision . c etait juste pour aider
apres si tu veux pas de réponse de ma part ne me me demande pas des choses.
Messages : 1,139
Sujets : 9
Inscription : Sep 2024
28-03-2026, 10:51 PM
(Modification du message : 31-03-2026, 11:33 AM par Lolo69.)
@ Alexandeur , tu as désactivé tes messages privés on ne peut pas répondre. Sinon la réponse est oui les 2 cohabitent très bien
@j59Jag . Tu es extrêmement brillant en math et en codage il n y a aucun doute.
Je retiens toutefois ta démarche car elle terriblement intéressante et l’optimisation du code très maligne pour réduire les ressources ESP32. Si ces optimisations sont de toi je dis chapeau bas
Je me suis triturer les méninges pour décoder car c est pas très humain de penser que cos(alpha)^2 c est 1 - sin( alpha) ^2 y a que Pythagore qui peut voir ca du premier coup d 'oeil !! Tout ça pour éviter de calcul le cos(alpha) pour réduire les cycles
Meme si la symetrie se voit , ce n'est pas très humain non plus de faire un double miroir de 0-50 pour voir le 50-100 poru gagner quelques cycles CPU,bonjour la relecture du programme... Bref ce n'est plus de mon age ces exercices mathematiques de haut vol ;-)
On a dû perdre pas mal de monde dans cette joute mathématique mais en tout cas merci et bravo ca fait plaisir à voir qu'il y a encore des personnes qui savent compter en France
Donc je résume Oui ton code est extrêmement précis car il fait une régression de Newton ( c est exactement ce que je ne voulais pas faire car trop complexe) . Mais de la à affirmer dans ta première réponse que mon code était trop compliqué, ce n est pas justifié du tout par rapport au tien qui l est beaucoup plus pour être finalement beaucoup plus gourmand en cycle CPU malgré les grosses optimisations trigonométriques et algébriques.
Et il faut bien se rendre à l évidence annoncée du départ cette fonction transcendante ne se laisse pas inverser sans effort!
Meme si le code que je propose ne te plaît pas, il remplit les objectifs et le resultat sur les courbes de routage sont là pour le démontrer.
Quand tu auras proposé les modifs à implémenter dans le RMS F1ATB je serais ravi de les implémenter pour voir le résultat sur le routage. Pour l’instant, je ne suis pas assez compétent pour faire tes modifs dans le code et gagner moins de 1% d écart par rapport à l idéal ne sera pas visible
voila un comparatif encore théorique mais je dirais quand meme avantage au polynome , un chouille moins precis mais bien plus rapide et facile à implementer
Messages : 53
Sujets : 14
Inscription : Sep 2024
(28-03-2026, 03:06 PM)Lolo69 a écrit : Ce serait mieux que tu ouvres une discussion plutôt que de polluer la mienne d autant plus que ta formule de base étant fausse tes comparaison le sont également. Moi j attend un programme pour le routeur que je puisse comparer les courbes de routages. C est étonnant qu une lecture d un tableau prends 30 fois plus de temps qu un polynôme , non ? Et tu es encore sur du pw entier , alors qu il faut intercaler la linéarisation en flottant avant la conversion en int sinon il n y a aucun intérêt
(27-03-2026, 04:40 PM)Lolo69 a écrit : En attendant la méthode de 59Jag, vous pouvez donc tester la méthode Polynôme qui fonctionne parfaitement chez moi sans engendrer aucun reset ESP depuis 1 semaine
Pour cela il suffit d'inserer les quelques lignes de code ci-dessous dans le fichier Solar_routeur_v17_06 , entre la ligne 1746 et 1748 (RetardF[i] = constrain(RetardF[i], 0.0, 100.0)
Code : //LBE Linearisation mode decoupe sinus uniquement faire un if mode decoupe sinus plus tard
// LBE Linearisation polynôme 7ème degré
if (Actif[i]==MODE_DECOUPE_ONOFF) {//Linearisation uniquement pour le mode découpe de sinus
float puissance_pid = 100.0f - RetardF[i]; // Sortie PID en puissance (0-100%)
//Polynome degré 7
// Merci Mike pour l'Optimisation methode Horner pour réduire les multiplications Estimations 90ns
// Merci Laurent53 pour le forcage en float poue eviter les calculs inutiles et gourmand en double
float puissance_corrigee =
(((((((
1.77247643e-10f * puissance_pid
- 6.20366752e-08f) * puissance_pid
+ 8.72516510e-06f) * puissance_pid
- 6.30374389e-04f) * puissance_pid
+ 2.48566569e-02f) * puissance_pid
- 5.26588432e-01f) * puissance_pid
+ 6.06926288e+00f) * puissance_pid
);
RetardF[i] = 100.0f - puissance_corrigee;
}
//fin linearisation
Pour expliquer un peu mieux comment cela fonctionne , avec l'image ci dessous prenons un exemple avec
Sortie PID = 20%
à 20 % de sortie si on ne linearise pas on va donc aller sur la courbe bleue, donc 5 % de puissance. , c est à dire un ratio de 20/5 = 4 à ce point de fonctionnenement
le probleme est que passe à 40% sur la courbe bleue on a 30% c est à dire un ratio de 40/30= 1.33 ce qui est très différent du point de fonctionnement précédent, donc le PID ne sait pas comment agir, et le reglage PID bon a un point sera mauvais à l'autre , entrainant une mauvaise performance
Avec la linearisation , on va aller sur la courbe violette ( Polynome simplfié ou la courbe Verte calcul par regression de Newton)
à 20% de sortie PID la courbe violette donne 5
à 5 la courbe violette donne 20
Donc 20 donne 20 Yessss c est lineaire ( ratio 20/20 =1)
Si vous faites l exercice à PID=40 % vous arriverez aussi 40% donne 40 Yessssss c est lineaire ( ratio 40/40 =1) et ca c est très bon pour regler le PID de façon très réactive sans partir en osclliation ( je vous laisse voir les messages au début de cette discussion pour voir les résultats)
Pour aller plus loin, l'interet du polynome par rapport à une table de correspondance c 'est que c est un calcul continu, sans arrondi
Exemple si PID OUT=10.5 % le polynome va piloter le triac à 28 % ( la valeur idéale) la où une table oscillerait en permanence entre 27 et 29 generant du flickering
On peut laisser les modifs de gain , même si c est moins nécessaires ça derange pas
Bonjour Lolo69, bravo pour le travail accompli. Peut-on l’intégrer à 17.16 ? Si ce n’est déjà pas le cas ?
Messages : 1,139
Sujets : 9
Inscription : Sep 2024
Ça c est pas moi qui décide lol
|