DB's nach Strings durchsuchen

Flying Maulwurf

Level-1
Beiträge
6
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

nachdem ich nun schon länger ein fleißiger Leser hier bin, und mich durch viele Themen gelesen habe, die mir sehr geholfen habe, bin ich nun auf ein Problem gestoßen auf dass ich noch keine Antwort gefunden habe.

Habe bei meiner jetzigen Anlage die Aufgabenstellung, dass ich aus 15 DB's mit jeweils 100 STRING[7]'s einen Vergleich durchführen muss mit einem Vergleichsstring, der mir von einer anderen Steuerung vorgegeben wird. Das ganze hat den Sinn, dass ich wenn ich weis in welchem DB der vorgegebene String steht, ich eine entsprechende Programmauswahl treffen kann. Das ganze soll so ablaufen, dass ich den neuen String mit den vorhandenen in den DB's vergleiche, bei positivem Ergebnis rausspringe und dann ein entsprechendes Programm anwähle.

Bin in AWL ziemlich fit, und denke dass ich das mit viel probieren und Zeit auch in AWL hinbekommen würde, jedoch erscheint mir der Aufwand in AWL sehr groß zu werden. Hier würde denke ich SCL ins Spiel kommen, von dem ich aber überhaupt keine Ahnung habe. Wo programmier ich das? In den Quellen? Wenn ja, wie wird dass Aufgerufen? Übersetzt die Step 7 Software dass so, dass es die SPS verarbeiten kann? Fragen über Fragen, bin dankbar für Lösungsansätze. Denke doch, dass man sowas mit String-Vergleichen über mehrerer DB's schonmal gebraucht hat irgendwo.

Ich setzte eine 317-2DP CPU ein, Step 7 Version müsst ich nachschauen falls die auch wichtig ist.

Danke für die tolle Arbeit von euch hier, und für die hoffentlich vielen Antworten :D
 
Hallo,
aus meiner Sicht wäre hier tatsächlich SCL für dich die richtige Wahl.
Der SCL-Compiler erzeugt aus den Pascal-ähnlichen Befehlen einen für die SPS lesbaren Code.
Zu dem Thema "Stringverarbeitung" und "SCL" findest du hier im über die Suche mit Sicherheit unzählige Beiträge, die dich weiterbringen können.
Fragen bitte nicht pauschal sondert konkret stellen.

Du solltest bei deinem "Projekt" allerdings berücksichtigen, dass dieser angedachte Suchdurchlauf ganz ordentlich Zykluszeit verschlingen wird. Hast du das berücksichtigt ?

Gruß
LL
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wo programmier ich das? In den Quellen? Wenn ja, wie wird dass Aufgerufen? Übersetzt die Step 7 Software dass so, dass es die SPS verarbeiten kann?

Ich setzte eine 317-2DP CPU ein, Step 7 Version müsst ich nachschauen falls die auch wichtig ist.

Hallo.
Das Programmierpaket SCL ist beim Step 7 Professional Paket mit dabei (genau wie Graph u. PlcSim). Hast Du nur Step 7 V5.x, dann musst Du vom großen S. eine zusätzliche Software/Lizenz kaufen.
Bei Vorhandensein von SCL wird beim Baustein-Editieren statt KOP, FUP oder AWL einfach SCL angegeben und dann kann es losgehen. Vorher würde ich aber lieber in den Handbüchern schnüffeln, z.B. HIER

Edit: Vielleicht ist ja in der OSCAT-Bibliothek (V3.11?) etwas für Dich dabei. Die ist echt gut, und man muss das Rad meist nicht neu erfinden, wenn es bereits frei verfügbar ist... ;-)

Gruß Approx
 
Zuletzt bearbeitet:
Bei Vorhandensein von SCL wird beim Baustein-Editieren statt KOP, FUP oder AWL einfach SCL angegeben und dann kann es losgehen. Vorher würde ich aber lieber in den Handbüchern schnüffeln, z.B. HIER
Das ist leider nicht ganz so einfach. SCL hat einen eigenen Editor. Um in SCL zu programmieren musst du vorher eine SCL-Quelle anlegen.
 
