SCL Array Initialization and Passing variables

ajaysharma

Member
Join Date
Dec 2011
Location
darmstadt
Posts
11
Hello I am writing a small code, I have two problems populating the arrays? I am getting an error Non-existing identifier. I also need help to optimize the code in terms of cycle time/ performance. Can some one also let me know procedure for simulation/debug this.

FUNCTION FC38: VOID

// Block Parameters
VAR_INPUT
// Input Parameters
PositionDB : INT;
ForceDB : INT;

AnalysisMode : INT;
NumPointsAverage : INT;
ServoPosOffest : REAL;
LgDiaForceDelta : REAL;
SmDiaForceDelta : REAL;
MinForceExpected : REAL;
PointOffset : INT;

END_VAR

VAR_IN_OUT
// I/O Parameters
DoneGood : BOOL;
DoneFail : BOOL;
END_VAR

VAR_OUTPUT
// Output Parameters
FinalForce : REAL;
SmDia_StartForce : REAL;
SmDia_StartPosition : REAL;
SmDia_EndForce : REAL;
SmDia_EndPosition : REAL;
LgDia_StartForce : REAL;
LgDia_StartPosition : REAL;

END_VAR

VAR_TEMP
// Temporary Variables
temp : BOOL;
PositionDBWord : WORD;
ForceDBWord : WORD;

x : WORD;
y : INT;
z : DWORD;
i : INT;
j : INT;
Count: INT;
Arraycounter: INT;
kk :INT;
L :DWORD; // Position
LL: DWORD; // StatForce

PreviousForce :REAL;
FinalPosition :REAL;
NumberOfDataPoints :INT;
CurrentForce :REAL;
CurrentPosition :REAL;
Acc_Real :REAL;
ChangeInPosition :REAL;
ChangeInForce :REAL;
StartIndex :INT;
Zone2StartIndex :INT;
Zone2EndIndex:INT;
SmallDia_Start_Index :INT;
Peak_Force_Temp :REAL;
Current_Force_T :REAL;
Previous_Force_Temp :REAL;

SumArray_Force :REAL;
TransArrayForce :REAL;
StartPosition :REAL;
LgDia_StartForce_Temp : REAL;
LgDia_StartPosition_Temp: REAL;


END_VAR

VAR
TransitionForce :ARRAY [1..30] OF REAL;
TransitionPosition :ARRAY [1..30] OF REAL;

END_VAR

LABEL
Fail;
Done;
TopOfCurve;
Scanning;
LgDiaStart;
SmDiaEnd;
SmDiaStart;
TransitionForceCase;

END_LABEL

BEGIN
// Code Section
FinalForce := 0.0;
SmDia_StartForce := 0.0;
SmDia_StartPosition := 0.0;
SmDia_EndForce := 0.0;
SmDia_EndPosition := 0.0;
LgDia_StartForce := 0.0;
LgDia_StartPosition := 0.0;

PreviousForce := 0.0;
FinalPosition:= 0.0;
CurrentForce := 0.0;
CurrentPosition := 0.0;
Acc_Real := 0.0;
ChangeInPosition := 0.0;
ChangeInForce := 0.0;

Peak_Force_Temp := 0.0;
Current_Force_T :=0.0;
Previous_Force_Temp:= 0.0;

DoneGood := 0;
DoneFail := 0;
Arraycounter:=1;

//Array Intialization
// TransitionForce[1..30] OF Real: = 30(0);
FOR Count:= 1 TO 30 DO

TransitionForce [Count] :=0;
TransitionPosition [Count] :=0;
END_FOR;

PositionDBWord := INT_TO_WORD(PositionDB);
ForceDBWord := INT_TO_WORD(ForceDB);

//find number of data points
x := WORD_TO_BLOCK_DB(PositionDBWord).DW[2];
NumberOfDataPoints := WORD_TO_INT (x) - 1; //Data Starts at Zero

y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Acc_Real := DWORD_TO_REAL (z);


// Find the final force by taking the average of the
// data points at the end of the curve. The number
// of data points is an input to the FC.

IF NumPointsAverage > NumberOfDataPoints Then
GOTO Fail;
END_IF;

FOR i := (NumberOfDataPoints - 1)TO (NumberOfDataPoints - NumPointsAverage + 1) BY -1 DO
//Add Current Force To Acc_Real
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Acc_Real := Acc_Real + DWORD_TO_REAL (z);

END_FOR;

FinalForce := Acc_Real/NumPointsAverage;

// LOACTION: TOp of the Curve
// Start scanning from top of the Curve to bottom and

