Meilleurs moyen calcul de moyenne

Salut,

Actuellement, je fais la mesure d'une sonde DS1825 toute les minutes. Avant de l'envoyer sur la base de donnée et l'afficher sous forme de courbe, je fais un "dtostrf(tempAquaTank,0,1,tempAquaTankTmp);" pour arrondir la valeur a 0.1 pres.

Pour stabiliser la courbe, je voudrais faire 4 mesures a la minute et faire une moyenne de ces valeurs.

Qu'elle est la meilleurs methode?

  • prendre les "4 mesures/4"
  • supprimer la valeur haute et la valeur basse et les "2 autres mesures/2"

Pourriez vous m'éclairer?

Merci!

Bonjour,

Pour faire une moyenne acceptable, il faut effectivement se créer un échantillon représentatif que l'on divisera pas le nombre d'échantillon. Il n'y a pas de secret.

Le tout est de savoir ce que tu cherches précisemment à faire et quelle précision tu veux atteindre.

Les deux méthodes que tu mets en avant sont combinables et tout à fait valables.

Je prendrais par contre plus de valeur, genre 10.

@+

Zoroastre.

La méthode dépend de la qualité de données aussi.
Si tu as des lectures erronées de temps en temps la suppression des extrema permet de s'affranchir du problème.

Autrement tu peux faire une moyenne glissante. Un tableau contient les n dernières mesures. La nouvelle mesure remplace la plus ancienne dans le tableau et tu fait ta moyenne dessus.

Ou un filtre à réponse impulsionnelle infinie de la forme:
moyenne = N * nouvelle_mesure + (1-N) * moyenne
N doit être inférieur ou égal à 1
Si N=1 le résultat c'est la dernière mesure.
Plus N est petit, moins la dernière mesure a d'influence sur le résultat.
Il faut éviter d'avoir un N trop petit sinon le résultat prend du temps pour se stabiliser.

Merci les gars!

Je ne pensait pas a la moyenne glissante, je prend note pour de futur application.

Je vais partir sur le principe de 4 mesures et supprimer les valeurs extrême et faire la moyenne des 2 autres.

Actuellement j'utilise 4 sondes de température en resolution: 12 bits(750ms/0,0625°c).

Donc je sais plus combien de temps qu'il me faut pour les 4 sondes mais dans un premier temps je vais me contenté de 4 mesures pour ne pas surchargé l'arduino.

Sur l'image ci-dessous voici une mesure de l'air ambiant et celle de l'hygro qui n'est pas du tout précise.

Mon problème vient peut-être du dtostrf() lors de l'arrondi?

Donc si vous avez des conseils supplémentaires...

Yep!

Normalement, ce genre de sonde a besoin de temps pour gagner en précision et réalisme. Je ne saurais dire combien de temps exactement, mais tes pics et crêtes ont peut-être d'autres origines (liaison 1-wire, qualité des câbles, etc). Je ne sais pas.

La fonction : char * dtostrf(double val, signed char width, unsigned char prec, char * s) permet de convertir un double en String. C'est bien pour afficher les valeurs sur un moniteur ou un écran, mais pas vraiment l'idéal pour réaliser des calculs.
Si j'ai bien compris, tu cherches à obtenir des chiffres avec une décimale, ceci peut-être :

float new_val = val / 1.f

Une possibilité parmis d'autre je pense.

[ERRATUM]
Ça affiche 2 décimales après la virgule en fait. Peut-être faire comme tu le fais et repasser par atof() pour revenir en float.

Fin bref! Je pense que l'on peut faire ce genre d'opération mathématiquement. Par exemple :

float x = 25.1234
float virgule = x - (int(x)); // ce qui donne 25.1234 - 25 = 0.1234
float decimal = int(virgule * 10)/10; //ce qui donne (int(0.1234*10) = 1) / 10 = 0.1
// reste plus qu'à additioner.

float _decimal(float nbr)

{
 float a = nbr - int(nbr); // on soustrait le nombre par son entier
 float b = a*10; // on multiplie la décimale
 float c = int(b); // on transforme la décimale en entier
 float d = c / 10; // on divise l'entier pour le remettre après la virgule
 float r = int(nbr) + d; // on additionne les résultats
 return r;
}

_decimal(125.1234); // renvoie bien 125.10




Tu auras par contre toujours 2 décimales à l'affichage mais la seconde vaudra 0. Les 2 chiffres après la virgule semble être une limitation/obligation du langage.
[/ERRATUM]

Enfin, théoriquement, si l'on compte 1 seconde par sonde (750 ms + 250 pour le reste du code), tu peux réaliser 15 mesures de l'ensemble du système à la minute. Avec une marge de sécurité raisonnable, tu peux faire 10 mesures à la minutes sans trop de soucis. Cela dépend bien entendu de la pesanteur des autres traitements que l'arduino doit réaliser.

@+

Zoroastre.

Merci!

Je test avec ce code!

int antier(float nbr)
{
  // on retourne la partie antiere du nombre
  return int(nbr);
}

byte decimal(float nbr)
{
  nbr -= int(nbr); // on soustrait le nombre par son entier
  nbr *= 10; // on multiplie *10 les décimales
  nbr /1.f; // on recupere qu'une seule decimal
  return nbr;
}

Mon code final est le suivant:

Apparemment, je n'est pas d'erreur du compilo, mais vu qu'il n'est pas très bavard, je préfère vous faire confiance :wink:

