Go Down

Topic: Anémomètre calcul de moyennes de vitesse et direction du vent (Read 1 time) previous topic - next topic

fitness04

Bonjour à tous,

Je suis sur un projet mesure et de direction du vent avec un anémomètre DAVIS que j'ai récupéré, une Arduino UNO et un Shield Ethernet.

Je me suis inspiré de ce site : http://cactus.io/projects/weather/arduino-weather-station-davis-anemometer

Pas de problème pour afficher la vitesse et la direction instantanées mais, en plus d'afficher les mesures de vent et direction instantanées, j'aimerais pouvoir afficher les mesures suivantes :
- Vent moyen sur 5 mn
- Direction moyenne sur 5 mn

Pour ce faire, j'utilise deux tableau de mesures (un pour la vitesse et un pour la direction) et je fais la moyenne.
Si pour la vitesse, il me semble que c'est correct, je ne pense pas que pour la direction ce soit la bonne méthode car on fait la moyenne sur des angles et la moindre oscillation de la girouette (autour de 0 à 360 par exemple)peut faire varier beaucoup cette moyenne et donner une direction fausse.

Pour tester le code, je fais une moyenne sur 2 mn seulement donc 48 mesures (tableau total).

Donc, je sollicite l'aide du forum pour :
- valider ou non mes calculs de moyenne
- Je fais deux tableaux de 120 mesures chacun pour calculer la moyenne vitesse et la moyenne direction. N'est-ce pas trop pour le stockage sur la mémoire de l'Arduino UNO ?

- Est-il possible de ne faire qu'un seul tableau pour les deux mesures avec un seul algorithme de déplacement dans ce tableau (code optimisé !) ?
 - Enfin, à la mise en route (dans le cas où, à terme, il serait alimenté en autonomie par un panneau solaire et coupé la nuit), le temps qu'il y ait suffisamment de valeurs de mesure dans les tableaux, les moyennes sont forcément fausses. Comment faire pour ne pas afficher de moyennes erronées ?

Bon, ça fait pas mal de questions pour un seul sujet mais, je plante un peu là !

Je poste le code sur un deuxième post car le message dépasse le maximum autorisé !

Fitness04 - Newby!

Artouste

Bonjour à tous,

Je suis sur un projet mesure et de direction du vent avec un anémomètre DAVIS que j'ai récupéré, une Arduino UNO et un Shield Ethernet.

Je me suis inspiré de ce site : http://cactus.io/projects/weather/arduino-weather-station-davis-anemometer

Pas de problème pour afficher la vitesse et la direction instantanées mais, en plus d'afficher les mesures de vent et direction instantanées, j'aimerais pouvoir afficher les mesures suivantes :
- Vent moyen sur 5 mn
- Direction moyenne sur 5 mn

Pour ce faire, j'utilise deux tableau de mesures (un pour la vitesse et un pour la direction) et je fais la moyenne.
Si pour la vitesse, il me semble que c'est correct, je ne pense pas que pour la direction ce soit la bonne méthode car on fait la moyenne sur des angles et la moindre oscillation de la girouette (autour de 0 à 360 par exemple)peut faire varier beaucoup cette moyenne et donner une direction fausse.
Bonjour
Dans ce genre d'appli , Il ne faut pas juste faire une simple moyenne arithmétique sur n echantillons , il faut introduire un peu de filtrage numérique.
Une methode assez souvent efficace consiste déjà à evacuer les acquisitions extremes (buffer circulaire)

fitness04

Oups ! posté trop vite! Voici le code entre balises :

Code: [Select]
//Capteur anémomètre-Girouette DAVIS
//Inspiré du site ci dessous
//http://cactus.io/hookups/weather/anemometer/davis/hookup-arduino-to-davis-anemometer-software

#include <SPI.h>   
#include <Ethernet.h>

#include "TimerOne.h"
#include <math.h>

#define TX_Pin 8
#define WindSensor_Pin (2)
#define WindVane_Pin (A2)
#define VaneOffset 0   

volatile unsigned long tipCount;   
volatile unsigned long contactTime;

volatile unsigned int  timerCount;   
volatile unsigned long rotations;   
volatile unsigned long contactBounceTime;
String girouette = "";

volatile float windSpeed;
int vaneValue;       
int vaneDirection; 
int calDirection;   
int lastDirValue;   

const int numReadings = 48;//2mn
const int numReadingsDir = 48;//2mn

int readings[numReadings];     
int readIndex = 0;
int total = 0;
int averageSpeed = 0;
int windSpeedMax = 0;

