Auswertung Impulse Volkswindmesser

Wenn Du

'Hierbei sieht man, dass mein "RISING" immer genau 2 Werte kommen'

heraus gefunden hast, dann nimm dies als einen stabilen Sensor Parameter. Impulse / 2 und habe fertisch...

Setze am Besten die Plausibilitätsbetrachtung um, dann filters Du eine Menge Fehler heraus.

Greetz,

Linpo

@ jurs

Du hast da vollkommen Recht. Ich hab das ganze nochmal getestet. Es werden genau 2 Signale durch den Reedkontakt pro Umdrehung erzeugt, wobei ein kurzer und ein langer Impuls entsteht.

Sorry nochmal für meine Beratungsresistens :D.

Momentan bin ich soweit, dass ich mir die Werte (die Abstände zwischen den einzelnen Schaltungen) im Serial Monitor ausgeben lasse.

Hierbei sieht man, dass zuerst ein kurzer und dann ein langer Impuls entsteht.

In der Interrupt Routine frage ich nun ab, ob meine Variable "Abstand" größer ist als 1000 (es hat sich gezeigt das der kurze Impuls max. 640 Mikrosekunden groß ist). Dann wird der Abstandswert in die Variable limpuls gespeichert (langer Impuls)...ansonten wird der Wert in der Variable kimpuls gespeichert (kurzer Impuls).

Hier der Code:

unsigned long i,abstand,kimpuls,limpuls;
unsigned long j=0;



void setup()
{
  Serial.begin(9600);

  attachInterrupt(0,Interrupt,RISING);
}

void Interrupt()
{

  noInterrupts();
  
  i = micros();
  
  abstand = i-j;
  
  j=i;
  
  if (abstand >= 1000)
  {
   limpuls=abstand;
  Serial.print("langer Impuls: ");
  Serial.println(limpuls); 
  }
  else
  {
   kimpuls=abstand;
  Serial.print("kurzer Impuls: ");
  Serial.println(kimpuls); 
  }

  interrupts();


}


void loop()
{

}

Mein vorrangiges Ziel besteht momentan darin, aus den Abständen (kurzer + langer Impuls) eine Periode zu bekommen, anhand derer ich direkt nach jeder Periode die ich gemessen habe, die Windgeschwindigkeit zu berechnen.

Hierzu habe ich anhand der Werte des Herstellers zu Frequenz und Windgeschwindigkeit in Excel eine Formel erstellt, die den Werten des Herstellers des Anemometers gleicht.

Nun meine Frage:

Wie kann ich es programmiertechnisch elegant lösen, das genau ein kurzer und ein langer Impuls addiert werden (die beide zusammen gehören) und dann erst wieder der nächste kurze und der nächste lange Impuls aufsummiert werden, nicht aber schon der bereits benutze lange und dann der nächste kurze Impuls?

Vielen Dank für eure Antworten!

Hier noch eine kurze Ausgabe meine Serial-Monitors:
langer Impuls: 1288736
kurzer Impuls: 548
langer Impuls: 1373776
kurzer Impuls: 552
langer Impuls: 940952
kurzer Impuls: 500
langer Impuls: 891320
kurzer Impuls: 496
langer Impuls: 571136
kurzer Impuls: 496
langer Impuls: 454896
kurzer Impuls: 496
langer Impuls: 422892

usw...

Summiere einfach 2 aufeinanderfolgende Impulse ohne zu kontrollieren ob es ein langer oder kurzer impuls ist.

lang - kurz und kurz - lang sind gleichwertig. Es ist egal in welcher Reihenfolge die Impulse kommen, Hauptsache es sind 2 aufeinanderfolgende.

Grüße Uwe

Stimmt. Es ist ganz egal wie rum ich die Werte aufsummiere.

Wenn ich das Programm mit folgendem Code nun durchlaufen lasse, bekomme ich aber kaum bzw. keine Werte.

Ich habe nun angefangen mir die Werte der einzelnen Variablen auszugeben. Hierbei ist mir aufgefallen, dass bis zur Variable "periode" die Werte auch richtig ausgegeben werden.