y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Previous_Force_Temp:= DWORD_TO_REAL (z);
FOR i := ((NumberOfDataPoints - 1))TO 10 BY-1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Current_Force_T := DWORD_TO_REAL (z);
Peak_Force_Temp:= Current_Force_T;
IF Current_Force_T > Previous_Force_Temp THEN

Peak_Force_Temp:= Current_Force_T;

ELSE

Previous_Force_Temp:= Current_Force_T;

END_IF;
END_FOR;

// Zone#2= ServoPOS(StartPosition + 5, FinalPosition - Offset Position)


TopOfCurve:
//Get Final Position
y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
FinalPosition := DWORD_TO_REAL (z);

//Get Start Position of the Servo

L:= WORD_TO_BLOCK_DB(PositionDBWord).DW[4];
StartPosition:= DWORD_TO_REAL (L);

LL :=WORD_TO_BLOCK_DB(ForceDBWord).DW[4];
CurrentForce := DWORD_TO_REAL (LL);


FOR i := (NumberOfDataPoints - 1)TO 10 BY -1 DO
//Get Current Position
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
CurrentPosition := DWORD_TO_REAL (z);
ChangeInPosition := FinalPosition - CurrentPosition;

IF ChangeInPosition > ServoPosOffest THEN
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
PreviousForce := DWORD_TO_REAL (z);
StartIndex := i;
Zone2StartIndex:=i;


//Location: Start of SmallDia
// SmDia Start Force AND Start Position

FOR j := 1 TO StartIndex BY 1 DO
IF CurrentForce > MinForceExpected THEN
SmDia_StartForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
SmDia_StartPosition := DWORD_TO_REAL (z);
SmallDia_Start_Index:= j;
GOTO LgDiaStart;
ELSE
PreviousForce := CurrentForce;

END_IF;
END_FOR;

//GOTO Scanning;

END_IF;
END_FOR;
GOTO Fail;


// LOACTION: Start of Large Diameter Press

LgDiaStart:
FOR i := (Zone2StartIndex)TO SmallDia_Start_Index BY -1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
CurrentForce := DWORD_TO_REAL (z);
ChangeInForce := PreviousForce - CurrentForce;

IF ChangeInForce < SmDiaForceDelta THEN //<100
SmDia_EndForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
SmDia_EndPosition := DWORD_TO_REAL (z);

StartIndex := i;
Zone2ENDIndex:= i;
GOTO Scanning;
ELSE
PreviousForce := CurrentForce;
END_IF;
END_FOR;
GOTO Fail;


Scanning:

//Check and Redo

FOR i := (Zone2StartIndex - 1)TO Zone2EndIndex BY -1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
CurrentForce := DWORD_TO_REAL (z);
ChangeInForce := PreviousForce - CurrentForce;

//IF ChangeInForce > 150

IF ChangeInForce > LgDiaForceDelta THEN
LgDia_StartForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
LgDia_StartForce_Temp := PreviousForce;
LgDia_StartPosition_Temp := DWORD_TO_REAL (z);


// The idea is when ever the condition is true I save the valus in the Array
TrasitionForce[Arraycounter]:= LgDia_StartForce_Temp;
// Problem with Arrays
TransitionPosition[Arraycounter]:= LgDia_StartPosition_Temp;

Arraycounter := Arraycounter+1;


ELSE
PreviousForce := CurrentForce;
END_IF;
END_FOR;

IF Arraycounter =1 THEN

GOTO Fail;
ELSE
GOTO TransitionForceCase;
// GOTO SmDiaStart;
END_IF;

TransitionForceCase:

CASE Arraycounter OF

1 :
LgDia_StartForce := TrasitionForce[1];
LgDia_StartPosition :=TransitionPosition[1];

1, 2 :
LgDia_StartForce := TrasitionForce[2];
LgDia_StartPosition :=TransitionPosition[2];

1..5 :

SumArray_Force := TrasitionForce[2]+TrasitionForce[3]+TrasitionForce[4];
LgDia_StartForce := SumArray_Force/3;
LgDia_StartPosition :=TransitionPosition[3];

1..14:

SumArray_Force := TrasitionForce[3]+TrasitionForce[4]+TrasitionForce[5]+TrasitionForce[6];
LgDia_StartForce := SumArray_Force/4;
LgDia_StartPosition :=TransitionPosition[4];


14..30:
SumArray_Force := TrasitionForce[4]+TrasitionForce[5]+TrasitionForce[6]+TrasitionForce[7]+TrasitionForce[8];
LgDia_StartForce := SumArray_Force/5;
LgDia_StartPosition :=TransitionPosition[6];

ELSE

GOTO Fail;


END_CASE;


// GOTO SmDiaStart;
SmDiaStart:
DoneGood := 1;
GOTO Done;

Fail:
DoneFail := 1;