int readingsDir[numReadingsDir];   
int readIndexDir = 0;
int totalDir = 0;
int averageDir = 0;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 19);
EthernetServer server(80);

void setup() {

  lastDirValue = 0;
  rotations = 0;

  timerCount = 0;

  // disable the SD card by switching pin 4 high
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);

  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();

  Serial.begin(9600);
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
  for (int thisReadingDir = 0; thisReadingDir < numReadingsDir; thisReadingDir++) {
    readingsDir[thisReadingDir] = 0;
  }

  pinMode(TX_Pin, OUTPUT);
  pinMode(WindSensor_Pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(WindSensor_Pin), isr_rotation, FALLING);

  // Setup the timer interupt for 0.5 second (500 000 microSecondes)
  Timer1.initialize(500000);
  Timer1.attachInterrupt(isr_timer);

  sei();
}

void loop() {

  getWindDirection();

  // Only update the display if change greater than 5 degrees.
  if (abs(calDirection - lastDirValue) > 5) {
    lastDirValue = calDirection;
  }


  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          digitalWrite(TX_Pin, HIGH);
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println("Refresh: 10");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.print("<br>&nbsp;&nbsp;Vent instantane : ");
          client.print(windSpeed);
          client.println(" Km/h<br />");
          client.print("<br>&nbsp;&nbsp;Vent moyen (sur 2 mn) ");
          client.print(averageSpeed);
          client.println(" Km/h<br />");
          client.print("<br>&nbsp;&nbsp;Vent maxi ");
          client.print(windSpeedMax);
          client.println(" Km/h<br />");
          getWindDirection();
          client.print("<br>&nbsp;&nbsp;Orientation : ");
          client.print(calDirection);
          client.print(" &deg -  ");
          getHeading(calDirection);
          client.print(girouette);
          client.print(" <br />");
          client.print("<br>&nbsp;&nbsp;Direction moyenne : ");
          client.print(averageDir);
          client.print(" &deg -  ");
          getHeading(averageDir);
          client.print(girouette);
          client.print(" <br />");
          client.print(" <br />");
          client.println("</html>");
          digitalWrite(TX_Pin, LOW);     // Turn the TX LED off
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
        } else if (c != '\r') {
          currentLineIsBlank = false;
        }

      }
    }
  }
  delay(1);
  client.stop();
  Ethernet.maintain();

}//Fin loop

// isr routine for timer interrupt
void isr_timer() {

  timerCount++;

  if (timerCount == 5)//5 x .5 = 2.5 s
  {
    // convert to mp/h using the formula V=P(2.25/T)- Davis Anemometer
    // V = P(2.25/2.5) = P * 0.9
    //en Km/h = P * 0.9 * 1.60934
    windSpeed = rotations * 0.9 * 1.60934;
    // Calcul moyenne sur 2 mn
    total = total - readings[readIndex];
    readings[readIndex] = windSpeed;
    total = total + readings[readIndex];
    readIndex = readIndex + 1;
    if (readIndex >= numReadings) {
      readIndex = 0;
    }
    averageSpeed = total / numReadings;
    if (windSpeed >= windSpeedMax ) {
      windSpeedMax = windSpeed;
    }
    Serial.print("vitesse moyenne : ");
    Serial.println(averageSpeed);
    Serial.print("Vitesse maxi : ");
    Serial.println(windSpeedMax);

    rotations = 0;
    timerCount = 0;
  }
}
// interrupt handler to increment the rotation count for wind speed
void isr_rotation ()   {

  if ((millis() - contactBounceTime) > 15 ) {
    rotations++;
    contactBounceTime = millis();
  }
}

// Get Wind Direction
void getWindDirection() {

  vaneValue = analogRead(WindVane_Pin);
  Serial.print(vaneValue);
  Serial.println();
  vaneDirection = map(vaneValue, 0, 1023, 0, 360);
  calDirection = vaneDirection + VaneOffset;

  if (calDirection > 360)
    calDirection = calDirection - 360;

  if (calDirection < 0)
    calDirection = calDirection + 360;

  // Calcul moyenne sur 2 mn
  totalDir = totalDir - readingsDir[readIndexDir];
  readingsDir[readIndexDir] = calDirection;
  totalDir = totalDir + readingsDir[readIndexDir];
  readIndexDir = readIndexDir + 1;
  if (readIndexDir >= numReadingsDir) {
    readIndexDir = 0;
  }
  averageDir = totalDir / numReadingsDir;
  Serial.print("direction moyenne : ");
  Serial.println(averageDir);
  //Fin calcul moyenne
}
// Converts compass direction to heading
void getHeading(int direction) {
  if (direction < 22)
    girouette = (" N");
  else if (direction < 67)
    girouette = (" NE");
  else if (direction < 112)
    girouette = (" E");
  else if (direction < 157)
    girouette = (" SE");
  else if (direction < 202)
    girouette = (" S");
  else if (direction < 247)
    girouette = (" SO");
  else if (direction < 292)
    girouette = (" O");
  else if (direction < 337)
    girouette = (" NO");
  else
    girouette = (" N");
}
Fitness04 - Newby!

