Calc block or multiple logic/math blocks?

Hi,

I've read elsewhere that one should avoid using CALC blocks when it's not required (mainly because of the impact on controller loading, and module execution priority). At what point would a CALC block be better than multiple logic & math blocks? How can I determine the 'better' method? I haven't figured out how launch the Load Estimator utility in Simulate...

As an example, I want to hold the last input value if the status is bad, but I also want the output value to have the same status as the input value. Which method is better in this case? A CALC block.... or a CND, XFR, ACT & some math block?

Thanks.

  • In reply to Brian Hrankowsky:

    Hi Brian,
    At your specific example above you can't be faster with the FB-Approach, because you use already in the CND and ACT the same code as you use in the CALC-FB.
    You can make the Calc-Expression even shorter.
    IF 'IN1.ST' >= 128 THEN
    'OUT1.CV' := 'IN1.CV';
    ENDIF;
    'OUT1.ST' := 'IN1.ST';
    The OUTx parameters of a Calc-FB are by the way critical block values, which save the value over an download.

    If you need the Bad-Status only for indication somewhere in a Display then pick it from the source which is connected to the Calc/IN1. You can get the hold last value function with a Multiplexer FB without a Calc block
    Connect the OUT of the MTLX with IN2 and your Source to IN1. Set the parameter SELECT_NEXT_GOOD to true and the status of the Selector-Input to 1 / GoodNonCascade.

    Check what Andre mention about read/write to external parameters. I do the same with the external parameters and references.
    General Guidelines do not really exist. I plan to write a book since many years about DeltaV and Good Practice and will definitely finish that next year when I retire.
    Especially in composites I try to avoid such links to/from an expression and look to create efficient code, but put some comment at the input from another function block if it is written by the Calc-FB. Set also the status to GoodNonCascade of those FB-Inputs.
    You do not need to write that status if that never change or don't must be used. I also use Parameter without the status if that is useless for this function.

    Expression / structured text can be like the early spaghetti code in BASIC or more efficient with some logical mind.
    Code should be as short as possible, internal variables (meaning other than the INx/ OUTx) are faster in execution than a reference to a parameter and save characters if you need those parameter more often in your expression.
    Avoid redundant code execution i.e. for conditions in IF THEN ELSE construct.
    The structured text will not compiled into direct assembler but in a p-Code like the Basic-Interpreter do it.
    That means the lines in an expression will be interpreted at every cycle again. You can help the CPU if your code is shorter by the chars. Do not save at comments. They are not in the character count!
    Some examples which I saw very often. It is really true.

    IF '^/ANY_IN_VAR.CV' = TRUE THEN
    '^/ANY_OUT_VAR.CV' := TRUE;
    ENDIF;
    IF '^/ANY_IN_VAR.CV' = FALSE THEN
    '^/ANY_OUT_VAR.CV' := FALSE;
    ENDIF;

    This example above is worse by several things.
    The evaluation of the condition '^/ANY_IN_VAR.CV' can only be true or false
    The IF construct have an ELSE path which execute if the condition is false.
    First Step to simplify that is

    IF '^/ANY_IN_VAR.CV' = TRUE THEN
    '^/ANY_OUT_VAR.CV' := TRUE;
    ELSE
    '^/ANY_OUT_VAR.CV' := FALSE;
    ENDIF;

    Let us check deeper how the CPU interpret the p-Code or what I learned from assembler in early days.
    The CPU see the IF. Everything between the IF and the THEN is a condition with finally a Boolean result.
    So the CPU need to collect the value from the '^/ANY_IN_VAR' and compare this against the constant TRUE.
    Depending on the result the CPU jump to the next code behind the THEN, behind the ELSE if exist or after the ENDIF;
    I'm not sure if the p-Code interpreter even must safe the true or false in between before it express the right jump.
    In Assembler exist a conditional jump which execute direct, dependent on the Accumulator Register.
    The next line after the THEN is an assignment. So the CPU check behind the := ...; and express that.
    The result will transfer into the memory for the '^/ANY_OUT_VAR.CV'
    then jump further behind the ENDIF:

    DeltaV has another IF THEN ELSE construct as inline IF similar to VBA with IIF(cnd, true return, false return)
    The syntax is Variable := Condition ? True value or expression : False value or expression;
    This make your code direct shorter, less memory, probably faster execution of the expression at all.
    A better code were therefore:

    '^/ANY_OUT_VAR.CV' := '^/ANY_IN_VAR.CV' = TRUE ? TRUE : FALSE;

    To make that example even better, cut the .CV of each parameter. It safe you further 3 byte!
    The CPU use by default the .CV but do not need to read it every cycle again and again. It might even safe some Nano seconds.

    '^/ANY_OUT_VAR' := '^/ANY_IN_VAR' = TRUE ? TRUE : FALSE;

    The next step is to short cut the condition.
    '^/ANY_IN_VAR' represent a value which can be true or false. It could be even an integer where 0 is false and any other value represent as true. The CPU need to convert that in any case before it can compare that result against the TRUE constant
    So, Why do not write direct

    '^/ANY_OUT_VAR' := '^/ANY_IN_VAR' ? TRUE : FALSE;

    Now have a look on our function. There is a variable which shall get a new value.
    In this special example the value depend direct from another variable which can express as a Boolean value.
    Finally the best resolution is therefore:

    '^/ANY_OUT_VAR' := '^/ANY_IN_VAR';
    Please compare this example with our first example!

    Some other point which might help you:
    Copy the outer variables into internal expression variables if the p-Code interpreter must express that several times trough the code.

    IF '^/ANY_IN_VAR1' AND '^/ANY_IN_VAR2' THEN
    '^/ANY_OUT_VAR' := '^/ANY_OTHER_VAR' * 4;
    ENDIF;
    IF '^/ANY_IN_VAR1' = FALSE THEN
    '^/ANY_OTHER_VAR' := FALSE;
    ENDIF;

    Here the '^/ANY_IN_VAR' is expressed two times. If you need the '^/ANY_IN_VAR1' more often then assign this to an internal variable
    internal variables are so called short distance variable and can be addressed easier with less bytes of code

    ANY_IN_VAR1 := '^/ANY_IN_VAR1'; REM I keep the name to avoid misspelling but delete only the '^/ around.
    IF ANY_IN_VAR1 AND '^/ANY_IN_VAR2' THEN
    '^/ANY_OUT_VAR' := '^/ANY_OTHER_VAR' * 4;
    ENDIF;
    IF ANY_IN_VAR1 = FALSE THEN
    '^/ANY_OTHER_VAR' := FALSE;
    ENDIF;
    Don't look now on the assignment but only on the usage of the variables.
    I only changed the ANY_IN_VAR1, but not the '^/ANY_IN_VAR2', '^/ANY_OUT_VAR', '^/ANY_OTHER_VAR'.
    The reason is simple because the need to be addressed only one time while the ANY_IN_VAR1 is evaluated two times.
    How more often you need the ANY_IN_VAR1 how more CPU load you can save. There is only the one time of the assignment from the Outer variable to the internal variable. You can use this similar to out variables. Assign first the many different values depending on different conditions to the inner variable and write at the end of the code that inner variable to your final out variable in the module.

    Finally nest the IF THEN ELSE construct
    IF '^/ANY_IN_VAR1 THEN
    IF '^/ANY_IN_VAR2' THEN
    '^/ANY_OUT_VAR' := '^/ANY_OTHER_VAR' * 4;
    ENDIF;
    ELSE
    '^/ANY_OTHER_VAR' := FALSE;
    ENDIF;

    So, ANY_IN_VAR1 need to expressed only one time. IF THEN ELSE Nesting can avoid redundant expression of conditions and therefore save it CPU load. Each of the example here is just one drop for the CPU, but the drops become Rain if you follow this principals everywhere.
    If you need to handle the status then there is no other rational way as to do this in a Calc block.
    Hop that helped you a bit.


    @Andre Dicaire : I still have this FST Handbook and miss that for DeltaV too :-) .
  • In reply to Michael Krispin:

    I look forward to helping you promote the book when you finish it!