Done:
temp := 1;


END_FUNCTION[/CODE]
 
Use Tia portal to write the code or use notepad++ and this UDL.

Then copy it into simatic manager. It's such a pain writing SCL in simatic manager because of no spellcheck or autocomplete on variables and stuff. Doing a find and replace of Trasition to Transition made it compile without errors though.
 
Last edited:
Can't tell if it was the webpage or if the code was written like that but you need to indent the code. It's unreadable like that.

Also "goto" has no place in structured programming. You need to restructure your code. Error handling might be an exception to that.

Also when there is a lot of type casting in the code (and there is) you should look over what types you are using.

When it comes to optimizing, it's inside the loops you look first because that code is executed the most times. Then floating point operations are slow and but integer is fast. So use real only when you need it.

Also while you could improve execution time maybe 20-30% (sometimes more) by optimizing your code, you can often get 200-300% faster code by optimizing your problem solving method instead. Basically, is there a smarter way to solve this problem?

I don't understand exactly what problem you are trying to solve with your code so can't offer any specific advice.

If you are searching trough your datapoints and they are sorted and you have lots of them, look at using a binary search instead of just scanning thru each one. https://en.wikipedia.org/wiki/Binary_search_algorithm

Different CPUs execute the code at different speed. I suggest just running the code in the CPU you are using and checking the scan time of the program. You can also execute your function block many times just to see how fast it runs. For instance if you run your function a hundred times per scan cycle you'll can easily calculate just how long one cycle takes.
 
Last edited:
I also need help to optimize the code in terms of cycle time/ performance. Can some one also let me know procedure for simulation/debug this.

Do your calcs have to be completed in one scan? if not, convert to an FB, use stat variables and spread the processing over several scans.
 
Example implementation (not tested)

Code:
FUNCTION_block FB38

// Block Parameters
VAR_INPUT
// Input Parameters
PositionDB : INT;
ForceDB : INT;

AnalysisMode : INT;
NumPointsAverage : INT;
ServoPosOffest : REAL;
LgDiaForceDelta : REAL;
SmDiaForceDelta : REAL;
MinForceExpected : REAL;
PointOffset : INT;

END_VAR

VAR_IN_OUT
// I/O Parameters
DoneGood : BOOL;
DoneFail : BOOL;
END_VAR

VAR_OUTPUT
// Output Parameters
FinalForce : REAL;
SmDia_StartForce : REAL;
SmDia_StartPosition : REAL;
SmDia_EndForce : REAL;
SmDia_EndPosition : REAL;
LgDia_StartForce : REAL;
LgDia_StartPosition : REAL;

END_VAR

VAR
    
iInitData:INT:=1;
    

Seq:STRUCT
    bStart:BOOL;
    bStartEdgeStore:BOOL;
    iStepNo:INT;
END_STRUCT; 

  

temp : BOOL;
PositionDBWord : WORD;
ForceDBWord : WORD;

x : WORD;
y : INT;
z : DWORD;
i : INT;
j : INT;
Count: INT;
Arraycounter: INT;
kk :INT;
L: WORD; // Position
LL: DWORD; // StatForce

PreviousForce :REAL;
FinalPosition :REAL;
NumberOfDataPoints :INT;
CurrentForce :REAL;
CurrentPosition :REAL;
Acc_Real :REAL;
ChangeInPosition :REAL;
ChangeInForce :REAL;
StartIndex :INT;
Zone2StartIndex :INT;
Zone2EndIndex:INT;
SmallDia_Start_Index :INT;
Peak_Force_Temp :REAL;
Current_Force_T :REAL;
Previous_Force_Temp :REAL;

SumArray_Force :REAL;
TransArrayForce :REAL;
StartPosition :REAL;
LgDia_StartForce_Temp : REAL;
LgDia_StartPosition_Temp: REAL;


TransitionForce :ARRAY [1..30] OF REAL;
TransitionPosition :ARRAY [1..30] OF REAL;

END_VAR

LABEL
Fail;
Done;
TopOfCurve;
Scanning;
LgDiaStart;
SmDiaEnd;
SmDiaStart;
TransitionForceCase;

END_LABEL

BEGIN

CASE Seq.iStepNo of

0: //init data

// Code Section
FinalForce := 0.0;
SmDia_StartForce := 0.0;
SmDia_StartPosition := 0.0;
SmDia_EndForce := 0.0;
SmDia_EndPosition := 0.0;
LgDia_StartForce := 0.0;
LgDia_StartPosition := 0.0;

PreviousForce := 0.0;
FinalPosition:= 0.0;
CurrentForce := 0.0;
CurrentPosition := 0.0;
Acc_Real := 0.0;
ChangeInPosition := 0.0;
ChangeInForce := 0.0;