dbrion06

Pour la direction, vous avez eu raison de constater que l'on ne peut pas la moyenner.
Par contre, si les écarts entre une direction de référence et la direction restent petits, on peut faire la moyenne.
On peut parier que, au cours du temps, la direction du vent ne s'écartera pas trop de la première mesure (j'espère que vos moyennes ne sont pas glissantes; sinon, c'est affreux)

l'écart est rendu "petit" de la façon suivante:
s'il est supérieur à 180 degrés, on retire 360 degrés (la mesure est modulo 360 degrés: ça garde un sens);
s'il est inférieur à -180 degrén on rajoute 360 degrés;

exemple : si votre première direction est de 359 degrés, et votre 15 ième direction de 10 degrés, l'écart vaut :
-349 degrés, une fois replié, il vaudra 11 degrés.

Après avoir calculé la valeur de ces écarts repliés, il suffit de rajouter à la direction de réference (et de replier le résultat, si besoin).

Une solution plus lourde (fait appel à de la trigo)  est de calculer la vitesse moyenne, composante par composante .... Cette solution n'utilise "que" des entiers... (en pratique, les résultats sont très voisins)

Zlika

Bonjour,

Je trouve que le calcul par vectorisation est plutôt intéressant à faire et pas si compliqué que cela à réaliser.

Il suffit de décomposer la direction en deux vecteurs (de deux directions perpendiculaires) et de les pondérer avec la vitesse du vent pour ne filtrer que les directions pertinentes.

les ranger dans un tableau de dimension (N échantillons, 2 (N/S, O/E)) avec stockage par glissement.

Puis faire la somme des vecteurs pour obtenir une direction unique.

Vous pouvez éventuellement analyser les valeurs des directions opposées dans le temps pour déceler un changement de direction important.

Edit : après analyse, modification du tableau (n, 4) => (n, 2) car le signe détermine la direction.
Si ça coince, forcez. Si ça casse, ça devait probablement être réparé, de toute façon.

dbrion06

Le calcul de direction par moyenne vectorielle, tel que vous l'envisagez, est interessant et a un sens physique.

Je vois deux inconvénients :

l'un qui relève de la mauvaise foi humaine (la paresse à faire de la trigo sur des floats: la charge de calcul du processeur (pas si hénaurme) peut être allégée par l'emploi de tables remplies automatiquement avec un programme C sur PC -voire avec Excel-). Le peu de trigo nécessaire reste à faire...

l'autre qui relève de la méchanceté du monde : que se passe-t-il si l'indication de vitesse est bloquée électriquement (défaut de branchement)  ou mécaniquement à zéro (un dur sur un anémomètre: une feuille qui s'est coincée dans sa mécanique) alors que la girouette reste fonctionnelle?  (c'est une valeur très probable en cas de panne)


Sinon, il est très bien, et on peut détecter un changement de direction avec le ratio
(norme de la moyenne vectorielle) / (vitesse moyenne)  qui demande deux lignes de code de plus. (si le vent souffle dans tous les sens,  sa moyenne vectorielle sera petite , sa moyenne (mesurée avec un anémomètre sain) sera assez grande).

Zlika

Pour ce qui est de la trigo, on parle d'un cosinus et un sinus par échantillon.

si on part sur l'hypothèse que (sens trigonométrique):

- Nord => 0°
- Ouest => 90°
- Sud => 180°
- Est => 225°

Donnée vecteur Nord/Sud = cos(angle)*vitesse
Donnée vecteur Ouest/Est = sin(angle)*vitesse

Pour retrouver l'angle final Après avoir additionné les Nord/Sud et les Ouest/Est:

angle = atan( Ouest/Est / Nord/Sud ) et ajouter 180° si Nord/Sud est négatif.

Si l'un des deux vecteurs est égale à 0, inutile de faire le calcul (en particulier si c'est Nord/Sud car pas de solution) car le résultat est évident ;).

Attention, l'unité utilisée est le degrés, ce qui n'est pas celui utilisé par la bibliothèque math.
Donc il faudra penser à convertir..

