Kennlinie / Lookup table in Perl umsetzen

Begonnen von der_oBi, 21 September 2016, 21:13:29

Vorheriges Thema - Nächstes Thema

igami

du kannst das powerMap-Attribut auch direkt in deinem Temperatur device setzen, dann brauchst du kein notify und dummy
Pi3 mit fhem.cfg + DbLog/logProxy
Komm vorbei zum FHEM Treffen im Kreis Gütersloh! Das nächste Mal im April 2020.

MAINTAINER: archetype, LuftdatenInfo, monitoring, msgDialog, Nmap, powerMap
ToDo: AVScene, FluxLED

Ajuba

Aber ich muss doch vorher noch durch 20 dividieren.
Wie stelle ich das ohne dummy und notify direkt im Device Temperatur an?
Am liebsten wäre es mir eh so kompakt wie möglich.
FHEM auf RPi3, Homematic CCU3 mit Cuxd und CUL 868 für FS20, Siemens S7 über CP343-1,
DbLog zu MySQL auf NAS QNAP TS-253D,
Yeelight

mumpitzstuff

#32
Wenn x positiv ist und der Abstand zwischen zwei x immer 1 ist, dann ist es relativ simpel.

1.) Array anlegen in denen die y Werte gespeichert sind.
2.) y = myarray[int(x)] + ((myarray[int(x + 0.5)] - myarray[int(x)]) / 2);

Ajuba

Die Werte kommen von einer PLC und die löst von 0 bis 27648 auf.
Die nichtlineare Temperaturkennlinie beansprucht davon ca. 15000.
Wollte ich also X=1 erreichen müsste man für die Temperatur Kennlinie 15000 Werte eingeben statt der auch schon vielen 110 laut Thermometer Datenblatt.
Abgesehen davon habe ich leider keinen Tau wie ich das in Fhem umsetzen sollte da ich ja noch mit primitivsten Grundlagen kämpfe und stolz darauf bin heute eine Division durch 20 geschafft zu haben.

Aber falls es mit dem Array wirklich einfach machbar ist und du mir einfaches Beispiel posten könntest würde ich es gerne versuchen.
FHEM auf RPi3, Homematic CCU3 mit Cuxd und CUL 868 für FS20, Siemens S7 über CP343-1,
DbLog zu MySQL auf NAS QNAP TS-253D,
Yeelight

mumpitzstuff

#34
Meine Antwort bezog sich auf den ersten Beitrag. Dein Problem ist ein anderes wenn ich es richtig verstehe. Du hast Werte von 0 bis 27648 (ich nenne sie x) und willst daraus auf eine Temperatur schließen z.B. von -10 bis +60 Grad (ich nenne sie y). Richtig? Der Fall ist genau anders rum und leider nicht mehr so simpel. Ich würde so vorgehen.

1.) Überlege dir wieviel Stützstellen du haben willst. Je weniger desto ungenauer wird das Ergebnis. Nehmen wir an pro 0.5 Grad hast du einen x Wert. Wenn du den Bereich von -10 bis +60 Grad abdecken willst, brauchst du dann 140 Stützstellen.
2.) Leg dir ein Array der Größe 140 an und leg dort die x Werte im Bereich von 0-27648 ab, jeweils für die entsprechenden Temperaturen. Index 0 enthält dann 0 und Index 139 des Arrays den Maximalwerte 27648. Index 1 ist dann der x Wert für -9,5 Grad, Index 2 der x Wert für -9 Grad usw.
3.) Leg dir eine Schleife an, die über alle 140-1 Einträge des Arrays geht und prüfe: if (value >= myarray && value <= myarray[i+1]) Ergebnis = ((i * 0.5) + 0.25) - 10

value ist dabei dein aktueller PLC Wert.

Ich hoffe das war verständlich. Dir jetzt den exakten Code zu geben ist nicht ganz so einfach, da ich den Kontext nicht genau kenne.

Ajuba

Bevor ich mich in das Matritzen/Schleifen Programmier-Abenteuer stürze hoffe, ich es doch mit powermap fertig zu bringen da ich ja anscheinend ganz knapp dran bin.

Ich hoffe, dass sich noch einer der Experten erbarmt mir für Dummies (nicht die Variable sondern in dem Fall ich selbst) zu erklären welches EVENT-Attribut ich noch wie setzten muss damit der sich ändernde dum3 die powermap Kennlinie Berechnung auslöst. Dann sollte es ja hoffentlich laufen.