Peak_Force_Temp := 0.0;
Current_Force_T :=0.0;
Previous_Force_Temp:= 0.0;

DoneGood := 0;
DoneFail := 0;
Arraycounter:=1;

//Array Intialization
// TransitionForce[1..30] OF Real: = 30(0);
FOR Count:= 1 TO 30 DO

TransitionForce [Count] :=0;
TransitionPosition [Count] :=0;
END_FOR;

PositionDBWord := INT_TO_WORD(PositionDB);
ForceDBWord := INT_TO_WORD(ForceDB);

//find number of data points
x := WORD_TO_BLOCK_DB(PositionDBWord).DW[2];
NumberOfDataPoints := WORD_TO_INT (x) - 1; //Data Starts at Zero

y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Acc_Real := DWORD_TO_REAL (z);

IF NumPointsAverage > NumberOfDataPoints Then
 Seq.iStepNo:=99;// Fail;
ELSE
 Seq.iStepNo:=Seq.istepNo+1;
END_IF;

//.....................

// Find the final force by taking the average of the
// data points at the end of the curve. The number
// of data points is an input to the FC.

1: 

FOR i := (NumberOfDataPoints - 1)TO (NumberOfDataPoints - NumPointsAverage + 1) BY -1 DO
//Add Current Force To Acc_Real
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Acc_Real := Acc_Real + DWORD_TO_REAL (z);

END_FOR;

FinalForce := Acc_Real/NumPointsAverage;

 Seq.iStepNo:=Seq.istepNo+1;

//.....................

2:
// LOACTION: TOp of the Curve
// Start scanning from top of the Curve to bottom and

y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Previous_Force_Temp:= DWORD_TO_REAL (z);
FOR i := ((NumberOfDataPoints - 1))TO 10 BY-1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Current_Force_T := DWORD_TO_REAL (z);
Peak_Force_Temp:= Current_Force_T;
IF Current_Force_T > Previous_Force_Temp THEN

Peak_Force_Temp:= Current_Force_T;

ELSE

Previous_Force_Temp:= Current_Force_T;

END_IF;
END_FOR;

 Seq.iStepNo:=Seq.istepNo+1;

//..............................

3:
// Zone#2= ServoPOS(StartPosition + 5, FinalPosition - Offset Position)


//Get Final Position
y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
FinalPosition := DWORD_TO_REAL (z);

//Get Start Position of the Servo

L:= WORD_TO_BLOCK_DB(PositionDBWord).DW[4];
StartPosition:= DWORD_TO_REAL (L);

LL :=WORD_TO_BLOCK_DB(ForceDBWord).DW[4];
CurrentForce := DWORD_TO_REAL (LL);


FOR i := (NumberOfDataPoints - 1)TO 10 BY -1 DO
//Get Current Position
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
CurrentPosition := DWORD_TO_REAL (z);
ChangeInPosition := FinalPosition - CurrentPosition;

IF ChangeInPosition > ServoPosOffest THEN
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
PreviousForce := DWORD_TO_REAL (z);
StartIndex := i;
Zone2StartIndex:=i;


 Seq.iStepNo:=Seq.istepNo+1;

//..............................



//Location: Start of SmallDia
// SmDia Start Force AND Start Position

FOR j := 1 TO StartIndex BY 1 DO
IF CurrentForce > MinForceExpected THEN
SmDia_StartForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
SmDia_StartPosition := DWORD_TO_REAL (z);
SmallDia_Start_Index:= j;
Seq.iStepNo:=Seq.istepNo+1;

//..............................

ELSE
PreviousForce := CurrentForce;

END_IF;
END_FOR;

//GOTO Scanning;

END_IF;
END_FOR;

 Seq.iStepNo:=99; //failt

//..............................

4:

// LOACTION: Start of Large Diameter Press

FOR i := (Zone2StartIndex)TO SmallDia_Start_Index BY -1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
CurrentForce := DWORD_TO_REAL (z);
ChangeInForce := PreviousForce - CurrentForce;

IF ChangeInForce < SmDiaForceDelta THEN //<100
SmDia_EndForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
SmDia_EndPosition := DWORD_TO_REAL (z);

StartIndex := i;
Zone2ENDIndex:= i;
Seq.iStepNo:=Seq.istepNo+1;

//..............................

ELSE
PreviousForce := CurrentForce;
END_IF;
END_FOR;
 Seq.iStepNo:=99;

//..............................



5:
//Check and Redo

FOR i := (Zone2StartIndex - 1)TO Zone2EndIndex BY -1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
CurrentForce := DWORD_TO_REAL (z);
ChangeInForce := PreviousForce - CurrentForce;
Seq.iStepNo:=Seq.istepNo+1;