Après, pour les chutes de météorites, la nidification des oiseaux, les tirs de carabine du voisin, etc... , je maitrise moins   :D


Si ça coince, forcez. Si ça casse, ça devait probablement être réparé, de toute façon.

dbrion06

Vous oubliez un atan2;

Le calcul d'une moyenne vectorielle avec des secteurs pas trop larges (22 ou 20 degrés) peut être fait de façon "standard" avec la librairie trigonomètrique, qui est très bien faite et très optimisée (pas la peine de bricoler pour s'adapter à un capteur grossier; un capteur ayant plus de secteurs peut sortir, être moins cher et ne devrait pas obliger à se refendre d'un code -soumis à bugs et fautes de frappe-)

Et, désolé, mais un appareil exposé en plein air est soumis de par son principe à de forts risques d'usure et de blocages.... que l'on ne peut malheureusement pas traiter avec sarcasme et désinvolture).
Calculer une moyenne des écarts de direction (outre le fait que, sur de tout petits micros, avec d'autres quantités, permet de s'affranchir de risques de débordements) et faire comme si l'anémomètre n'existait pas permet de maîtriser ... la moitié du risque d'une panne très courante.

Zlika

Oups, désolé. Notation anglo-saxon de atan. Je corrige...
atan car je fait la division avant. Je n'est donc qu'un seul paramètre.
Mais j'aurais très bien pu le faire avec atan2.

De quel code parlez vous, je n'en ai pas écrit.

Sarcasme ?? Désinvolture ?? Ce n'est qu'une interprétation faites par vous-même.

Si vous partez du principe que de toute façon ça va merder un jour, ne faites rien et laissez aux autres le plaisir de créer.

Je suis là pour proposer des solutions et faire des remarques qui apportent une réflection.
Je ne livre jamais une solution clé en main sinon j'aurais moi même écrit le code, mais ça n'a pas d'intérêt.
Le but est de partager et d'apprendre des autres. Sans réflection, pas de plaisir.

 Vos commentaires ne proposent rien, ou alors vous n'avez pas fini votre post.
Si ça coince, forcez. Si ça casse, ça devait probablement être réparé, de toute façon.

J-M-L

Quote
Sarcasme ?? Désinvolture ?? Ce n'est qu'une interprétation faites par vous-même
Si vous partez du principe que de toute façon ça va merder un jour, ne faites rien et laissez aux autres le plaisir de créer.
les joies de la communication écrite et des interprétations :)

Pour moi le point est valide, et les adjectifs qualificatifs inutiles...

On a 2 capteurs, d'un point de vue reflexion on peut se demander si on peut trouver une approche qui fonctionne encore si l'un des 2 capteurs est défaillant.

est-ce que la vitesse du vent est une donnée pertinente et importante si on ne sait pas dans quel sens le vent souffle ? inversement est-ce que le sens du vent est utile si on ne sait pas sa vitesse ?

On pourrait aussi envisager un code qui part sur l'idée que les 2 fonctionnent mais que s'il détecte qu'un des 2 capteurs semble "mort" (à définir) alors il bascule sur un mode dégradé qui utilise une approche différente.

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Zlika

On peut toujours mettre en place une 'surveillance' des capteurs dans le temps (évolution sur une période donnée), mais quand il n'y a pas de vent, cela ne veut pas dire que le capteur est hs.

En pondérant la direction avec la vitesse, on élimine une information 'direction' qui n'a aucun sens (quand tous fonctionne).
Si ça coince, forcez. Si ça casse, ça devait probablement être réparé, de toute façon.

J-M-L

Quote
mais quand il n'y a pas de vent, cela ne veut pas dire que le capteur est hs.
c'est vrai :)
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

dbrion06

Si un anémomètre ne detecte pas de vent, (vent affiché  nul constamment),
ça veut dire (énumération sans prétention à l'exhaustivité)
a) qu'il n'y a pas de vent
b) que le capteur impulsionnel est débranché (mais qu'il reste fonctionnel.... une fois rebranché)
c) que le seuil de démarrage de l'anémomètre n'a pas été atteint (il y a un hysteresis dû au frottement)

Le point c est à détailler, il peut indiquer que
c1) l'anémomètre est encrassé ou ses roulements ovalisés .
 Celà le disqualifie pour des calculs d'évaporation -pilotage d'irrigation -, ou liés aux concentrations d'éventuels polluants mais pas pour des calculs de vent fort.
c2) l'anemomètre a perdu une coupelle lors de tempêtes, ou est faussé par les mêmes causes. La mesure est alors fausse.... et est pire qu'inutile...

