# Probleme mit Zykluszeit



## Steve81 (8 Dezember 2007)

Hallo,

habe folgende Aufgabe zu lösen:

Ich hab 20 Einzelwerte (REAL) und einen Sollwert (REAL).
Der Sollwert ergibt sich im Normalfall aus einer beliebigen kombination mehrerer Einzelwerte.
Ich soll immer nach der Kombination suchen, die am nähsten über dem Sollwert liegt oder genau den Sollwert ergibt.
Aus wieviel Einzelwerten sich dann der Ermittelte ideale Wert zusammensetzt ist egal.

Einen Baustein der mir das macht habe ich bereits mit SCL geschrieben (allerdings mit nur 10 Einzelwerten) und er funktioniert auch einwandfrei.

Mein eigentliches Problem:

Bei 20 Einzelwerten habe ich 2^20 - 1 Kombinationsmöglichkeiten.
Das ergibt doch sehr wahrscheinlich eine extrem hohe Zykluszeit.

Was für eine CPU eingesetzt werden soll weiß ich noch nicht (aber irgendeine von Siemens oder evtl. VIPA). Ihr könnt mir ja mal was empfehlen.

Wie seht ihr das Problem mit der Zykluszeit?


----------



## Onkel Dagobert (8 Dezember 2007)

Hallo Steve,

http://sps-forum.de/showthread.php?t=14230

Teil 2?


Gruß, Onkel


----------



## zotos (8 Dezember 2007)

Bei solchen Aufgaben ist doch die Frage ob man das Ergebnis in dem gleichen Zyklus benötigt in dem man den Algorithmus gestartet hat. 

Ich kenne ja Deinen Code nicht. Aber ich gehe mal davon aus das Du es in einer Art schleife ohne Backtracking (Rekursion) gelöst hast. Eine Schleife kann man ja recht leicht so umbauen das sie statt einen eigenen Sprung zu veranstalten  einfach den Zyklischen Ablauf der SPS nutzt. Wichtig hier bei ist natürlich das alle Lokal verwendeten Variablen auch statisch deklariert sind.

Man kann dann ein Busy-Flag an den Prozess geben und wenn eine Abbruchbedingung im Algorithmus eintritt Busy-Flag wegnehmen und Ergebnis präsentieren.


----------



## Steve81 (8 Dezember 2007)

Onkel Dagobert schrieb:


> Hallo Steve,
> 
> http://sps-forum.de/showthread.php?t=14230
> 
> ...


 
Stimmt!

und hier mal der Code:


```
//---------------------------------------Bausteinbezeichnung-------------------------------------------------------------
FUNCTION_BLOCK FB11
TITLE = 'Gewichtberechnung'
VERSION : '2.0'
AUTHOR : 'C&S'
//---------------------------------------Variablendeklaration------------------------------------------------------------
VAR_INPUT
    Anzahl_p_P_min, Anzahl_p_P_max : INT ;
    Sollgewicht, Max_Diff_max_min, min_Gewicht_p_St, max_Gewicht_p_St, max_Plus_Abw_Soll, G1, G2, G3, G4, G5, G6, G7, G8, G9, G10 : REAL ;
END_VAR
VAR_OUTPUT
     SPEICHER  :INT:=0;  
     BITSUMOUT : INT:=0;
     ISTIDEAL  : REAL:=0.0;
END_VAR    
VAR_IN_OUT
        ENABLE : BOOL ;
END_VAR
VAR    
    X, I, J, S, T, U, ADR, HBits : INT ;
    IST, MAXIMUM, MINIMUM, SUMME : REAL ;
    HO : DWORD ;
    GEWICHTE : ARRAY [1..10] OF REAL ;
    Gewichtesort : ARRAY [1..10] OF REAL ;
    wordi : WORD ;
    wordj : WORD ;
    wordk : WORD ;
    DBNRW : WORD ;
    IasDINT : DINT ;
END_VAR
//---------------------------------------Anweisungsteil------------------------------------------------------------------
BEGIN
IF ENABLE THEN
        GEWICHTE[1] := G1 ;
        GEWICHTE[2] := G2 ;
        GEWICHTE[3] := G3 ;
        GEWICHTE[4] := G4 ;
        GEWICHTE[5] := G5 ;
        GEWICHTE[6] := G6 ;
        GEWICHTE[7] := G7 ;
        GEWICHTE[8] := G8 ;
        GEWICHTE[9] := G9 ;
        GEWICHTE[10] := G10 ;
        DBNRW := INT_TO_WORD(3) ;
        ISTIDEAL := 0 ;             
 
        [COLOR=red]FOR I := 1 TO 1023 DO[/COLOR]        
 
        HBits := BITSUM (IN :=  DINT_TO_DWORD(INT_TO_DINT(I)));               
 
 
 
        IF (HBits >= Anzahl_p_P_min) AND (HBits <= Anzahl_p_P_max) THEN
 
        IST := 0;
        J := 1;
        S := 1;
        T := 10;    
            FOR X := 1 TO 10 DO                
                wordi := INT_TO_WORD(I);
                wordj := INT_TO_WORD(J);
                wordk := wordi AND wordj;                                                                                      
                IF wordk<>0 THEN                    
                    //IST := IST + GEWICHTE [X] ;
                    Gewichtesort [S] := GEWICHTE [X] ;
                    S := S + 1 ;
                ELSE
                    Gewichtesort [T] := 0 ;
                    T := T - 1 ;                
                END_IF ;                            
                J := J * 2 ;
            END_FOR ;
 
            ADR := 0 ;
            FOR U := 1 TO 10 DO                                
                WORD_TO_BLOCK_DB(DBNRW) .DD[ADR] := REAL_TO_DWORD(Gewichtesort[u]) ;
                ADR := ADR + 4;
            END_FOR ;
 
        FC63 (DBNR:=3, MNR:=0, ANZ:=HBits, MAXIMUM:=MAXIMUM, MINIMUM:=MINIMUM, SUMME:=IST);
 
            IF (MAXIMUM <= max_Gewicht_p_St) AND (MINIMUM >= min_Gewicht_p_St) AND ((MAXIMUM - MINIMUM) <= Max_Diff_max_min) AND (IST <= (Sollgewicht + max_Plus_Abw_Soll)) AND (IST >= Sollgewicht) THEN
 
                IF IST = Sollgewicht THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;            
                    I := 1024 ;
 
                ELSIF (IST > ISTIDEAL) AND (Sollgewicht > ISTIDEAL) THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;
 
                ELSIF (Sollgewicht < ISTIDEAL) AND (IST < ISTIDEAL) AND (Sollgewicht < IST) THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;
 
                END_IF ;
            END_IF ;
        END_IF ;
    [COLOR=red]END_FOR ;[/COLOR]
ENABLE := 0 ;
END_IF;
//--------------------------------------Bausteinende---------------------------------------------------------------------
END_FUNCTION_BLOCK
```
 
Also dass ich dich richtig verstehe Zotos, ich sollte die Schleife also pro Zyklus ein paar mal durchlaufen lassen z.B. 100 mal, und dann beim nächsten dort weitermachen wo ich aufgehört habe!

Der Prozess ließe das in einem gewissen Ausmaß zu, allerdings brauch ich ca. alle Sekunde ein Ergebnis. Ich vermute sogar das wird knapp bei 20 Einzelwerten. Oder irre ich mich da?


----------



## Perfektionist (8 Dezember 2007)

Steve81 schrieb:


> ...
> und hier mal der Code:
> ...
> allerdings brauch ich ca. alle Sekunde ein Ergebnis.
> ...


 
Guten Morgen,

das riecht mir danach, dass da ein anderer Algorithmus her muss. Da ich meine Videos regelmäßig passend auf Video-CD zurechtschnippel, schildere ich mal kurz, wie ich das mach:

alle Portionen nach Größe sortieren - bei zwanzig Werten ist das mit Bubblesort noch bequem machbar.
Dann die zwei größten Portionen miteinander addieren und wenn nicht gut passend, weil deutlich zu viel, größte und zweitgrößte Portion miteinander addieren ... usw. Wenn die zwei Größten Portionen zu wenig, dann noch die dritte Portion hinzunehmen. Das löst aber noch nicht vollständig, da dann zunehmend immer mehr kleine Portionen liegen bleiben.
Also abwechselnd dazu immer die kleinsten Portionen miteinander kombinieren und dann entsprechend von dort aus gehend dreier und vierer-Kobinationen probieren.
Heuristische Abkürzung: was nicht zur Lösung beiträgt sind wahrscheinlich fünfer-sechser bis eben zwanziger-Kombinationen, die also nur Rechenlast darstellen und daher vom Algorithmus ausgeblendet werden müssen. So kenne ich das jedenfalls aus meiner Praxis, wenn es darum geht, Sechserpacks mit Äpfeln zu einem Kilo zu kombinieren. Hier steht die Anzahl der zu kombinierenden Portionen bereits von vorneherein fest.

Vermutlich spreche ich da schon das bereits angesprochene Rucksackproblem an - hab mir nicht die Mühe gemacht, das in Wiki nachzulesen ...


----------



## zotos (8 Dezember 2007)

Steve81 schrieb:


> Also dass ich dich richtig verstehe Zotos, ich sollte die Schleife also pro Zyklus ein paar mal durchlaufen lassen z.B. 100 mal, und dann beim nächsten dort weitermachen wo ich aufgehört habe!


 
Genau das meinte ich.

Hier mal einfach in den Code rein geschrieben und nichts getestet da kann es sehr gut sein das beim Übergang  +/- eins zum Schleifenzähler muss.

Aber ich traue Dir zu, dass Du das selbst testen und verbessern kannst.


