Probleme mit Zykluszeit

Steve81

Level-1
Beiträge
505
Reaktionspunkte
77
Zuviel Werbung?
-> Hier kostenlos registrieren
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?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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.
 

Stimmt!

und hier mal der Code:

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?
 
...
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 ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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.

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;
     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
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).
 
Zuletzt bearbeitet:
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.
 
Ich habe mal einfach eine FOR-Schleife die von 0..1023 läuft auf 8 SPS Zyklen verteilt.

Code:
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;
 
es wird nichts nützen

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.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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 ...
 
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.
...

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.
 
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.


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;  
     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)
 
...
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.

Code:
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.
Code:
Bereich    
0..1048575
Bits     Kombinationen
    2 ->  190
    3 -> 1140
    4 -> 4845
2,3,4 -> 6175
 
Ich glaube, es ist vielleicht besser, nicht alle Kombinationen zu berechnen.


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


Gruß, Onkel
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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)
Code:
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.
Code:
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
Code:
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.
Code:
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).
 

Anhänge

  • Gewichtb08_12_07.zip
    343,2 KB · Aufrufe: 7
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.

Code:
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.
Code:
Bereich    
0..1048575
Bits     Kombinationen
    2 ->  190
    3 -> 1140
    4 -> 4845
2,3,4 -> 6175

Hallo Zotos,

mit welcher Gleichung kommst du auf die Kombinationsmöglichkeiten?
Entweder es ist nicht so einfach zu errechnen oder ich steh aufm Schlauch!:confused:
 
Das ist wie bei den Lottozahlen nur statt 6 aus 49 sind es eben 3 aus 20:

Code:
      20!
X =--------
   17! * 3!

bzw. 2 aus 20 oder eben 4 aus 20.
 
Zurück
Oben