Auswertung Impulse Volkswindmesser

Hi Leute,

ich habe mir den Volkswindmesser (Link:http://www.schubert-gehaeuse.de/anemometer.htm) zugelegt und möchte diesen gern über ein Arduino Uno + Ethernet Shield auswerten und die gewonnen Daten auf einer SD-Karte speichern. Das Messintervall soll hierbei eine Sekunde betragen. Das Anemometer erzeugt hierbei pro Umdrehung eine Schaltung mittels Reed-Kontakt.

Hierbei betragen die Datenpaare der Kennlinie: m / s..........Hz 1 2,1 2 4,6 3 7,0 4 10,0 5 12,5 6 15,0 7 18,2 8 20,9 9 24,3 10 27,2...usw.. Hier ist der Link dazu: http://www.schubert-gehaeuse.de/Anemometerbilder/VWM-Kennlinie1U_6Imp.jpg

Meine Frage ist jetzt hierbei, wie würdet ihr das ganze auswerten?

Meine Überlegungen hierzu waren: 1. Die Anzahl der Impulse pro Sekunde zählen und dann Anhand der Kennlinie auswerten. Dies würde bspw. bei 2 Impulsen bedeuten, dass 1 m/s Wind weht. Nach einer Vergleichsmessung heute mit einem Handwindmesser musste ich leider feststellen, dass das so nicht funktioniert. Bei 20 km/h (5,55 m/s) bekam ich genau 2 Impulse.

  1. Wie bei einem Fahrradtacho. Ich habe den Umfang des Anemometers berechnet (meine Fahrradfelge). Nun messe ich die Zeit zwischen Impulsen und berechne Wegstrecke pro Zeit, was die Geschwindigkeit ergibt. Hier geht mir dann aber das Messintervall von einer Sekunde flöten, oder?

Wie würdet ihr das Problem lösen?

Vielen Dank schonmal für eure Antworten!

P.S. Vllt. hat von euch jemand ja auch den Volkswindmesser und kann mir mit seinen praktischen Erfahrungen weiterhelfen :).

Die Kennlinie beruht auf ein Windrad mit 6 Impulsen pro Umdrehung. http://www.schubert-gehaeuse.de/Anemometerbilder/VWM-Kennlinie1U_6Imp.jpg

Du hast aber ein Windrad mit 1 Impuls pro Umdrehung?

12 Impulse/Umdrehung ^= 5m/s Also ist alles richtig.

Grüße Uwe

Stimmt, da lag mein Denkfehler.
Das bedeutet also, das ich folgende Frequenzen für die einzelnen Windgeschwindigkeiten zur Verfügung habe:
m/s Hz (6 Imp.) Hz (1 Imp.)
1 2,1 0,35
2 4,6 0,77
3 7,0 1,17
4 10,0 1,67
5 12,5 2,08
6 15,0 2,50
7 18,2 3,03
8 20,9 3,48
9 24,3 4,05
10 27,2 4,53
11 30,5 5,08
12 34,0 5,67
13 36,7 6,12
14 39,7 6,62
15 43,2 7,20
16 46,2 7,70
17 49,6 8,27
18 52,5 8,75
19 56,4 9,40
20 59,6 9,93

Jetzt steht für mich noch die Frage im Raum, wie genau die Messung wird. Ich denk dort immernoch an den Fahrradcomputer der auch auf einem Reed-Kontakt beruht und konstant die aktuelle Geschwindigkeit anzeigt. Dies müsste doch hier auch möglich sein, um dabei die “durchschnittliche” Windgeschwindigkeit in einer Sekunde zu messen, oder?

Wie könnte man das hierbei mit dem Arduino Uno realisieren?

Am genausten ist es, wenn Du die Zeit zwischen 2 Impilsen mißt. Grüße Uwe

In die Richtung wollte ich auch schon gehen, bin dann aber irgendwie nicht weiter gekommen.
Wenn ich die Zeit zwischen zwei Impulsen messe, inwiefern werte ich dann die Windgeschwindigkeit im Messintervall von einer Sekunde aus?

Irgendwie steh ich da auf dem Schlauch.

f=1/T f = Frequenz T= Periodendauer Grüße Uwe

BigBangTheory: Das Messintervall soll hierbei eine Sekunde betragen.

Vielleicht solltest du hier mal ansetzen.

Brauchst du wirklich die Messdaten im Sekundenintervall?