Das Programmierpaket SCL ist beim Step 7 Professional Paket mit dabei (genau wie Graph u. PlcSim). Hast Du nur Step 7 V5.x, dann musst Du vom großen S. eine zusätzliche Software/Lizenz kaufen.
Ja das habe ich heute auch gemerkt. Haben leider die Version ohne SCL. Werd mich mal schlau machen, habe aber wenig hoffnung dass da eine neue Lizenz erworben wird. So nach dem Motto, das ham mer noch nie gebraucht etc...

Du solltest bei deinem "Projekt" allerdings berücksichtigen, dass dieser angedachte Suchdurchlauf ganz ordentlich Zykluszeit verschlingen wird. Hast du das berücksichtigt ?
Ja daran habe ich auch schon gedacht. Wollte es irgendwie hinbekommen, dass ich pro Zyklus nur einen DB durchsuche.

Fragen bitte nicht pauschal sondert konkret stellen.
Ja ich bemüh mich, suche im Moment eher nach Lösungsansätzen für das Problem, damit ich nicht gleich aufs völlig falsche Pferd setze... Sobald ich mal einen Weg eingeschlagen habe, geh ich dann denk ich mal ins Detail.

Wäre als Lösungsansatz es nicht möglich einen FC zu schreiben, dem ich in jedem Zyklus (natürlich nur wenn ich das möchte) neue Werte - sprich den zu durchsuchenden DB übergebe, zusammen mit einem Vergleichsstring. Der FC würde nur einen Zyklus lang mit dem Suchen eines DB's verbringen, und im nächsten Zyklus würde ich einen neuen DB Wert übergeben, bis der Vergleich irgendwann positiv ist oder alle DB's durchsucht sind und der Vergleich somit negativ wäre. Denke das wäre auch mit AWL drin, sollte das SCL nix werden. Bräuchte natürlich irgendwie einen externen Zähler der mitläuft damit ich weis wann alle DB's durchsucht sind.

Gruß FM
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Bei der Menge an Daten bietet es sich an die Strings in den DBs sortiert vorzuhalten.
Dann kannst du mittels binärer Suche (Teile und Herrsche) deinen String lokalisieren, und würdest damit nur noch log2(15*100) = 11 Iterationen benötigen.

Wenn der zu durchsuchende DB fix ist, also während der Projektierung einmal angelegt wird, ist das recht einfach vorzusortieren. Ansonsten müsstest du einen Sortieralgorithmus in der SPS programmieren, hast dann aber auch wieder das Problem mit der Zykluszeit.
 
Datenstrukturen: Listen und Bäume

Bei der Menge an Daten bietet es sich an die Strings in den DBs sortiert vorzuhalten.
Das Finden eines Strings ist dann in der Tat sehr schnell erledigt, so wie Thomas schon beschreibt.

Damit das Einsortieren von neu hinzukommenden Strings nicht lange dauert, wäre eine doppelt verkettete Liste oder ein
balancierter Binär-Baum das Mittel meiner Wahl.
http://de.wikipedia.org/wiki/Liste_(Datenstruktur)
http://de.wikipedia.org/wiki/Baum_(Graphentheorie)
http://de.wikipedia.org/wiki/Balancierter_Baum

In verketteten Listen und Bäumen können außerdem Strings unterschiedlicher Länge effizienter als in Arrays gespeichert werden.

Für das Programmieren der sehr abstrakten elementaren Daten-Operationen würde ich SCL empfehlen.

Gruß
Harald
 
Zuletzt bearbeitet:
Nachtrag

Die Daten-Operationen dürfen aber nicht rekursiv programmiert werden, man beachte die maximale Baustein-Schachtelungstiefe!
Die 11 bis 15 Iterationen müssen für die S7-CPU leider direkt nacheinander programmiert werden.

Gruß
Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Bei der Menge an Daten bietet es sich an die Strings in den DBs sortiert vorzuhalten.

