Arc en trigo

Bonjour,
Je suis sur un projet de gestion de chauffage, et je coince sur la courbe de la "loi de chauffe" que je veux mettre en place.
L'écran tactile que j'utilise m'oblige à certaines choses pour afficher.

Mon problème (j'y viens enfin...) est que je dois afficher une courbe que je ne peux que dessiner de droite à gauche, pixel par pixel et qui doit représenter la courbe désirée.
J'ai joins un petit croquis pour que ce soit plus clair. Les flèches vertes représentent un bouton virtuel qui permettrai la déformation de la courbe. La courbe linéaire a été facile à faire, mais la courbe expo ou log ??? J'ai essayé le cercle, l’ellipse (arc) ou les courbes exponentielle ou logarithmique mais sans succès (il est vrai que je ne suis pas doué)
Merci par avance.

Arc.jpg

Ce que tu veux c'est définir une courbe qui passe par trois points

  • 0,0
  • 1,1
  • Et une valeur que tu choisis par exemple pour 0.5
    La courbe la plus simple pour ça est une parabole. C'est une courbe d'équation y=ax^2+bx+c (x^2 c'est x au carré)

En étudiant un peu le problème on voit qu'il faut le séparer en deux cas, selon que la valeur à 0.5 est supérieure ou inférieure à 0.5 (si elle vaut exactement 0.5 la courbe est une droite)
Appelons cette valeur cible V, je te passe les calculs intermédiaires...

Premier cas : V<0.5
L'équation est
y = (2-4V) x^2 + (4V-1) x

Deuxième cas : V>0.5
y = (2-4V) (1-x)^2 + (4V-3) (1-x) +1
Soit
y = (2-4V) x^2 + (4-4V) x

(sauf erreur... :confused: )
Selon la valeur de ton paramètre V, tu n'as plus qu'à calculer les coefficients et tracer la bonne courbe, x variant entre 0 et 1

Super ! Merci pour la réponse, je vais essayer de mettre ça en application et je reviens donner le résultat.

Bon ma réjouissance n'a été que de courte durée, mais je l'ai dis, je suis nul.
Je n'obtiens qu'un nuage de points pour V < 0.5 ou V > 0.5
Voici un court extrait du programme qui doit faire le job:

    hChauffe = 80;                                    // Point haut de la courbe de chauffe (loi de chauffe)
    bChauffe = 10;                                    // Point bas de la courbe de chauffe (loi de chauffe)
    lChauffe = 4;                                       // Coefficient de linéarité (courbe lin, log ou exp etc...)

    float m = bChauffe - 10.0;                     // Position graphique, l'échelle verticale commence à 10
    float d = hChauffe - bChauffe;                // Différence entre température mini et maxi de chauffage
    float h = ((225.0 / 80.0) * d) / 369.0;     // Proportions graphique => 225 = hauteur, 369 = largeur
    float s = lChauffe / 10.0;                       // lChauffe / 10 (lChauffe est stocké sous forme d'entier)

    for (i=369; i>=0; i--) {                          
      if (lChauffe == 5) {
        value = (h * i) + m;
      } else if(lChauffe < 5) {
        value = (2-4*s) * pow(i, 2) + (4*s-1) * i;
      } else {
        value = (2-4*s) * pow(i, 2) + (4-4*s) * i;
      }
      Serial.print(F("Value => "));
      Serial.print(value);
      TFTlcd.SetWaveformValue(pageID,9,1,value);
      delay(10);
    }

J'ai dû me perdre dans tes explications, je t'en demande pardon.

Non, j'ai omis d'expliquer une étape. Pour simplifier le problème de mon côté, j'ai utilisé des variables "reduites", c'est à dire que j'ai tout ramené entre 0 et 1.

Ta température en abscisse qui varie entre -20 et 20 je l'ai ramenée entre 0 et 1. Idem pour celle qui varie entre 10 et 80.

Donc, avant de faire les calculs des courbes, tu dois mapper ta température pour la mettre entre 0 et 1, avec la fonction map (tu connais ?). Ensuite tu appliques les formules, qui te donnent un résultat entre 0 et 1, que tu mappes aussi pour le ramener entre 10 et 80.

Est-ce clair ? Pense à mapper aussi la valeur cible pour que V soit entre 0 et 1.

fonction "map"

En français :
langage mathématique : on parle d’une translation associée à une homothétie.
langage populaire : ce n'est pas une simplissime règle de trois mais ce n'en est vraiment pas loin.

L'avantage d'utiliser "map" c'est que tu n'a aucun code à écrire mais autant comprendre ce que fait la fonction.

Je n'ai pas compris ce que "trigo" vient faire ici.
Au cas où je précise qu'en mathématiques et donc en C/C++ les degrés sont inconnus il faut utiliser les radians comme unité d'angle dans les fonctions trigonométriques comme sinus, cosinus, tangente.

68tjs => Tout a fait d'accord avec toi, mais si j'ai parlé de trigo c'est parce que je suis partie sur sinus et cosinus pour ma courbe (j'avais tout faux) et je sais qu'il faut utiliser le radian en c/c++ comme dans beaucoup d'autres langages.

lesept => je dois être encore plus nul que prévu, mais cette fois j'obtiens une ligne à hauteur de 10°.
Comme je l'ai déjà dis, je ne peux pas maitriser x, car il est réglé par le firmware de l'écran, j’envoie que Y et X se décale automatiquement d'un pixel à chaque envoi.

    hChauffe = 80;
    bChauffe = 10;
    lChauffe = 4;

    float V = lChauffe / 10.0;
    float x = 0;
    float y = 0;
    
    for (i=369; i>=0; i--) {
      x = map(i, 0, 369, 0, 1);
      if (lChauffe == 5) {
        value = (h * i) + m;
      } else if(lChauffe < 5) {
        y = (2-4*V) * pow(x, 2) + (4*V-1) * x;
        value = map(z, 0, 1, 10, 80) + m;
      } else {
        y = (2-4*V) * pow(x, 2) + (4-4*V) * x;
        value = map(z, 0, 1, 10, 80) + m;
      }
      TFTlcd.SetWaveformValue(pageID,9,1,value); // Point à écrire dans le graphisme
      delay(10);
    }

C'est y qu'il faut mapper et pas z

Désolé, j'ai modifié certaine variables pour coller à ton exemple, mais je viens de recompiler et j'ai pareil parce qu'avant de poster j'avais bien la bonne variable en map.
Sinon pour toi il n'y a pas d'erreur dans le code ?

Bonjour,

Attention, map calcule en long retourne un long. Donc il va retourner soit 0 soit 1.
Il faut faire le calcul explicitement en flottants.

J'ai tout mis en flottant mais cela ne change rien, la ligne est toujours aussi plate.
lesept => Juste une chose, ai-je bien interprété la formule ?

Code corrigé :

hChauffe = 80;
bChauffe = 10;
lChauffe = 4; 

float m = bChauffe - 10.0;
float d = hChauffe - bChauffe;
float h = ((225.0 / 80.0) * d) / 369.0;

float V = lChauffe / 10.0;
float x = 0;
float y = 0;

for (i=369; i>=0; i--) {
  x = map(i, 0.0, 369.0, 0.0, 1.0);
  if (lChauffe == 5) {
    value = (h * i) + m;
  } else if(lChauffe < 5) {
    y = (2.0-4.0*V) * pow(x, 2) + (4.0*V-1.0) * x;
    value = map(y, 0.0, 1.0, 10.0, 80.0) + m;
  } else {
    y = (2.0-4.0*V) * pow(x, 2) + (4.0-4.0*V) * x;
    value = map(y, 0.0, 1.0, 10.0, 80.0) + m;
  }
  TFTlcd.SetWaveformValue(pageID,9,1,value);
  delay(10);
}

Il ne faut pas utiliser map!
Tu as beau mettre des arguments flottants les calculs sont faits en entiers longs.

Ha ! Ok, je n'avais pas compris, je vais faire les calculs en direct et je reposte.

Tu peux te faire une fonction map qui calcule en flottant par exemple fmap et tu l'utilises pour tes calculs

float fmap(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Je pense que value devrait être un tableau et que tu dois faire
value[ i ] = map (...)
Mais je ne sais pas ce que fait SetWaveformValue

Sinon je ne comprends pas ce que représente lChauffe

S'il ne faut pas utiliser map, il suffit de refaire une fonction qu'on appellerait mapfloat par exemple et qui contient exactement les mêmes lignes que map

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Edit : Damned, grillé par Kamill !

YES ! Ça commence à venir, j'ai essayé avec V = 0.4 et V = 0.7 et la courbe change bien de coté.

Ce qui ne va pas en revanche, c'est que le haut de la courbe devrait atteindre 80° et elle atteint péniblement 40° avec V=0.4 et 23° avec V=0.7.

Si vous avez une idée sur la question...

Merci à tous.

Bon ben cette fois c'est gagné, grâce à vous, merci beaucoup pour votre aide.

Code final qui fonctionne :

hChauffe = 80; // Point haut de la courbe de chauffe (loi de chauffe)
bChauffe = 10; // Point bas de la courbe de chauffe (loi de chauffe)
lChauffe = 4;  // Coefficient de linéarité (courbe linéaire ou logarithmique etc...)

float m = bChauffe - 10.0; // Position graphique, l'échelle verticale commence à 10
float d = hChauffe - bChauffe; // Différence entre température mini et maxi de chauffage
float h = ((225.0 / 80.0) * d) / 369.0; // Proportions graphique => 225 = pixels pour Y

float V = lChauffe / 10.0; // lChauffe / 10 (lChauffe Coef courbe => stocké entier)
float x = 0;
float y = 0;

for (i=369; i>=0; i--) { // Balayage de la largeur graphique (369 = pixels pour X)
  x = (1.0/369.0) * i;
  if (lChauffe == 5) {
    value = (h * i) + m; // Courbe linéaire
  } else if(lChauffe < 5) {
    y = (2.0-4.0*V) * pow(x, 2) + (4.0*V-1.0) * x;
    value = mapfloat(y, 0.0, 1.0, 10.0, 80.0);
    value = ((225.0 / 90.0) * value) + m;
  } else {
    y = (2.0-4.0*V) * pow(x, 2) + (4.0-4.0*V) * x;
    value = mapfloat(y, 0.0, 1.0, 10.0, 80.0);
    value = ((225.0 / 90.0) * value) + m;
  }
  TFTlcd.SetWaveformValue(pageID,9,1,value); // Point (plot(y) seulement)
  delay(10);
}

Une petite photo de l'écran pour les deux cas ? Ça fait toujours plaisir de voir des choses qui fonctionnent...

Je fais le coucou mais c'est pour la bonne cause.

Je n'ai pas retrouver dans quel fichier est défini la fonction map mais puisqu'elle traite des entiers ce devrait être :

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

J'ai des connaissances limités mais je pense avoir compris qu'il n'est pas utile de renommer map.
Si le compilateur trouve sous le même nom de fonction plusieurs versions avec soit des types de variables différents soit un nombre de paramètre différent il saura très bien se débrouiller et choisir la bonne version

Donc si en plus de la version "officielle" il trouve :

float map(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Il se débrouillera tout seul comme un grand.
Inutile de créer un nouveau nom.

J'ai dit une connerie ?

En fait j'ai parlé un peu vite, car avec une valeur V>0.5 ça ne fonctionnait pas, alors j'ai utilisé ça
y = (2-4V) (1-x)^2 + (4V-3) (1-x) +1 au lieu de y = (2-4V) x^2 + (4-4V) x et maintenant c'est sur, ça marche.
Pour les photos, je posterai demain car là j'ai essayé avec un petit appareil mais c'est très flou, j’essaie demain promis avec un go pro.

68tjs => intéressant, en tout cas à essayer et je pense qu'effectivement le compilateur se débrouille bien puisqu'il opte également pour la bonne librairie lorsque qu'un choix est à faire.
Perso j'utilise couramment dans mes programmes les fonctions utf8ascii au nombre de 3 et qui convertissent en fonction du besoin. Dans les classes de librairies c'est aussi très courant, alors pour map, je pense que ça doit marcher. Ceci dit, ça permet de faire la différence et une fois compilé il n'y a plus d'importance (si tu as programmé en assembleur tu vois de quoi je parle)

Les photos demain promis, merci à vous, je vais enfin pouvoir avancer.