Auch den Vorschlag von igami zum einfacheren Setup nähme ich gerne an wenn ich nur wüsste wie. Gestern habe ich noch versucht diesen Vorschlag innerhalb von dum3 umzusetzen (da schon durch 20 dividiert und für powermap verdaubar), bin aber gescheitert.

Heute abend werde ich mal das von Loredo empfohlene update machen und schauen wie sich das statische Berechnungsverhalten ändert.
Und dann bräuchte ich noch einen detaillierten Tip bezüglich Eventauslösung für dynamische Berechnung.

Sorry, dass ich mich vielleicht noch dumm anstelle aber umsonst poste ich ja nicht in der Kategorie Anfänger.  :-X
FHEM auf RPi3, Homematic CCU3 mit Cuxd und CUL 868 für FS20, Siemens S7 über CP343-1,
DbLog zu MySQL auf NAS QNAP TS-253D,
Yeelight

mumpitzstuff

Alternativ kannst du dir auch eine Näherungsfunktion berechnen z.B. hier: http://www.xuru.org/rt/nlr.asp

Einfach Wertepaare eingeben und berechnen lassen (Anzahl der Parameter würde ich mal auf 4 stellen. Dann bekommst du z.B. sowas schönes hier:

y=6.666666395·10-2 x3 - 0.742857137 x2 + 2.890476257 x - 2.240000154

Da kannst du dann einfach deine x Werte einsetzen und dir y berechnen lassen. Das würde dir das rumhantieren mit Schleifen usw. ersparen...

Ajuba

Eine Polynomialfunktion hatte ich auch schon früher überlegt. Leider ist der Fehler gerade im häufigsten Bereich (0-20°C) teilweise mehr als 3°C.  :'(
Also voererst nochmal mit powermap probieren. Sonst bleibt mir eh nichts anderes übrig als zu programmieren.
FHEM auf RPi3, Homematic CCU3 mit Cuxd und CUL 868 für FS20, Siemens S7 über CP343-1,
DbLog zu MySQL auf NAS QNAP TS-253D,
Yeelight

mumpitzstuff

Hast die Datenreihen dazu noch rumliegen und kannst sie mir schicken?

Prof. Dr. Peter Henning

Das mit der Näherungsfunnktion habe ich schon weiter oben vorgeschlagen. Allerdings ist ein Polynom an der Stelle nicht sinnvoll, sondern man benötigt zuerst einmal ein Modell.

LG

pah

Ajuba

Laut dem Datenblatt (attached) des Thermometer/Hygrometer Kombigeräts wird die Steinhart-Hart Gleichung zur Annäherung empfohlen.
Das ist ein Polynom von natürlichen Logarithmen. https://de.wikipedia.org/wiki/Steinhart-Hart-Gleichung
Ich kämpfe momentan noch damit die richtigen Koeffizienten herauszufinden, denn die habe ich am Datenblatt nicht gefunden.

Als PLC-Wert bekomme ich natürlich nicht den temeperaturabhängigen Widerstand rein sondern die entsprechende Spannung welche auf ein einige tausend digits aufgelöst wird. aber das ist dann eine einfache Umrechnung.
FHEM auf RPi3, Homematic CCU3 mit Cuxd und CUL 868 für FS20, Siemens S7 über CP343-1,
DbLog zu MySQL auf NAS QNAP TS-253D,
Yeelight

Prof. Dr. Peter Henning

Diese Koeffizienten kann man aber wunderbar anfitten - wie bereits gesagt: Mathematica oder Maple sind dafür ideal geeignet. Mathematica lässt sich online über Wolfram Alpha nutzen.

LG

pah

Ajuba

Halleluja, ich habs geschafft.
Dieses tolle OnlineTool wirft aufgrund meiner Kennlinie die Parameter für die Steinhart-Hart Gleichung aus
http://www.thinksrs.com/downloads/programs/Therm%20Calc/NTCCalibrator/NTCcalculator.htm
A=0.0009387137905
B=0.0002553311771
C=0.00000008157780989
Nach Umformen der Gleichung und gleichzeitiger Einbindung meiner
- Versorgungsspannung=6.07V
- Spannungsteilerwiderstand=11970 Ohm
- PLC Auflösungsspannung=10V
- PLC Auflöungsdigits=27468
und Abzug der obligaten 273,15K
kommt man zu folgendem tollen langen Polynom, das zwei natürliche Logarithmen und eine dritte Potenz enthält.
Der INPUT von der PLC kommend kommt darin vier mal vor

T=1/(0.0009387137905+0.0002553311771*LN(INPUT*10*11970/(27648*6.07-INPUT*10))+0.00000008157780989*(LN(INPUT*10*11970/(27648*6.07-INPUT*10)))^3)-273.15

Einige Zahlen könnte man zusammenfassen aber "Übersichtlichkeit" halber habe ich es nicht gemacht.
In Excel funktioniert die Formel ziemlich genau.

Jetzt bräuchte ich bitte noch eine Anfänger-Anleitung (deppensicher), wie ich FHEM diese Rechnung beibringe.
Kann mir da bitte jemand helfen?
FHEM auf RPi3, Homematic CCU3 mit Cuxd und CUL 868 für FS20, Siemens S7 über CP343-1,
DbLog zu MySQL auf NAS QNAP TS-253D,
Yeelight

Prof. Dr. Peter Henning

#43
Na ja, das ist kein Polynom - die enthalten nämlich nur Potenzen. von "INPUT"

In 99_myUtils.pm


sub doit($){
  my ($input)=@;
  my $T=1/(0.0009387137905+0.0002553311771*log($input*10*11970/(27648*6.07-$input*10))+0.00000008157780989*(log($input*10*11970/(27648*6.07-$input*10)))**3)-273.15;
  return $T;
}


und im FHEM-Modul

attr <device> userReadings temperature:input {doit(input)}

Voausgesetzt natürlich, die Ursprungsgröße heißt wirklich "input".

LG

pah


Ajuba

Weit bin ich nicht gekommen
Nachdem ich mir 99_myUtils.pm aus dem Template erstellt habe, habe ich dort deinen Code eingefügt und SAVE gedrückt

##############################################
# $Id: myUtilsTemplate.pm 7570 2015-01-14 18:31:44Z rudolfkoenig $
#
# Save this file as 99_myUtils.pm, and create your own functions in the new
# file. They are then available in every Perl expression.

package main;

use strict;
use warnings;
use POSIX;

sub
myUtils_Initialize($$)
{
  my ($hash) = @_;
}

# Enter you functions below _this_ line.
sub doit($){
  my ($input)=@
  my $T=1/(0.0009387137905+0.0002553311771*log($input*10*11970/(27648*6.07-$input*10))+0.00000008157780989*(log($input*10*11970/(27648*6.07-$input*10)))**3)-273.15;
  return $T;
}

1;

Dann kommt dick und fett folgende Fehlermeldung
ERROR:

Global symbol "@my" requires explicit package name at ./FHEM/99_myUtils.pm line 22. syntax error at ./FHEM/99_myUtils.pm line 22, near "@ my $T" Global symbol "$T" requires explicit package name at ./FHEM/99_myUtils.pm line 22. Global symbol "$input" requires explicit package name at ./FHEM/99_myUtils.pm line 22. Global symbol "$input" requires explicit package name at ./FHEM/99_myUtils.pm line 22. Global symbol "$input" requires explicit package name at ./FHEM/99_myUtils.pm line 22. Global symbol "$input" requires explicit package name at ./FHEM/99_myUtils.pm line 22. Global symbol "$T" requires explicit package name at ./FHEM/99_myUtils.pm line 23.


Übrigens, die Zeile 26 1;   war schon im Template so. Soll das so sein?

Außerdem gleich vorweg Fragen zu userReadings:
attr <device> userReadings temperature:input {doit(input)}

- Muss ich also ein Dummy (z.B. Temp) anlegen dessen Name bei <device> reinkommt?
- Muss temperature ein Reading unter Temp sein?
- Oder kann/soll man das userReading gleich unter dem Device PLC Eingang machen?
  Dieses device sieht so aus:
define input S7_ARead db 209 20 u32
attr input IODev PLC
FHEM auf RPi3, Homematic CCU3 mit Cuxd und CUL 868 für FS20, Siemens S7 über CP343-1,
DbLog zu MySQL auf NAS QNAP TS-253D,
Yeelight