Wenn du die Zeit zwischen den Impulsen misst, dann kriegst du jede noch so kleine Böe aufgelöst. Wenn du das brauchst - gut.

Wenn nicht, dann mess doch einfach in größeren Intervallen, z.B. 10sek. Das hat den Vorteil, dass du bereits automatisch eine Mittelung der Messwerte über die letzten 10sec kriegst.

Meine Herangehensweise ist immer: erst überlegen: wie genau und schnell brauche ich das Signal? dann das passende Messverfahren auswählen.

Für eine Wetterstation zur Anzeige der Windgeschwindigkeit reicht es über eine Minute zu mitteln. Wenn du Böen und die daraus resultierende Windlast ermitteln willst, dann solltest du jeden Impuls einzeln zählen.

Gunther

Ich möchte, wenn genug Wind an der Stelle weht, wo das Anemometer jetzt hinkommt, ein vertikales Windrad zur Stromerzeugung aufstellen. Daher brauche ich die Erfassung jeder kleinen Windböe um quasi ein "Referenzjahr" an Winddaten aufzuzeichnen.

Mein Problem ist jetzt noch, wenn ich die Zeit zwischen zwei Impulsen messe und damit die Frequenz heraus bekomm und diese dann einordne in die Tabelle (s.o.), wie komm ich dann auf mein Messintervall?

Gruß Alex

Hey Leute,

ich merke gerade, dass ich bei folgendem Problem nicht weiter komm:

Ich möchte gern die WIndgeschwindigkeit (welche in meinem Fall abhängig von der Frequenz ist, s.o.) messen. Somit muss ich die Frequenz im mit dem Arduino ermitteln. Hierzu habe ich jetzt versucht die Dauer zwischen 2 Impulsen zu messen. Dies ist mir mit der Funktion PulseIn() auch gelungen, indem ich hiermit die Zeit gemessen habe, in der kein Signal am Pin anliegt (LOW).

Jetzt meine Frage: Ich will die Windgeschwindigkeit im Messintervall von einer Sekunde messen. Wie lässt sich das mit dem Arduino und der Frequenzmessung in Einklang bringen?

Vielen Dank für eure Antworten!

Also, erstens, wenn du nur die LOW-zeit mißt, kriegst du nicht die Zeit zwischen den Pulsen, sondern eben nur die LOW-Zeit. Die Pulslänge ist aber LOW-Zeit plus HIGH-Zeit. Du mußt immer am Flankenwechsel triggern, am besten mit einem Interrupt, aber wie das mit dem Arduino funktioniert, kann ich (noch) nicht sagen, ich kenns nur von anderen Echtzeitsytemen mit Drehzahlerfassung, die wir in der Firma bauen.

zweitens: Trenn mal Erfassung und Aufzeichnung. Du hast eine Funktion, die die Pulslängen erfasst. Das kann sehr schnell erfolgen! Diese Funktion stellt die Pulslänge als Wert (gefiltert?) zur Verfügung. Du hast eine andere Funktion, die in festen Intervallen aufgerufen wird (bei dir 1000ms) und die aktuelle Windgeschwindigkeit errechnet und mit Zeitstempel abspeichert. Dadurch ist beides voneinander unabhängig und du kannst jederzeit dein aufzeichnungsintervall ändern (Falls dir die 86400 Datensätze pro Tag zuviel sind. :cold_sweat:)

die Umrechung Pulsdauer => Windgeschwindigkeit kannst du so machen: zuerst baust du dir eine Tabelle mit ZWEI Spalten: Pulsdauer und Windgeschwindigkeit (Pulsdauer[µs] = 1000000/Frequenz) Die anderen beiden Spalten habe ich nur drin gelassen, damit du deine Tabelle wieder erkennst.

m/s Hz(6 Imp.) Hz(1 Imp.) Dauer1p[µs]
20  59,6     9,93      100705
19  56,4     9,4        106383
18  52,5    8,75     114286
17  49,6     8,27      120919
16  46,2     7,7        129870
15  43,2     7,2        138889
14  39,7     6,62      151057
13  36,7     6,12      163399
12  34     5,67       176367
11  30,5     5,08      196850
10  27,2     4,53      220751
9    24,3    4,05      246914
8    20,9    3,48      287356
7    18,2    3,03      330033
6    15    2,5     400000
5    12,5    2,08      480769
4    10    1,67       598802
3    7      1,17     854701
2    4,6      0,77    1298701
1    2,1      0,35    2857143

