Ankündigung

Einklappen
Keine Ankündigung bisher.

Ein Lernmakro für verschiedene Anwendungen

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    [Codebeispiel] Ein Lernmakro für verschiedene Anwendungen

    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]
    • 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

    #2
    Zitat von pernozzoli Beitrag anzeigen
    Anregungen und Ideen sind willkommen!
    Schade, dass der Wettbewerb schon vorbei ist
    Ohne das genauer getestet zu haben, kann ich da nur zustimmen. Hört sich interessant an. Vielleicht wäre es gut, das auch mal in Codeschnipsel reinstellen?
    offizielles Supportforum für den Enertex® EibPC: https://knx-user-forum.de/eibpc/
    Enertex Produkte kaufen

    Kommentar


      #3
      Zitat von pernozzoli Beitrag anzeigen
      Speichern des Lernvektors, z.B. im Remanentspeicher: wie oft verträgt das der eibPC, bevor sich die Hardware verabschiedet (Täglich, Wochenweise?)
      Täglich wäre wohl schon ok. Die Flashspeicher können einige zigtausend Zyklen, wobei alles zusammen (Garbagecollection,Blockoperationen etc.) zählt. Immerhin kann das Dateisystem defekte Blöcke aus dem Verkehr ziehen und verschieben, das heisst einige Jahre sind da sicher drinne,va. weil die 512 MB derzeit ziemlich leer sind (ich weiss, jetzt werden schon die Münder wässrig...)
      offizielles Supportforum für den Enertex® EibPC: https://knx-user-forum.de/eibpc/
      Enertex Produkte kaufen

      Kommentar

      Lädt...
      X