Hierbei tritt nun folgendes Problem auf:

Bsp.: periode = 1354464

Ab "periodes" (Umrechnung der Mikrosekunden in Sekunden), bekomm ich anstatt bspw. periodes = 1354464 / 1000000 = 1,354464 nur folgende Werte:

0
0
1
1
usw. (periodes als unsigned long)

0..00
0.00
1.00
usw. (periodes als float)

Welchen Variablentyp müsste "periodes" haben, damit die Zahl bspw. "1,354464" richtig dargestellt wird?

Sind die nachfolgenden Variablen frequenz und wind mit den richtigen variablentypen float und double ausgestattet?

Vielen Dank für eure hilfreichen Antworten!

Anbei noch mein aktueller Code:

unsigned long i,abstand,kimpuls,limpuls, periode;
float frequenz, periodes;
double wind;
unsigned long j=0;



void setup()
{
  Serial.begin(9600);

  attachInterrupt(0,Interrupt,RISING);
}

void Interrupt()
{

  noInterrupts();
  
  i = micros();
  
  abstand = i-j;
  
  j=i;
  
  if (abstand >= 1000)
  {
   limpuls=abstand;
  }
  else
  {
   kimpuls=abstand;
  }
  periode = kimpuls + limpuls;
  periodes= periode / 1000000;
  frequenz = 1 / periodes;
  wind = 2.58 * (pow(frequenz,0.8927));
  interrupts();


}


void loop()
{

}

Ich würde garnix addieren.

ich würde einfach den kurzen Impuls ignorieren, und nur die micros() bei der Flanke des langen abspeichern.

in etwa so: (keine Garantie, ohne Test schnell geschrieben)

void Interrupt(){
  noInterrupts();  
  i = micros();  
  if (i-j > 1000){  
    periode =i-j;
    j=i;  
    periodes= periode / 1000000;
    frequenz = 1 / periodes;
    wind = 2.58 * (pow(frequenz,0.8927));
    interrupts();
  }
}

Wobei ich nach wie vor die ganze Berechnung ausserhalb des Interrupts machen würde.

Hallo BigBangTheory,

Ich habe vor längerer Zeit auch mit diesem Volkswindmesser eine Wetterstation gebaut.

Das Prellen des Reedkontaktes war damals das erste Problem, ich habe den Reedkontakt ausgebaut und eine kleine Gablellichtschranke (glaube die war aus nem kaputten Drucker) eingebaut.
Dann braucht man noch eine Lochscheibe, damals selbst gebaut - gibt es aber auch zu kaufen.

Wenn ein sauberes Recheckesignal kommt, ist die Sache Softwaremässig einfacher zu händeln.

Dannach stimmen die Werte des Windmessers nicht mehr mit denen überein die vom Hersteller angegeben sind.
Habe damals an einem windstillem Tag das Ding aus dem Auto gehalten und mit einem geeichtem Windmesser eine Tabelle aufgebaut. ( Bin natürlich nicht selbst gefahren)
Ein kleines Testprogramm auf dem Atmel und ein LCD zeigte mir die Impulse pro Sekunde an.

Heute würde ich auch die Impulsdauer messen :wink:

Nachtrag: Mein Anemometer mit Reedkontakt zeigte damals nicht das Verhalten wie jurs beschreibt (also kurzer und langer Impuls)
Mus aber auch zugeben das Posting nicht genau genug durchgelesen zu haben - sorry dafür.

Die ganze Berechnung werde ich denke ich noch aus der Interrupt Routine herausnehmen.

Das Problem an dem ich momentan nicht weiter komme ist, dass wenn ch den von aus der Variable Periode umrechne, also durch 1000000 teile, ich dann in der Ausgabe der Variable periodes sehr merkwürdige Werte erhalte.

Habe ich hier den falschen Variablentyp gewählt?

Das Problem habe ich in meinem letzten Post noch genauer erklärt.

Wär toll wenn ihr mir da helfen könntet :)!