//IF ChangeInForce > 150

IF ChangeInForce > LgDiaForceDelta THEN
LgDia_StartForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
LgDia_StartForce_Temp := PreviousForce;
LgDia_StartPosition_Temp := DWORD_TO_REAL (z);


// The idea is when ever the condition is true I save the valus in the Array
transitionForce[Arraycounter]:= LgDia_StartForce_Temp;
// Problem with Arrays
TransitionPosition[Arraycounter]:= LgDia_StartPosition_Temp;

Arraycounter := Arraycounter+1;


ELSE
PreviousForce := CurrentForce;
END_IF;
END_FOR;

IF Arraycounter =1 THEN

 Seq.iStepNo:=99;

//..............................

ELSE
 Seq.iStepNo:=Seq.istepNo+1;

//..............................

END_IF;

6:


CASE Arraycounter OF

1 :
LgDia_StartForce := transitionForce[1];
LgDia_StartPosition :=TransitionPosition[1];

1, 2 :
LgDia_StartForce := transitionForce[2];
LgDia_StartPosition :=TransitionPosition[2];

1..5 :

SumArray_Force := transitionForce[2]+transitionForce[3]+transitionForce[4];
LgDia_StartForce := SumArray_Force/3;
LgDia_StartPosition :=TransitionPosition[3];

1..14:

SumArray_Force := transitionForce[3]+transitionForce[4]+transitionForce[5]+transitionForce[6];
LgDia_StartForce := SumArray_Force/4;
LgDia_StartPosition :=TransitionPosition[4];


14..30:
SumArray_Force := transitionForce[4]+transitionForce[5]+transitionForce[6]+transitionForce[7]+transitionForce[8];
LgDia_StartForce := SumArray_Force/5;
LgDia_StartPosition :=TransitionPosition[6];

ELSE

 Seq.iStepNo:=99;

//..............................



END_CASE;

 Seq.iStepNo:=Seq.istepNo+1;

//..............................

7: DoneGood:=1;
   DoneFail:=0;
   temp:=1;
   Seq.iStepNo:=0;
    

   
99:    
   DoneGood:=0;
   DoneFail:=1;
   temp:=1;
   Seq.iStepNo:=0;
 

END_CASE;

END_FUNCTION_BLOCK;
 
Example implementation (not tested)

Code:
FUNCTION_block FB38

// Block Parameters
VAR_INPUT
// Input Parameters
PositionDB : INT;
ForceDB : INT;

AnalysisMode : INT;
NumPointsAverage : INT;
ServoPosOffest : REAL;
LgDiaForceDelta : REAL;
SmDiaForceDelta : REAL;
MinForceExpected : REAL;
PointOffset : INT;

END_VAR

VAR_IN_OUT
// I/O Parameters
DoneGood : BOOL;
DoneFail : BOOL;
END_VAR

VAR_OUTPUT
// Output Parameters
FinalForce : REAL;
SmDia_StartForce : REAL;
SmDia_StartPosition : REAL;
SmDia_EndForce : REAL;
SmDia_EndPosition : REAL;
LgDia_StartForce : REAL;
LgDia_StartPosition : REAL;

END_VAR

VAR
    
iInitData:INT:=1;
    

Seq:STRUCT
    bStart:BOOL;
    bStartEdgeStore:BOOL;
    iStepNo:INT;
END_STRUCT; 

  

temp : BOOL;
PositionDBWord : WORD;
ForceDBWord : WORD;

x : WORD;
y : INT;
z : DWORD;
i : INT;
j : INT;
Count: INT;
Arraycounter: INT;
kk :INT;
L: WORD; // Position
LL: DWORD; // StatForce

PreviousForce :REAL;
FinalPosition :REAL;
NumberOfDataPoints :INT;
CurrentForce :REAL;
CurrentPosition :REAL;
Acc_Real :REAL;
ChangeInPosition :REAL;
ChangeInForce :REAL;
StartIndex :INT;
Zone2StartIndex :INT;
Zone2EndIndex:INT;
SmallDia_Start_Index :INT;
Peak_Force_Temp :REAL;
Current_Force_T :REAL;
Previous_Force_Temp :REAL;

SumArray_Force :REAL;
TransArrayForce :REAL;
StartPosition :REAL;
LgDia_StartForce_Temp : REAL;
LgDia_StartPosition_Temp: REAL;


TransitionForce :ARRAY [1..30] OF REAL;
TransitionPosition :ARRAY [1..30] OF REAL;

END_VAR

LABEL
Fail;
Done;
TopOfCurve;
Scanning;
LgDiaStart;
SmDiaEnd;
SmDiaStart;
TransitionForceCase;

