Can I compare multiple variable values to 1 variable value in a clean way?

loganr4l
2022-04-25
2022-05-03
  • loganr4l - 2022-04-25

    Example of what I am doing. Can this be simplified, especially if I am using more variables.

    IF PVL.dut_PonyGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure OR PVL.dut_MidGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure OR PVL.dut_MainGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure OR PVL.dut_HFGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure THEN
        DoTask := TRUE;
    END_IF
    
     
  • BY - 2022-04-29

    I would write each OR statement under the other. For example;

    IF xVar1 OR
       xVar2 OR 
       xVar3 OR
       xVar4 THEN
    
        DoTask := TRUE;
    
    END_IF
    

    or you can create an action with FBD language then you can see this with a box view.

     

    Last edit: BY 2022-04-29
    • loganr4l - 2022-04-29

      Much cleaner thank you for the tip!

       
  • hermsen

    hermsen - 2022-04-29

    This could even be improved upon readability wise;

    xDoTask := xVar1 OR
               xVar2 OR 
               xVar3 OR
               xVar4;           
    

    But the original question was;

    IF PVL.dut_PonyGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure OR
    PVL.dut_MidGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure OR PVL.dut_MainGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure OR PVL.dut_HFGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure THEN
        DoTask := TRUE;
    END_IF
    

    which could be rewritten for better readability into

    DoTask := (PVL.dut_PonyGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure) OR
    
    (PVL.dut_MidGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure) OR
    
    (PVL.dut_MainGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure) OR 
    
    (PVL.dut_HFGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure);
    

    If you mix 1 and 2 you get;

    xVar1 := (PVL.dut_PonyGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure);
    
    xVar2 := (PVL.dut_MidGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure);
    
    xVar3 := (PVL.dut_MainGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure); 
    
    xVar4 := (PVL.dut_HFGroupSettings.ProcessVariable_ci = GVL.c_ai_DischargePressure);
    
    xDoTask := xVar1 OR
               xVar2 OR 
               xVar3 OR
               xVar4;  
    

    In my opinion, "smart code" should NOT be as compact as possible, but it should be READABLE, especially at 03:00 saturday night!
    You could try to rework the code into a CASE statement, but since it uses all kinds of GVL's that isn't simply possible.

     

    Last edit: hermsen 2022-04-29
  • loganr4l - 2022-04-29

    Maybe there was to much garbage, the variables being INT.

    IF iVar1 = iVar10 OR
       iVar1 = iVar10 OR
       iVar1 = iVar10 OR
       iVar1 = iVar10 THEN
    
       DoTask := TRUE;
    
    END_IF
    

    EDIT!!!!

    IF iVar1 = iVar10 OR
       iVar2 = iVar10 OR
       iVar3 = iVar10 OR
       iVar4 = iVar10 THEN
    
       DoTask := TRUE;
    
    END_IF
    
     

    Last edit: loganr4l 2022-04-29
    • loganr4l - 2022-04-29

      Thank you kindly for your time I, I like the method you prescribe! But it sounds like its not possible to compare multiple variables collectively against one.

       
      • hermsen

        hermsen - 2022-04-29

        If you want your variable (Integer types only!) to be assessed against a value range, you could use a CASE OF Statement;

        CASE MyUIntValue OF
        
            0 : ;
                // Do stuff
            1 : ;
                // Do more stuff
            2..100 ;
                // RANGE1
        
            101..65000: ; 
                // RANGE2;
        ELSE
            //anything 65001 .. 65535 go here
            ;
        END_CASE
        
         

        Last edit: hermsen 2022-04-29
    • hermsen

      hermsen - 2022-04-29
      IF iVar1 = iVar10 OR
         iVar1 = iVar10 OR
         iVar1 = iVar10 OR
         iVar1 = iVar10 THEN
      
         DoTask := TRUE;
      
      END_IF
      

      Could be rewritten into;

         DoTask := (iVar1 = iVar10) ;
      

      Albeit DoTask is now continously evaluated.

       

      Last edit: hermsen 2022-04-29
      • loganr4l - 2022-04-29

        oh man i messed up, I edited my mistake

         
        • hermsen

          hermsen - 2022-04-29

          Don't worry, just don't use such code in your program ;-)

           
          • loganr4l - 2022-04-29

            I am sure you are busy, and I thanks for your help and your time good sir.

             
  • sgronchi - 2022-05-02

    You can build a list of pointers (or interfaces, if you use function blocks), and then batch process it.

    VAR CONSTANT
        settingsNumber : UINT := 4;
    END_VAR
    VAR
        apSettings : ARRAY [1..settingsNumber] OF dut_Settings;
        i : __XWORD;
        xDoTask : BOOL;
        axDoTask : ARRAY [1..settingsNumber]; (* For option #2 *)
    END_VAR
    
    (* Initialization, somewhere *)
    apSettings[0] := ADR(PVL.dut_PonyGroupSettings);
    apSettings[1] := ADR(PVL.dut_MidGroupSettings);
    apSettings[2] := ADR(PVL.dut_MainGroupSettings);
    apSettings[3] := ADR(PVL.dut_HFGroupSettings);
    
    
    (* Evaluation, perhaps somewhere else *)
    (* Option #1 - very compact, not very readable *)
    xDoTask := FALSE;
    FOR i := 1 TO settingsNumber DO
        xDoTask S= (apSettings[i]^.ProcessVariable_ci = GVL.c_ai_DischargePressure);
    END_FOR
    
    (* Option #2 - "MapReduce" - less compact, a bit more readable (and perhaps useful if you need conditions later on *)
    FOR i := 1 TO settingsNumber DO
        axDoTask[i] := (apSettings[i]^.ProcessVariable_ci = GVL.c_ai_DischargePressure);  // Map -> evaluate all the conditions separately
    END_FOR
    
    xDoTask := FALSE;
    FOR i := 1 TO settingsNumber DO
        xDoTask S= axDoTask[i];  // Reduce
        // could also be written as xDoTask := xDoTask OR axDoTask[i];
    END_FOR
    

    This is less readable than yours, but is more flexible (it becomes more and more readable the more conditions you have).

     

    Related

    Talk.ru: 1
    Talk.ru: 2
    Talk.ru: 3

    • loganr4l - 2022-05-02

      Ah the funny thing is I am turning everything into Arrays anyways for other purposes! Reading through this there were a couple of new things I haven't seen, I looked them up and learned some new functions. I will probably end up doing something like the first example you gave. Thank you so much for your time and detailing. I am learning a lot from all the help!

       
      • hermsen

        hermsen - 2022-05-03

        Just steer clear of writing "too compact" code and prefer readability over "performance". Usually "performance" isn't an issue nowadays (unless it is but then you should focus on low hanging fruit first).

         

Log in to post a comment.