Interpolation von Temperaturgerade
-
Hallo zusammen,
ich programmiere im Rahmen eines informationtechnologischen Projektes einen Arduino Uno. Dieser soll erlernen ein kleines Gewächshaus zu betreiben und zu steuern in den Parametern Temperatur und Feuchtigkeit. Da ich jedoch noch am Beginn meines Projektes stehe und der Parameter Temperatur für mich von höherer Bedeutung ist, möchte ich gerne zunächst auf diesen eingehen.
Ich vermute, dass ähnliche Fragen immer wieder hier auftauchen. Ich habe auch schon ähnliche Fragen bei der guten alten Googlerecherche gefunden, jedoch ist keine Antwort auf diese Fragen eine Problemlösung für mich.
Mein Grundkonzept steht. Der Arduino ist in der Lage für jeden Tag im Jahr einen maximalen Temperaturwert und einen minimalen Temperaturwert zwischen zwei von mir gesetzte Grenzen zu generieren. Der nächste Schritt wäre es, dem Arduino beizubringen, mittels dieser max. Werten und min. Werten (für immer jeweils einen Tag im Jahr) einen Temperaturtagesverlauf abzubilden. Hierfür wird zunächst angenommen, dass:
- die Temperatur lediglich vom Sonnenverlauf abhängig ist
- der Sonnverlauf (Sonnenaufgang/Sonnenhochpunkt/Sonnenuntergang) für jeden Tag gleich ist
- der min. Wert kurz nach Sonnenaufgang erreicht wird (z.B. um 06:20)
- der max. Wert kurz nach Sonnenhochpunt erreicht wird (z.B. um 14:20)
Das entspricht natürlich keineswegs der Realität, ist aber nicht weiter schlimm für das Projekt. Sollte das Konzept stehen, kann man immer noch nachträglich einen variierenden Sonnenverlauf implementieren (somit würde nur noch Annahme 1 zutreffen und 2,3,4 weg fallen)
Ist nicht so, dass ich es selber nicht versucht habe ... habe mich auch schon auf anderen Plattformen informiert ... der Quelltext ist demnach auch nicht komplett von mir (kann dennoch voll nachvollziehen was geschieht und warum es geschieht), trotzdem hänge ich nun schon seit mehr als 3 Tagen a 8-10 Stunden an dieser Interpolation ... zunächst nahm ich noch an, dass der Temperaturverlauf einer Funktion höheren Grades entspricht. Das war mir dann jedoch noch deutlich komplizierter zu realisieren O.o
Also hier mal mein Code:
int climateTemps[12][2]={ {140, 220}, {145, 230}, {150, 235}, {150, 240}, {155, 250}, {160, 270}, {165, 280}, {160, 285}, {160, 275}, {155, 265}, {155, 250}, {150, 235}, }; int aktTemp; void setup() { Serial.begin(9600); } void loop() { unsigned int year= scatter(); while (year<1583) year+=100; calculateYear(year); //zu calculateMonth(Month) } int scatter() { int year=2017; randomSeed(year); return year; } void calculateYear(int year) //kann weg wenn RTC da { for (int month=1; month<=12; month++) { for (int day=1; day<=daysInMonth(year,month); day++) { calculateDay(year, month, day); //direkt übergabe der Parameter von RTC } } } byte daysInMonth(int year, byte month) //generiert Taganzahl für unterschiedliche Monate { if (month == 4 || month == 6 || month == 9 || month == 11) return 30; else if (month == 2) { byte isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); if (isLeapYear) return 29; else return 28; } else return 31; } void calculateDay(int year, int month, int day) { int lastday; int climateAvg= (climateTemps[month-1][0]+climateTemps[month-1][1])/2; int dailyAvg= climateAvg+ random(-20,20); int grenzeMax= (climateTemps[month-1][1]+dailyAvg)/2; int grenzeMin= (dailyAvg+climateTemps[month-1][0])/2; int dailyHigh= random(grenzeMax,climateTemps[month-1][1]); int dailyLow= random(climateTemps[month-1][0],grenzeMin); Serial.println("Bitte Minute seit Mitternacht eingeben"); //Uhr while(Serial.available()==0); //Uhr int Minute=Serial.parseInt(); //Uhr if (Minute>0 && Minute<380) interpolator1(dailyHigh, dailyLow, Minute); else if (Minute>=380 && Minute<860) interpolator2(dailyHigh, dailyLow, Minute); else if (Minute>=860 && Minute<1440) interpolator3(dailyHigh, dailyLow, Minute); else Serial.println("Ungueltiger Minutenwert"); Serial.print(dailyHigh*0.1); Serial.print("Max"); Serial.print(dailyLow*0.1); Serial.print("Min"); Serial.print(aktTemp); Serial.println("Akt"); // lastday=dailyLow+((dailyHigh-dailyLow)/3); } void interpolator1(int Max, int Min, int Minute) { //von 00:00 bis 06:20 (380 Minuten) int x=960; int x1=0; int x2=380; aktTemp= Min-((Minute-x1)/(x2-x1)*(Max-Min)); // double m= (Max-Min)/x; // aktTemp= Min-m*Minute; } void interpolator2(int Max, int Min, int Minute) { //von 06:20 bis 14:20 (480 Minuten) int x=480; double m= (Max-Min)/x; aktTemp= Min+m*(Minute-480); } void interpolator3(int Max, int Min, int Minute) { //von 14:20 bis 24:00 (580 Minuten) int x=960; double m= (Max-Min)/x; aktTemp= Max-m*(Minute-860); }interpolator 1 bis 3 sollten dabei meine Funktionen zum interpolieren sein. Wobei die:
1 Funktion für den Temperaturverlauf von Mitternacht bis Sonnenaufgang zuständig ist
2 Funktion für den Temperaturverlauf von Sonnenaufgang bis Sonnenhochpunkt zuständig ist
3 Funktion für den Temperaturverlauf von Sonnenhochpunkt bis Mitternacht zuständig istSollte Bildlich dann ne Zickzackgraphen ergeben.
Naja es läuft leider nicht .... daher hier mein Appell an euch. Kann mir jemand sagen, wie ich am besten weiter vorgehen sollte? Konstruktive Kritik ist sowieso erwünscht
Konstruktive Vorschläge zur Problemlösung aber genau so ^^
-
Edit:
Was natürlich auch bisher vollkommen unberücksichtigt in meine Code ist, wäre, dass beim Interpolieren der ersten und dritten Funktion (also Mitternacht bis Sonnenaufgang und Sonnenhochpunkt bis Mitternacht) jeweils eine Stützstelle falsch ist.
Für die Gerade im Zeitraum Mitternacht und Sonnenaufgang benötigt man rein theoretisch ja den Max. Wert des vorherigen Tages. So auch für den Zeitraum zwischen Sonnenhochpunkt und Mitternacht. Hierfür müsste man wissen, wie der Min. Wert des kommenden Tages ist.
Da ich keine Werte über vorherige oder kommende Tage zwischenspeicher, ist das nicht leicht zu programmieren ....
Mein erstes Entwurf des Codes speicherte auch alle Werte für jeden Tag, doch da hat der RAM des Arduinos leider nicht mitgemacht. Way 2 much values undso ...Ach wär ich doch ein IT-Crack und könnte das mal eben so programmieren

-
Hallo,
bin mir nicht sicher ob ich deine Aufgabenstellung korrekt verstanden habe.
Du willst also durch dein Programm einen Temperaturwert berechnen, abhängig von Tageszeit und Datum.
Also Temp=f(Zeit, Datum).
Ist das soweit mal korrekt?Meine naive Vorstellung bzgl. Gewächshaus wäre jetzt mal, dass es den Pflanzen relativ egal ist ob du nun exakt die richtige Kurve abfährst - Hauptsache Min/Max sowie Mittelwert passen halbwegs, sodass man die entsprechenden Reize setzt.
D.h.: keep it simple! Für natürliche Vorgänge bietet sich ja die Sinusfunktion geradezu an.
1. Der Tagesmittelwert ist eine Sinusfunktion über den Jahrestag (0 [1. Jänner] ... 364 [31. Dezember]). Er schwankt um sagen wir mal 10°C um den Mittelwert von 10°C (fiktive Werte!!!).
Also hast du folgende Funktion: Tagesmittel=10-10*cos(2pi*Tag/364)
Damit hast du am 1. Jänner (Tag=0) 10-10*1=0°C. Danach wird es entsprechend wärmer, mit dem Maximum im Juli und dann gehts wieder bergab.2. Je Tag schwankt die Temperatur dann nochmal um den Mittelwert (der unter 1. berechnet wurde). Entsprechend kannst du zum Mittelwert einen Wert dazurechnen, der in dem Fall wieder von der Tageszeit anhängt, also AktuelleTemperatur=Tagesmittel+Tageshub*sin(...)
-
Du willst also durch dein Programm einen Temperaturwert berechnen, abhängig von Tageszeit und Datum.
Also Temp=f(Zeit, Datum).
Ist das soweit mal korrekt?Mehr oder weniger. Genauer würde es heißen f(Uhrzeit)=SollTemperatur
Die Funktion soll in Abhängigkeit von TempMax des Tages und TempMin des Tages eine Verlauf SollTemperaturverlauf beschreiben (Quasi aus den Extremas dessen Zeitpunkt (x-Wert) bekannt sind). Dann soll durch ablesen der Uhrzeit über eine RTC (leider noch nicht eingebaut) eine SollTemperatur bestimmt werden. Diese wird dann mit einem gemessenem Wert verglischen aber darum sorg ich mich jetzt noch nicht ^^ Wichtig ist zunächst die SollTemperatur. Im Code heißt diese übrigends aktTemp (für aktuelle Temperatur)
-
D.h.: keep it simple! Für natürliche Vorgänge bietet sich ja die Sinusfunktion geradezu an.
Das ist auch mein Motto
aber den Temperaturverlauf über eine Sinusfunktion zu beschreiben, wäre mir dann doch zu ungenau.Vorallem
Damit hast du am 1. Jänner (Tag=0) 10-10*1=0°C. Danach wird es entsprechend wärmer, mit dem Maximum im Juli und dann gehts wieder bergab.
wäre mir das viel zu sehr ungenau. Das würde ja bedeuten, dass z.b. in den ersten Tagen des Jahres die Temperatur nur ansteigt und ansteigt bis sie zum extrama kommt, wo sie dann einige Tage erst einmal absinkt und absinkt. Mhm vielleicht hab ich es auch falsch verstanden. Wenn man die Periode der schwingung auf einen Tag reduzieren würde, ergäb das wieder für mich Sinn. Trotzdem immernoch etwas ungenauer als ich es gerne hätte ^^
-
Oh_Ce schrieb:
wäre mir das viel zu sehr ungenau. Das würde ja bedeuten, dass z.b. in den ersten Tagen des Jahres die Temperatur nur ansteigt und ansteigt bis sie zum extrama kommt, wo sie dann einige Tage erst einmal absinkt und absinkt. Mhm vielleicht hab ich es auch falsch verstanden. Wenn man die Periode der schwingung auf einen Tag reduzieren würde, ergäb das wieder für mich Sinn. Trotzdem immernoch etwas ungenauer als ich es gerne hätte ^^
lies nochmal genau.
Du hast sowohl eine langfristige Schwingung (übers Jahr) sowie eine überlagerte, kurzfristige Schwingung (über den Tag), also grob gesagt: sin(Tag des Jahres)+sin(Stunde des Tages)Hab mal kurz bei Google diese Verläufe angeschaut. Klar - handelt sich nicht um exakte Sinuskurven, aber grob annähern kann man sie schon.
Andernfalls halt ein paar Sinus Schwingungen überlagern ... Stichwort Fourier Reihe.
-
Leider immernoch keine Fortschritte machen können ... und mein Prof treffe ich leider erst frühestens morgen irgendwann

-
Oh_Ce schrieb:
Leider immernoch keine Fortschritte machen können ... und mein Prof treffe ich leider erst frühestens morgen irgendwann

Was ist denn überhaupt genau deine Frage? Aus dem Eingangsbeitrag lese ich nur "es läuft leider nicht" heraus, was keine brauchbare Problembeschreibung ist.
Ich hätte das ganze Problem ja von vornherein ganz anders aufgezogen, mittels einer Differentialgleichung anstelle von Interpolationsfunktionen und einer anschließenden Lösung mittels Zeitdiskretisierung (Klingt schlimmer als es ist. Ist eigentlich ganz intuitiv). Aber das Projekt innerhalb eines Tages komplett neu zu programmieren ist wohl ein bisschen ambitioniert.
-
Ich hätte das ganze Problem ja von vornherein ganz anders aufgezogen, mittels einer Differentialgleichung anstelle von Interpolationsfunktionen und einer anschließenden Lösung mittels Zeitdiskretisierung (Klingt schlimmer als es ist. Ist eigentlich ganz intuitiv). Aber das Projekt innerhalb eines Tages komplett neu zu programmieren ist wohl ein bisschen ambitioniert.
So in der Art wollte ich zu Beginn die Sache auch in etwa angehen. Ich dachte ich bring dem Arduino bei, Gleichungen zu lösen und so eine mathematische Funktion aufzustellen, die den Temperaturverlauf eines Tages beschreibt. Das wäre auch mitunter die genauste Lösung meines Problems. Da ich jedoch merkte, dass ich damit noch viel weniger zurecht komme, dachte ich, bring ich dem Arduino bei zu interpolieren. Sollte für ihn deutlich weniger zu rechnen sein.
Konkret brauch ich eine Funktion, die in der Lage ist aus einem Punkt (x1,y1) und einem weiteren Punkt (x2,y2) einen dirrten Punkt zu ermitteln (wobei x3 bereits bekannt ist und lediglich y3 gesucht ist). Typisches Interpolieren. Mathematisch auf Papier bekomm ich das ja hin, nur fehlt mir die Programmierererfahrung um dafür den Code zu tippen.
-
Allgemein für die Interpolation gilt z.B.:
int interpoliere( int x1, int y1, int x2, int y2, int x ) { typedef double Float; // ggf. statt double float wählen, falls Arduiono oder Oh_Ce kein double kennt return int(y1 + (y2-y1) * Float(x-x1)/(x2-x1) + Float(0.5)); // einigermaßen richtig runden }und in Deinem Fall liegen einige Stützstellen am Vortag bzw. am nächsten Tag
int tm_min = 6 * 60 + 20; // 6:20 Zeit des Temperaturminimums int tm_max = 14 * 60 + 20; // 14:20 Zeit des Temperaturmaximums int tm_tag = 24 * 60; // int Minute = 12; int aktTemp; // Variablen lokal definieren if (Minute > 0 && Minute < tm_min) aktTemp = interpoliere (tm_max-tm_tag, dailyHigh, tm_min, dailyLow, Minute); // x1,y1 war gestern else if (Minute < tm_max) aktTemp = interpoliere (tm_min, dailyLow, tm_max, dailyHigh, Minute); else if (Minute < tm_tag) aktTemp = interpoliere (tm_max, dailyHigh, tm_min+tm_tag, dailyLow, Minute); // x2,y2 ist erst morgen else ...; // Minute out of range