mit deinen aktuell gemessenen Pulsdauerwerten gehst du dann in die Tabelle, suchst dir die beiden benachbarten Werte und interpolierst dazwischen linear. Such doch mal nach linare Interpolation C

Es sei denn, du brauchst garkeine Zwischenwerten, es reichen dir die ganzzahligen Windgeschwindigkeiten, dann kannst du dir die Interpolation sparen, und gleich den nächsten Wert nehmen.

Reicht das?

Gunther

Danke schonmal für die tolle ausführliche Antwort! Damit komm ich schonmal ein ganzes Stück weiter :)!

Fragen treten ja leider immer erst auf, wenn man sich dran setzt und alles in die Tat umsetzen will.

Meine letzte Frage die mir momentan noch aufkommt ist, ich hab ja die beiden Funktionen, einmal das Messen der Pulsdauer und einmal die Errechnung der Windgeschwindigkeit. Wenn sich jetzt die Pulsdauer innerhalb der Sekunde ändert, muss ich das doch in der Windgeschwindigkeit wiederspiegeln, oder?

Dort hängt es momentan gedanklich noch bei mir, also wenn ich aus der Pulsdauer die Windgeschwindigkeit berechne, dann müsste ich ja quasi für alle Windgeschwindigkeiten die ich im Messintervall umgerechnet habe, einen Mittelwert bilden und diesen dann nach der Sekunde ausgeben, oder?

So würde das gerad für mich Sinn ergeben :).

Vielen vielen Dank schonmal für die tollen Antworten!!

Hallo hatte mich auch mal mit dem Thema befasst und bin über diese Seite http://macherzin.net/Arduino%20%20Sensoren%20%20Wind%20und%20Regen im Netz gestolpert.

BigBangTheory:
Dort hängt es momentan gedanklich noch bei mir, also wenn ich aus der Pulsdauer die Windgeschwindigkeit berechne, dann müsste ich ja quasi für alle Windgeschwindigkeiten die ich im Messintervall umgerechnet habe, einen Mittelwert bilden und diesen dann nach der Sekunde ausgeben, oder?

Da bist du über ein Grundproblem der Signaltheorie gestolpert:
wenn ich schnell ändernde Signale nur gelegentlich abtaste (=Wert speichern), dann bekomme ich zufällige Werte.
Dafür gibt es die Regel, dass Signale gefiltert sein müssen, und zwar ein Filter mit einer Grenzfrequenz die niedriger liegt (<0,6 mal) als die Abtast (=Speicher) frequenz.

In deinem Falle gibt es nun zwei Wege:
a) wie du sagst, alle Werte zwischen zwei Speicherintervallen Mitteln. ( Was dann das gleiche wäre, wie alle Pulse zwischen zwei Speicherintervallen zählen, da wären wir wieder am Anfang!)
b) die Werte filtern.

Filtern kann man z.B. einfach mittels “gleitendem Mittelwert”
das funktioniert so:
Mittelwert = Mittelwert*filterfaktor + Messwert * (1-filterfaktor)

mit filterfaktor = 0 wird garnicht gefiltert,
mit filterfaktor = 0,5 besteht jeder neue Mittelwert je zur Hälfte aus dem neuen Meßwert und dem alten Mittelwert
mit filterfaktor = 0,1 besteht jeder neue Mittelwert zu 1/10tel aus dem neuen Meßwert und zu 9/10teln aus dem alten Mittelwert.

das kannst du in Excel schön durchspielen.
Zur Umsetzung in Code gibts aber geschicktere Versionen, die mathematische Grundlage bleibt gleich.

Der erste Filter ist der Windmesser selber. Das Rad mit den 4 Halbkugeln (oder wie heissen die Teile) wirkt durch sein Trägheitsmoment bereits wie ein Tiefpaß. Die geschicktere Variante heißt Kalmann Filter http://de.wikipedia.org/wiki/Kalman-Filter. Daß was Du gleitenden Mittelwert nennst ist kein gleitender Mittelwert sondern ein exponentieller Filter. http://de.wikipedia.org/wiki/Gleitender_Mittelwert Exponentielle Filter sind im Vergleich zum Aufwand allerdings super. Vor allem wenn man sie sauber auf das Problem anpasst. Wie man sowas macht habe ich mal hier breitgetreten: http://blog.blinkenlight.net/experiments/dcf77/binary-clock/. Bei einem Windmesser hätte ich zunächst aber gar keine Idee wie ich die Parameter ansetzen würde. Vermutlich würde ich dann doch gleich einen Kalmann Filter nehmen ;)