```
//---------------------------------------Bausteinbezeichnung-------------------------------------------------------------
FUNCTION_BLOCK FB11
TITLE = 'Gewichtberechnung'
VERSION : '2.0'
AUTHOR : 'C&S'
//---------------------------------------Variablendeklaration------------------------------------------------------------
VAR_INPUT
    Anzahl_p_P_min, Anzahl_p_P_max : INT ;
    Sollgewicht, Max_Diff_max_min, min_Gewicht_p_St, max_Gewicht_p_St, max_Plus_Abw_Soll, G1, G2, G3, G4, G5, G6, G7, G8, G9, G10 : REAL ;
END_VAR
VAR_OUTPUT
     SPEICHER  :INT:=0;  
     BITSUMOUT : INT:=0;
     ISTIDEAL  : REAL:=0.0;
     BUSY      : BOOL; (* ZoToS: der Algorithmus läuft *)
END_VAR    
VAR_IN_OUT
        ENABLE : BOOL ;
END_VAR
VAR    
    X, I, J, S, T, U, ADR, HBits : INT ;
    IST, MAXIMUM, MINIMUM, SUMME : REAL ;
    HO : DWORD ;
    GEWICHTE : ARRAY [1..10] OF REAL ;
    Gewichtesort : ARRAY [1..10] OF REAL ;
    wordi : WORD ;
    wordj : WORD ;
    wordk : WORD ;
    DBNRW : WORD ;
    IasDINT : DINT ;
    forCount :INT; (* ZoToS: zum splitten der Forschleife *)
END_VAR
//---------------------------------------Anweisungsteil------------------------------------------------------------------
BEGIN
IF ENABLE AND NOT BUSY THEN  (* ZoToS: ENABLE ohne BUSY -> Initialisierung *)
        GEWICHTE[1] := G1 ;
        GEWICHTE[2] := G2 ;
        GEWICHTE[3] := G3 ;
        GEWICHTE[4] := G4 ;
        GEWICHTE[5] := G5 ;
        GEWICHTE[6] := G6 ;
        GEWICHTE[7] := G7 ;
        GEWICHTE[8] := G8 ;
        GEWICHTE[9] := G9 ;
        GEWICHTE[10] := G10 ;
        DBNRW := INT_TO_WORD(3) ;
        ISTIDEAL := 0 ;
        BUSY := TRUE;  (* ZoToS: Jezt läuft der Algorithmus *)
        forCount := 1; (* ZoToS: die schleife soll von vorne Beginnen *)
ELSE (* ZoToS *)
  IF ENABLE AND BUSY AND I < 1023 THEN  (* ZoToS: Also es läuft und ist noch unter den 1023 Elementen *)
    
    forCount := I; (* ZoToS: forCount festlegen  *)
    
    FOR I := forCount TO forCount + 127 DO (* ZoToS *)
        HBits := BITSUM (IN :=  DINT_TO_DWORD(INT_TO_DINT(I)));               
 
        IF (HBits >= Anzahl_p_P_min) AND (HBits <= Anzahl_p_P_max) THEN
 
        IST := 0;
        J := 1;
        S := 1;
        T := 10;    
            FOR X := 1 TO 10 DO                
                wordi := INT_TO_WORD(I);
                wordj := INT_TO_WORD(J);
                wordk := wordi AND wordj;                                                                                      
                IF wordk<>0 THEN                    
                    //IST := IST + GEWICHTE [X] ;
                    Gewichtesort [S] := GEWICHTE [X] ;
                    S := S + 1 ;
                ELSE
                    Gewichtesort [T] := 0 ;
                    T := T - 1 ;                
                END_IF ;                            
                J := J * 2 ;
            END_FOR ;
 
            ADR := 0 ;
            FOR U := 1 TO 10 DO                                
                WORD_TO_BLOCK_DB(DBNRW) .DD[ADR] := REAL_TO_DWORD(Gewichtesort[u]) ;
                ADR := ADR + 4;
            END_FOR ;
 
        FC63 (DBNR:=3, MNR:=0, ANZ:=HBits, MAXIMUM:=MAXIMUM, MINIMUM:=MINIMUM, SUMME:=IST);
 
            IF (MAXIMUM <= max_Gewicht_p_St) AND (MINIMUM >= min_Gewicht_p_St) AND ((MAXIMUM - MINIMUM) <= Max_Diff_max_min) AND (IST <= (Sollgewicht + max_Plus_Abw_Soll)) AND (IST >= Sollgewicht) THEN
 
                IF IST = Sollgewicht THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;            
                    I := 1024 ;
 
                ELSIF (IST > ISTIDEAL) AND (Sollgewicht > ISTIDEAL) THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;
 
                ELSIF (Sollgewicht < ISTIDEAL) AND (IST < ISTIDEAL) AND (Sollgewicht < IST) THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;
 
                END_IF ;
            END_IF ;
        END_IF ;
    END_FOR ;
  ELSE 
    BUSY := FALSE; (* ZoToS *)  
  END_IF; (* ZoToS *)     
ENABLE := 0 ;
END_IF;
//--------------------------------------Bausteinende---------------------------------------------------------------------
END_FUNCTION_BLOCK
```



Steve81 schrieb:


> Der Prozess ließe das in einem gewissen Ausmaß zu, allerdings brauch ich ca. alle Sekunde ein Ergebnis. Ich vermute sogar das wird knapp bei 20 Einzelwerten. Oder irre ich mich da?



Ich denke mit einem Aufteilen des Algorithmus und einer schnellen CPU sollte das zu machen sein. Wenn nicht greif eben zu einem schnellen System (z.B. CoDeSys/Beckhoff).


----------



## Steve81 (8 Dezember 2007)

Hallo zotos,

danke für die schnelle Hilfe, habs zwar noch nicht ausprobiert, sieht aber ziemlich vielversprechend aus.
Melde mich dann wieder wenn ich ein Ergebnis hab.


----------



## zotos (8 Dezember 2007)

Ich habe mal einfach eine FOR-Schleife die von 0..1023 läuft auf 8 SPS Zyklen verteilt.


```
VAR
    myArray   :ARRAY[0..1023] OF INT;
    forIndex  :INT;
    forTarget :INT;
    Busy      :BOOL;
END_VAR

IF NOT BUSY THEN
    (* Initialisierung *)
    forIndex := 0;
    forTarget :=0;
    Busy := TRUE;
ELSE
    IF BUSY AND forIndex <1023 THEN (* Die Schleife Läuft *)
        forTarget := forIndex + 127; (* hier bestimmt man indirekt die Anzahl der SPS-Zyklen *)
        FOR forIndex:=forIndex TO forTarget DO (* for Index wurde im Init gesetzt danach wird er Statisch gehalten *)
            (* Inhalt der eigentlichen Forschleife *)
            myArray[forIndex] := forIndex * 2; (* Nur zum Testen *)
        END_FOR;
    ELSE
        (* Ende der gesamten Schleife *)
        BUSY := FALSE;
    END_IF;
END_IF;
```


----------



## Perfektionist (8 Dezember 2007)

Steve81 schrieb:


> ...
> Mein eigentliches Problem:
> Bei 20 Einzelwerten habe ich 2^20 - 1 Kombinationsmöglichkeiten.
> ...


genau DA sehe ich Dein Problem - reden wir nun von 1023 Schleifendurchläufen oder von 1048575?


----------



## zotos (8 Dezember 2007)

Perfektionist schrieb:


> genau DA sehe ich Dein Problem - reden wir nun von 1023 Schleifendurchläufen oder von 1048575?



