Step 7 DB mit Alarm TOP 10 erstellen

Chromzone

Level-2
Beiträge
15
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich habe einen DB, der für 1600 verschiedene Alarme die Häufigkeit des Auftretens zählt. Mit Hilfe von diesem DB soll eine TOP 10 der häufigsten Alarme erstellt werden. Dazu habe ich einen Code geschrieben, der die 10 größten Zahl im DB findet und nach Größe sortiert in den "DB Zwischenspeicher" schreibt. Nun sollen in einer weiteren Funktion alle Zähler mit den gefundenen 10 höchsten Anzahlen verglichen und die Alarm-Nummern erfasst werden. Diese werden dann in den "DB Fehler TOP10" geschrieben. Würde jeder Alarm eine verschiedene Anzahl besitzen wäre das alles kein Problem. Dann könnte man einfach den "DB Fehleranzahl" nach der jewiligen Anzahl durchsuchen.

Das Problem ist jetzt, dass ich nicht weiß wie ich die Abfrage machen soll, wenn mehrere Alarme die gleiche Anzahl besitzen.


Hier mal der Code für den einfachen Fall, dass alle eine verschiedene Anzahl besitzen würden:
Code:
NW 4:
      L     "DB Zwischenspeicher".NR1
      T     #tInAnzahl
      L     0
      T     #tInAlarmNr

      AUF   DB [#tWoDBAnzahl]
      LAR1  P#0.0
      L     1
      L     #tWoAnzByteInDB
      SRW   1                           // Durch 2 Teilen, um von BYTE zu INT zu wandeln
      >I    
      SPB   END
      T     #tWoAnzWerteImDB            // Anzahl der INT Datensätze im DB
M001: T     #tInCount                   // Schleifenzähler mit Anzahl der Datensätze laden
      L     DBW [AR1,P#0.0]             // Mit Anzahl in Zwischenspeicher Platz 1 vergleichen
      L     #tInAnzahl
      ==I   
      SPBN  WEI1                        // Wenn ungleich, dann überspringen
      L     #tWoAnzWerteImDB            // Hier wird die Alarmnummer aus dem Loopzähler berechnet
      L     1
      +I    
      L     #tInCount
      -I    
      T     #tInAlarmNr
WEI1: NOP   0
      +AR1  P#2.0                       // Adressregister erhöhen für nächsten Durchlauf
      L     #tInCount
      LOOP  M001
      L     #tInAlarmNr                 // Ãœbertragen des gefundenen Fehlers in TOP 10 DB
      T     "DB Fehler TOP10".Nr1.AlarmNR
      L     #tInAnzahl
      T     "DB Fehler TOP10".Nr1.Anzahl

NW 5:
      L     "DB Zwischenspeicher".NR2
      T     #tInAnzahl
      L     0
      T     #tInAlarmNr

      AUF   DB [#tWoDBAnzahl]
      LAR1  P#0.0
      L     1
      L     #tWoAnzByteInDB
      SRW   1                           // Durch 2 Teilen, um von BYTE zu INT zu wandeln
      >I    
      SPB   END
      T     #tWoAnzWerteImDB            // Anzahl der INT Datensätze im DB
M002: T     #tInCount                   // Schleifenzähler mit Anzahl der Datensätze laden
      L     DBW [AR1,P#0.0]
      L     #tInAnzahl
      ==I   
      SPBN  WEI2
      L     #tWoAnzWerteImDB
      L     1
      +I    
      L     #tInCount
      -I    
      T     #tInAlarmNr
WEI2: NOP   0
      +AR1  P#2.0
      L     #tInCount
      LOOP  M002
      L     #tInAlarmNr
      T     "DB Fehler TOP10".Nr2.AlarmNR
      L     #tInAnzahl
      T     "DB Fehler TOP10".Nr2.Anzahl
.
.
.
.
Und so weiter...bis "DB Fehler TOP10".Nr10...

Das soll am Ende dann ugf. so aussehen:
Platz
Alarm-Nr.
Häufigkeit
1
0025
423
2
1456
410
3
0512
398
4
0649
398
5
1232
270
6
0789
269
7
1234
241
8
1599
241
9
0002
223
10
1394
189
 
Wieso erstellst du deinen DB nicht gleich als Array of Struct oder UDT?
Dann könntest du gleich die AlarmNr die Häufigkeit und was sonst noch dazugehört mitsortieren.

als Beispiel in SCL geht aber natürlich in AWL auch nur nicht so komfortabel.
Code:
FUNCTION "Sortieren" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_IN_OUT 
      values_sortet : Array
[*] of Struct
         Menge : DInt;
         ID : Int;
         AlarmID : Int;
         Beschreibung : String[20];
      END_STRUCT;
      Bedienung : Struct
         Sort : Bool;
         Abs : Int;
         Config : HW_IEPORT;
      END_STRUCT;
   END_VAR


   VAR_TEMP 
      index : Int;
      swapped : Bool;
      merker : Struct
         sortierwert : Real;
         ID : Int;
         Fehler : Bool;
         Beschreibung : String[20];
      END_STRUCT;
      Low : DInt;
      High : DInt;
   END_VAR




BEGIN
	#Low := LOWER_BOUND(ARR := #values_sortet, DIM := 1);
	#High := UPPER_BOUND(ARR := #values_sortet, DIM := 1);
	
	IF #Bedienung.Sort THEN
	    #Bedienung.Sort := false;
	    REPEAT
	        #swapped := false;
	        FOR #index := #High TO #Low BY -1 DO
	            IF #values_sortet[#index - 1].Menge > #values_sortet[#index].Menge THEN
	                #merker := #values_sortet[#index];
	                #values_sortet[#index] := #values_sortet[#index - 1];
	                #values_sortet[#index - 1] := #merker;
	                #swapped := true;
	            END_IF;
	        END_FOR;
	    UNTIL NOT #swapped
	    END_REPEAT;
	END_IF;
END_FUNCTION
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo vollmi,

danke für deine Antwort.

Wieso erstellst du deinen DB nicht gleich als Array of Struct oder UDT?
Dann könntest du gleich die AlarmNr die Häufigkeit und was sonst noch dazugehört mitsortieren.

Das wäre grundsätzlich eine Überlegung wert. Allerdings ist der DB schon so vorgegeben. Die TOP 10 Auswertung soll als Ergänzung in ein bestehendes Programm eingefügt werden, daher sollte ich an den Strukturen nichts verändern und AWL verwenden.

Habt ihr eine Idee, wie man es mit den gegebenen Umständen umsetzen könnte?

Danke :)

PS: Falls es wichtig ist...
S7-300 mit CPU 319-3 PN/DP
Step 7 V5.5 SP4
 
Habe es noch hinbekommen.
Zwar recht unschön, aber es funktioniert wie ich es mir vorgestellt habe. Ich habe einen Zähler mit einprogrammiert, der die Einträge in die TOP 10 Liste mit zählt und dem Zählerstand entsprechend über Sprungbefehle an die richtige Stelle im DB schreibt.
Ist zwar jetzt sehr viel Code geworden für eine eigentlich triviale Anwendung, aber es tut was es soll.

Falls irgendjemandem noch eine professionellere Lösung einfällt, bin ich dafür offen.

Ansonsten, viele Grüße
Chrom ;)
 
BestandsAufnahme:

DB-Fehleranzahl mit 1600 Einträgen
- Aus der "PlatzNr" (z.B. DW-Nr) ist die AlarmNr eindeutig rekonstruierbar
- Ein Eintrag enthält nur die Information, wie oft ein Alarm aufgetreten ist
- Dieser DB soll nicht "umorganisiert" werden

DB-Zwischenspeicher

DB-FehlerTOP10
- Dieser DB enthält 10 "Plätze" für Kombinationen aus AlarmNr und FehlerAnzahl

Vorschlag:

DB-Zwischenspeicher abschaffen(!) und in folgender ProgrammSchleife direkt "DB-FehlerTOP10" bearbeiten.

Code:
ProgrammSchleife (liest je Durchlauf einen Eintrag in "DB-Fehleranzahl")
    AlarmNr aus Platz in "DB-Fehleranzahl" berechnen
    gelesenen Eintrag Fehleranzahl mit Fehleranzahl auf Platz 10 von "DB-FehlerTOP10" vergleichen
    -  wenn kleiner, dann weiter bei Weitersuchen
    -  wenn grösser, dann weiter bei Eintragen
    wenn AlarmNr entsprechend Platz in "DB-Fehleranzahl" geringere Priorität hat als AlarmNr auf Platz 10 von "DB-FehlerTOP10", dann weiter bei Weitersuchen
Eintragen:
    auf Platz 10 von "DB-FehlerTOP10" Fehleranzahl UND AlarmNr eintragen (= alten Eintrag auf Platz 10 überschreiben!)
    "DB-FehlerTOP10" sortieren nach absteigender Fehleranzahl, bei gleicher Fehleranzahl nach absteigender Priorität     
Weitersuchen:
    SchleifenEnde (weiter mit nächstem Eintrag in "DB-Fehleranzahl")
Ich habe dabei unterstellt, dass es eine gewisse "PrioritätenRegelung" bei den AlarmNrn gibt.
Könnte mir z.B. vorstellen, dass Alarme mit kleinen Nrn "wichtiger" und Alarme mit hohen Nrn eher für "FolgeFehler" vergeben sind.

Gruss, Heinileini

PS:
Wenn es Dir Sorgen bereitet, eine Tabelle mit 10 Zeilen und 2 Spalten zu sortieren
und Du lieber eine Tabelle mit 10 Zeilen und 1 Spalte sortieren würdest
und die maximale Anzahl Stellen der AlarmNr plus der maximalen Anzahl Stellen der FehlerAnzahl nicht grösser als 9 sein sollte,
dann fass doch die beiden Zahlen zu einer einzigen (DINT) zusammen.
Z.B. AlarmNr 5-stellig und FehlerAnzahl 4-stellig:
x = 100000 * FehlerAnzahl + AlarmNr (wenn grosse AlarmNr höhere Priorität als kleine AlarmNr hat)
oder
x = 100000 * FehlerAnzahl + 100000 - AlarmNr (wenn kleine AlarmNr höhere Priorität als grosse AlarmNr hat)

 
Zuletzt bearbeitet:
Zurück
Oben