void floatTo2TabChar(float nbr)
{
  // On met la partie antiere du nombre dans le tableau
  memset(dataTmp,NULL,DATATMP_PACKET_SIZE); 
  itoa (int(nbr), dataTmp, 10);
  strcat(data,dataTmp);
  // On ajoute le point de separation des antiers de la decimal
  strcat(data,"."); 
  // On recupere la partie decimal
  nbr -= int(nbr); // On soustrait le nombre par son entier
  nbr *= 10; // On multiplie *10 les décimales
  nbr = int(nbr); // On recupere une seule decimale
  // On met la partie decimal du nombre dans le tableau
  memset(dataTmp,NULL,DATATMP_PACKET_SIZE); 
  itoa (nbr, dataTmp, 10);
  strcat(data,dataTmp);
}

Utilisation:

/**** Menu Temperature ****/
      // Sonde de temperature
      floatTo2TabChar(tempAquaTank); strcat(data,",");

Dans le même principe mon cast est il correct itoa a besoin d'une valeur de type "int", mais j'utilise la fonction pour des types "boolean" et des types "byte"

void intToTabChar(int(nbr))
{
  memset(dataTmp,NULL,DATATMP_PACKET_SIZE);
  itoa(nbr,dataTmp,10); 
  strcat(data,dataTmp);
}

Et avec

sprintf(data,"%d.%0d",int(temp),int(100*(temp-int(temp))))

On doit arriver au même résultat non?

Si j'ai bien suivi en rajoutant strcat(), on est sur la même voie.

J'attends que ma base de donnée se remplisse et je poste le résultat..

Peut-on faire un cast dans la déclaration d'une fonction?

void intToTabChar(int(nbr))

non

Merci!

dudux2:
Peut-on faire un cast dans la déclaration d'une fonction?

void intToTabChar(int(nbr))

Dans la déclaration d'une fonction on indique qu'elles arguments elle attend donc on donne le type exact attendu.

Par contre lorsqu'on appelle la fonction on peut faire un cast sur les arguments qu'on lui passe.

bonsoir
pour info la précision d'un DS1825 n'est "que" de +/-0.5°C entre -10/+85 °C

la résolution elle pouvant varier de 9 à 12 bits (0.0625 °C pour 12 bits)
Cette résolution n'a réellement d’intérêt que pour des capteurs préalablement étalonnés et à condition de prendre la courbe en compte.

Tu réduirais à 11 bits voir même a 10 bits vue que je ferais une moyenne?

Pour info: // Resolution : 9 bits (94ms/0,5°c) 10 bits (188ms/0,25°c) 11 bits (375ms/0,125°c) 12 bits(750ms/0,0625°c)

dudux2:
Tu réduirais à 11 bits voir même a 10 bits vue que je ferais une moyenne?

Voir même à 9 :grin:

Il est inutile là de s'attacher (sauf etalonage préalable ) aux "pouillèmes" quasi insignifiants 8)
un 1820 pour du courant est aussi bien qu'un 18B20 (1845) :smiley:

Autre façon de voir pour que tu trouve la réponse toi même :
Puisque le capteur n'est pas étalonné l'avantage de travailler sur 12 bits est de déceller des faibles variations de température autour d'une mesure absolue qui n'est connue qu'à +/- 0,5°C.
Autrement dit sur 12bits tu peux détecter que la température a varié de 0,0625 °C autour de quelque chose qui fait entre 20 à 20,5°C.
Cela permet par exemple de détecter par anticipation que la température monte ou qu'elle diminue.
Dans certain cas c'est utile, mais dans le tien en as tu besoin ?

A vrai dire, je n'est pas encore creusé de se côté là.

Tout ce que je peux répondre c'est qu'a l'avenir, j'airais une régule de chauffage au sol d'un aquarium de 500L a mettre en place dans le programme et peux être un refroidissement.

Mieux ça régulera, mieux ça sera, quand a définir si en 11 bits ou en 12 bits j'obtiendrais le même résultat, je n'en est aucune idée.

Sachant que j'ai 50 kg de pouzzolane par dessus, je devrais surement avoir un effet tampon.

Pour le moment, j'en ai aucune idée du comportement que cela aura et de la maniere que je vais regulé cela.

Ce qui est sur, c'est qu'une seule sondes aura besoin d'être plus précise sur les 3.

J'ai pas regardé coté drivers si l'on peut changé la résolution entre 2 sondes et si cela reste rentable, ce qui est sure c'est que le mode 11 bits conviendra pour mes 4 sondes.

Bonsoir, je mets mon petit grain de sable ...

Pour la regulation, avant de se demander si on mesure en 12 ou 36 bits de résolution, il faut savoir quelle precision de regulation on recheche, la puissance de chauffe par rapport au volume d'eau ... Je m'explique :

Il faut une précision adaptée à ton niveau de regulation :
Si tu cherches à réguler à 25° +/- 0,1 il faut pouvoir mesurer des variations inférieures au 1/10 ieme de degré ... Si tu es a 25+/- 1° mesurer à 0,5° pré peut suffire.

Ensuite ton aquarium a une grande inertie ... L'eau est brassée (donc température homogène), j'imagine aussi qu'il est dans un pièce avec une température contrôlée .. Donc tout est réuni pour que la température varie très lentement ...

Après pour ce que j'en sais, les chauffages d'aquarium ont une puissance faible (par rapport au volume chauffé) et une faible inertie (dès que tu coupes le chauffage, l'eau ne monte plus en température) ... Pas la peine de faire 10 mesures par seconde pour avoir une régulation correcte .. Et un simple tout ou rien devrait suffire (si moins de 24.5 je chauffe, si plus de 25.5 je coupe)

J'utilise une DS18B20 en 11 bits au bout de 25m de câble non blindé dans ma piscine ... En ce moment la mesure est d'une stabilité presque parfaite ... Donc ne te fais pas de soucis avec ces sondes