Ja bei 1048575 wird es so nicht gehen. Das habe ich überlesen ;o(


----------



## argv_user (8 Dezember 2007)

*es wird nichts nützen*



zotos schrieb:


> Ich habe mal einfach eine FOR-Schleife die von 0..1023 läuft auf 8 SPS Zyklen verteilt.



n=10:
2^10-1 = 1023

Aber n=20:
2^20-1 = 1048575

Tausend mal Tausend gibt auch 'ne Million.
Haut das denn zeitlich immer noch hin?
Was ist, wenn noch eins dazukommt (n=21)...

Perfektionist hat vollkommen Recht, ohne einen anderen
Algorithmus kommt man bei ausreichend großem n nicht zurande.
Eine vetretbare Lösung wäre zB, nicht nach einer optimalen
Lösung zu suchen, sondern einen Toleranzbereich festzulegen,
und die erste Lösung zu nehmen, die da drin liegt.

BTW:
Steve81 hätte sein Programm der Einfachheit halber auch mit
n=3 testen können.


----------



## Larry Laffer (8 Dezember 2007)

Vielleicht ist der Vorschlag von Perfektionist nicht so schlecht, die übergebenen 20 Variablen zunächst nach Größe zu sortieren (Größte nach vorn/oben) und entsprechend der Vorgabe-Variablen zu überprüfen, ob überhaupt alle in Frage kommen (ist einer oder mehrere der Werte von vornherein größer, dann muß er nicht mehr mit berücksichtigt werden). Entsprechend würde ich mit der Differenz von dem gerade gewählten Wert zur Vorgabe verfahren. Auch da werden dann warscheinlich gar nicht mehr alle Variablen in Frage kommen.

Das hat als Algorythmus aber schon Anforderungs-Charakter ...


----------



## zotos (8 Dezember 2007)

argv_user schrieb:


> n=10:
> 2^10-1 = 1023
> 
> Aber n=20:
> ...



Ihr habt ja recht ich habe ja eben schon geschrieben das ich die 2^20 - 1 überlesen habe. 

Also wenn man im Internet nach den Rucksack Problem und dessen Optimierung sucht landet man schnell bei rekursiven Aufrufen. Das beist sich eben leider mit so ziemlich jeder SPS Systemarchitektur die ich kenne.

Also was bleibt einem übrig? Die vom werten Kollegen argv_user angesprochene Toleranz Grenze die als Abbruch Bedingung in Frage kommt plus einer Abschaltung. 
Je nach Anwendung ist es ja auch vorgegeben das nicht mehr als X werte gleichzeitig dazu gehören können. Also wenn es um drei Schnitzel geht die zusammen z.B. möglichst 500g wiegen sollen ist die Anzahl der Möglichkeiten geringer. 

Und auch wenn ich vorhin das mit der über eine Million Schleifen Durchläufen nicht beachtet habe bin ich immer noch der Meinung das es nützlich wäre die Berechnung auf mehrere SPS-Zyklen zu verteilen. Da ja ca. 1 Sekunde zur Verfügung steht sollte man nicht mit gewallt an die 15-20ms Grenze gehen.


----------



## Steve81 (8 Dezember 2007)

Hier ist jetzt der funktionierende Code der über mehrere Zyklen durchgearbeitet wird. Der Code von zotos hat bis auf das rot markierte gepasst.
Vielen Dank nochmal für die Unterstützung.



```
//---------------------------------------Bausteinbezeichnung-------------------------------------------------------------
FUNCTION_BLOCK FB11
TITLE = 'Gewichtberechnung'
VERSION : '2.0'
AUTHOR : 'C&S'
//---------------------------------------Variablendeklaration------------------------------------------------------------
VAR_INPUT
    Anzahl_p_P_min, Anzahl_p_P_max : INT ;
    Sollgewicht, Max_Diff_max_min, min_Gewicht_p_St, max_Gewicht_p_St, max_Plus_Abw_Soll, G1, G2, G3, G4, G5, G6, G7, G8, G9, G10 : REAL ;
END_VAR
VAR_OUTPUT
     SPEICHER  :INT;  
     BITSUMOUT : INT;
     ISTIDEAL  : REAL;
     BUSY      : BOOL; (* ZoToS: der Algorithmus läuft *)
END_VAR    
VAR_IN_OUT
        ENABLE : BOOL ;
END_VAR
VAR    
    X, I, J, S, T, U, ADR, HBits : INT ;
    IST, MAXIMUM, MINIMUM, SUMME : REAL ;
    HO : DWORD ;
    GEWICHTE : ARRAY [1..10] OF REAL ;
    Gewichtesort : ARRAY [1..10] OF REAL ;
    wordi : WORD ;
    wordj : WORD ;
    wordk : WORD ;
    DBNRW : WORD ;
    IasDINT : DINT ;
    forCount :INT; (* ZoToS: zum splitten der Forschleife *)
END_VAR
//---------------------------------------Anweisungsteil------------------------------------------------------------------
BEGIN
IF ENABLE AND NOT BUSY THEN  (* ZoToS: ENABLE ohne BUSY -> Initialisierung *)
        GEWICHTE[1] := G1 ;
        GEWICHTE[2] := G2 ;
        GEWICHTE[3] := G3 ;
        GEWICHTE[4] := G4 ;
        GEWICHTE[5] := G5 ;
        GEWICHTE[6] := G6 ;
        GEWICHTE[7] := G7 ;
        GEWICHTE[8] := G8 ;
        GEWICHTE[9] := G9 ;
        GEWICHTE[10] := G10 ;
        DBNRW := INT_TO_WORD(3) ;
        ISTIDEAL := 0 ; 
        SPEICHER  :=0;  
        BITSUMOUT :=0;
        [COLOR=red]I := 1;[/COLOR]       
        BUSY := TRUE;  (* ZoToS: Jezt läuft der Algorithmus *)
        [COLOR=red]//forCount := 1; (* ZoToS: die schleife soll von vorne Beginnen *)[/COLOR]
ELSE (* ZoToS *)
  IF ENABLE AND BUSY AND I < 1023 THEN  (* ZoToS: Also es läuft und ist noch unter den 1023 Elementen *)
    
    forCount := I; (* ZoToS: forCount festlegen  *)
    
    FOR I := forCount TO forCount + 127 DO (* ZoToS *)
        HBits := BITSUM (IN :=  DINT_TO_DWORD(INT_TO_DINT(I)));               
 
        IF (HBits >= Anzahl_p_P_min) AND (HBits <= Anzahl_p_P_max) THEN
 
        IST := 0;
        J := 1;
        S := 1;
        T := 10;    
            FOR X := 1 TO 10 DO                
                wordi := INT_TO_WORD(I);
                wordj := INT_TO_WORD(J);
                wordk := wordi AND wordj;                                                                                      
                IF wordk<>0 THEN                    
                    //IST := IST + GEWICHTE [X] ;
                    Gewichtesort [S] := GEWICHTE [X] ;
                    S := S + 1 ;
                ELSE
                    Gewichtesort [T] := 0 ;
                    T := T - 1 ;                
                END_IF ;                            
                J := J * 2 ;
            END_FOR ;
 
            ADR := 0 ;
            FOR U := 1 TO 10 DO                                
                WORD_TO_BLOCK_DB(DBNRW) .DD[ADR] := REAL_TO_DWORD(Gewichtesort[u]) ;
                ADR := ADR + 4;
            END_FOR ;
 
        FC63 (DBNR:=3, MNR:=0, ANZ:=HBits, MAXIMUM:=MAXIMUM, MINIMUM:=MINIMUM, SUMME:=IST);
 
            IF (MAXIMUM <= max_Gewicht_p_St) AND (MINIMUM >= min_Gewicht_p_St) AND ((MAXIMUM - MINIMUM) <= Max_Diff_max_min) AND (IST <= (Sollgewicht + max_Plus_Abw_Soll)) AND (IST >= Sollgewicht) THEN
 
                IF IST = Sollgewicht THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;            
                    I := 1024 ;
 
                ELSIF (IST > ISTIDEAL) AND (Sollgewicht > ISTIDEAL) THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;
 
                ELSIF (Sollgewicht < ISTIDEAL) AND (IST < ISTIDEAL) AND (Sollgewicht < IST) THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMOUT := HBits ;
 
                END_IF ;
            END_IF ;
        END_IF ;
    END_FOR ;
  ELSE 
    BUSY := FALSE; (* ZoToS *) 
    [COLOR=red]ENABLE := 0 ; 
[/COLOR]  END_IF; (* ZoToS *)
[COLOR=red]hier stand ENABLE:=0;[/COLOR]     
END_IF;
//--------------------------------------Bausteinende---------------------------------------------------------------------
END_FUNCTION_BLOCK
```
 
Also jetzt noch mal die genauere beschreibung:

Im Moment habe ich 10 Einzelwerte, aber es soll später mal mit 20 gehen.
Ebenfalls sollen nur bestimmte Kombinationen möglich sein z.B. nur aus 3 Werten oder aus 2-4 Werten.
Ebenfalls möchte ich den Autraggeber davon überzeugen, nicht das Absolut bete Ergebnis abzuwarten sonder eine gewisse Toleranz vorzugeben wann die Kombination nahe genug bei Soll ist.
Natürlich soll auch alles möglichst flexibel sein.

Die meisten Kombinationen berechne ich ja auch garnicht (siehe BITSUM im CODE)


----------



## Onkel Dagobert (8 Dezember 2007)

*Buchtipp*

Hallo Steve,

hier nur ein Hinweis von mir. Ich selber kenne das Buch nicht!
http://www.amazon.de/Knapsack-Problems-H-Kellerer/dp/3540402861

Interessante und anspruchsvolle Sache. Leider habe ich aufgrund eigener Projekte nicht die notwendige Zeit, mich damit zu beschäftigen. 


Gruß, Onkel


----------



## zotos (9 Dezember 2007)

Steve81 schrieb:


> ...
> Ebenfalls sollen nur bestimmte Kombinationen möglich sein z.B. nur aus 3 Werten oder aus 2-4 Werten.
> ...
> Die meisten Kombinationen berechne ich ja auch garnicht (siehe BITSUM im CODE)



Die Aufgabe gefällt mir. 

Wenn man nur die Kombinationen aus wenigen werten Berücksichtigt kommt man ja wieder auf humane Werte.

Im Bereich 2^10 (also 0..1023) Kommt man wenn man nach den Kombinationen aus 2,3 und 4 Einzelwerten sucht, gerade mal auf 375 zu überprüfende Kombinationen.


```
Bereich
0..1023
Bits     Kombinationen
    2 ->  45
    3 -> 120
    4 -> 210
2,3,4 -> 375
```
Im Bereich 2^20 (also 0..1048575) Kommt man wenn man nach den Kombinationen aus 2,3 und 4 Einzelwerten sucht, schon auf 6175  zu überprüfende Kombinationen. Was aber innerhalb einer Sekunde ja wohl zu schaffen ist.

```
Bereich    
0..1048575
Bits     Kombinationen
    2 ->  190
    3 -> 1140
    4 -> 4845
2,3,4 -> 6175
```


----------



## Onkel Dagobert (9 Dezember 2007)

Ich glaube, es ist vielleicht besser, nicht alle Kombinationen zu berechnen.


möglicher Ansatz:

Die ersten (oder beliebige) der Werte aufaddieren, bis der Sollwert über- oder unterschritten ist (kleinste absolute Abweichnug verwenden).
SCHLEIFE:
Anschließend die Differenzen jedes verwendeten Wertes zu den verblieben Werten ermitteln.
Sollwertabweichung mit den soeben berechneten Differenzen vergleichen und Austausch mit dem Wert, mit dessen Differenz eine beste Sollwertanpassung erreicht wird.
Solange ein Austausch stattgefunden hat, Schleife wiederholen
Hat kein Austausch stattgefunden, wurde das Optimum erreicht.
Sicherlich nicht einfach zu programmieren, vielleicht aber möglich.


Gruß, Onkel


----------



## Steve81 (9 Dezember 2007)

Hallo,

also ich mache es in meinem Programm bereits so, dass ich nur bei den zulässiges Kombinationen was die Einzelwertmenge betrifft weiterrechne.
Anzahl_p_P_min und Anzahl_p_P_max sind die min und max Stückzahl pro Packung. (z.B. 3 oder 2-4 Schnitzel pro 500g Pack) 

```
FOR I := forCount TO forCount + 127 DO 
        HBits := BITSUM (IN :=  DINT_TO_DWORD(INT_TO_DINT(I)));               
 
        IF (HBits >= Anzahl_p_P_min) AND (HBits <= Anzahl_p_P_max) THEN
```
 
dann übergebe ich die Werte an den FC63 der mir den minimalen den maximalen und die Summe der Einzelwerte zurück liefert.

```
IST := 0;
        J := 1;
        S := 1;
        T := 10;    
            FOR X := 1 TO 10 DO                
                wordi := INT_TO_WORD(I);
                wordj := INT_TO_WORD(J);
                wordk := wordi AND wordj;                                                                                      
                IF wordk<>0 THEN                    
                    
                    Gewichtesort [S] := GEWICHTE [X] ;
                    S := S + 1 ;
                ELSE
                    Gewichtesort [T] := 0 ;
                    T := T - 1 ;                
                END_IF ;                            
                J := J * 2 ;
            END_FOR ;
 
            ADR := 0 ;
            FOR U := 1 TO 10 DO                                
                WORD_TO_BLOCK_DB(DBNRW) .DD[ADR] := REAL_TO_DWORD(Gewichtesort[u]) ;
                ADR := ADR + 4;
            END_FOR ;
 
        FC63 (DBNR:=3, MNR:=0, ANZ:=HBits, MAXIMUM:=MAXIMUM, MINIMUM:=MINIMUM, SUMME:=IST);
```
 
dann prüfe ich ob die zurückgelieferten Werte in der Toleranz sind

```
IF (MAXIMUM <= max_Gewicht_p_St) AND (MINIMUM >= min_Gewicht_p_St) AND ((MAXIMUM - MINIMUM) <= Max_Diff_max_min) AND (IST <= (Sollgewicht + max_Plus_Abw_Soll)) AND (IST >= Sollgewicht) THEN
```
 
und erst wenn das alles zutrifft, prüfe ich ob die jetztige Kombination die nähste an meinem Sollwert ist. Habe ich genau den sollwert, setze ich I auf 1024 damit die äusere FOR-Schleife bgebrochen wird.

```
IF IST = Sollgewicht THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMME := HBits ;            
                    I := 1024 ;
 
                ELSIF (IST > ISTIDEAL) AND (Sollgewicht > ISTIDEAL) THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMME := HBits ;
 
                ELSIF (Sollgewicht < ISTIDEAL) AND (IST < ISTIDEAL) AND (Sollgewicht < IST) THEN
                    ISTIDEAL := IST ;
                    SPEICHER := I ;
                    BITSUMME := HBits ;
 
                END_IF ;
```
 

Ich häng jetzt noch das Projekt an, falls jemand lust hat zu testen und freu mich über jede (konstruktive) Kritik und Vorschläge zur Verbesserung.

die SCL-Quelle "Gewichtberechnung FB11" arbeitet den Baustein in einem Zyklus ab, die Quelle "test" in mehreren Zyklen.
Beide Quellen erstellen den FB 11.

Die Toleranzvorgaben stehen in DB101 bis DB109. Die die für das jeweilige Produkt genutzt wertden, werden in DB100 geladen (mit FC303).


----------



## Steve81 (9 Dezember 2007)

zotos schrieb:


> Die Aufgabe gefällt mir.
> 
> Wenn man nur die Kombinationen aus wenigen werten Berücksichtigt kommt man ja wieder auf humane Werte.
> 
> ...


 
Hallo Zotos,

mit welcher Gleichung kommst du auf die Kombinationsmöglichkeiten? 
Entweder es ist nicht so einfach zu errechnen oder ich steh aufm Schlauch!


----------



## zotos (9 Dezember 2007)

Das ist wie bei den Lottozahlen nur statt 6 aus 49 sind es eben 3 aus 20:


```
20!
X =--------
   17! * 3!
```

bzw. 2 aus 20 oder eben 4 aus 20.


----------



## zotos (9 Dezember 2007)

Steve81 schrieb:


> ...
> also ich mache es in meinem Programm bereits so, dass ich nur bei den zulässiges Kombinationen was die Einzelwertmenge betrifft weiterrechne.
> Anzahl_p_P_min und Anzahl_p_P_max sind die min und max Stückzahl pro Packung. (z.B. 3 oder 2-4 Schnitzel pro 500g Pack)
> ...
> ...



Also ich denke eben das es nicht sinnvoll ist alle 2^20 Kombinationen überhaupt in betracht zu ziehen.
Wenn Du jeden Wert darauf prüfst ob er nur aus z.B. 3 Bit besteht musst Du ja immer noch über eine Million Prüfungen machen.

Ich würde nur die Kombinationen ansteuern die aus z.B. 3 Bit bestehen. 

Wenn man dann noch die Durchläufe auf mehrere SPS-Zyklen verteilt ist die Aufgabe schon gar nicht mehr so groß.

Wenn die Werte nun noch sortiert vorhanden wären, wäre das ganze noch leicht zu optimieren. Aber das lasse ich hier mal außen vor da dies jetzt die Übersichtlichkeit nicht fördern würde. 

Ich habe das ganze mal für die Aufgabe 3 aus 20 (also 1140 Möglichkeiten) in CoDeSys Programmiert. Die Varianten 2 bzw. 4 aus 20 müssten da noch rein. 

Die Umsetzung von diesem ST-Code nach SCL sollte eigentlich nicht so schwer sein. 

Bei myDWORD_C.0 müsste eben ein Array über 20 BOOL mit dem AT auf das myDWORD_C gesetzt werden das man z.B. myDWORD_Array[0] schreiben kann. Da könnte man dann die IF-THEN-ELSE Batterie auch schnell noch durch eine FOR-Schleife ersetzen. (* Ich schweife ab ;o( *)

So hier mal mein Code:


```
PROGRAM Opti
VAR_INPUT
    ENABLE                :BOOL;
    Target              :REAL;
  ValueArray    :ARRAY[0..19] OF REAL;
END_VAR

VAR
    myENABLE            :BOOL;
    myOptimum            :REAL;
    myOptimumCom    :DWORD;
    myDWORD_1            :DWORD;
    myDWORD_2            :DWORD;
    myDWORD_3            :DWORD;
    myDWORD_C            :DWORD;
    myActual            :REAL;
    myRealArray     :ARRAY[0..19] OF REAL;
    myCount                :INT;
END_VAR

VAR_OUTPUT
    BUSY                    :BOOL;
    Optimum                :REAL;
    OptimumCom        :DWORD;
END_VAR

IF ENABLE AND NOT myENABLE THEN (* Eine positive Flanke am Enable dient als Startsignal *)
    (* Initialisierung  *)
  myRealArray  := ValueArray;
    myActual         := 0.0;
    myOptimum    := 0.0;
  myOptimumCom := 0;
    myDWORD_1    := 1; (* Kleinstwertige Variation von drei Bits *)
    myDWORD_2    := 2; (* " *)
    myDWORD_3    := 4; (* " *)
    BUSY         := TRUE;
    myCount      := 0;
ELSIF BUSY THEN

    WHILE myCount <= 255 DO (* Schleife wie viele Durchläufe max. pro SPS Zyklus gemacht werden *)

        (* Kombiniertes DWORD erstellen *)
        myDWORD_C := myDWORD_1 OR myDWORD_2 OR myDWORD_3;

        (* Gewichtsberechnung der aktuellen Kombination *)
         myActual := 0.0;
        IF myDWORD_C.0  THEN myActual := myActual + myRealArray[ 0]; END_IF;
        IF myDWORD_C.1  THEN myActual := myActual + myRealArray[ 1]; END_IF;
        IF myDWORD_C.2  THEN myActual := myActual + myRealArray[ 2]; END_IF;
        IF myDWORD_C.3  THEN myActual := myActual + myRealArray[ 3]; END_IF;
        IF myDWORD_C.4  THEN myActual := myActual + myRealArray[ 4]; END_IF;
        IF myDWORD_C.5  THEN myActual := myActual + myRealArray[ 5]; END_IF;
        IF myDWORD_C.6  THEN myActual := myActual + myRealArray[ 6]; END_IF;
        IF myDWORD_C.7  THEN myActual := myActual + myRealArray[ 7]; END_IF;
        IF myDWORD_C.8  THEN myActual := myActual + myRealArray[ 8]; END_IF;
        IF myDWORD_C.9  THEN myActual := myActual + myRealArray[ 9]; END_IF;
        IF myDWORD_C.10 THEN myActual := myActual + myRealArray[10]; END_IF;
        IF myDWORD_C.11 THEN myActual := myActual + myRealArray[11]; END_IF;
        IF myDWORD_C.12 THEN myActual := myActual + myRealArray[12]; END_IF;
        IF myDWORD_C.13 THEN myActual := myActual + myRealArray[13]; END_IF;
        IF myDWORD_C.14 THEN myActual := myActual + myRealArray[14]; END_IF;
        IF myDWORD_C.15 THEN myActual := myActual + myRealArray[15]; END_IF;
        IF myDWORD_C.16 THEN myActual := myActual + myRealArray[16]; END_IF;
        IF myDWORD_C.17 THEN myActual := myActual + myRealArray[17]; END_IF;
        IF myDWORD_C.18 THEN myActual := myActual + myRealArray[18]; END_IF;
        IF myDWORD_C.19 THEN myActual := myActual + myRealArray[19]; END_IF;

        (* Kombination bewerten *)
        IF ABS(myActual - Target) < ABS(myOptimum - Target) THEN
            myOptimum := myActual;
            myOptimumCom := myDWORD_C;
        END_IF;

        IF myDWORD_C.19 AND myDWORD_C.18 AND  myDWORD_C.17 THEN (* Fertig *)
            Optimum    := myOptimum;
            OptimumCom := myOptimumCom;
            BUSY       := FALSE;
        ELSE
            IF myDWORD_C.19 AND myDWORD_C.18 THEN    (* Schiebe alle drei Bits *)
                myDWORD_1 := SHL(myDWORD_1,1);
                myDWORD_2 := SHL(myDWORD_1,1);
                myDWORD_3 := SHL(myDWORD_2,1);
            ELSE
                IF myDWORD_C.19 THEN (* Schiebe die zwei hochwertigen Bits *)
                    myDWORD_2 := SHL(myDWORD_2,1);
                    myDWORD_3 := SHL(myDWORD_2,1);
                ELSE
                    myDWORD_3 := SHL(myDWORD_3,1); (* Schiebe nur das höchstwertige Bit *)
                END_IF
            END_IF
        END_IF
        myCount := myCount + 1; (* Zähler zur Zyklus Verteilung inkrementieren *)
    END_WHILE;
    myCount := 0; (* Zähler zur Zyklus Verteilung nullen *)
END_IF;

myENABLE := ENABLE; (* Wert für Flankenerkennung *)
```

Ich denke das dort schon die Grundlegenden Ideen ersichtlich sind.


----------



## zotos (9 Dezember 2007)

Da mich das Thema interessiert, habe ich noch den Code auf 2,3,4 Bits erweitert.


```
PROGRAM Opti
VAR_INPUT
  ENABLE        :BOOL;
  Target        :REAL;
  ValueArray    :ARRAY[0..19] OF REAL;
END_VAR

VAR
  myENABLE      :BOOL;
  myOptimum     :REAL;
  myOptimumCom  :DWORD;
  myDWORD_1     :DWORD;
  myDWORD_2     :DWORD;
  myDWORD_3     :DWORD;
  myDWORD_4     :DWORD;
  myDWORD_C     :DWORD;
  myActual      :REAL;
  myRealArray   :ARRAY[0..19] OF REAL;
  myCount       :INT;
END_VAR

VAR_OUTPUT
  BUSY          :BOOL;
  Optimum       :REAL;
  OptimumCom    :DWORD;
END_VAR

IF ENABLE AND NOT myENABLE THEN (* Eine positive Flanke am Enable dient als Startsignal *)
  (* Initialisierung  *)
  myRealArray  := ValueArray;
  myActual     := 0.0;
  myOptimum    := 0.0;
  myOptimumCom := 0;
  myDWORD_1    := 0; (* Kleinstwertige Variation von zwei Bits *)
  myDWORD_2    := 0; (* " *)
  myDWORD_3    := 1; (* " *)
  myDWORD_4    := 2; (* " *)
  BUSY         := TRUE;
  myCount      := 0;
ELSIF BUSY THEN

  WHILE myCount <= 512 AND BUSY DO (* Schleife wie viele Durchläufe max. pro SPS Zyklus gemacht werden *)

    (* Kombiniertes DWORD erstellen *)
    myDWORD_C := myDWORD_1 OR myDWORD_2 OR myDWORD_3 OR myDWORD_4;

    (* Gewichtsberechnung der aktuellen Kombination *)
     myActual := 0.0;
    IF myDWORD_C.0  THEN myActual := myActual + myRealArray[ 0]; END_IF;
    IF myDWORD_C.1  THEN myActual := myActual + myRealArray[ 1]; END_IF;
    IF myDWORD_C.2  THEN myActual := myActual + myRealArray[ 2]; END_IF;
    IF myDWORD_C.3  THEN myActual := myActual + myRealArray[ 3]; END_IF;
    IF myDWORD_C.4  THEN myActual := myActual + myRealArray[ 4]; END_IF;
    IF myDWORD_C.5  THEN myActual := myActual + myRealArray[ 5]; END_IF;
    IF myDWORD_C.6  THEN myActual := myActual + myRealArray[ 6]; END_IF;
    IF myDWORD_C.7  THEN myActual := myActual + myRealArray[ 7]; END_IF;
    IF myDWORD_C.8  THEN myActual := myActual + myRealArray[ 8]; END_IF;
    IF myDWORD_C.9  THEN myActual := myActual + myRealArray[ 9]; END_IF;
    IF myDWORD_C.10 THEN myActual := myActual + myRealArray[10]; END_IF;
    IF myDWORD_C.11 THEN myActual := myActual + myRealArray[11]; END_IF;
    IF myDWORD_C.12 THEN myActual := myActual + myRealArray[12]; END_IF;
    IF myDWORD_C.13 THEN myActual := myActual + myRealArray[13]; END_IF;
    IF myDWORD_C.14 THEN myActual := myActual + myRealArray[14]; END_IF;
    IF myDWORD_C.15 THEN myActual := myActual + myRealArray[15]; END_IF;
    IF myDWORD_C.16 THEN myActual := myActual + myRealArray[16]; END_IF;
    IF myDWORD_C.17 THEN myActual := myActual + myRealArray[17]; END_IF;
    IF myDWORD_C.18 THEN myActual := myActual + myRealArray[18]; END_IF;
    IF myDWORD_C.19 THEN myActual := myActual + myRealArray[19]; END_IF;

    (* Kombination bewerten *)
    IF ABS(myActual - Target) < ABS(myOptimum - Target) THEN
      myOptimum := myActual;
      myOptimumCom := myDWORD_C;
    END_IF;

    IF myDWORD_C.19 AND myDWORD_C.18 AND myDWORD_C.17 AND myDWORD_C.16 THEN (* Fertig *)
      Optimum    := myOptimum;
      OptimumCom := myOptimumCom;
      BUSY       := FALSE;
    ELSE
      IF myDWORD_C.19 AND myDWORD_C.18 AND myDWORD_C.17 THEN  (* Schiebe alle vier Bits *)
        IF myDWORD_1 = 0 THEN (* Übergang von 3 auf 4 Bit *)
          myDWORD_1 := 1;
        ELSE
          myDWORD_1 := SHL(myDWORD_1,1);
        END_IF;

        myDWORD_2 := SHL(myDWORD_1,1);
        myDWORD_3 := SHL(myDWORD_2,1);
        myDWORD_4 := SHL(myDWORD_3,1);
      ELSE
        IF myDWORD_C.19 AND myDWORD_C.18 THEN (* Schiebe die drei hochwertigen Bits *)
          IF myDWORD_2 = 0 THEN (* Übergang von 2 auf 3 Bit *)
            myDWORD_2 := 1;
          ELSE
            myDWORD_2 := SHL(myDWORD_2,1);
          END_IF;

          myDWORD_3 := SHL(myDWORD_2,1);
          myDWORD_4 := SHL(myDWORD_3,1);
        ELSE
          IF myDWORD_C.19 THEN (* Schiebe die zwei hochwertigen Bits *)
            myDWORD_3 := SHL(myDWORD_3,1);
            myDWORD_4 := SHL(myDWORD_3,1);
          ELSE
            myDWORD_4 := SHL(myDWORD_4,1); (* Schiebe nur das höchstwertige Bit *)
          END_IF
        END_IF
      END_IF
    END_IF
    myCount := myCount + 1; (* Zähler zur Zyklus Verteilung inkrementieren *)
  END_WHILE;
  myCount := 0; (* Zähler zur Zyklus Verteilung nullen *)
END_IF;

myENABLE := ENABLE; (* Wert für Flankenerkennung *)
```

Kommst Du mit der Umsetzung nach SCL klar?


----------



## Perfektionist (9 Dezember 2007)

*da auch mich das Thema interessiert, will ich auch noch mal ...*

da ich ja unprofessioneller bin, hab ich das mal in Basic geklopft und auch gleich mal ne Simulation drübergelegt ...


```
0 REM BEGINN SPAGHETTICODE
1 REM geschrieben fuer MS-DOS Q-Basic V1.1
2 REM Quelle: Win98SE-Setup-Disk
3 REM moegliche alternative Quellen: Win95, WinNT
4 REM ich nutze Basic-Eigenschaft, dass variablen grundsaetzlich bei erstverwendung mit Null vorbelegt sind
5 REM
6 RANDOMIZE TIMER
7 Sollgewicht% = 1000
8 DIM produkt%(20): OPEN "report.txt" FOR OUTPUT AS #1
9 REM
10 FOR ablaufdauer% = 1 TO 1000: PRINT ablaufdauer%; : REM Maschinentest auf 1000 Zyklen begrenzen
11 REM
12 REM Behaelter vorbelegen bzw. nachfuellen
13 REM *************************************
14 REM
20 FOR t% = 1 TO 20
21 IF produkt%(t%) <> 0 THEN GOTO 29
22 wert% = (RND + RND + RND) * 222: REM Zufall mit ein bisschen Struktur generieren
23 IF wert% < 100 THEN GOTO 22
24 IF wert% > 700 THEN GOTO 22
25 produkt%(t%) = wert%
29 NEXT t%
100 REM
101 REM Bubblesort - damit der Mensch schneller begreift, Maschine braucht keine Sortierung
102 REM **********
103 REM
110 istsortiert% = 1
112 FOR t% = 1 TO 19
113 IF produkt%(t%) <= produkt%(t% + 1) THEN GOTO 115
114 istsortiert% = 0: wert% = produkt%(t% + 1): produkt%(t% + 1) = produkt%(t%): produkt%(t%) = wert%
115 NEXT t%
118 IF istsortiert% = 0 THEN GOTO 110
178 REM
179 REM Vorbereitung der Suche
180 zeiger1% = 0
181 zeiger2% = 0
182 zeiger3% = 0
183 zeiger4% = 0
184 besteSumme% = 32767
200 REM
201 REM beste Zweierkombination suchen
202 FOR t% = 1 TO 19
203 FOR i% = t% + 1 TO 20
204 wert% = produkt%(t%) + produkt%(i%)
205 IF wert% < Sollgewicht% OR wert% > besteSumme% GOTO 299
206 zeiger1% = t%
207 zeiger2% = i%
208 besteSumme% = wert%
299 NEXT i%: NEXT t%
300 REM
301 REM bessere Dreierkombination suchen
302 FOR a% = 1 TO 18
303 FOR b% = a% + 1 TO 19
304 FOR c% = b% + 1 TO 20
310 wert% = produkt%(a%) + produkt%(b%) + produkt%(c%)
311 IF wert% < Sollgewicht% OR wert% > besteSumme% GOTO 399
312 zeiger1% = a%
313 zeiger2% = b%
314 zeiger3% = c%
320 besteSumme% = wert%
399 NEXT c%: NEXT b%: NEXT a%
400 REM
401 REM noch bessere Viererkombination suchen
402 FOR a% = 1 TO 17
403 FOR b% = a% + 1 TO 18
404 FOR c% = b% + 1 TO 19
405 FOR d% = c% + 1 TO 20
410 wert% = produkt%(a%) + produkt%(b%) + produkt%(c%) + produkt%(d%)
411 IF wert% < Sollgewicht% OR wert% > besteSumme% GOTO 499
412 zeiger1% = a%
413 zeiger2% = b%
414 zeiger3% = c%
415 zeiger4% = d%
420 besteSumme% = wert%
499 NEXT d%: NEXT c%: NEXT b%: NEXT a%
1000 REM so, jetzt ist der Suchalgorithmus vorbei, weiter mit Maschinensimulation und Report zur Analyse des Prozessverhaltens ...
1100 FOR t% = 1 TO 20
1101 PRINT #1, produkt%(t%);
1102 NEXT t%
1103 PRINT #1, "gewaehlt:";
1104 IF zeiger1% <> 0 THEN PRINT #1, produkt%(zeiger1%);
1105 IF zeiger2% <> 0 THEN PRINT #1, produkt%(zeiger2%);
1106 IF zeiger3% <> 0 THEN PRINT #1, produkt%(zeiger3%);
1107 IF zeiger4% <> 0 THEN PRINT #1, produkt%(zeiger4%);
1108 PRINT #1, "gibt"; besteSumme%
1200 REM naechster Durchlauf, dafuer verbrauchte Produkte loeschen
1201 IF zeiger1% <> 0 THEN produkt%(zeiger1%) = 0
1202 IF zeiger2% <> 0 THEN produkt%(zeiger2%) = 0
1203 IF zeiger3% <> 0 THEN produkt%(zeiger3%) = 0
1204 IF zeiger4% <> 0 THEN produkt%(zeiger4%) = 0
9999 NEXT ablaufdauer%
```
 
und dazu noch den Output, den der Algorithmus mitsamt seiner drübergelegten Maschinensimulation lieferte, siehe Anhang!

ich will jetzt nicht behaupten, dass das absolut fehlerfrei ist - ich hab halt mal die Spaghetti gekocht, bis sie mir essbar schienen. Aber so könnte man, denke ich, das Problem lösen, ohne an absolute CPU-Leistungsgrenzen zu stoßen. Ich denke mal, der benutzte Algorithmus macht mal den Unterschied zwischen 319 und 317 aus.

so, die Übersetzung davon nach SCL überlasse ich anderen - äh, Professionellen!  

Ich geb ja zu, als AWL-Progger hab ich da dann einiges mit Pointern zu hantieren, um das ohne SCL umzusetzen ... oder irgend ein Geniestreich mit sortierten Werten - egal - wollt ja mal die Richtung, ich muss ja nicht ins Ziel treffen  

Schöne Grüße!


----------



## Perfektionist (9 Dezember 2007)

... o.k., was mir ergänzend nebenbei noch so auffällt: so ne dumme 317 ist weder in  der Lage, ein Teilprozessabbild für einen Weckalarm zu generieren, so dass man den Weckalarm als zyklisches Programm missbrauchen könnte, noch ist Hintergrundbearbeitung bei ihr vorgesehen. Also muss man den von mir vorgeschlagenen Algorithmus auf irgend eine unkomfortable Art und Weise auf mehrere Zyklen aufteilen ...

aber jetzt FEIERABEND!!! bis morgen ....


----------



## zotos (9 Dezember 2007)

Ich habe mich gerade an die Umsetzung von CoDeSys-ST auf Step7-SCL gewagt.

Also ich hänge gerade an der beschissenen Step7 Byte Anordnung. Damit quäle ich mich heute Abend nicht mehr. 

Gute Nacht!


----------



## Steve81 (9 Dezember 2007)

zotos schrieb:


> Ich habe mich gerade an die Umsetzung von CoDeSys-ST auf Step7-SCL gewagt.
> 
> Also ich hänge gerade an der beschissenen Step7 Byte Anordnung. Damit quäle ich mich heute Abend nicht mehr.
> 
> Gute Nacht!


 
Also ich komm heut Abend auch nicht mehr dazu aber hoffentlich morgen. Wobei es da auch eng wird, da ich geschätlich unterwegs bin.  

Werde mich mal nach einem Handbung für CoDeSys-ST umsehen (falls ich nichts finde könnt ihr mir bestimmt auch weiterhelfen) damit mir die Umsetzung auf S7-SCL leichter fällt.
Danke nochmal für die Unterstützung, kann ich wirklich gut gebrauchen als "SCL-Anfänger".


----------



## zotos (10 Dezember 2007)

Wie kann man sich das nur freiwillig zumuten? Siemens Byteverknotung am Morgen. Und wer jetzt kommt und diese Scheiß Siemens Byteanordnung noch gut heißt, der zählt zu dem Rudel hirnloser Irrer, die als erste an die Wand gestellt werden, wenn die Revolution kommt.

So die Siemensianische Byteseuche ist bewältigt. 

Der Algorithmus kommt mit PLCsim auf meinem Rechner auch ca 240ms Wobei dies mit einer Zykluszeit von ca 20ms schon etwas an die Resourchen geht. Also wenn man die Abbruchbedingung der While-Schleife von 512 auf einen kleineren Wert setzt geht die Zykluszeit wieder runter dafür wird die Laufzeit der Algorithmus etwas größer. Das muss man aber wohl mit dem Rest des Programms auf der Realen Hardware Testen und dann schauen das man bei Lauf- und Zykluszeit nicht an die Grenze geht.


----------



## zotos (10 Dezember 2007)

Also um die Funktionsweise dieses Algorithmus zu verstehen rate ich das den ST-Code oben zu lesen da hier im SCL Code keine Zuordnung der Bits mehr zu verstehen ist ohne laut zu fluchen.

Hier die Siemens Bytewurschtelversion:

```
FUNCTION_BLOCK FB10
VAR_INPUT
  ENABLE         :BOOL;
  Target         :REAL;
  IN_Real_01     :REAL;
  IN_Real_02     :REAL;
  IN_Real_03     :REAL;
  IN_Real_04     :REAL;
  IN_Real_05     :REAL;    
  IN_Real_06     :REAL;
  IN_Real_07     :REAL;
  IN_Real_08     :REAL;
  IN_Real_09     :REAL;
  IN_Real_10     :REAL;    
  IN_Real_11     :REAL;
  IN_Real_12     :REAL;
  IN_Real_13     :REAL;
  IN_Real_14     :REAL;
  IN_Real_15     :REAL;    
  IN_Real_16     :REAL;
  IN_Real_17     :REAL;
  IN_Real_18     :REAL;
  IN_Real_19     :REAL;
  IN_Real_20     :REAL;    
  
END_VAR

VAR
  myENABLE      :BOOL;
  myOptimum     :REAL;
  myOptimumCom  :DWORD;
  myOptimum_Array  AT myOptimumCom :ARRAY[0..31] OF BOOL;
  myDWORD_1     :DWORD;
  myDWORD_2     :DWORD;
  myDWORD_3     :DWORD;
  myDWORD_4     :DWORD;
  myDWORD_C     :DWORD;
  myDWORD_Array  AT myDWORD_C :ARRAY[0..31] OF BOOL;  
  myActual      :REAL;
  myRealArray   :ARRAY[0..31] OF REAL;
  
  myCount       :INT;
END_VAR

VAR_OUTPUT
  BUSY       :BOOL;
  Optimum    :REAL;
  OUT_01     :BOOL;
  OUT_02     :BOOL;
  OUT_03     :BOOL;
  OUT_04     :BOOL;
  OUT_05     :BOOL;
  OUT_06     :BOOL;
  OUT_07     :BOOL;
  OUT_08     :BOOL;
  OUT_09     :BOOL;
  OUT_10     :BOOL;
  OUT_11     :BOOL;
  OUT_12     :BOOL;
  OUT_13     :BOOL;
  OUT_14     :BOOL;
  OUT_15     :BOOL;
  OUT_16     :BOOL;
  OUT_17     :BOOL;
  OUT_18     :BOOL;
  OUT_19     :BOOL;
  OUT_20     :BOOL;
END_VAR


IF ENABLE AND NOT myENABLE THEN (* Eine positive Flanke am Enable dient als Startsignal *)
  (* Initialisierung  *)
  myActual     := 0.0;
  myOptimum    := 0.0;
  myOptimumCom := 0;
  myDWORD_1    := 0; (* Kleinstwertige Variation von zwei Bits *)
  myDWORD_2    := 0; (* " *)
  myDWORD_3    := 1; (* " *)
  myDWORD_4    := 2; (* " *)
  BUSY         := TRUE;
  myCount      := 0;
  myRealArray[ 0] := IN_Real_01; 
  myRealArray[ 1] := IN_Real_02; 
  myRealArray[ 2] := IN_Real_03; 
  myRealArray[ 3] := IN_Real_04; 
  myRealArray[ 4] := IN_Real_05; 
  myRealArray[ 5] := IN_Real_06; 
  myRealArray[ 6] := IN_Real_07; 
  myRealArray[ 7] := IN_Real_08; 
  myRealArray[ 8] := IN_Real_09; 
  myRealArray[ 9] := IN_Real_10; 
  myRealArray[10] := IN_Real_11; 
  myRealArray[11] := IN_Real_12; 
  myRealArray[12] := IN_Real_13; 
  myRealArray[13] := IN_Real_14; 
  myRealArray[14] := IN_Real_15; 
  myRealArray[15] := IN_Real_16; 
  myRealArray[16] := IN_Real_17; 
  myRealArray[17] := IN_Real_18; 
  myRealArray[18] := IN_Real_19; 
  myRealArray[19] := IN_Real_20;   
ELSIF BUSY THEN

  WHILE myCount < 512 AND BUSY DO (* Schleife wie viele Durchläufe max. pro SPS Zyklus gemacht werden *)

    (* Kombiniertes DWORD erstellen *)
    myDWORD_C := myDWORD_1 OR myDWORD_2 OR myDWORD_3 OR myDWORD_4;

    (* Gewichtsberechnung der aktuellen Kombination *)
     myActual := 0.0;
    IF myDWORD_Array[24] THEN myActual := myActual + myRealArray[ 0]; END_IF;
    IF myDWORD_Array[25] THEN myActual := myActual + myRealArray[ 1]; END_IF;
    IF myDWORD_Array[26] THEN myActual := myActual + myRealArray[ 2]; END_IF;
    IF myDWORD_Array[27] THEN myActual := myActual + myRealArray[ 3]; END_IF;
    IF myDWORD_Array[28] THEN myActual := myActual + myRealArray[ 4]; END_IF;
    IF myDWORD_Array[29] THEN myActual := myActual + myRealArray[ 5]; END_IF;
    IF myDWORD_Array[30] THEN myActual := myActual + myRealArray[ 6]; END_IF;
    IF myDWORD_Array[31] THEN myActual := myActual + myRealArray[ 7]; END_IF;
    IF myDWORD_Array[16] THEN myActual := myActual + myRealArray[ 8]; END_IF;
    IF myDWORD_Array[17] THEN myActual := myActual + myRealArray[ 9]; END_IF;
    IF myDWORD_Array[18] THEN myActual := myActual + myRealArray[10]; END_IF;
    IF myDWORD_Array[19] THEN myActual := myActual + myRealArray[11]; END_IF;
    IF myDWORD_Array[20] THEN myActual := myActual + myRealArray[12]; END_IF;
    IF myDWORD_Array[21] THEN myActual := myActual + myRealArray[13]; END_IF;
    IF myDWORD_Array[22] THEN myActual := myActual + myRealArray[14]; END_IF;
    IF myDWORD_Array[23] THEN myActual := myActual + myRealArray[15]; END_IF;
    IF myDWORD_Array[ 8] THEN myActual := myActual + myRealArray[16]; END_IF;
    IF myDWORD_Array[ 9] THEN myActual := myActual + myRealArray[17]; END_IF;
    IF myDWORD_Array[10] THEN myActual := myActual + myRealArray[18]; END_IF;
    IF myDWORD_Array[11] THEN myActual := myActual + myRealArray[19]; END_IF;
    
    (* Kombination bewerten *)
    IF ABS(myActual - Target) < ABS(myOptimum - Target) THEN
      myOptimum := myActual;
      myOptimumCom := myDWORD_C;
    END_IF;
  
    (* Dank Siemens nicht mehr zu kapieren. Die 11,10,9,8 sind die hochwertigen Bits *)

    IF myDWORD_Array[11] AND myDWORD_Array[10] AND myDWORD_Array[9] AND myDWORD_Array[8] THEN (* Fertig *) 
      (* Ausgabe! *)
      Optimum    := myOptimum;
      BUSY       := FALSE;      
      OUT_01 := myOptimum_Array[24]; 
      OUT_02 := myOptimum_Array[25]; 
      OUT_03 := myOptimum_Array[26]; 
      OUT_04 := myOptimum_Array[27]; 
      OUT_05 := myOptimum_Array[28]; 
      OUT_06 := myOptimum_Array[29]; 
      OUT_07 := myOptimum_Array[30]; 
      OUT_08 := myOptimum_Array[31]; 
      OUT_09 := myOptimum_Array[16]; 
      OUT_10 := myOptimum_Array[17]; 
      OUT_11 := myOptimum_Array[18]; 
      OUT_12 := myOptimum_Array[19]; 
      OUT_13 := myOptimum_Array[20]; 
      OUT_14 := myOptimum_Array[21]; 
      OUT_15 := myOptimum_Array[22]; 
      OUT_16 := myOptimum_Array[23]; 
      OUT_17 := myOptimum_Array[ 8]; 
      OUT_18 := myOptimum_Array[ 9]; 
      OUT_19 := myOptimum_Array[10]; 
      OUT_20 := myOptimum_Array[11];             
    ELSE
      IF myDWORD_Array[11] AND myDWORD_Array[10] AND myDWORD_Array[9] THEN  (* Schiebe alle vier Bits *)
        IF myDWORD_1 = 0 THEN (* Übergang von 3 auf 4 Bit *)
          myDWORD_1 := 1;
        ELSE
          myDWORD_1 := SHL(IN:=myDWORD_1,N:=1);
        END_IF;

        myDWORD_2 := SHL(IN:=myDWORD_1,N:=1);
        myDWORD_3 := SHL(IN:=myDWORD_2,N:=1);
        myDWORD_4 := SHL(IN:=myDWORD_3,N:=1);
      ELSE
        IF myDWORD_Array[11] AND myDWORD_Array[10] THEN (* Schiebe die drei hochwertigen Bits *)
          IF myDWORD_2 = 0 THEN (* Übergang von 2 auf 3 Bit *)
            myDWORD_2 := 1;
          ELSE
            myDWORD_2 := SHL(IN:=myDWORD_2,N:=1);
          END_IF;
          myDWORD_3 := SHL(IN:=myDWORD_2,N:=1);
          myDWORD_4 := SHL(IN:=myDWORD_3,N:=1);
        ELSE
          IF myDWORD_Array[11] THEN (* Schiebe die zwei hochwertigen Bits *)
            myDWORD_3 := SHL(IN:=myDWORD_3,N:=1);
            myDWORD_4 := SHL(IN:=myDWORD_3,N:=1);
          ELSE
            myDWORD_4 := SHL(IN:=myDWORD_4,N:=1); (* Schiebe nur das höchstwertige Bit *)
          END_IF;
        END_IF;
      END_IF;
    END_IF;
    myCount := myCount + 1; (* Zähler zur Zyklus Verteilung inkrementieren *)
  END_WHILE;
  myCount := 0; (* Zähler zur Zyklus Verteilung nullen *)
END_IF;

myENABLE := ENABLE; (* Wert für Flankenerkennung *)

END_FUNCTION_BLOCK
```


----------



## Larry Laffer (10 Dezember 2007)

zotos schrieb:


> Also um die Funktionsweise dieses Algorithmus zu verstehen rate ich das den ST-Code oben zu lesen da hier im SCL Code keine Zuordnung der Bits mehr zu verstehen ist ohne laut zu fluchen.


 
@Zotos:
Hast du in dem Zusammenhang mal den AT-Befehl erwogen ?
Damit hättest du dir doch eine Zuordnung erzeugen können, die deiner Bit-Adressierung von ST entspricht ...


----------



## zotos (10 Dezember 2007)

Larry Laffer schrieb:


> @Zotos:
> Hast du in dem Zusammenhang mal den AT-Befehl erwogen ?
> Damit hättest du dir doch eine Zuordnung erzeugen können, die deiner Bit-Adressierung von ST entspricht ...



Hast Du Dir mal meinen SCL Code Angeschaut da sind AT-Befehle drin und das ist KEINESWEGS so wie in ST.

Hier was zum Hirnverknoten:


```
OUT_01 := myOptimum_Array[24];
OUT_02 := myOptimum_Array[25];
OUT_03 := myOptimum_Array[26];
OUT_04 := myOptimum_Array[27];
OUT_05 := myOptimum_Array[28];
OUT_06 := myOptimum_Array[29];
OUT_07 := myOptimum_Array[30];
OUT_08 := myOptimum_Array[31];
OUT_09 := myOptimum_Array[16];
OUT_10 := myOptimum_Array[17];
OUT_11 := myOptimum_Array[18];
OUT_12 := myOptimum_Array[19];
OUT_13 := myOptimum_Array[20];
OUT_14 := myOptimum_Array[21];
OUT_15 := myOptimum_Array[22];
OUT_16 := myOptimum_Array[23];
OUT_17 := myOptimum_Array[ 8];
OUT_18 := myOptimum_Array[ 9];
OUT_19 := myOptimum_Array[10];
OUT_20 := myOptimum_Array[11];
```


----------



## Larry Laffer (10 Dezember 2007)

...
ich hatte in Anlehnung an dein erstes Beispiel gedacht :

```
myDWORD_C : DWORD :
myDWORD_C_Bits at my DWORD_C : struct 
                   b24 : bool ;
                   b25 : bool ;
                   etc ...
                   end_struct ;
```
 
Entschuldige bitte, falls wir uns da missverstanden haben ...


----------



## zotos (10 Dezember 2007)

Larry Laffer schrieb:


> ...
> ich hatte in Anlehnung an dein erstes Beispiel gedacht :
> 
> ```
> ...



Die Idee mit dem Struct gefällt mir gut.

Aber ich denke ab hier kann der Steve81 den Code Anpassen. z.B. kann man die Suche Abrechen wenn der aktuelle Wert gleich dem Sollwert ist da das Ergebnis dann ja nicht mehr besser werden kann.


----------



## Steve81 (10 Dezember 2007)

Guten Abend,

schön dass ihr euch heute nochmal mit dem Thema beschäftigt habt. Ich denke dass ich dank eurer Hilfe die Problematik recht praxistauglich lösen kann. 

Vielen Dank noch mal an alle Helfer!!!


----------



## zotos (11 Dezember 2007)

Steve81 schrieb:


> Guten Abend,
> 
> schön dass ihr euch heute nochmal mit dem Thema beschäftigt habt. Ich denke dass ich dank eurer Hilfe die Problematik recht praxistauglich lösen kann.
> 
> Vielen Dank noch mal an alle Helfer!!!



Gern geschehen. Aber Du hältst uns doch bitte auf dem Laufenden. Würde mich ja schon interessieren wie performant der Algorithmus, auf einer Realen Hardware, läuft. Bist Du mit dem Beispielprojekt klar gekommen?


----------



## Steve81 (11 Dezember 2007)

zotos schrieb:


> Gern geschehen. Aber Du hältst uns doch bitte auf dem Laufenden. Würde mich ja schon interessieren wie performant der Algorithmus, auf einer Realen Hardware, läuft. Bist Du mit dem Beispielprojekt klar gekommen?


 
Natürlich halte ich euch auf dem Laufenden, schließlich will man ja wenn man Hilft auch wissen was dabei heraus kommt. (kann aber noch etwas dauern bis das Projekt fertig ist)

Mit dem Bsp. bin ich sehr gut zurecht gekommen (trotz bekloppter Byteanordnung von Siemens).
Muss jetzt nur noch einen Teil von meiner Quelle mit deiner verheiraten (Toleranzauswertung) und dann müsste es ganz gut funktionieren.

Hab mir jetzt auch mal die CoDeSys Software runtergeladen um damit ein bisschen rum zu probieren. Mach auf den ersten Blick einen echt guten Eindruck!


----------



## Steve81 (12 Dezember 2007)

So, ich hab jetzt die SCL-Quelle 3aus20 (machte allerdings 2-4 aus 20) von Zotos auf jetzt wirklich 3aus20 geändert und mit meiner Toleranzauswertung versehen!

Sieht jetzt so aus:


```
FUNCTION_BLOCK FB33
VAR_INPUT
  ENABLE         :BOOL;
  Sollgewicht    :REAL;
  Ideal_Tol      :REAL;
  min_Gewicht_p_St :REAL;
  max_Gewicht_p_St :REAL;
  Max_Diff_max_min :REAL;
  max_Plus_Abw_Soll:REAL;
  Gewicht_01     :REAL;
  Gewicht_02     :REAL;
  Gewicht_03     :REAL;
  Gewicht_04     :REAL;
  Gewicht_05     :REAL;    
  Gewicht_06     :REAL;
  Gewicht_07     :REAL;
  Gewicht_08     :REAL;
  Gewicht_09     :REAL;
  Gewicht_10     :REAL;    
  Gewicht_11     :REAL;
  Gewicht_12     :REAL;
  Gewicht_13     :REAL;
  Gewicht_14     :REAL;
  Gewicht_15     :REAL;    
  Gewicht_16     :REAL;
  Gewicht_17     :REAL;
  Gewicht_18     :REAL;
  Gewicht_19     :REAL;
  Gewicht_20     :REAL;    
 
END_VAR
VAR
  FP_ENABLE      :BOOL;
  Ist_Ideal     :REAL;
  Ist_IdealCom  :DWORD;
  Ist_Ideal_Array  AT Ist_IdealCom :ARRAY[0..31] OF BOOL;
  DWORD_1     :DWORD;
  DWORD_2     :DWORD;
  DWORD_3     :DWORD;
  DWORD_4     :DWORD;
  DWORD_C     :DWORD;
  DWORD_Array  AT DWORD_C :ARRAY[0..31] OF BOOL;  
  Actual      :REAL;
  RealArray   :ARRAY[0..31] OF REAL;  
  Count       :INT;
  Sort        :INT;
  SortArray   :ARRAY[0..31] OF REAL;
  MINIMUM     :REAL;
  MAXIMUM     :REAL;
  Treffer     :BOOL;
END_VAR
VAR_OUTPUT
  BUSY       :BOOL;
  Optimum    :REAL;
  Waage_01     :BOOL;
  Waage_02     :BOOL;
  Waage_03     :BOOL;
  Waage_04     :BOOL;
  Waage_05     :BOOL;
  Waage_06     :BOOL;
  Waage_07     :BOOL;
  Waage_08     :BOOL;
  Waage_09     :BOOL;
  Waage_10     :BOOL;
  Waage_11     :BOOL;
  Waage_12     :BOOL;
  Waage_13     :BOOL;
  Waage_14     :BOOL;
  Waage_15     :BOOL;
  Waage_16     :BOOL;
  Waage_17     :BOOL;
  Waage_18     :BOOL;
  Waage_19     :BOOL;
  Waage_20     :BOOL;
END_VAR
 
IF ENABLE AND NOT FP_ENABLE THEN (* Eine positive Flanke am Enable dient als Startsignal *)
  (* Initialisierung  *)
  Actual     := 0.0;
  Sort       :=0;
  Treffer    :=FALSE;
  Ist_Ideal    := 0.0;
  Ist_IdealCom := 0;
  DWORD_1    := 1; (* Kleinstwertige Variation von drei Bits *)
  DWORD_2    := 2; (* " *)
  DWORD_3    := 4; (* " *)
  //DWORD_4    := 2; (* " *)
  BUSY         := TRUE;
  Count      := 0;
  RealArray[ 0] := Gewicht_01; 
  RealArray[ 1] := Gewicht_02; 
  RealArray[ 2] := Gewicht_03; 
  RealArray[ 3] := Gewicht_04; 
  RealArray[ 4] := Gewicht_05; 
  RealArray[ 5] := Gewicht_06; 
  RealArray[ 6] := Gewicht_07; 
  RealArray[ 7] := Gewicht_08; 
  RealArray[ 8] := Gewicht_09; 
  RealArray[ 9] := Gewicht_10; 
  RealArray[10] := Gewicht_11; 
  RealArray[11] := Gewicht_12; 
  RealArray[12] := Gewicht_13; 
  RealArray[13] := Gewicht_14; 
  RealArray[14] := Gewicht_15; 
  RealArray[15] := Gewicht_16; 
  RealArray[16] := Gewicht_17; 
  RealArray[17] := Gewicht_18; 
  RealArray[18] := Gewicht_19; 
  RealArray[19] := Gewicht_20;   
ELSIF BUSY THEN
  WHILE Count < 512 AND BUSY DO (* Schleife wie viele Durchläufe max. pro SPS Zyklus gemacht werden *)
    (* Kombiniertes DWORD erstellen *)
    DWORD_C := DWORD_1 OR DWORD_2 OR DWORD_3;
    (* Gewichtsberechnung der aktuellen Kombination *)
     Actual := 0.0;
     Sort := 0;
    IF DWORD_Array[24] THEN 
        Actual := Actual + RealArray[ 0]; 
        SortArray[Sort] := RealArray[ 0];
        Sort := Sort+1;   
    END_IF;
    IF DWORD_Array[25] THEN 
        Actual := Actual + RealArray[ 1];
        SortArray[Sort] := RealArray[ 1];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[26] THEN 
        Actual := Actual + RealArray[ 2];
        SortArray[Sort] := RealArray[ 2];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[27] THEN 
        Actual := Actual + RealArray[ 3];
        SortArray[Sort] := RealArray[ 3];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[28] THEN 
        Actual := Actual + RealArray[ 4];
        SortArray[Sort] := RealArray[ 4];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[29] THEN 
        Actual := Actual + RealArray[ 5];
        SortArray[Sort] := RealArray[ 5];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[30] THEN 
        Actual := Actual + RealArray[ 6];
        SortArray[Sort] := RealArray[ 6];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[31] THEN 
        Actual := Actual + RealArray[ 7];
        SortArray[Sort] := RealArray[ 7];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[16] THEN 
        Actual := Actual + RealArray[ 8];
        SortArray[Sort] := RealArray[ 8];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[17] THEN 
        Actual := Actual + RealArray[ 9];
        SortArray[Sort] := RealArray[ 9];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[18] THEN 
        Actual := Actual + RealArray[10];
        SortArray[Sort] := RealArray[10];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[19] THEN 
        Actual := Actual + RealArray[11];
        SortArray[Sort] := RealArray[11];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[20] THEN 
        Actual := Actual + RealArray[12];
        SortArray[Sort] := RealArray[12];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[21] THEN 
        Actual := Actual + RealArray[13];
        SortArray[Sort] := RealArray[13];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[22] THEN 
        Actual := Actual + RealArray[14];
        SortArray[Sort] := RealArray[14];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[23] THEN 
        Actual := Actual + RealArray[15];
        SortArray[Sort] := RealArray[15];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[ 8] THEN 
        Actual := Actual + RealArray[16];
        SortArray[Sort] := RealArray[16];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[ 9] THEN 
        Actual := Actual + RealArray[17];
        SortArray[Sort] := RealArray[17];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[10] THEN 
        Actual := Actual + RealArray[18];
        SortArray[Sort] := RealArray[18];
        Sort := Sort+1; 
    END_IF;
    IF DWORD_Array[11] THEN 
        Actual := Actual + RealArray[19];
        SortArray[Sort] := RealArray[19];
        Sort := Sort+1; 
    END_IF;
Sort := Sort-1;
MINIMUM:=9.9E37;
MAXIMUM:=-9.9e37;
REPEAT
    IF SortArray[Sort] < MINIMUM THEN
        MINIMUM:=SortArray[Sort];
    END_IF;
    IF SortArray[Sort] > MAXIMUM THEN
        MAXIMUM:=SortArray[Sort];
    END_IF;
    Sort:=Sort-1;
  UNTIL Sort=-1
END_REPEAT;
 
    (* Kombination bewerten *)
    IF (MAXIMUM <= max_Gewicht_p_St) AND (MINIMUM >= min_Gewicht_p_St) AND ((MAXIMUM - MINIMUM) <= Max_Diff_max_min) AND (Actual <= (Sollgewicht + max_Plus_Abw_Soll)) AND (Actual >= Sollgewicht) THEN
 
        IF (Actual >= Sollgewicht) AND (Actual <= (Sollgewicht+Ideal_Tol)) THEN
            Ist_Ideal := Actual ;
            Ist_IdealCom := DWORD_C ;
            Treffer := TRUE ;
 
        ELSIF (Actual > Ist_Ideal) AND (Sollgewicht > Ist_Ideal) THEN
            Ist_Ideal := Actual ;
            Ist_IdealCom := DWORD_C ;            
 
        ELSIF (Sollgewicht < Ist_Ideal) AND (Actual < Ist_Ideal) AND (Sollgewicht < Actual) THEN
            Ist_Ideal := Actual ;
            Ist_IdealCom := DWORD_C ;            
 
        END_IF ;
    END_IF ;
 
    (* Dank Siemens nicht mehr zu kapieren. Die 11,10,9,8 sind die hochwertigen Bits *)
    IF DWORD_Array[11] AND DWORD_Array[10] AND DWORD_Array[9] OR Treffer THEN (* Fertig *) 
      (* Ausgabe! *)
      Optimum    := Ist_Ideal;
      BUSY       := FALSE;      
      Waage_01 := Ist_Ideal_Array[24]; 
      Waage_02 := Ist_Ideal_Array[25]; 
      Waage_03 := Ist_Ideal_Array[26]; 
      Waage_04 := Ist_Ideal_Array[27]; 
      Waage_05 := Ist_Ideal_Array[28]; 
      Waage_06 := Ist_Ideal_Array[29]; 
      Waage_07 := Ist_Ideal_Array[30]; 
      Waage_08 := Ist_Ideal_Array[31]; 
      Waage_09 := Ist_Ideal_Array[16]; 
      Waage_10 := Ist_Ideal_Array[17]; 
      Waage_11 := Ist_Ideal_Array[18]; 
      Waage_12 := Ist_Ideal_Array[19]; 
      Waage_13 := Ist_Ideal_Array[20]; 
      Waage_14 := Ist_Ideal_Array[21]; 
      Waage_15 := Ist_Ideal_Array[22]; 
      Waage_16 := Ist_Ideal_Array[23]; 
      Waage_17 := Ist_Ideal_Array[ 8]; 
      Waage_18 := Ist_Ideal_Array[ 9]; 
      Waage_19 := Ist_Ideal_Array[10]; 
      Waage_20 := Ist_Ideal_Array[11];             
    ELSE
      IF DWORD_Array[11] AND DWORD_Array[10] THEN  (* Schiebe alle drei Bits *)
 
        DWORD_1 := SHL(IN:=DWORD_1,N:=1);
        DWORD_2 := SHL(IN:=DWORD_1,N:=1);
        DWORD_3 := SHL(IN:=DWORD_2,N:=1);
      ELSE
        IF DWORD_Array[11] THEN (* Schiebe die zwei hochwertigen Bits *)
 
          DWORD_2 := SHL(IN:=DWORD_2,N:=1);
          DWORD_3 := SHL(IN:=DWORD_2,N:=1);
 
        ELSE
          DWORD_3 := SHL(IN:=DWORD_3,N:=1); (* Schiebe nur das höchstwertige Bit *)
        END_IF;
      END_IF;      
    END_IF;
    Count := Count + 1; (* Zähler zur Zyklus Verteilung inkrementieren *)
  END_WHILE;
  Count := 0; (* Zähler zur Zyklus Verteilung nullen *)
END_IF;
FP_ENABLE := ENABLE; (* Wert für Flankenerkennung *)
END_FUNCTION_BLOCK
```
 
Die 20 IF abfragen könnte ich eventuell noch in eine Schleife packen wenn ich die Bits im DWORD_Array einem zusätzliches Array so zuordne, dass ich eine "Vernünftige" und keine "Siemenssche" Byteanordnung mit von 0 an aufsteigenden Bits (wie bei ST) bekomme.
Denke aber dass es nur optisch besser aussehen würde mich dafür aber etwas Bearbeitungszeit kosten würde.


----------



## Perfektionist (12 Dezember 2007)

nAbend Steve81,

mich würd noch ein wenig interessieren, wie Deine Maschine beschaffen ist. Ich kenne da im wesentlichen zwei Ausprägungen:

Stückige Güter: Äpfel, Schnitzel, Käsestücke sollen zu einem Sollgewicht kombiniert werden.

Schüttgut: Chips, Bonbons, ... etc. werden per Rüttler in Wägeschalen befördert. Dabei sind Wägeschalen mit besonders hohen Gewichten mit Vorrang zu entleeren, weil sie sonst mit mehr als Sollgewicht befüllt sind, weil der Rüttler immer alle mitsammen voller füllt ....

Ich frach mal so dumm - weil bei Schüttgut wird das nämlich in Zusammenhang mit Rüttler so richtig blöd ... (habs selbst nie gemacht, aber halt schon live bei Bonbon-Kunde selbst gesehen und dann drüber nachgedacht - auch die Käsestückevariante ist mir schon live begegnet).

Gruß!


----------



## Steve81 (12 Dezember 2007)

Es handelt sich um Stückige Güter (Gemüse) deren Einzelgewichte über Klappwagen ermittelt wird. Das Gemüse muss mit einer vorgegebenen Stückzahl ein vorgegebenes Gewicht erreichen und verpackt werden.


----------



## kiestumpe (13 Dezember 2007)

Das heißt es ist eigentlich vollkommen Wurscht ob die einmal 10 Karotten und 1 Bohne abpacken oder umgekehrt, hauptsache es ist immer 1kg Gemüse in der Packung ?!?

Seltsames vorgehen...


----------



## Steve81 (13 Dezember 2007)

kiestumpe schrieb:


> Das heißt es ist eigentlich vollkommen Wurscht ob die einmal 10 Karotten und 1 Bohne abpacken oder umgekehrt, hauptsache es ist immer 1kg Gemüse in der Packung ?!?
> 
> Seltsames vorgehen...


Natürlich nicht!

1. Immer nur eine Gemüsesorte! 
2. Das Gewicht muss durch eine vorgegebene Stückzahl erreicht werden! (z.B. muss 1kg immer aus 5 Einzelgewichten bestehen also z.B. 5Karotten mit je 200g)

Hab ich aber schon geschrieben:


> Das Gemüse muss mit einer vorgegebenen Stückzahl ein vorgegebenes Gewicht erreichen und verpackt werden.


3. Es gibt verschiedene Toleranzen! (z.B. dürfen die Einzelgewichte nicht zu leicht oder zu schwer sein und die Differenz zwischen dem leichtesten und dem schwersten darf auch nicht zu groß sein.)


----------



## kiestumpe (13 Dezember 2007)

Sorry, war mir nicht klar- du meintest es handelt sich immer nur um eine Sorte.
Gemüse = Kartoffel, Karotten, Wirsing, etc.
Stückzahl = 9 = 4 Kartoffel + 5 Karotten = 2 Kartoffel + 7 Karotten ;-)

Naja, lassen wir das ;-)


----------



## Steve81 (13 Dezember 2007)

kiestumpe schrieb:


> Sorry, war mir nicht klar- du meintest es handelt sich immer nur um eine Sorte.
> Gemüse = Kartoffel, Karotten, Wirsing, etc.
> Stückzahl = 9 = 4 Kartoffel + 5 Karotten = 2 Kartoffel + 7 Karotten ;-)
> 
> Naja, lassen wir das ;-)


 
Ist aber garnicht so abwegig was du da schreibst, man bekommt ja auch so Gemüsemischungen zu kaufen.
Aber bei mir handelt es sich zum Glück immer nur um eine Sorte.


----------



## kiestumpe (13 Dezember 2007)

genau, hab ich neulich auch im Supermarkt gesehen - und bei Aldi.

Ich hab da spontan an die Ausmischanlage für Fruchtsaft gedacht die ich früher mal Programmiert habe- aber das Rezept wurde da natürlich vom Operator eingegeben, wir musste nur dafür sorgen, dass bei Angaben von 2400l Sirup das auch +/-10 im Tank drinnen war...

(Aber es war nicht nur Sirup drinnen)


----------



## Steve81 (13 Dezember 2007)

kiestumpe schrieb:


> (Aber es war nicht nur Sirup drinnen)


 
Also ob auch wirklich das gleiche (oder selbe?) Gemüse drin liegt kontrolliere ich nicht. Wenn sich mal eine Ratte in die Anlage verirrt, die das Passende Gewicht hat, wird die auch verpackt!


----------



## zotos (14 Dezember 2007)

Nach dem Du ja nun zu dem Algorithmus gegriffen hast, der nur die 3er Kombinationen prüft (also 1140 Durchläufe), solltest Du vielleicht noch den Wiederholungszähler von 512 auf einen kleineren Wert setzen. Da dieser Thread ja eigentlich um das Problem mit der stark erhöhten Zykluszeit abzielte.

Damit würden sich die zwei Peaks in der Zykluszeit auch vermeiden lassen. Ich denke das man mit einem Wert um die 200-300 für die While-Schleife deutlich  besser liegen würde.


----------



## Steve81 (15 Dezember 2007)

zotos schrieb:


> Nach dem Du ja nun zu dem Algorithmus gegriffen hast, der nur die 3er Kombinationen prüft (also 1140 Durchläufe), solltest Du vielleicht noch den Wiederholungszähler von 512 auf einen kleineren Wert setzen. Da dieser Thread ja eigentlich um das Problem mit der stark erhöhten Zykluszeit abzielte.
> 
> Damit würden sich die zwei Peaks in der Zykluszeit auch vermeiden lassen. Ich denke das man mit einem Wert um die 200-300 für die While-Schleife deutlich besser liegen würde.


 
Hallo,

bin bereits auf 256 gegangen. 
Der FB der mir irgendeine Kombination aus 10 errechnet, allerding alle Konstellationen mit BITSUM überprüft, läuft mittlerweile auf einer Anlage mit 10 Waagen. Der Kunde wollte plötzlich 3er bis 6er Packs.
Ich werde wohl mehrere Bausteine für alle möglichen Kombinatioen schreiben müssen und je nach bedarf diese dann aufrufen.


----------