END_LABEL

BEGIN

CASE Seq.iStepNo of

0: //init data

// Code Section
FinalForce := 0.0;
SmDia_StartForce := 0.0;
SmDia_StartPosition := 0.0;
SmDia_EndForce := 0.0;
SmDia_EndPosition := 0.0;
LgDia_StartForce := 0.0;
LgDia_StartPosition := 0.0;

PreviousForce := 0.0;
FinalPosition:= 0.0;
CurrentForce := 0.0;
CurrentPosition := 0.0;
Acc_Real := 0.0;
ChangeInPosition := 0.0;
ChangeInForce := 0.0;

Peak_Force_Temp := 0.0;
Current_Force_T :=0.0;
Previous_Force_Temp:= 0.0;

DoneGood := 0;
DoneFail := 0;
Arraycounter:=1;

//Array Intialization
// TransitionForce[1..30] OF Real: = 30(0);
FOR Count:= 1 TO 30 DO

TransitionForce [Count] :=0;
TransitionPosition [Count] :=0;
END_FOR;

PositionDBWord := INT_TO_WORD(PositionDB);
ForceDBWord := INT_TO_WORD(ForceDB);

//find number of data points
x := WORD_TO_BLOCK_DB(PositionDBWord).DW[2];
NumberOfDataPoints := WORD_TO_INT (x) - 1; //Data Starts at Zero

y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Acc_Real := DWORD_TO_REAL (z);

IF NumPointsAverage > NumberOfDataPoints Then
 Seq.iStepNo:=99;// Fail;
ELSE
 Seq.iStepNo:=Seq.istepNo+1;
END_IF;

//.....................

// Find the final force by taking the average of the
// data points at the end of the curve. The number
// of data points is an input to the FC.

1: 

FOR i := (NumberOfDataPoints - 1)TO (NumberOfDataPoints - NumPointsAverage + 1) BY -1 DO
//Add Current Force To Acc_Real
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Acc_Real := Acc_Real + DWORD_TO_REAL (z);

END_FOR;

FinalForce := Acc_Real/NumPointsAverage;

 Seq.iStepNo:=Seq.istepNo+1;

//.....................

2:
// LOACTION: TOp of the Curve
// Start scanning from top of the Curve to bottom and

y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Previous_Force_Temp:= DWORD_TO_REAL (z);
FOR i := ((NumberOfDataPoints - 1))TO 10 BY-1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
Current_Force_T := DWORD_TO_REAL (z);
Peak_Force_Temp:= Current_Force_T;
IF Current_Force_T > Previous_Force_Temp THEN

Peak_Force_Temp:= Current_Force_T;

ELSE

Previous_Force_Temp:= Current_Force_T;

END_IF;
END_FOR;

 Seq.iStepNo:=Seq.istepNo+1;

//..............................

3:
// Zone#2= ServoPOS(StartPosition + 5, FinalPosition - Offset Position)