Les girouettes ont un peu les mêmes défauts, mais moins marqués...

J'ai bien indiqué que cette liste est forcément sommaire, et non exhaustive. Les services météorologiques anglais, dans les années 80, se sont automatisés et ont réussi à faire une liste cohérente dans les années 90 -il leur à fallu 10 ans pour constater et analyser les dégâts, et cesser de pifomètrer des algorithmes censés exercer le plaisir de créer. Je ne sais pas,  si, en 20 ans, on a fait mieux et je sais que ma mémoire simplifie.
Notez aussi que passer d'une description en français -ou en anglais-   d'un algorithme à son codage est presque automatique,  et ne relève, ni de la reflection -elle a été faite en amont,dans ... certains cas), ni du plaisir de creer..

En passant, je trouve assez prétentieux le fait de qualifier de création le fait de balancer des idées de code basées, dans le meilleur des cas, sur un capteur de direction à 4 valeurs (pour un prix analogue, on sait faire mieux avec un encodeur optique sur l'axe de la girouette, générant moins de frottements qu'un capteur à bases de résistances dérivant dans le temps).
Et manifestement, la gestion des pannes n'a pas été prévue (comme création, on peut se demander ce qui reste à créer après des analyses approfondies de pannes par le UK Met Office au millénaire dernier: ça relève plutôt dans votre cas de la réinvention de la roue,  carrée de plus -codage sur 4 valeurs des positions  surun cercle, sans se poser la question des erreurs introduites par une quantification grossière)


J-M-L

bon.... fitness04 a pas dit non plus qu'il voulait travailler à météo france et recouvrir la france de son invention pour calculer le temps à 10 jours ...

l'important c'est la spécification, ce que l'on veut.

Pour un bidouillage qui peut planter sans conséquences (si ce n'est pour son amour propre) ou ne marchera que une semaine, installé au fond du jardin sous un arbre, juste pour le fun et après on le démonte, c'est pas la même chose qu'un truc installé au sommet du mont Washington et doit résister à des vents incroyables ou qui est sensé donner aux avions des informations pour atterrir...

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

Zlika

@dbrion06

Vous ne semblez pas comprendre que les quatre points cardinaux évoqués dans mon post précédent ne sont là que pour donner une relation entre l'orientation réelle (N/S/E/O) et l'angle en degrés retournée par la girouette (qui bien sûr, ne se limite pas à ces quatre positions).

Sans cette relation, les propositions de calcul faisant intervenir des cosinus et des sinus d'angles (et non pas quatre directions comme vous semblez le croire, sinon je me serais limité aux résultats, soit -1, 0 ou 1) n'auraient aucun sens. Une girouette de base ne sait pas où se trouve le Nord, c'est à l'utilisateur de l'orienter. Et dans la mesure où, dans ma démonstration, je donne un résultat faisant référence aux points cardinaux, cette relation me semble être un minimum à donner pour la compréhension de la démarche.

Libre à vous de proposer un autre algorithme de calcul. Je serais l'un des premier à le lire avec plaisir. Vous pouvez, de même, me corriger si je fais une erreur (ce ne serait pas la première fois et sûrement pas la dernière) du moment que vous apportez les arguments pour le prouver.

Ma proposition d'algorithme de calcul n'est certes pas à la hauteur de ceux de météo France, mais elle est facile à comprendre et ne nécessite pas l'utilisation d'un tableur Excel comme vous le suggérez. On parle d'un projet à base d'arduino Uno, qui nous limite donc en terme de capacité et de puissance.

Comme précisé par @J-M-L, je ne pense pas que ce projet soit destiné à une utilisation proche de celle de la NASA pour envoyer un satellite dans l'espace.

Il ne s'agit que d'un projet diy avec du matériel de récupération (cf premier post) destiné à apprendre et comprendre.

Est-il nécessaire de fiabiliser à outrance un tel système?

C'est à @fitness04 de décider. Mais je ne crois pas trop m'avancer en supposant qu' il ne va doubler ou tripler les capteurs pour s'assurer de la validité des valeurs retournées alors qu'un simple regard sur les arbres va déjà lui fournir un indice sur un éventuel disfonctionnement.

Faut-il prévoir un guide de dépannage pour un tel système?

Si, pour 2 capteurs et une carte Arduino Uno, vous avez besoin d'un guide de dépannage , j'aurais tendance à douter de votre capacité à gérer un système plus complexe, mais je peux me tromper...

Si ça coince, forcez. Si ça casse, ça devait probablement être réparé, de toute façon.

Go Up