Hallo,
aus dem Experimentierkasten, ein "lernfähiges" Makro zum zeitabhängigen Schalten:
Ausgangslage:
Für die "intelligente" Schaltung einer Zirkulationspumpe soll der eibPC das Verhalten der Hausbewohner lernen und speichern. Der eibPC soll an Hand des gelernten Verhaltens die Zirkulationspumpe vorausschauend für eine definierte Zeit einschalten.
Lösung:
Ein generisches Makro, dass das Verhalten über eine parametrierbare Eingangsvariable erlernt und vorausschauend und abhängig von der Schalthäufigkeit der Eingangsvariablen eine definierte Ausgangsvariable einschaltet.
Der Tag wird in festen Zeitscheiben eingeteilt. Innerhalb der Zeitscheibe prüft das Makro, ob die Eingangsvariable geschaltet wurde und erhöht in diesem Fall den Zähler für diese Zeitscheibe. Ansonsten wird der Zähler erniedrigt.
Überschreitet die Schalthäufigkeit der aktuellen Zeitscheibe (vorausschauend um eine angegebene Anzahl von Takten) den Mittelwert aller Schalthäufigkeiten des Tages um einen definierbaren Prozentanteil, so wird die Ausgangsvariable geschaltet.
Zur Unterscheidung, beispielsweise zwischen Wochenenden und Arbeitstagen, kann eine Modusvariable aus dem Hauptprogramm heraus gesetzt werden.
Und hier das Makro:
[highlight=epc]
:begin Lernzyklus(Name, Modus, ModusNext, Vorausschau, AnzahlModi, Periode, Schaltschwelle, Lernvariable, Schaltvariable, Schaltzeit, Schaltfreigabe)
:info $Innerhalb der durch "Periode" definierten Zeitabschnitte erfasst dieses Makro den Zustand \\
einer Lernvariablen und schaltet eine definierbare Variable abhängig vom gelernten Zustand $\\
$Name für das Lernmakro$ \\
$Mit Hilfe der Modusvariable kann das Verhalten beispielsweise an Werk- und Wochenend- oder \\
gesteuert werden, der Modus muss über Ihr eigenes eibPC Programm gesetzt werden. $ \\
$Modus des nächsten Tages-Zyklus, wichtig für die vorausschauende Schaltung. $ \\
$Vorausschauendes Schalten um die hier angegebene Anzahl von Takten. $ \\
$Definiert die Anzahl verschiedener Modi$ \\
$Periode / Erfassungsabschnitt in 5 Minuten Takte$ \\
$Der Algorithmus schaltet nach Überschreitung des Mittelwerts des Lernvektors um den hier angegebenen Anteil in Prozent (u32)$ \\
$Variable, die den zu lernenden Zustand beinhaltet (0b01) $ \\
$Zu schaltende Variable (0b01), muss sich von der Lernvariable unterscheiden $ \\
$Zeit, nach der die Variable wieder ausgeschaltet wird $ \\
$Variable für die Schaltfreigabe $
:shortinfo $Lernalgorithmus$
Name_Signal = AUS
Name_Vector = $$
// erste vier Bytes im Vektor beinhalten die Vektorsumme für die Durchschnittsberechnung
Name_Offset = 4u16 * AnzahlModi
Name_Mean = 0u32
Name_Sum = 0u32
Name_Clock = 5u16
Name_Index = Name_Offset + (convert(hour(),0u16)*60u16 + convert(minute(),0u16))/Name_Clock/Periode+288u16/Periode*Modus
// Beginne immer mit vollem Takt zu zählen
Name_Minutes = mod(convert(minute(),0u16),Name_Clock*Periode)
Name_Value = 0u08
// Minutenzähler
if stime(0) then Name_Minutes = Name_Minutes + 1u16 endif
if (Name_Minutes == (Periode*Name_Clock)) then {
Name_Minutes = 0u16;
if (Name_Signal) then {
Name_Value = stringcast(Name_Vector,0u08,Name_Index);
if (Name_Value < 255u08) then {
stringset(Name_Vector, Name_Value + 1u08,Name_Index);
Name_Sum = stringcast(Name_Vector,0u32,Modus*4u16);
if (Name_Sum < 4294967295u32) then stringset(Name_Vector,Name_Sum + 1u32,Modus*4u16) endif
} endif;
Name_Signal = AUS
}
else {
Name_Value = stringcast(Name_Vector,0u08,Name_Index);
if (Name_Value > 0u08) then {
stringset(Name_Vector, Name_Value - 1u08,Name_Index);
Name_Sum = stringcast(Name_Vector,0u32,Modus*4u16);
if (Name_Sum > 0u32) then stringset(Name_Vector,Name_Sum - 1u32,Modus*4u16) endif
} endif
} endif;
Name_Index = (convert(hour(),0u16)*60u16 + convert(minute(),0u16))/Name_Clock/Periode + Vorausschau;
if (Name_Index < (288u16/Periode)) then {
Name_Index = Name_Offset + mod(Name_Index, 288u16/Periode) + 288u16/Periode*Modus;
Name_Mean = stringcast(Name_Vector,0u32,Modus*4u16) / convert((288u16 / Periode),0u32)
}
else {
Name_Index = Name_Offset + mod(Name_Index, 288u16/Periode) + 288u16/Periode*ModusNext;
Name_Mean = stringcast(Name_Vector,0u32,ModusNext*4u16) / convert((288u16 / Periode),0u32)
} endif;
Name_Mean = Name_Mean + (Name_Mean * Schaltschwelle / 100u32);
if Schaltfreigabe and (stringcast(Name_Vector,0u08,Name_Index) >= convert(Name_Mean,0u08)) then Schaltvariable = EIN endif;
Name_Index = Name_Offset + (convert(hour(),0u16)*60u16 + convert(minute(),0u16))/Name_Clock/Periode + 288u16/Periode*Modus
} endif
// Signalvariable setzen
if (Lernvariable) then Name_Signal = EIN; Lernvariable=AUS endif
// Nach Schaltzeit wieder abschalten
if after(Schaltvariable,Schaltzeit) then Schaltvariable = AUS endif
:end
[/highlight]
Aufrufbeispiel:
[highlight=epc]
Lernzyklus(Zirkulation,Zirkulation_Modus,Zirkulati on_ModusNext,1u16,2u16,3u16,10u32,Zirkulation_Anfo rderung,Zirkulation_Schalten,600000u64,Zirkulation _Freigabe)
[/highlight]
Beispiel für Setzen des Modus:
[highlight=epc]
if (dayofweek() == SAMSTAG) or (dayofweek() == FREITAG) or (Feiertag > 1u08) then Zirkulation_ModusNext = 1u16 else Zirkulation_ModusNext = 0u16 endif
if (dayofweek() == SONNTAG) or (dayofweek() == SAMSTAG) or (Feiertag > 0u08) then Zirkulation_Modus = 1u16 else Zirkulation_Modus = 0u16 endif
[/highlight]
Noch offen:
Anregungen und Ideen sind willkommen!
Schade, dass der Wettbewerb schon vorbei ist
Gruss
Arno
aus dem Experimentierkasten, ein "lernfähiges" Makro zum zeitabhängigen Schalten:
Ausgangslage:
Für die "intelligente" Schaltung einer Zirkulationspumpe soll der eibPC das Verhalten der Hausbewohner lernen und speichern. Der eibPC soll an Hand des gelernten Verhaltens die Zirkulationspumpe vorausschauend für eine definierte Zeit einschalten.
Lösung:
Ein generisches Makro, dass das Verhalten über eine parametrierbare Eingangsvariable erlernt und vorausschauend und abhängig von der Schalthäufigkeit der Eingangsvariablen eine definierte Ausgangsvariable einschaltet.
Der Tag wird in festen Zeitscheiben eingeteilt. Innerhalb der Zeitscheibe prüft das Makro, ob die Eingangsvariable geschaltet wurde und erhöht in diesem Fall den Zähler für diese Zeitscheibe. Ansonsten wird der Zähler erniedrigt.
Überschreitet die Schalthäufigkeit der aktuellen Zeitscheibe (vorausschauend um eine angegebene Anzahl von Takten) den Mittelwert aller Schalthäufigkeiten des Tages um einen definierbaren Prozentanteil, so wird die Ausgangsvariable geschaltet.
Zur Unterscheidung, beispielsweise zwischen Wochenenden und Arbeitstagen, kann eine Modusvariable aus dem Hauptprogramm heraus gesetzt werden.
Und hier das Makro:
[highlight=epc]
:begin Lernzyklus(Name, Modus, ModusNext, Vorausschau, AnzahlModi, Periode, Schaltschwelle, Lernvariable, Schaltvariable, Schaltzeit, Schaltfreigabe)
:info $Innerhalb der durch "Periode" definierten Zeitabschnitte erfasst dieses Makro den Zustand \\
einer Lernvariablen und schaltet eine definierbare Variable abhängig vom gelernten Zustand $\\
$Name für das Lernmakro$ \\
$Mit Hilfe der Modusvariable kann das Verhalten beispielsweise an Werk- und Wochenend- oder \\
gesteuert werden, der Modus muss über Ihr eigenes eibPC Programm gesetzt werden. $ \\
$Modus des nächsten Tages-Zyklus, wichtig für die vorausschauende Schaltung. $ \\
$Vorausschauendes Schalten um die hier angegebene Anzahl von Takten. $ \\
$Definiert die Anzahl verschiedener Modi$ \\
$Periode / Erfassungsabschnitt in 5 Minuten Takte$ \\
$Der Algorithmus schaltet nach Überschreitung des Mittelwerts des Lernvektors um den hier angegebenen Anteil in Prozent (u32)$ \\
$Variable, die den zu lernenden Zustand beinhaltet (0b01) $ \\
$Zu schaltende Variable (0b01), muss sich von der Lernvariable unterscheiden $ \\
$Zeit, nach der die Variable wieder ausgeschaltet wird $ \\
$Variable für die Schaltfreigabe $
:shortinfo $Lernalgorithmus$
Name_Signal = AUS
Name_Vector = $$
// erste vier Bytes im Vektor beinhalten die Vektorsumme für die Durchschnittsberechnung
Name_Offset = 4u16 * AnzahlModi
Name_Mean = 0u32
Name_Sum = 0u32
Name_Clock = 5u16
Name_Index = Name_Offset + (convert(hour(),0u16)*60u16 + convert(minute(),0u16))/Name_Clock/Periode+288u16/Periode*Modus
// Beginne immer mit vollem Takt zu zählen
Name_Minutes = mod(convert(minute(),0u16),Name_Clock*Periode)
Name_Value = 0u08
// Minutenzähler
if stime(0) then Name_Minutes = Name_Minutes + 1u16 endif
if (Name_Minutes == (Periode*Name_Clock)) then {
Name_Minutes = 0u16;
if (Name_Signal) then {
Name_Value = stringcast(Name_Vector,0u08,Name_Index);
if (Name_Value < 255u08) then {
stringset(Name_Vector, Name_Value + 1u08,Name_Index);
Name_Sum = stringcast(Name_Vector,0u32,Modus*4u16);
if (Name_Sum < 4294967295u32) then stringset(Name_Vector,Name_Sum + 1u32,Modus*4u16) endif
} endif;
Name_Signal = AUS
}
else {
Name_Value = stringcast(Name_Vector,0u08,Name_Index);
if (Name_Value > 0u08) then {
stringset(Name_Vector, Name_Value - 1u08,Name_Index);
Name_Sum = stringcast(Name_Vector,0u32,Modus*4u16);
if (Name_Sum > 0u32) then stringset(Name_Vector,Name_Sum - 1u32,Modus*4u16) endif
} endif
} endif;
Name_Index = (convert(hour(),0u16)*60u16 + convert(minute(),0u16))/Name_Clock/Periode + Vorausschau;
if (Name_Index < (288u16/Periode)) then {
Name_Index = Name_Offset + mod(Name_Index, 288u16/Periode) + 288u16/Periode*Modus;
Name_Mean = stringcast(Name_Vector,0u32,Modus*4u16) / convert((288u16 / Periode),0u32)
}
else {
Name_Index = Name_Offset + mod(Name_Index, 288u16/Periode) + 288u16/Periode*ModusNext;
Name_Mean = stringcast(Name_Vector,0u32,ModusNext*4u16) / convert((288u16 / Periode),0u32)
} endif;
Name_Mean = Name_Mean + (Name_Mean * Schaltschwelle / 100u32);
if Schaltfreigabe and (stringcast(Name_Vector,0u08,Name_Index) >= convert(Name_Mean,0u08)) then Schaltvariable = EIN endif;
Name_Index = Name_Offset + (convert(hour(),0u16)*60u16 + convert(minute(),0u16))/Name_Clock/Periode + 288u16/Periode*Modus
} endif
// Signalvariable setzen
if (Lernvariable) then Name_Signal = EIN; Lernvariable=AUS endif
// Nach Schaltzeit wieder abschalten
if after(Schaltvariable,Schaltzeit) then Schaltvariable = AUS endif
:end
[/highlight]
Aufrufbeispiel:
[highlight=epc]
Lernzyklus(Zirkulation,Zirkulation_Modus,Zirkulati on_ModusNext,1u16,2u16,3u16,10u32,Zirkulation_Anfo rderung,Zirkulation_Schalten,600000u64,Zirkulation _Freigabe)
[/highlight]
- Name des Objekts: Zirkulation
- Modus für Wochenende / Arbeitstag: Zirkulation_Modus
- Modus für den nächsten Tag: Zirkulation_ModusNext
- Vorausschauend schalten: 1 Takt
- Gesamtanzahl Modi: 2 (Wochenende/Feiertag, Arbeitstag)
- Taktlänge: 15 Minuten (3 x 5 Minuten)
- Schwelle: 10% über Mittelwert
- Eingangsvariable: Zirkulation_Anforderung (im Hauptprogramm zu setzen)
- Ausgangsvariable: Zirkulation_Schalten (im Hauptprogramm zu interpretieren)
- Ausschalten der Ausgangsvariablen nach: 10min (Angabe in ms)
- Generelle Freigabe: Zirkulation_Freigabe
Beispiel für Setzen des Modus:
[highlight=epc]
if (dayofweek() == SAMSTAG) or (dayofweek() == FREITAG) or (Feiertag > 1u08) then Zirkulation_ModusNext = 1u16 else Zirkulation_ModusNext = 0u16 endif
if (dayofweek() == SONNTAG) or (dayofweek() == SAMSTAG) or (Feiertag > 0u08) then Zirkulation_Modus = 1u16 else Zirkulation_Modus = 0u16 endif
[/highlight]
Noch offen:
- Vorbelegung des Lernvektors, z.B. alle 30 min Vorbelegung der Zelle mit dem Wert 50.
- Speichern des Lernvektors, z.B. im Remanentspeicher: wie oft verträgt das der eibPC, bevor sich die Hardware verabschiedet (Täglich, Wochenweise?)
Anregungen und Ideen sind willkommen!
Schade, dass der Wettbewerb schon vorbei ist

Gruss
Arno
Kommentar