//Get Final Position
y := (NumberOfDataPoints * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
FinalPosition := DWORD_TO_REAL (z);

//Get Start Position of the Servo

L:= WORD_TO_BLOCK_DB(PositionDBWord).DW[4];
StartPosition:= DWORD_TO_REAL (L);

LL :=WORD_TO_BLOCK_DB(ForceDBWord).DW[4];
CurrentForce := DWORD_TO_REAL (LL);


FOR i := (NumberOfDataPoints - 1)TO 10 BY -1 DO
//Get Current Position
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
CurrentPosition := DWORD_TO_REAL (z);
ChangeInPosition := FinalPosition - CurrentPosition;

IF ChangeInPosition > ServoPosOffest THEN
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
PreviousForce := DWORD_TO_REAL (z);
StartIndex := i;
Zone2StartIndex:=i;


 Seq.iStepNo:=Seq.istepNo+1;

//..............................



//Location: Start of SmallDia
// SmDia Start Force AND Start Position

FOR j := 1 TO StartIndex BY 1 DO
IF CurrentForce > MinForceExpected THEN
SmDia_StartForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
SmDia_StartPosition := DWORD_TO_REAL (z);
SmallDia_Start_Index:= j;
Seq.iStepNo:=Seq.istepNo+1;

//..............................

ELSE
PreviousForce := CurrentForce;

END_IF;
END_FOR;

//GOTO Scanning;

END_IF;
END_FOR;

 Seq.iStepNo:=99; //failt

//..............................

4:

// LOACTION: Start of Large Diameter Press

FOR i := (Zone2StartIndex)TO SmallDia_Start_Index BY -1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
CurrentForce := DWORD_TO_REAL (z);
ChangeInForce := PreviousForce - CurrentForce;

IF ChangeInForce < SmDiaForceDelta THEN //<100
SmDia_EndForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
SmDia_EndPosition := DWORD_TO_REAL (z);

StartIndex := i;
Zone2ENDIndex:= i;
Seq.iStepNo:=Seq.istepNo+1;

//..............................

ELSE
PreviousForce := CurrentForce;
END_IF;
END_FOR;
 Seq.iStepNo:=99;

//..............................



5:
//Check and Redo

FOR i := (Zone2StartIndex - 1)TO Zone2EndIndex BY -1 DO
//Get Current Force
y := (i * 4) + 4;
z := WORD_TO_BLOCK_DB(ForceDBWord).DD[y];
CurrentForce := DWORD_TO_REAL (z);
ChangeInForce := PreviousForce - CurrentForce;
Seq.iStepNo:=Seq.istepNo+1;


//IF ChangeInForce > 150

IF ChangeInForce > LgDiaForceDelta THEN
LgDia_StartForce := PreviousForce;
y := ((i+1) * 4) + 4;
z := WORD_TO_BLOCK_DB(PositionDBWord).DD[y];
LgDia_StartForce_Temp := PreviousForce;
LgDia_StartPosition_Temp := DWORD_TO_REAL (z);


// The idea is when ever the condition is true I save the valus in the Array
transitionForce[Arraycounter]:= LgDia_StartForce_Temp;
// Problem with Arrays
TransitionPosition[Arraycounter]:= LgDia_StartPosition_Temp;

Arraycounter := Arraycounter+1;


ELSE
PreviousForce := CurrentForce;
END_IF;
END_FOR;

IF Arraycounter =1 THEN

 Seq.iStepNo:=99;

//..............................

ELSE
 Seq.iStepNo:=Seq.istepNo+1;

//..............................

END_IF;

6:


CASE Arraycounter OF

1 :
LgDia_StartForce := transitionForce[1];
LgDia_StartPosition :=TransitionPosition[1];

1, 2 :
LgDia_StartForce := transitionForce[2];
LgDia_StartPosition :=TransitionPosition[2];

1..5 :

SumArray_Force := transitionForce[2]+transitionForce[3]+transitionForce[4];
LgDia_StartForce := SumArray_Force/3;
LgDia_StartPosition :=TransitionPosition[3];

1..14:

SumArray_Force := transitionForce[3]+transitionForce[4]+transitionForce[5]+transitionForce[6];
LgDia_StartForce := SumArray_Force/4;
LgDia_StartPosition :=TransitionPosition[4];


14..30:
SumArray_Force := transitionForce[4]+transitionForce[5]+transitionForce[6]+transitionForce[7]+transitionForce[8];
LgDia_StartForce := SumArray_Force/5;
LgDia_StartPosition :=TransitionPosition[6];

ELSE

 Seq.iStepNo:=99;

//..............................



END_CASE;

 Seq.iStepNo:=Seq.istepNo+1;

//..............................

7: DoneGood:=1;
   DoneFail:=0;
   temp:=1;
   Seq.iStepNo:=0;
    

   
99:    
   DoneGood:=0;
   DoneFail:=1;
   temp:=1;
   Seq.iStepNo:=0;
 

END_CASE;

END_FUNCTION_BLOCK;

@ L D[AR2,P#0.0] thanks for the code, If I am correct you introduced labels and removed GOTO, CORRECT.

Can you please help me with the these questions:

1) Why I cannot use GOTO?
2) How to debug the program to check the functionality as a simulation? Say I implement this function then can i check the code functionality like in VBA/C++. Is it possible to do debugging offline i.e. without PLC.

regards
ajay
 
Can't tell if it was the webpage or if the code was written like that but you need to indent the code. It's unreadable like that.

Also "goto" has no place in structured programming. You need to restructure your code. Error handling might be an exception to that.

Also when there is a lot of type casting in the code (and there is) you should look over what types you are using.

When it comes to optimizing, it's inside the loops you look first because that code is executed the most times. Then floating point operations are slow and but integer is fast. So use real only when you need it.

Also while you could improve execution time maybe 20-30% (sometimes more) by optimizing your code, you can often get 200-300% faster code by optimizing your problem solving method instead. Basically, is there a smarter way to solve this problem?

I don't understand exactly what problem you are trying to solve with your code so can't offer any specific advice.

If you are searching trough your datapoints and they are sorted and you have lots of them, look at using a binary search instead of just scanning thru each one. https://en.wikipedia.org/wiki/Binary_search_algorithm

Different CPUs execute the code at different speed. I suggest just running the code in the CPU you are using and checking the scan time of the program. You can also execute your function block many times just to see how fast it runs. For instance if you run your function a hundred times per scan cycle you'll can easily calculate just how long one cycle takes.


