This is copied from plctalk.net, and it is in reference to an Omron PLC program I am writing. I know only a few people here are PLC-aware, but this is textual programming (IEC 61131-3 Structured Text) that should look familiar or at least intelligible to most of you, so maybe you can help me out. The problem is that, as it is written, this function block consumes 989 available steps, and I call on it 4 times in the main program, and I have only 6100 steps total allowable; so this function block *4 leaves me with very little room for the rest of my program.
strantor said:Hello, I would like to see if anyone can give me some pointers on how to optimize this function block that I have written for a Omron CJ2M. It is just simple piecewise line formula, but the only way I know to handle the piecewise portion is with a slew of if-then statements, which is gobbling up more memory than I can spare. This FB consumes 989 steps and 78 non-retain memory locations! As you can see, I'm not the text-based programming savant. please help!
I see one obvious thing: defining constants like "X2_Neg80:= -80.0;" and then using X2_Neg80 in the code when I could just use -80.0, but I don't think that's the bulk of the problem. I think the problem is deeper and there is an entirely different, better way to write the code from the ground up. I just don't know what that might be.Code:(* This function block takes a bipolar floating point -100 to +100 reference with zero deadband and converts it to a unipolar integer reference with deadband compensation and multipoint mapping linearization for a bidirectional analog proportional flow control valve with nonlinear output. (EX: 2500 [full reverse] to 7500 [full forward] with deadband [zero speed] from 4000 to 6000) (*define variables and constants:*) X1_Neg100:= -100.0; Y1_NEG100Float:= INT_TO_REAL(NEG100); X2_Neg80:= -80.0; Y2_NEG80Float:= INT_TO_REAL(NEG80); X3_Neg60:= -60.0; Y3_NEG60Float:= INT_TO_REAL(NEG60); X4_Neg40:= -40.0; Y4_NEG40Float:= INT_TO_REAL(NEG40); X5_Neg20:= -20.0; Y5_NEG20Float:= INT_TO_REAL(NEG20); X6_Neg1:= -1.0; Y6_NEG1Float:= INT_TO_REAL(NEG1); X7_Pos1:= +1.0; Y7_POS1Float:= INT_TO_REAL(POS1); X8_Pos20:= +20.0; Y8_POS20Float:= INT_TO_REAL(POS20); X9_Pos40:= +40.0; Y9_POS40Float:= INT_TO_REAL(POS40); X10_Pos60:= +60.0; Y10_POS60Float:= INT_TO_REAL(POS60); X11_Pos80:= +80.0; Y11_POS80Float:= INT_TO_REAL(POS80); X12_Pos100:= +100.0; Y12_POS100Float:= INT_TO_REAL(POS100); (*INPUT CONDITIONING - invert incoming value an apply speed limit if speed limit if desired*) IF Invert = TRUE THEN IF SpeedLimit = TRUE THEN InputFloat_X:= Input_float100*(-1.0)*ScalingFactor*(0.5); ELSE InputFloat_X:= Input_float100*(-1.0)*ScalingFactor; END_IF; ELSE IF SpeedLimit = TRUE THEN InputFloat_X:= Input_float100*ScalingFactor*(0.5); ELSE InputFloat_X:= Input_float100*ScalingFactor; END_IF; END_IF; (*calculate slope and y-intercept of line segments for positive range and negative range:*) IF Input_float100 > X11_Pos80 THEN ValveCenter:= FALSE; M_Slope:= (Y12_POS100Float-Y11_POS80Float)/(X12_Pos100-X11_Pos80); Y_Int_B:= Y12_POS100Float-(M_Slope*X12_Pos100); ELSIF Input_float100 < X11_Pos80 AND Input_float100 > X10_Pos60 THEN ValveCenter:= FALSE; M_Slope:= (Y11_POS80Float-Y10_POS60Float)/(X11_Pos80-X10_Pos60); Y_Int_B:= Y11_POS80Float-(M_Slope*X11_Pos80); ELSIF Input_float100 < X10_Pos60 AND Input_float100 > X9_Pos40 THEN ValveCenter:= FALSE; M_Slope:= (Y10_POS60Float-Y9_POS40Float)/(X10_Pos60-X9_Pos40); Y_Int_B:= Y10_POS60Float-(M_Slope*X10_Pos60); ELSIF Input_float100 < X9_Pos40 AND Input_float100 > X8_Pos20 THEN ValveCenter:= FALSE; M_Slope:= (Y9_POS40Float-Y8_POS20Float)/(X9_Pos40-X8_Pos20); Y_Int_B:= Y9_POS40Float-(M_Slope*X9_Pos40); ELSIF Input_float100 < X8_Pos20 AND Input_float100 > X7_Pos1 THEN ValveCenter:= FALSE; M_Slope:= (Y8_POS20Float-Y7_POS1Float)/(X8_Pos20-X7_Pos1); Y_Int_B:= Y8_POS20Float-(M_Slope*X8_Pos20); ELSIF Input_float100 < X7_Pos1 AND Input_float100 > X6_Neg1 THEN ValveCenter:= TRUE; ELSIF Input_float100 < X6_Neg1 AND Input_float100 > X5_Neg20 THEN ValveCenter:= FALSE; M_Slope:= (Y6_NEG1Float-Y5_NEG20Float)/(X6_Neg1-X5_Neg20); Y_Int_B:= Y6_NEG1Float-(M_Slope*X6_Neg1); ELSIF Input_float100 < X5_Neg20 AND Input_float100 > X4_Neg40 THEN ValveCenter:= FALSE; M_Slope:= (Y5_NEG20Float-Y4_NEG40Float)/(X5_Neg20-X4_Neg40); Y_Int_B:= Y5_NEG20Float-(M_Slope*X5_Neg20); ELSIF Input_float100 < X4_Neg40 AND Input_float100 > X3_Neg60 THEN ValveCenter:= FALSE; M_Slope:= (Y4_NEG40Float-Y3_NEG60Float)/(X4_Neg40-X3_Neg60); Y_Int_B:= Y4_NEG40Float-(M_Slope*X4_Neg40); ELSIF Input_float100 < X3_Neg60 AND Input_float100 > X2_Neg80 THEN ValveCenter:= FALSE; M_Slope:= (Y3_NEG60Float-Y2_NEG80Float)/(X3_Neg60-X2_Neg80); Y_Int_B:= Y3_NEG60Float-(M_Slope*X3_Neg60); ELSIF Input_float100 < X2_Neg80 THEN ValveCenter:= FALSE; M_Slope:= (Y2_NEG80Float-Y1_NEG100Float)/(X2_Neg80-X1_Neg100); Y_Int_B:= Y2_NEG80Float-(M_Slope*X2_Neg80); END_IF; (*write valve output*) IF ValveCenter= TRUE THEN OutputFloat_Y:= +5000.0; ELSE OutputFloat_Y:= M_Slope*InputFloat_X+Y_Int_B; END_IF; OutputInt:= REAL_TO_INT(OutputFloat_Y);