Was ist damit gemeint? Die DB's werden einmal im Projekt angelegt und sind dann fest. Die Strings in den DB's werden von außen via Ethernet durch einen OPC Server gefüllt bzw. gepflegt. Habe keinen Einfluß auf was da drinnen steht. Nur den Vergleichsstring kenne ich vorher.

Gruß
FM
 
OK, da war ich wohl schon zu müde letzte Nacht. :(

Mein Vorschlag mit der verketteten Liste paßt hier doch nicht so gut.
Da kann man zwar schnell neue Strings sortiert einfügen aber das Finden dauert lange.

Und für den balancierten Binär-Baum lohnt der Aufwand nicht, wenn jeder DB in sich sortiert ist.
100 Strings sind einfach noch zu wenig Daten.

Da würde es sich eher anbieten, zusätzlich zu dem ARRAY[0..99] OF STRING[7] einen Sortier-Index
ARRAY[0..99] OF BYTE einzufügen. Dann braucht nur dieses Index-Array sortiert werden.

Noch eine Idee:
Wenn diese Strings tatsächlich nur Ziffern und keine anderen Zeichen enthalten, dann würde ein
ARRAY[0..99] OF DINT schon mal den Speicherplatzbedarf in den DB um zwei Drittel verringern.
Und die Vergleichsoperation für DINT wäre viel simpler als für STRING.

Die Strings in den DB's werden von außen via Ethernet durch einen OPC Server gefüllt bzw. gepflegt. Habe keinen Einfluß auf was da drinnen steht.
Läßt sich vereinbaren, daß der OPC-Server die Daten in den DB irgendwie sortiert ablegt?
Oder jeden String einzeln an die SPS schickt und die SPS sortiert den in die DB ein?
Wenn nicht, dann ist es wohl doch am besten, das Suchen in den DB auf mehrere Zyklen aufzuteilen.

Gruß
Harald
 
Hallo,
mich würde an dieser Stelle mal interessieren, wie die vielen String-Daten in die SPS kommen / gekommen sind ...

Ein Such- / Sortier-Algorhythmus gleich welcher Art ist mit Sicherheit nicht nicht unbedingt für ein zyklisch arbeitendes Programm geeignet. Auch mit einer superschnellen CPU wirst du hier ganz leicht auf Zykluszeit von mehreren 100 Millisekunden kommen.

Ein PC (z.B. eine Visu) hätte hier allerdings überhaupt keine Probleme Vielleicht mal so als Gedanken-Anstoss ...

Gruß
LL
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Läßt sich vereinbaren, daß der OPC-Server die Daten in den DB irgendwie sortiert ablegt?
Oder jeden String einzeln an die SPS schickt und die SPS sortiert den in die DB ein?
mich würde an dieser Stelle mal interessieren, wie die vielen String-Daten in die SPS kommen / gekommen sind ...
Der OPC Server legt immer den kompletten DB ab, ich muss keine Sortierung vornehmen, nur eine Suche nach einem mir vorgegebenen Referenzstring. Das ganze läuft so ab, dass der OPC wenn er seine Datenbank aktuallisiert hat, er die Daten in die entsprechenden DB's in meiner SPS schickt.
Der Grund ist, dass die Programmauswahl von einer anderen Steuerung angetriggert wird, diese Steuerung kennt aber nur den aktuellen String (Artikelnummer) vom jeweiligen Auftrag. Meine Aufgabe besteht darin diese Artikelnummer in einem DB bei mir zu finden und daraufhin zu entscheiden welches Programm benötigt wird.

Ein PC (z.B. eine Visu) hätte hier allerdings überhaupt keine Probleme Vielleicht mal so als Gedanken-Anstoss ...
Über eine Visu? Setze ein MP277 ein, habe aber keine Idee wie ich über eine Visuallisierung die Auswertung machen könnte.
 
Also ich fasse das jetzt mal zusammen :
Ein OPC-Server ballert dir gemäß einer nach irgendwelchen Kriterien getroffenen Auswahl deine DB's voll.
In einem Bediengerät wird ein Artikel per Name ausgewählt und diesen Namen sollst du dann finden nebst den dahinter stehenden Daten, die du für den Ablauf deiner Anlage brauchst.
Dieses Bediengerät kennt die Daten des OPC-Rechners nicht ...

Wie wäre es, wenn der OPC-Rechner sich die aktuelle Anwahl/Auswahl abholt und den dazugehörenden Index dann zurück liefert ? Das wäre doch dann ein PC, dem es keine Schwierigkeiten bereitet, ein paar 100 Datensätze zu durchsuchen ...

Gruß
LL
 
Ja das wäre sicherlich die für einen Programmierer einfachste Lösung, aber das lässt sich Kundenseitig nicht verwirklichen, trotz mehrfacher Nachfrage, da das EDV "Team" beim Kunden das nicht will.

Die Zusammenfassung ist Richtig, der OPC wird das natürlich nur in meine DB's schreiben wenn sich an der Stammdatenbank was ändert, also nicht laufend. Für mich ist der DB in dem der Datensatz gefunden wird entscheidend, über den weis ich dann, welches Programm ich vorwählen muss...

Thx
FM
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So, habe eine Lösung gefunden, in AWL realisiert und funktioniert. Pro Zyklus durchsuche ich einen DB, was bei 100 Strings ca 10ms dauert...



L #Such_laenge_loop
CON2: T #loop_2

// ANY Pointer zusammenstellen, dessen Adresse in jedem Loop erhöht wird

// 10 für S7
L B#16#10
T LB 0

// Datentyp welcher kopiert werden soll (2=Byte)
L B#16#2
T LB 1

// Wiederholfaktor wieviele Datentypen kopiert werden soll (10=10 Bytes)
L 10
T LW 2

// DB-Nummer aus welchen DB kopiert werden soll
L #Such_DB
T LW 4

// Speicherbereich auswählen (84=DB)
L B#16#84
T LB 6

// Bit Adresse festlegen
L 0
T LB 7

// Byte Adresse festlegen (muss 3 Bits nach links geschoben werden)
L #Byte_Such_Speicher
SLW 3
T LW 8

// den zu suchenden aktuellen String im DB zuweisen (Abhängig vom loop)

CALL "BLKMOV"
SRCBLK :=#Block_IN
RET_VAL:=#fehler
DSTBLK :=#aktueller_Suchstring

// Vergleich beider aktuellen Strings

CALL "EQ_STRNG"
S1 :="DB 180 MDE Daten Belade1".Beladeplatz_1.Artikelnummer
S2 :=#aktueller_Suchstring
RET_VAL:=#Ergebnis

// String gefunden --> Sprung zu TRUE

U #Ergebnis
= #Artikel_gefunden

SPB TRUE

// String nicht gefunden, Anfangsadresse um 10 Byte erhöhen, Suche fortfahren

L #Byte_Such_Speicher
L 10
+I
T #Byte_Such_Speicher

L #loop_2
LOOP CON2

// Loop wurde #Such_laenge_loop x durchlaufen ohne Erfolg

SET
= #Artikel_nicht_gefunden

BEA

TRUE: NOP 0

// String wurde gefunden, BEA und FC verlassen

BEA
 
String suche...

Hab dir hier auch mal die Quelle eines von mir irgendwann mal programmierten stringsuchers in einer struktur, vielleicht kannst ja gebrauchen...

Code:
FUNCTION FC 124 : VOID
TITLE =STD_ANY_SUCHEN
//===================================================
//Technische Daten:
//====================================================
//           Version: 1.00
//             Datum: 25.09.2009
//====================================================
//             Autor: Kühner J.
//Baustein Name Symb: STD_ANY_SUCHEN
//
//====================================================
//Beschreibung:
//
//Such nach einem gegebenen ANY in einem DB.
//
//Dazu kann die Struct größe in der Sich der Any befindet,
//der DB, und die Startadresse eingegeben werden.
//Die Any Länge wird aus den zu suchenden Daten ausgelesen.
//
//Der FC gibt 0 zurück wenn nichts gefunden wurde und >0
//die Nummer des Structes!
//====================================================
VERSION : 0.1


VAR_INPUT
  VERGLEICHS_ANY : ANY ;	//Any zu den Daten die Verglichenwerden sollen (Bsp. der gescannte Barcode)
  DB_VERGLEICH : INT ;	//DB in dem die Daten stehen
  GROESE_STRUCT_VERGLEICH : INT ;	//Größse des zu durchlaufenden Structes
  ANZAHL_VERGLEICH : INT ;	//Anzahl der Struct Elemente
  START_VERGLEICH : INT ;	//Adresse im STruct
END_VAR
VAR_OUTPUT
  ZAEHLER_AUSGABE : INT ;	//Nummer des Datensatzes, 0 = keinen gefunden!
END_VAR
VAR_TEMP
  ANY1 : ANY ;	
  ANY2 : ANY ;	
  ZAEHLER_1 : INT ;	
  ZAEHLER_2 : INT ;	
  RET_VAL_INT : INT ;	
  LAENGE_ANY : INT ;	
  STARTADRESSE_IN_LOKALDAT : INT ;	
  DATEN : ARRAY  [1 .. 100 ] OF BYTE ;	
END_VAR
BEGIN
NETWORK
TITLE =

      L     0; 
      T     #ZAEHLER_AUSGABE; 
      T     #ZAEHLER_1; 

//Startadresse der Temporär in den Lokaldaten abgelegten Daten!
      L     30; 
      T     #STARTADRESSE_IN_LOKALDAT; 

//Vergleichsdaten in Lokaldaten kopieren
//ANY 1 auf Vergleichsdaten nutzen
      L     P##VERGLEICHS_ANY; 
      LAR1  ; 
      L     D [AR1,P#0.0]; 
      T     LD     0; 
      L     D [AR1,P#4.0]; 
      T     LD     4; 
      L     W [AR1,P#8.0]; 
      T     LW     8; 

//ANY 2 auf Lokaldaten befüllen
      L     28; 

      L     W#16#1002; //Typ BYTE
      T     LW    10; 
      L     LW     2; //Anzahl Bytes
      T     LW    12; 
      T     #LAENGE_ANY; 
      L     0; //Quell-DB
      T     LW    14; 
      L     #STARTADRESSE_IN_LOKALDAT; //Startadresse in Lokaldaten
      SLD   3; 
      OD    DW#16#87000000; //87 Vorgänger-Lokaldatenbereich
      T     LD    16; 

      CALL SFC   20 (
           SRCBLK                   := #ANY1,
           RET_VAL                  := #RET_VAL_INT,
           DSTBLK                   := #ANY2);


sl1:  L     #ZAEHLER_1; 
      +     1; 
      T     #ZAEHLER_1; 
      L     #ANZAHL_VERGLEICH; 
      >I    ; 
      BEB   ; 

      L     #ZAEHLER_1; 
      +     -1; 
      L     #GROESE_STRUCT_VERGLEICH; 
      *D    ; 
      L     #START_VERGLEICH; 
      +D    ; 
      SLD   3; 
      LAR1  ; 

      L     #STARTADRESSE_IN_LOKALDAT; 
      SLD   3; 
      LAR2  ; 

      L     0; 
sl2:  T     #ZAEHLER_2; 

      L     DBB [AR1,P#0.0]; 
      L     LB [AR2,P#0.0]; 
      <>I   ; 
      SPB   sl1; //ungleich, weiter springen!

      L     P#1.0; 
      +AR1  ; 
      +AR2  ; 

      L     #LAENGE_ANY; 
      +     -2; 
      L     #ZAEHLER_2; 
      <=I   ; 
      SPB   gl; 

      +     1; 
      SPA   sl2; 

//ergebnis ist gleich
gl:   L     #ZAEHLER_1; 
      T     #ZAEHLER_AUSGABE; 
END_FUNCTION
 
Zurück
Oben