@ Pete thanks for the reply.


I have attached an image for the algorithm, that I want to implement also. In the Image you I have explained the forces, I want to find.

The idea is to find the forces in the specified zones marked as #1, #2, and #3. The most problematic is to find the Ftrans as this is really critical for me to find as I want this to be accurate. The logic that i am using is the change in the forces is always greater than 150 N.
I have problem in finding the transition forces , if I just move backwards and scan the first point with the change in force > 150 due to the fact that sometimes I have data jumps. So I decided to do it like this.

There was another idea in mind is to find the slope and draw the line and look for the intercepts and then look for the knee.
But i am not sure that will be to complex or not?


Image
AlgorthimForce.png

let me know if you have another idea to improve the algorithm.


[/QUOTE]I suggest just running the code in the CPU you are using and checking the scan time of the program. You can also execute your function block many times just to see how fast it runs. For instance if you run your function a hundred times per scan cycle you'll can easily calculate just how long one cycle takes.[/QUOTE]

Can you please provide an example.


regards
ajay
 
If the data doesn't change, wouldn't it be easier to just log all the data and then import it into something like mathcad and analyze it there?
 
@ Pete thanks for the reply.

I have attached an image for the algorithm, that I want to implement also. In the Image you I have explained the forces, I want to find.

The idea is to find the forces in the specified zones marked as #1, #2, and #3. The most problematic is to find the Ftrans as this is really critical for me to find as I want this to be accurate. The logic that i am using is the change in the forces is always greater than 150 N.
I have problem in finding the transition forces , if I just move backwards and scan the first point with the change in force > 150 due to the fact that sometimes I have data jumps. So I decided to do it like this.

There was another idea in mind is to find the slope and draw the line and look for the intercepts and then look for the knee.
But i am not sure that will be to complex or not?


Image
View attachment 40924

let me know if you have another idea to improve the algorithm.

Is it your program that collects the data that you need to analyze?

If that is the case my first idea is that you should analyze the data sequentially as it comes in. You look for the points in the data. and when you hit them you store the information you want to keep. So when you need the information from the curve you already have everything you need and no processing is required.

You need keep track of what you are looking, aka finite state machine.

So first you look for the start of the curve. Since you have disturbances in the value you could make a running average of you last 10 values. When the mean goes above 10N you save the position of the oldest value as the starting point.

Don't know if you need the exact point of the knee but if you do you could for instance save the change (delta) of the last 10 values. When the mean value of the change goes over some threshold you know that you are at the start of the knee. So you save that position.

Third step would be to look for your peak. I think you get the idea.


By doing this as you collect the data you will spread out all the analyzing over the time it take to collect the data for the curve.

It's also fairly easy to filter the data as you collect it. Method depending on how much variation you have in the data you are collecting. One way would be to use a running average. Another simple method is disregard values that are outside your running average unless you have several of them. There is probably some book written about stuff like that so you can read up how to implement it.
 
Hello All,

I have written a Function(Function FC38) for scanning the data in DB as explained above. Now after that I wanted to generate the output. I was happy no error the code looks fine. I wanted to compare the output values the existing function (FC36) with the one I have written.

I have done the following steps on the PLC:

1) I am compile without error.
2) I generated the debug info and downloaded the block in the PLC.
3) I have called the Block in an FC (This FC 1602 is called in an FB1600 which is then called in OB33)
4) Started the Machine and did the operation. The existing Function is working perfect. But the Function I have written no Output. I am not sure What is happening.

Now question, That I have in Mind:

How to debug this code using PLC Sim/ or How to debug first ?? ;)

The flow is that when the current DB is finishing in the very next network I am calling my function to perform the operation? If this makes any difference?
Please help..:geek:

o_O


regards
ajay
 

Similar Topics

Hello I wanna know if are some function to check what is the max value from an array or if I have to loop the array to compare all numbers to get...
Replies
4
Views
1,888
Hello, When you want compare values of an array to a range of numbers is it a right way to do that? FUNCTION ADD VAR_IN_OUT A:ARRAY[1..50]...
Replies
5
Views
2,067
Hi guys. I have a challenge that I'm struggling with and I can't help thinking there's a really easy solution. I want to move a series of...
Replies
18
Views
5,841
Hi, I just can't wrap my head around this one so all ideas and comments are more than welcome. My SCL programming skills are beginner level. What...
Replies
3
Views
1,934
Looking for some help with an array of strings in SCL. I have an array of 99 string[98] I also have an array of 99 INT My first 4 chars of the...
Replies
9
Views
2,442
Back
Top Bottom