Hi Leute,

ich habe mir einen ersten Code erarbeitet, bei dem momentan die Periodendauern (HIGH + LOW) in einem großen Array gespeichert werden. Nach dem Messintervall werden alle Werte des Arrays addiert, sowie im Anschluss durch die Periodenanzahl geteilt, sodass ich einen Mittelwert bekomme.
Der Code funktioniert noch nicht richtig, ist aber denk ich erstmal eine gute Grundlage.
Ich bin hierbei davon ausgegangen, dass wenn ein “HIGH-Signal” anliegt und ich dessen Länge messe, hiernach direkt ein LOW-Signal folgen muss, welches die erste Messung beendet und die Messung der Länge des LOW-Signals startet, und umgekehrt.

Was sagt ihr dazu? Wo sollte ich noch Veränderungen am Code vornehmen und wie kann man ihn noch besser machen, sodass er auch bei langsamen Windgeschwindigkeiten richtig funktioniert?

Bin ich vielleicht mit dem Code auch auf dem totalen Holzweg? Lasst euch aus darüber :)!

int AnemometerPin = 2;
int Messintervall = 1000;
int StartZeit = 0;
int EndZeit = 0;
int i = 0;
int j = 0;
int k = 0;
int HIGHZeit = 0;
int LOWZeit = 0;
int Periodendauer;
int PinStatus;
int Anzahl;
float SummePulsdauer = 0;
float Mittelwert = 0;
float pulsearray[99];


void setup()
{
  Serial.begin(9600);
  pinMode(AnemometerPin, INPUT);
  
}

void loop()
{
  for (k = 0; k < 100; k++)
  {
    pulsearray[k]=0;
  }
  
  StartZeit = EndZeit;
  
  i = 0;

  Mittelwert = 0;
  
  SummePulsdauer = 0;

  while (EndZeit-StartZeit < Messintervall)
  {
    
    PinStatus = digitalRead(AnemometerPin);
    
    if (PinStatus == HIGH)
    {
      HIGHZeit = pulseIn(AnemometerPin, HIGH);
      LOWZeit = pulseIn(AnemometerPin, LOW);
    }
    else if (PinStatus == LOW)
    {
      LOWZeit = pulseIn(AnemometerPin, LOW);
      HIGHZeit = pulseIn(AnemometerPin, HIGH);
    }
    Periodendauer = HIGHZeit + LOWZeit;
    
    pulsearray[i]=Periodendauer;
    
    i++;
   
    EndZeit = millis();  
    
    Anzahl = i;
  }
  for (j=0; j<=Anzahl; j++){
  
  SummePulsdauer = SummePulsdauer + pulsearray[j];
  }
  
  Mittelwert = SummePulsdauer / Anzahl;
  
  Serial.print("Pulsdauer Mittelwert:  ");
  Serial.println(Mittelwert);
}

Vielen Dank schonmal für eure vielen tollen Antworten zu diesem Thema, die bisher kamen und hoffentlich noch weiter kommen :)!

Hallo,

nur zwei Anmerkungen: 1. wenn du den Pinstatus nur im Loop abfragst, um die Zeiten zu ermitteln, dann bekommst du zwangsläufig Ungenauigkeiten, weil der Durchlauf des Loops ja auch Zeit braucht. Besser wäre hier ein Interrupt. 2. Du versuchst die Zeiten HIGH und LOW zu messen, addierst die auf um einen Mittelwert übers Speicherintervall zu bilden. Damit errechnest du dir die Anzahl der Pulse pro Speicherintervall. Einfacher (und genauer) wäre es hier, die Impulse [u]zu zählen[/u]. Das ist letztlich genau das, was du gerade machst, nur du machst es aufwändig, umständlich und Fehlerbehaftet.

Die Sache mit der gemessenen und im Anschluss gemittelten Periodendauer pro Sekunde um hieraus die “gemittelte” Frequenz zu berechnen, schien mir irgendwie logisch. Daher habe ich versucht das ganze über den Weg der Periodendauermessung zu beschreiten.

Ich habe den Code jetzt in Richtung Interrupt angepasst. Jetzt bekomm ich aber gar keinen Wert mehr ausgegeben :D. Was habe ich hier falswch gemacht?

