Hi zusammen,
ich stehe gerade vor folgendem Problem:
Ich würde gerne in einem Reading eine Kennlinie (also x=>y) hinterlegen. Wird diese Kennlinie mit einem Eingangswert (x) "gefüttert", soll ein innerhalb der Kennlinie interpolierter Ausgangswert (y) rauskommen.
Beispiel:
x | 1 | 2
----------
y | 0 | 1
für x=1,5 sollte als Ergebnis demnach y=0,5 ausgegeben werden.
Gibt es hierfür bereits eine Funktion in Perl? Ich könnte es mit Sicherheit auch (mit viel Aufwand) mit einer selbstgebauten Routine umsetzen, hoffe aber, dass es eine einfachere Lösung gibt.
Sorry, wenn ich mich vielleicht ein wenig umständlich ausgedrückt habe. Ich kann weder im Forum noch sonstwo im Netz irgendwas finden. Vielleicht auch einfach nur weil mir der richtige Suchbegriff fehlt?! ???
Ich hoffe jemand hat eine Idee :)
Ich bin mir nicht sicher, ob ich verstehe was du meinst.... Möchtest du ein Funktion (im von dir genannten Beispiel y = x-1) in einem Reading hinterlegen? Wie soll diese dann "gefüttert" werden?
Vielleicht kannst du den Anwendungsfall etwas konkreter darstellen...
Grüße,
Oli
Vielleicht könntest userReadings benutzen und in den Kennlinienabschnitten linear interpolieren.
Kannst Du Deine Idee etwas genauer beschreiben?
Zitat von: der_oBi am 24 September 2016, 06:56:50
Kannst Du Deine Idee etwas genauer beschreiben?
In das Gerät, in dem x entsteht baust Du ein userReading, das den zugehörigen y-Wert berechnet, s. userReadings (http://fhem.de/commandref_DE.html#attributes)
Mit Kennlinienabschnitt meine ich den Bereich zwischen zwei nebeneinander liegenden Wertepaaren. Dein Beispiel hat 2 Wertepaare, also nur einen Kennlinienabschnitt. Den Wert berechnest Du so, wie Du auf 0,5 gekommen bist oder durch lineare Interpolation (http://www.peter-junglas.de/fh/vorlesungen/thermodynamik1/html/app-a.html).
Was lineare Interpolation ist, weiß ich von Berufs wegen leider nur zu genau ;)
Ich habe eben das Problem, dass meine Kennlinie nicht (wie in meinem Beispiel oben) durch eine einfache mathematische Funktion abzubilden wäre. Wenn ich Deine Idee richtig verstanden habe, müsste ich aber in dem userReading eine Funktion hinterlegen, die mir das Ergebnis berechnet, oder?
Ich habe nun nach langem Bemühen von Google doch noch etwas gefunden, was meine Anforderungen erfüllen sollte:
Math::Interpolate (https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjjq8DN36nPAhUmC8AKHXY_DjAQFgggMAA&url=http%3A%2F%2Fsearch.cpan.org%2F~bzajac%2FMath-Interpolate-1.05%2Flib%2FMath%2FInterpolate.pm&usg=AFQjCNGD0O3eWnNuak-YRo_3-e38kNIgew&sig2=DvyG-_v8RbyoEeb0hPI_VQ)
Wenn ich heute Abend dazu komme, werde ich mal mein Glück damit versuchen.
Vielleicht kennt/nutzt ja jemand diese Lib schon?
Hallo oBi
Konntest du dein Problem lösen?
Ich muss auch Messwerte eines nicht-linearen Thermometers umrechnen. Eine lange Tabelle mit x mA entspricht y °C
Bei den Readings fehlt mir noch der Durchblick und ich wäre dankbar wenn du deine Lösung hier posten könntest.
Guck dir mal das powerMap Modul an, ist zwar eigentlich für Leistung und Energie gedacht, aber funktioniert ja trotzdem.
Danke für den Tip mit powerMap. Das könnte tatsächlich sein, was ich brauche.
Ich durchschaue nur noch nicht wie ich meinen Input "reinbringe" und wie ich das Ergebnis "auslese".
Ich habe mir mal zum Üben einen Dummy namens IN angelegt und möchte abhängig von dessen Wert Ausgaben auf OUT sehen.
Außerdem habe ich versucht dem IN das Attribut Powermap zuzuweisen (habe ich wahrscheinlich falsch gemacht). Was muss ich beim Attribut setzten in das leere Feld eintragen? 1 oder .* oder sonst was ?
Meine Powermap habe ich "Kennlinie" getauft.
Set assign gibt mir nur "Kennlinie" als Auswahl
Get devices liefert ebenfalls nur "Kennlinie"
Leider bin ich mit Perl Code auch noch auf Kriegsfuß.
Wenn ich unter attr Powermap folgendes eingebe
{
'IN' => {
'1' => <10>,
'2' => <20>,
'3' => <30>,
},
sieht meine config folgendermaßen aus
define Kennlinie powerMap
attr Kennlinie powerMap {\
'IN' => {\
'1' => <10>,\
'2' => <20>,\
'3' => <30>,\
},
define IN dummy
attr IN powerMap .*
define OUT dummy
Wie ist das überhaupt gemeint?
{
'<reading>' => {
'<value>' => <power>,
'<value>' => <power>,
...
},
Was ist reading, value und power?
Welche Sonderzeichen '<>' müssen stehen bleiben und was durch was ersetzt?
Und wie weise ich das meinen Variablen IN und OUT zu?
Sorry für die vielen hilflosen Fragen.
Zitat von: Ajuba am 31 Januar 2017, 22:05:59
Ich habe mir mal zum Üben einen Dummy namens IN angelegt und möchte abhängig von dessen Wert Ausgaben auf OUT sehen.
Das wird so nicht funktionieren, powermap erzeugt neue Readings im bestehenden Device.
Du könntest das so machen:
Ein Dummy mit Namen Kennlinie und den Readings IN und OUT.
Ein powerMap mit Namen Powermap.
Zitat von: Ajuba am 31 Januar 2017, 22:05:59
Außerdem habe ich versucht dem IN das Attribut Powermap zuzuweisen (habe ich wahrscheinlich falsch gemacht). Was muss ich beim Attribut setzten in das leere Feld eintragen? 1 oder .* oder sonst was ?
In das Attribut poweMap musst du deine Kennlinie eintragen.
Zitat von: Ajuba am 31 Januar 2017, 22:05:59
Set assign gibt mir nur "Kennlinie" als Auswahl
powerMap verfügt über eine Datenbank in der schon Werte fur Hue Leuchten und Sonos Lautsprecher stehen. Würde dein Thermometer in dieser Datenbank stehen würde das powerMap Attribut darüber auch gefüllt werden um es manuell zu bearbeiten. Da dies aber nicht der Fall ist passiert nichts ;)
Zitat von: Ajuba am 31 Januar 2017, 22:05:59
Get devices liefert ebenfalls nur "Kennlinie"
Da zeigt dir powerMap für welche devices es Berechnungen anstellt, scheinbar bisher nur Kennline.
Zitat von: Ajuba am 31 Januar 2017, 22:05:59
Wie ist das überhaupt gemeint?
{
'<reading>' => {
'<value>' => <power>,
'<value>' => <power>,
...
},
Ein device kann verschiedene Readings haben. Ich hatte gehofft, dass es durch das Beispiel für die HUE white besser zu verstehen ist:
'pct' => {
'0' => 0.4,
'10' => 1.2,
'20' => 1.7,
'30' => 1.9,
'40' => 2.3,
'50' => 2.7,
'60' => 3.4,
'70' => 4.7,
'80' => 5.9,
'90' => 7.5,
'100' => 9.2,
},
'state' => {
'unreachable' => 0,
'*' => 'pct',
},
Zitat von: Ajuba am 31 Januar 2017, 22:05:59
Was ist reading, value und power?
reading ist der Name des Readings, value ist der Wert des Readings und power ist die Leistungsaufnahme.
Bei der HUE wird bei einem pct, also Dimmwert, von 60 % eine Leistung von 3.4 Watt aufgenommen.
Zitat von: Ajuba am 31 Januar 2017, 22:05:59
Welche Sonderzeichen '<>' müssen stehen bleiben und was durch was ersetzt?
Ich weiß nicht ob das irgendwo ofiziell steht, aber ich habe es so verstanden, dass das was in <> steht ein Bezeichner ist und die <> entfallen dabei. Aus '<reading>' wird 'pct'. Sollten noch eckige Klammern vorkommen [] so handelt es sich um ein optionales Element.
Hier ein Beispiel für dei Umsetzung als Raw definition
defmod powerMap powerMap
defmod Kennlinie dummy
attr Kennlinie powerMap {'IN' => {\
'1' => 10,\
'2' => 20,\
'3' => 30,\
},\
}
attr Kennlinie powerMap_noEnergy 1
attr Kennlinie powerMap_rname_P OUT
attr Kennlinie readingList IN
attr Kennlinie setList IN
Du bekommst einen Dummy mit Namen Kennlinie, welche zwei Readings besitzt: IN und OUT.
Durch das Attribut powerMap_noEnergy wird festgelegt, dass kein Energieverbrauch berechnet wird. Mit dem Attribut powerMap_rname_P wird festgelegt, dass das Ausgabe Reading OUT heißt.
Ich hoffe ich konnte dir deine Fragen verständlich beantworten und würde mich freuen wenn es klappt. In jedem Fall aber bitte Feedback geben :)
Grüße
igami
Ahhh. Schön langsam dämmert es bei mir.
Vor allem die Raw definition hat geholfen.
Kann es erst am Abend ausprobieren und werde dann berichten.
Danke
OK, das wäre geschafft. Aber ohne dein Beispiel hätte es nicht geklappt. DANKE
Ich kann jetzt innerhalb von Kennlinie mit "set Kennlinie IN" Werte setzen und gleich unterhalb die Readings IN und OUT korrekt ablesen. :)
Jetzt noch folgende Fragen:
- Wie kann ich den OUT Wert nun einer Variable (z.B. dem dummy Temperatur) zuweisen?
- Der STATE von Kennlinie bleibt dabei immer "? ? ?". Ich nehme an, das ist normal
- In Fhem werden Kommazahlen offensichtlich im englischen Format (2.9) und nicht im deutschen Format (2,9) akzeptiert. Hab ich was falsch eingestellt, oder ist das so gewollt. Mein Excel akzeptiert das deutsche Format (2,9) als Zahl.
- Nur aus Interesse: Warum heißt es in der raw definition defmod, im config aber trotzdem define?
Zitat von: Ajuba am 01 Februar 2017, 23:21:14
Wie kann ich den OUT Wert nun einer Variable (z.B. dem dummy Temperatur) zuweisen?
Warum möchtest du das tun? Das ist möglich mit readingsProxy, notify oder DOIF, aber dann hättest du den Wert ja doppelt in fhem. Du kannst ja auch einfach das Reading statt OUT temperature nennen.
Zitat von: Ajuba am 01 Februar 2017, 23:21:14
Der STATE von Kennlinie bleibt dabei immer "? ? ?". Ich nehme an, das ist normal
STATE zeigt standardmäßig den Wert vom Readings state. Dies gibt es hier jedoch nicht. Es lässt sich aber über das Attribut stateFormat beeinflussen, sodass dann der Wert von OUT angezeigt wird. Wie das geht steht in der commandref unter readingFnAttributes (https://fhem.de/commandref.html#readingFnAttributes). Beispiele lassen sich finden indem man in der commandref nach stateFormat sucht.
Zitat von: Ajuba am 01 Februar 2017, 23:21:14
In Fhem werden Kommazahlen offensichtlich im englischen Format (2.9) und nicht im deutschen Format (2,9) akzeptiert. Hab ich was falsch eingestellt, oder ist das so gewollt. Mein Excel akzeptiert das deutsche Format (2,9) als Zahl.
Mir ist nicht bekannt, dass man das ändern kann, auch nicht in einer anderen Programmiersprache als perl.
Zitat von: Ajuba am 01 Februar 2017, 23:21:14
Nur aus Interesse: Warum heißt es in der raw definition defmod, im config aber trotzdem define?
wirf mal einen Blick in die commandref (https://fhem.de/commandref.html#define), dort sind beide Befehle erklärt. Auch kannst du mal die Befehle "define Kennlinie dummy" und "defmod Kennlinie dummy" ausführen und gucken was passiert ;)
Hey,
ja ich konnte mein Problem lösen, allerdings nicht in FHEM sondern in Perl.
Es gibt ein Perl-Modul Math::Interpolate (einfach mal googlen).
Darin ist genau das umgesetzt, was ich brauchte und nicht selbst programmieren wollte ;)
Zitat von: der_oBi am 02 Februar 2017, 19:39:03
ja ich konnte mein Problem lösen, allerdings nicht in FHEM sondern in Perl.
Es gibt ein Perl-Modul Math::Interpolate (einfach mal googlen).
Darin ist genau das umgesetzt, was ich brauchte und nicht selbst programmieren wollte ;)
Würdest du auch deine Lösung mitteilen?
Habe ich doch. Die Lösung für mein Interpolationsproblem an sich.
Die individuelle Umsetzung kommt natürlich auf die Problemstellung an. Einfach mal bei cpan nachlesen:
https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjoueWEl_LRAhWE7xQKHVyoB9AQFggcMAA&url=http%3A%2F%2Fsearch.cpan.org%2F~bzajac%2FMath-Interpolate-1.05%2Flib%2FMath%2FInterpolate.pm&usg=AFQjCNGD0O3eWnNuak-YRo_3-e38kNIgew&sig2=4q_AJbqLs2pWccqO_pEWiw (https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjoueWEl_LRAhWE7xQKHVyoB9AQFggcMAA&url=http%3A%2F%2Fsearch.cpan.org%2F~bzajac%2FMath-Interpolate-1.05%2Flib%2FMath%2FInterpolate.pm&usg=AFQjCNGD0O3eWnNuak-YRo_3-e38kNIgew&sig2=4q_AJbqLs2pWccqO_pEWiw)
In meinem speziellen Fall habe ich es so gemacht:
Interpolate braucht jeweils ein Array mit den x-Werten und eines mit den y-Werten. In meiner Sub habe ich die dann aus einem FHEM-Reading ausgelesen. Dort hatte ich die Wertepaare in folgender Form hinterlegt: "x1:y1,x2:y2,x3:y3". Das Ganze eingelesen und mit split() zerlegt und die beiden Arrays (@x und @y) gefüttert.
Dann kann ich meiner Sub einen x-Wert übergeben und diese gibt mir den interpolierten y-Wert zurück.
Also für mich funktioniert die powermap im Prinzip perfekt. Mit stateFormat klappt auch die Anzeige gut.
Nur bei der Berechnung zickt powermap irgendwie.
Ich habe es nun mit meinen echten Readings von der PLC befüllt.
Das Analog-Thermometer geht von +80°C bis -30°C entsprechend liefert der Analogeingang der PLC Werte von 1793 bis 15501.
Somit sieht mein Powermap attribut folgendermaßen aus (ich spare mir hier die Auflistung aller Werte.
{'IN' => {
'1793' => 80,
'1847' => 79,
'1898' => 78,
'1949' => 77,
'2003' => 76,
'2058' => 75,
.....
'15037' => -24,
'15122' => -25,
'15203' => -26,
'15282' => -27,
'15358' => -28,
'15431' => -29,
'15501' => -30,
},
}
NUN ZUM PROBLEM:
Genaue Werte werden perfekt umgesetzt.
ABER die interpolierten Zwischenwerte !!!
Werte unterhalb dem einstelligen positiven Temperaturbereich scheinen auch zu passen.
Aber oberhalb:
Während 1949 perfekt die 77°C ergibt kommt bei 1848 2.11990502572221948°C heraus. Es sind immer einstellige Falsch-Ergebnisse.
Ich blicke nicht dahinter wo das Problem liegt. ???
Zitat von: Ajuba am 02 Februar 2017, 21:53:32
NUN ZUM PROBLEM:
Genaue Werte werden perfekt umgesetzt.
ABER die interpolierten Zwischenwerte !!!
Werte unterhalb dem einstelligen positiven Temperaturbereich scheinen auch zu passen.
Aber oberhalb:
Während 1949 perfekt die 77°C ergibt kommt bei 1848 2.11990502572221948°C heraus. Es sind immer einstellige Falsch-Ergebnisse.
Ich blicke nicht dahinter wo das Problem liegt. ???
Was meinst du mit einstellig Falsche-Ergebnisse?
Das Problem liegt glaube ich im Modul selbst, ich bin nie davon ausgegangen, dass negative bzw. Absteigende Werte berücksichtigt werden müssen.
Sorry, da habe ich mich unklar ausgedrückt. Und sehe gerade, dass ich mich bei einem Wert auch noch vertippt habe.
Ich meinte, dass im Fall einer falschen Interpolations-Berechnung die Zahl vor der Kommastelle einstellig (2.xxx) ist selbst wenn die Lösung im zweistelligen Bereich (55.xxx oder 78.xxx) sein sollte.
Also 1949 ergibt korrekt die 77°C.
Aber 1948 ergibt 2.1199050257222194 °C statt 77.06xxx °C.
Die negativen Werte scheinen für powermap kein Problem darzustellen und die absteigenden Werte grundsätzlich auch nicht.
Die absteigenden Werte könnte ich zur Not auch beheben indem ich das in der PLC invertiere. Nur an den negative Werten kann ich bei der Temperatur naturgemäß nichts ändern wie man aktuell im Freien ja gerade merkt :D.
Also meiner Meinung nach geht es perfekt für alles unter ca. 10°C und darüber fängt es beim Interpolieren zu spinnen an.
Kann es sein, dass es zu viele Werte sind? Gibt es eine Limitierung?
Was kann ich überprüfen oder versuchen um zur Lösung beizutragen?
Wie schon erwähnt: wenn Du sowieso schon in Perl zugange bist, probier einfach mal Math::Interpolate. Da ist mit Sicherheit auch für Dich die richtige Funktion dabei.
Diese Ansätze sind alle grenzwertig. Math::Interpolate beispielsweise bewirkt einen ziemlichen Rechenaufwand.
Es ist viel sinnvoller, sich aus den bekannten Werten mit einem Computeralgebraprogramm (sagen wir Wolfram Alpha) eine interpolierende Funktion zu bauen und diese direkt in Perl umzusetzen.
LG
pah
Also das Problem von Powermap habe ich vermutlich herausgefunden.
Es sind Inputwerte >1000
Wenn die Inputwerte unter 1000 bleiben geht es mit negativen sowie absteigenden Werten korrekt um und weist korrekt die interpolierten Ergebnisse zu (Soweit ich es halt empirisch feststellen konnte).
Für mich wäre in work arround, meinen PLC Input immer durch 20 zu dividieren. Dadurch verliere ich zwar an Auflösung, sollte aber am Ergebnis hoffentlich nichts ändern.
Ich scheitere dabei nur wieder an Fhem Grundlagen.
Kann man diese Division gleich als userReading durchführen?
define Temperatur S7_ARead db 209 20 u32
attr Temperatur IODev PLC
attr Temperatur userReadings Temp { ReadingsVal("Temperatur")/20;; }
Mein jämmerlicher Versuch entsprechend CommandRef bringt folgende Fehlermeldung:
<pre>Error evaluating Temperatur userReading Temp: Not enough arguments for main::ReadingsVal at (eval 2582) line 1, near ""Temperatur")" </pre>
Sehe ich das überhaupt richtig, dass ich den Wert als UserReading unter "Temperatur" gleich dividieren kann und wie macht man das korrekt?
Wenn ja, kann ich dann die PowerMap Aufrufe auch gleich mit einbauen?
Oder muss ich das über Zwischenvariablen machen und wenn ja, wie?
Ich hatte beim ersten Einlesen in Fhem mal was gefunden über rechnen mit Variablen finde es aber leider nicht mehr. :-[
Ich möchte noch darauf hinweisen, dass man das Modul zwar augenscheinlich dafür zweckentfremden kann, diese Spezialfälle aber in der möglichen Weiterentwicklung keine sonderliche Beachtung finden werden und können.
Ein gutes Beispiel ist die Unit Integration. Die Typen der Readings werden bereits als "Wh/Watt pro Stunde" bzw. "W/Watt" deklariert und das Modul arbeitet intern auch bereits damit, es ist lediglich aufgrund der fehlenden Unterstützung in FHEMWEB nicht sichtbar (und es steht in den Sternen, ob wir Rudi davon jemals überzeugen können). Wenn man es also zweckentfremdet, muss man die Einheiten (später) auch entsprechend abändern. Das funktioniert aktuell aber noch nicht unbedingt zuverlässig über das Attribut readingsDesc.
Ich, als Anfänger, folge diesem Weg auch nur weil es anscheinend kein anderes Modul gibt, das Kennlinien einfach ohne externe Tools umsetzen kann .
Soweit dürfte es für mich auch funktionieren.
Nun habe ich endlich auch das Dividieren mit notify geschafft und habe und somit Inputwerte unter 1000 für die Powermap korrekte Ergebnisse liefern sollte.
Leider scheitere ich als nächstes daran, dass meine Kennlinie automatisch bei Wertänderung updated. :-\
Mein Input Wert heisst nun "dum3" und ich habe das ehemalige "IN" durch "dum3" ersetzt.
Schaue ich zum vom PLC Wert errechneten "dum3" werden dort fleissig die PLC Werte errechnet und ändern sich.
ABER bei "Kennlinie" ändert sich absolut nichts
Ich kann (komischerweise) mit "SET Kennlinie dum3" den Eingabe-Wert sogar verändern und Powermap rechnet das Ergebnis korrekt aus.
Hier meine Raw definition
defmod Kennlinie dummy
attr Kennlinie powerMap {'dum3' => {\
'90' => 80,\
'92' => 79,\
'95' => 78,\
.....
'768' => -28,\
'772' => -29,\
'775' => -30,\
},\
}
attr Kennlinie powerMap_noEnergy 1
attr Kennlinie powerMap_rname_P OUT
attr Kennlinie readingList dum3
attr Kennlinie room Wetter
attr Kennlinie setList dum3
attr Kennlinie stateFormat OUT
setstate Kennlinie 0
setstate Kennlinie 2017-02-04 13:30:18 IN 720
setstate Kennlinie 2017-02-05 20:06:12 OUT 0
setstate Kennlinie 2017-02-05 20:06:12 dum3 600
Was fehlt für ein automatisches Update?
Muss ich die Fhem Variable anders nennen (Klammer, Hochkomma, etc.)?
Warte mal das Update von powerMap morgen ab, da ist die Sortierreihenfolge gefixt.
Gruß
Julian
Also wegen mir brauchst du nichts ändern.
Es scheint doch korrekt zu funktionieren. Mein einziges Problem waren Inputs > 1000 und selbst das kann ich durch dividieren lösen.
Oder habe ich da was übersehen?
Momentan frage ich mich wie ich bei Wert Änderungen automatisch berechnete Ergebnisse bekomme. Siehe mein letzter Post. Ist sicher eine absolut dumme Anfängerfrage. Sorry.
Gesendet von meinem SM-G920F mit Tapatalk
Das Modul arbeitetet Event basiert und du hast bei dir das Reading dum3 genannt. Es findet somit nur eine neue Berechnung des Readings mit dem Namen aus powerMap_rname_P statt, wenn dum3 ein Event auslöst.
Wenn du das Reading IN als Eingangswert nutzen willst, musst du das auch entsprechend so definieren.
Das hatte ich mir schon gedacht und schon vorher folgendes ausprobiert
attr Kennlinie event-on-change-reading dum3
Aber obwohl dum3 fröhlich seine Werte ändert tut sich in der Detailansicht gar nichts?
Das muss ich doch bei Kennlinie reinschreiben, oder?
event-on-* muss nicht gesetzt sein. Das schränkt Events ein, es definiert sie nicht explizit.
Die Detailansicht ändert sich nur sofort, wenn du Longpoll in FHEMWEB aktiviert hast. Ansonsten musst du die Seite manuell im Browser neu laden, um geänderte Werte zu sehen.
Browserupdate und Longpoll bringt nichts.
Abgesehen davon sehe ich jede andere Wertänderung auf anderen Devices auch sofort.
Wie löse ich nun das erwähnte Event mit dum3 aus? Muss ich da beim Notify mit reinpacken?
ZitatEs findet somit nur eine neue Berechnung des Readings mit dem Namen aus powerMap_rname_P statt, wenn dum3 ein Event auslöst.
Hier noch mal die aktuelle Config (nur die wesentlichen Teile aller Beteiligten)
Bei Kennlinie lasse ich die mittleren Werte weg und ersetzte sie durch .....
define Powermap powerMap
define Kennlinie dummy
attr Kennlinie powerMap {'dum3' => {\
'90' => 80,\
'92' => 79,\
'95' => 78,\
.....
'768' => -28,\
'772' => -29,\
'775' => -30,\
},\
}
attr Kennlinie powerMap_noEnergy 1
attr Kennlinie powerMap_rname_P OUT
attr Kennlinie readingList dum3
attr Kennlinie room Wetter
attr Kennlinie setList dum3
attr Kennlinie stateFormat OUT
define Temperatur S7_ARead db 209 20 u32
attr Temperatur IODev PLC
attr Temperatur room Wetter
define dum3 dummy
attr dum3 room Dummys
define dumNot notify Temperatur {fhem("set dum3 " . (Value("Temperatur") /20))}
attr dumNot room Dummys
du kannst das powerMap-Attribut auch direkt in deinem Temperatur device setzen, dann brauchst du kein notify und dummy
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.
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);
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.
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.
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
Alternativ kannst du dir auch eine Näherungsfunktion berechnen z.B. hier: http://www.xuru.org/rt/nlr.asp (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...
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.
Hast die Datenreihen dazu noch rumliegen und kannst sie mir schicken?
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
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 (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.
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
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 (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?
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
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
my ($input)=@_;
Danke, Speichern ohne Probleme möglich.
Kannst du mir vielleicht auch meine weiteren Fragen zu userReadings beantworten?
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:
Also ich habe nun versucht einem dummy dum2 ein reading mit dem Namen temperature zuzuweisen und dann noch den userReadings Aufruf dazu.
define dum2 dummy
attr dum2 readingList temperature
attr dum2 room Dummys
attr dum2 userReadings temperature:input {doit(input)}
Aber das war wohl nix
Ich trau mich schon fast nicht mehr zu fragen warum mein userreading nicht geht. :-X :'(
Zitat von: Prof. Dr. Peter Henning am 07 Februar 2017, 15:18:36
und im FHEM-Modul
attr <device> userReadings temperature:input {doit(input)}
Voausgesetzt natürlich, die Ursprungsgröße heißt wirklich "input".
Im Forum hatte ich was gelesen, dass vor einiger Zeit umgestellt wurde und ein .* eingebaut sein müsste um einen Trigger auszulösen. Kann es das sein?
Uns nochmal die Frage:
Muss <device> ein Dummy sein oder kann ich das userReading auch direkt in meinem Device "PLC Eingang" also in meinem Fall "input" anlegen?
Muss ich das reading "temperature" vorher mittels "readingList" erstellen oder nicht?
Da ich damit noch null Erfahrung habe, tappe ich voll im Dunkeln.