Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Skripten / Logik
  4. Mittelwertbildung für die Windrichtung mit JavaScript

NEWS

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.8k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    2.2k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    16
    1
    3.2k

Mittelwertbildung für die Windrichtung mit JavaScript

Geplant Angeheftet Gesperrt Verschoben Skripten / Logik
1 Beiträge 1 Kommentatoren 624 Aufrufe
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • S Offline
    S Offline
    SabineT
    schrieb am zuletzt editiert von SabineT
    #1

    Ich hatte vor 4 Jahren mal für FHEM ein Script geschrieben, um die von meiner Wetterstation (WH3080) gelieferte Windrichtung für die grafische Darstellung aufzubereiten. Das Problem ist ja, dass speziell bei schwachem Wind oder Windstille die Windfahne irgendwo hin zeigt (z.B. durch eine Thermikablösung oder Verwirbelung an umgebenden Hindernissen). Damals hatte ich folgende Grafik zur Verdeutlichung verwendet:
    WindDirAverage_fhem.png

    Man sieht bei der Windrichtung, dass die Originaldaten eher unbrauchbar sind.

    Hier ein Beispiel, wie es jetzt bei mir ausschaut:
    WinddirAverage.png

    Die Grafiken werden bei mir ausserhalb von ioBroker aus den mit dem SQL-Adapter in MariaDB gespeicherten Daten erstellt.
    Wenn der Wind zu schwach ist, wird die Windrichtung überhaupt unterdrückt.

    Allerdings ist die Mittelwertbildung bei der Windrichtung etwas komplizierter, da man es hier mit Polarkoordinaten hat. D.h. man kann nicht einfach den Winkelwert mitteln. Z.b. wäre der arithmetische Mittelwert zw. NO (45°) und NW (315°) dann 180°, also S, tatsächlich ist er aber 0° (N). Daher muss man den Winkel in West-Ost Komponente und Nord-Süd Komponente zerlegen und getrennt den Mittelwert berechnen.
    Die Grundidee für die Berechnung hab ich dabei PYWWS abgeschaut.

    Jetzt hab ich mich endlich dazu aufgerafft, das Script in Javascript zu erstellen um es direkt in IoBroker verwenden zu können:

    const logit = false;	// hier kann bei Bedarf die Logausgabe aktiviert werden
    
    /*
    	minage:
    	Erst nach Ablauf dieser Zeit wird ein neuer Wert berücksichtigt.
    	Ist quasi eine Art Entprellung.
    */
    const minage = 0;
    
    /*
    	avtime:
    	Maxmimaler Zeitraum, der gemittelt werden soll
    */
    const avtime = 900;
    
    /*
    	decay:
    	1 -> alle Werte werden gleich gewichtet
    	0 -> nur der aktuelle Wert wird verwendet.
    	in der Praxis wird man Werte so um 0.75 nehmen
    */
    const decay = 0.75;
    
    /*
    	minspeed:
    	da bei sehr geringer Windgeschwindigkeit die Windrichtung üblicherweise nicht
        eindeutig ist, kann mit minspeed ein Schwellwert angegeben werden
        Ist die (gewichtetete) mittlere Geschwindigkeit < minspeed wird undef zurück geliefert
    */
    const minspeed = 0.5;
    
    
    /*
    	Maximalgröße des Arrays
    	Der Wert hängt davon ab, in welchem Intervall die Wetterstation die Daten liefert.
    	Richtwert: avtime / Intervall + 1;
    */
    const maxentries = 40;
    
    /*
    	ID's der Quellobjekte für Windgeschwindigkeit und Richtung
    */
    const wsid = "alias.0.Wetterstation.windspeed";			// Windgeschwindigkeit in m/s
    const wdid = "alias.0.Wetterstation.winddir";				// Windrichtung (0 - 15)
    
    /*
    	Die folgenden 3 Objekte müssen manuell angelegt werden!
    	hier wird dann jeweis die ID eingetragen:
    */
    const historyid = "0_userdata.0.WindDirAverage.history";			// Speicher der History vom Typ Array
    const wdavgid = "0_userdata.0.WindDirAverage.WindDirAvgDegree";	// Mittelwert der Windrichtung in Grad vom Typ Number
    const wdavgtid = "0_userdata.0.WindDirAverage.WindDirAvgText";		// Mittelwert der Windrichtung als Text vom Typ String
    
    var i = 0;
    var age = 0;
    var ltime = 0;
    let oldhistory = getState(historyid).val;				// gespeicherten Buffer holen
    var history = new Array();								// Datenbuffer initialisieren
    
    if (decay > 1){		// darf nicht >1 sein
    	decay= 1;
    }
    if (decay < 0){		// darf nicht <0 sein
    	decay= 0;
    }
    
    
    if (oldhistory.length > 0) {							// wenn im gespeicherten Buffer Daten vorhaden sind
    	history = oldhistory;								// diese in den Datenbuffer übernehmen
    	ltime = history[history.length - 1].time;			// Zeitstempel des letzten Eintrages 
    }
    
    var num = history.length;
    
    on({id: wsid, change: 'any'}, function(wsobj) {
    	let ws = wsobj.state.val;							// WindSpeed(m/s)
    	let ctime = (wsobj.state.ts / 1000).toFixed(0);		// Timestamp (s)
    	let wd = getState(wdid).val * 22.5;					// WindDirection (Grad)
    	let stime = history[0].time;						// Zeitpunkt des ältesten Wertes
    	age = ctime - ltime;								// Zeitspanne seit dem vorhergehenden Wert
    
    	if (age > minage) {									// erst nach Ablauf von minage einen neuen Wert verarbeiten (Entprellung)
    		if (history.length >= maxentries) {				// falls der Datenbuffer voll ist,
    			history.shift();							// den ältesten Eintrag entfernen
    		}
    		let wdr = (degToRad(wd)).toFixed(3);
    		let newentry = {
                windspeed: ws,
                winddir: wdr,
                time: ctime
            };
    		history.push(newentry);							// neue Daten dem Datenbuffer hinzufügen
    		num = history.length;
    		if (logit) {
    			log(sprintf("num: %u ts: %u age: %u ws: %0.1f, wd: %u, wdr: %u", num, newentry.time, age, newentry.windspeed, wd, newentry.winddir));
    		}
    		ltime = ctime;
    		var anz = 0;
    		var sanz = 0;
    		var sumsin = 0.0;
    		var sumcos = 0.0;
    		var sumspeed = 0.0;
    		var wdavg = 0;
    		var weight = 0;
    		age = 0;
    		maxage = 0;
    		for (let i = 0; i < num; i++) {					// nun die Daten im Buffer verarbeiten
    			ws = history[i].windspeed;
    			wdr = history[i].winddir;
    			ts = history[i].time;
    			age = ctime - ts;
    			if (age > avtime) {							// zu alte Einträge entfernen
    				history.shift();
    				i--;
    				num--;
    			} else {									// Werte aufsummieren, Windrichtung gewichtet über Geschwindigkeit, decay und age
    				weight = ws * decay ** (age / avtime);
    				if (age < (avtime / 4)) {				// für die Mittelwertsbildung der Geschwindigkeit wird nur ein 4tel von avtime genommen
    					sumspeed += weight;
    					sanz++;
    				}
    				sumsin += ((Math.sin(wdr)).toFixed(3) * weight);
    				sumcos += ((Math.cos(wdr)).toFixed(3) * weight);
    				anz++;
    			}
    		}
    		setState(historyid, {							// Datenbuffer im Datenpunkt speichern
    			val: history,
    			ack: true
    		});
    		let avg = radToDeg(Math.atan2(sumsin, sumcos));
    		wdavg = ((avg + 360) % 360).toFixed(0);			// Mittlere Windrichtung in Grad
    		wdt = wd_to_text(wdavg);						// und als Text
    		let wdstr = '-';
    														// neuen Wert nur ausgeben, wenn die durchschnittliche Geschwindigkeit groß genug ist
    														// und überhaupt ein Wert berechnet wurde
    		if ((anz > 0) && (sanz > 0) && ((sumspeed / sanz) >= minspeed)) {
    			setState(wdavgid, {
    				val: Number(wdavg),
    				ack: true
    			});
    			wdstr = wdt;
    		}
    		setState(wdavgtid, {
    			val: wdstr,
    			ack: true
    		});
    		if (logit) {
    			log(sprintf("sanz: %u ws: %0.1f avgws: %0.1f anz: %u avg: %0.1f wdavg: %u wdt: '%s'", sanz, ws, sumspeed / sanz, anz, avg, wdavg, wdstr));
    		}
    	}
    });
    
    function degToRad(degrees) {
      return degrees * (Math.PI / 180);
    };
    
    function radToDeg(rad) {
      return rad / (Math.PI / 180);
    };
    
    function wd_to_text(wd) {
    	let wdt = ['N', 'NNO', 'NO', 'ONO', 'O', 'OSO', 'SO', 'SSO', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N'];
    	let w = (wd / 22.5).toFixed(0);
    	return wdt[w];
    }
    
    
    

    Ich hab versucht, möglichst viel in den Kommentaren zu erklären! Anpassen muss man auf jedenfall die beiden Variablen wsid und wdid (Zeilen 41 und 42), das sind die Objekte, die für die Berechnung herangezogen werden. Bei mir ist wdid ein Objekt, in das von der Wetterstation nur eine Zahl (0-15) geschrieben wird. In der Zeile 76 wird daraus dann die Windrichtung in ° berechnet. Je nach eigener Wetterstation ist hier also eventuell auch eine Anpassung nötig!

    Die Ausgabe erfolgt dann in die in den Zeilen 48-50 definierten Objekte. Die Objekte müssen zuvor manuell angelegt werden! Ich hab aber mal meinen Objektbaum in eine JSON-Datei exportiert, die man in der Objektansicht oben mit dem Aufwärtspfeil importieren kann:
    0_userdata.0.WindDirAverage.json

    Ich muss noch erwähnen, dass ich keine professionelle Javascript Programmiererin bin, es kann also durchaus sein, dass man das eine oder andere noch eleganter lösen könnte. Aber das Script tut, was ich damit erreichen will.

    Sabine

    1 Antwort Letzte Antwort
    2
    Antworten
    • In einem neuen Thema antworten
    Anmelden zum Antworten
    • Älteste zuerst
    • Neuste zuerst
    • Meiste Stimmen


    Support us

    ioBroker
    Community Adapters
    Donate

    697

    Online

    32.4k

    Benutzer

    81.5k

    Themen

    1.3m

    Beiträge
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
    ioBroker Community 2014-2025
    logo
    • Anmelden

    • Du hast noch kein Konto? Registrieren

    • Anmelden oder registrieren, um zu suchen
    • Erster Beitrag
      Letzter Beitrag
    0
    • Home
    • Aktuell
    • Tags
    • Ungelesen 0
    • Kategorien
    • Unreplied
    • Beliebt
    • GitHub
    • Docu
    • Hilfe