Versuche es mal nach dem Vorschlag von guntherb:

Bei der Umrechnung
Frequenz = 1 / (Periodendauer * Umrechnung);
Bin ich mir nicht sicher. Aber ich weiß, dass der Arduino mit sehr kleinen Zahlen Probleme hat.
Ich würde das eher so lösen:

Umrechnung = 1000000;
Frequenz = Umrechnung / Periodendauer ;

Hey Leute,

ich habe jetzt die Berechnung des ganzen aus der Interrupt in die Loop-Routine überführt. guntherb's Vorschlag mit der Berechnung der Frequenz habe ich ebenso umgesetzt.

Wenn ich mir nun die Periode in Mikrosekunden jede Sekunde anzeigen lasse, funktioniert das wunderbar. Lass ich mir hingegen die Periode anzeigen, dann hakt das ganze und ich seh nur folgende Werte:

1
1
2
2
1
4
1
usw...

Was mache ich hierbei falsch? Muss ich für die Frequenz einen anderen Variablentyp verwenden oder woran kann das ganze liegen?

Hier noch mein aktueller Code:

unsigned long i,abstand,kimpuls,limpuls, periode, Zeitscheibe, frequenz, wind;
unsigned long j=0;

void setup()
{
  Serial.begin(9600);
  attachInterrupt(0,Interrupt,RISING);
}

void Interrupt()
{
  noInterrupts();  
  i = micros();
  interrupts();
}

void loop()
{
  abstand = i-j;

  j=i;
  
  if (abstand >= 1000)
  {
   limpuls=abstand;
  }
  else
  {
   kimpuls=abstand;
  }

  periode = kimpuls + limpuls;
  
  frequenz = 1000000 / periode;
  
  wind = 2.58 * (pow(frequenz,0.8927));
  
  if (millis() > Zeitscheibe )    
  { 
    detachInterrupt(0); 
    
    Zeitscheibe  = millis()+1000;
    
    Serial.print("Windgeschwindigkeit = ");
    Serial.println(wind);
    
    attachInterrupt(0,Interrupt,RISING);
  }
}

Lass ich mir hingegen die Periode anzeigen, dann hakt das ganze und ich seh nur folgende Werte

Du meinst die Frequenz anzeigen ?
Wenn du das Windrad mit der Hand drehst, sind die Werte doch fast plausibel, nur halt etwas ungenau zur späteren Weiterberechnung in Windspeed.
Die Variable frequenz hast du als unsigned long definiert, versuche es mal mit float.

Dein Windmesser (1 imp pro Umdrehung) hat diese Werte, ist auch dein Zitat:

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

Ich habe bei der Variable Frequenz schon die Variablentypen unsigned long, float, double usw. ausprobiert. Leider mit keinem guten Ergebnis.

Ist es an dieser Stelle möglich mit dem Arduino folgende Rechenschritte durchzuführen?

Bsp.:

periode = 357016

frequenz = 1000000 / periode = 1000000 / 357016 = 2,8009949133932372778811033679163 Hz

Welchen Variablentyp muss in diesem Fall die Variable Frequenz haben?

Wenn ich für die Frequenz den Variablentyp "float" verwende, erhalte ich folgende Ausgaben: 1.00, 2.00 usw. (immer mit .00).

Wenn ich für die Frequenz den Variablentyp "unsigned long" verwende, erhalte ich folgende Ausgaben: 1, 2 usw..

Wär toll wenn ihr mir da weiter helfen könntet!

Gruß

100000 / periode ist eine Integer (long) - Division

100000.0 / periode ist eine Gleitkomma ( float ) - Division

BigBangTheory:
frequenz = 1000000 / periode = 1000000 / 357016 = 2,8009949133932372778811033679163 Hz