int AnemometerPin = 2;
int Messintervall = 1000;
int StartZeit = 0;
int EndZeit = 0;
int i = 0;
int j = 0;
int k = 0;
int Periodendauer;
int PinStatus;
int Anzahl;
int last;
float SummePulsdauer = 0;
float Mittelwert = 0;
float pulsearray[99];
unsigned long m;
unsigned long v;


void setup()
{
  Serial.begin(9600);
  pinMode(AnemometerPin, INPUT);
  attachInterrupt(0,UebergangHighLow, RISING);
}

void loop()
{
  for (k = 0; k < 100; k++)
  {
    pulsearray[k]=0;
  }
  
  StartZeit = EndZeit;
  
  i = 0;

  Mittelwert = 0;
  
  SummePulsdauer = 0;

  while (EndZeit-StartZeit < Messintervall)
  {
   
    pulsearray[i]=Periodendauer;
    
    i++;
   
    EndZeit = millis();  
    
    Anzahl = i;
  }
  for (j=0; j<=Anzahl; j++){
  
  SummePulsdauer = SummePulsdauer + pulsearray[j];
  }
  
  Mittelwert = SummePulsdauer / Anzahl;
  
  Serial.print("Pulsdauer Mittelwert:  ");
  Serial.println(Mittelwert);
}

void UebergangHighLow()
{
  detachInterrupt(0);                         // Interrupt ausschalten damit er uns nicht 
  m = millis();                               // Millisekundenzähler auslesen
  v = m - last;                               // Differenz zum letzten Durchlauf berechnen
  if (v > 10) {                               // ignorieren wenn <= 10ms (Kontaktpreller)
  Periodendauer = v;                          // Wert in Periodendauer übernehmen
  last = m;                                   // und wieder den letzten Wert merken
  }
  attachInterrupt(0, UebergangHighLow, RISING );
}

Ich messe hierbei die Zeit vom Übergang HIGH zu LOW bis dieser wieder auftaucht. Das müsste ja genau der Periodendauer entsprechen, oder? Dieser Wert der Periodendauer wird dann in das Array geschrieben, die Anzahl der Array-Elemente gezählt und im Anschluss der Mittelwert gebildet und ausgegeben. Trotzdem muss ich mich hier irgendwo verhaspelt haben, da ich momentan gar keine Ausgabe mehr bekomme.

Gruß Alex

Hallo Alex,

spontan fällt mir auf:

  • zu zählst in loop eine whileschleife hoch, in der du erwartest, dass bei jedem Schleifendurchgang ein neuer Wert "Periodendauer" zur Verfügung steht. aber du weißt ja nicht, wann der Impuls kommt und deinen Interrupt auslöst, das sind Prozesse die parallel und voneinander unabhängig laufen!
  • deine Interruptroutine ist sehr lang. Interruptroutinen sollten so knapp wie möglich sein. ich würde in der Interruptroutine nur den aktuellen Micros()-Wert in einem Array abspeichern und einen (globalen) Indexzähler hochsetzen.
void UebergangHighLow()
{
  detachInterrupt(0);                         // Interrupt ausschalten damit er uns nicht 
  m[i++] = micros();                               // Microsekundenzähler auslesen
  attachInterrupt(0, UebergangHighLow, RISING );
}

Und dann erst in der Auswertung die Zeiten ausrechen:

{
  detachInterrupt(0);   
  Periodendauer = (m[i-1] - m[0])/(i-1);
  i = 0;
  attachInterrupt(0, UebergangHighLow, RISING );
}

generell solltest du aber versuchen mit "Serial.print" an den verschiedenen Stellen des Codes versuchen rauszufinden was wo gerechnet wird, ob der Interrupt überhaupt aufgerufen wird, etc. Diese Form von debuggen ist unverzichtbar. Ich hatte schon funktionen, da habe ich nach jeder Codezeile mit "Serial.print" alle Variablen ausgegeben, weil ich den Fehler anders nicht gefunden habe.

Diese Form von debuggen ist unverzichtbar...

... geht nur nicht gut innerhalb der Interrupt-Routine.

Eigentlich ist es ganz tabu, aber 64 Zeichen passen in den Ausgabepuffer, und werden dann am Ende von loop() gesendet. Aber die Interrupt-Routine darf nicht auf das Leeren des Puffers warten müssen.

michael_x: ... geht nur nicht gut innerhalb der Interrupt-Routine.

Richtig.

aber man kann im Interrupt ein Flag setzen, und dieses in der Loop auswerten...