Ich weiß nicht, war meine Schule so streng? Aber wenn ich eine solche Rechnung dem Lehrer in Meßtechnik gezeigt hätte, hätte ich sofort die negativste mögliche Note erhalten.
Wieso?
Du gibst als Ergebnis eine Zahl mit einer Genauigkeit von 32 Stellen an, wo Du doch bei der Messung der Periode nur einen Genauigkeit von +/-0,9% ( 3 Stellen) hast. Dese Genauigkeit ist durch den Systemtakt des Arduinos gegeben und der ist durch den Resonator nicht sonderlich genau.

Also kannst Du nur 2,801 Hz schreiben wobei die Tausendstelstelle schon zweifelhaft ist.

Grüße Uwe

Mein ganzer Fehler lag wohl darin, in der Rechnung frequenz = 1000000 / periode zu schreiben: frequenz = 1000000.0 / periode :D.

Gibt es denn eine Möglichkeit festzulegen, wie viele Nachkommastellen man angezeigt bekommen möchte, wenn man solch eine Float-Division durchführt?

Gibt es denn eine Möglichkeit festzulegen, wie viele Nachkommastellen man angezeigt bekommen möchte

Ja, mehrere.
Ist ausserdem keine Frage der Division, sondern der Anzeige.
Schau dir mal Serial.print an

Float hat beim Arduino meist 6 bis 7 Stellen, also z.B. 1.23456 *10^-4
Du kannst dir natürlich mehr Stellen anzeigen lassen (z.B. mit Serial.println(frequenz, 18), aber die machen keinen Sinn.
mehr als die 6-7Stellen genauigkeit wirst du nicht bekommen, und das reicht ja meist auch.

Ich komme aus Delphi/Pascal Welt, deshalb wundere ich ab und an schon was ein C-Compiler so macht

frequenz = 1000000 / periode

Bei Delphi - Wenn frequenz eine Integer Variable wäre wurde der Compiler sofort meckern.
Er will das dies in einer Gleitkomma Variable gespeichert werden soll, weil das Ergebnis ein Gleitkomma sein wird.
Wenn zwei ganze Zahlen dividiert werden ist das meist der Fall

Wenn ich nun in C frequenz expliziert als float definiere muß ich dies dann wirklich so schreiben,
damit auch eine Float-Division durchgeführt wird.

frequenz = 1000000.0 / periode

Ich wäre genauso wie BigBangTheory in diese Falle getappt.

Ist zwar etwas OT sorry dafür, aber dieses Beispiel passte genau für meine Frage

...weil das Ergebnis ein Gleitkomma sein wird.

Der Fehler liegt erstmal im "weil", dann konkret daran dass in c Integer/Integer als Ergebnis immer ein Integer ist. Was sonst :wink:

Ganz fies wird es übrigens, wenn z.B. 1000 und 1000L einen Unterschied macht.
( z.B. wenn man es mit int i = 100 multipliziert und das Ergebnis in einem long ablegt. )

int i = 100;
long l = 1000 * i; 
Serial.print(l); 
if ( l == -31072) Serial.println (" ist ein erstaunliches Ergebnis");

Bei c für MicroController sollte man übrigens auch immer überlegen, ob man tatsächlich den Datentyp float braucht.

michael_x:
Bei c für MicroController sollte man übrigens auch immer überlegen, ob man tatsächlich den Datentyp float braucht.

Schon klar, immer schön die ressourcen schonen.

int i = 100;
long l = 1000 * long( i); 
Serial.print(l); 
if ( l == -31072) Serial.println (" ist ein erstaunliches Ergebnis");

Dann müsste man in diesen Fall einen typecast machen =( oder i gleich als long denfinieren
Danke für solche Hinweise, als Delphi Mensch hätte so einen Fehler nie gesehen.
Ich möchte jetzt keine Diskussion über Programmiersprachen lostreten, weil obsolet ..... C++ hat sich durchgesetzt. :~

Ob C++ zu Objekt Pascal wirklich besser ist ??

Das obigen Beispiel ist ganz simples C und selbst dort gibt es Dinge die in meinen Pascal Augen gar nicht gehen dürften.

C und C++ ist für Masochisten, sagen die einen.

Basic, C# , Java und dein Pascal ist für Weicheier, sagen die anderen.