0

I am using ABB HMI and programming it on panel builder 600. I have used meters to display angles and set the scale from -100 to +100. I have acheived success in displaying angles but the problem is the change in angle is very frequent and the needle of the meter gets out of control. For example: the angle is 5 degree then it suddenly increased to 10 degree and the decreased to 3 degree again in a very short span of time and my needle in display meter gets out of control. What should I do to resolve this issue? I am using ABB plc and writing my code in codesys in CFC language. Awaiting for the helpful replies TIA

Mar_60
  • 13
  • 3
  • From what I understand, your problem isn't strictly codesys or cfc related. Your problem is a quickly changing value. The only 2 solutions I can come up, is to either decrease the sample rate (i.e. Only update the value every half second, or every second, or every 2 seconds, etc.), or to average your value over some time (i.e. Take the [Moving Average](https://pages.mtu.edu/~shene/COURSES/cs201/NOTES/chap08/mov-avg.html) to smoothe the value) – Guiorgy Mar 27 '21 at 13:30
  • Thanks @Guiorgy for your reply. Can you please help me how to change the sample rate ? Or how to average the values? Will it be average in codesys code or panel builder? – Mar_60 Mar 27 '21 at 13:34
  • You can do both either in the PLC or HMI if it allows for local variables. As for an example, I don't use CFC, but I can give 1 in ST – Guiorgy Mar 27 '21 at 14:12
  • It will be helpful for me if you can give in ST too. TIA – Mar_60 Mar 27 '21 at 14:21
  • Can you please help me to do this in ABB HMI Panel builder 600? – Mar_60 Apr 06 '21 at 09:12

2 Answers2

1

Decreasing Sampling Rate

VAR
    plcValue: INT; // this value changes a lot
    hmiValue: INT := plcValue; // this value is sent to the HMI to be displayed
    sampleRate: TIME := T#2S; // hmiValue will change every 2 seconds
    timer: TON; // the timer
END_VAR
timer(IN := TRUE, PT := sampleRate);
IF (timer.Q) THEN
    hmiValue := plcValue;
    timer(IN := FALSE, PT := sampleRate); // reset
END_IF

Moving Average

VAR CONSTANT
    SIZE: INT := 100; // the number of values to average
END_VAR
VAR
    plcValue: INT; // this value changes a lot
    hmiValue: INT := plcValue; // this value is sent to the HMI to be displayed
    movingAverage: ARRAY [0..SIZE] OF INT; // last SIZE number of values of plcValue
    maIndex: INT := 0;
    maFilled: BOOL;
    sum: REAL;
    i: INT;
END_VAR
movingAverage[maIndex] := plcValue;
sum := 0;
IF (maFilled) THEN
    FOR i := 0 TO SIZE DO
        sum := sum + movingAverage[i];
    END_FOR
    hmiValue := REAL_TO_INT(sum / SIZE);
ELSE
    FOR i := 0 TO maIndex DO
        sum := sum + movingAverage[i];
    END_FOR
    hmiValue := REAL_TO_INT(sum / (maIndex + 1));
END_IF
IF (maIndex = SIZE) THEN
    maIndex := 0;
    maFilled := TRUE;
ELSE
    maIndex := maIndex + 1;
END_IF

Comparison

running this code:

IF (plcValue = 5) THEN
    plcValue := 10;
ELSIF (plcValue = 10) THEN
    plcValue := 3;
ELSE
    plcValue := 5;
END_IF

Reduced sampling rate results in the hmiValue still jumping every 2 seconds (or whatever sampleRate was set), while moving average was stuck at 6, which usually makes it the more preferred of the two, though a little bigger codewise, as well as slower to execute (though it shouldn't matter, unless you are counting thousands of averages every cycle). You can also change the average size: The bigger it is, the smoother the value, but also slower to react to change. Try not to make it too big

Guiorgy
  • 1,405
  • 9
  • 26
  • Thank u so much. To decrease sample rate is quite easy i think. I will give it a try. But i am confused in these variables which u have used in decreasing sample rate code: IN, Q, PT. What is timer.Q in the code? – Mar_60 Mar 27 '21 at 15:01
  • TON is a standard Function Block in CODESYS, you can read the [documentation](https://help.codesys.com/webapp/nZzsIvNv0ruZ1f6MRyM0e-wgLKU%2FTON;product=standard;version=3.5.14.0). The TL;DR is, that if `IN` is TRUE, the time is counting, otherwise it resets. `PT` is the time the TON timer should count for, and `Q` is the output, which becomes TRUE when `PT` time has gone by (it will stay true unless you manually reset it) – Guiorgy Mar 27 '21 at 15:21
  • It means tha Q, IN and PT these all are pre-defined ? Right? The same code will work to decrease refresh rate without any error? – Mar_60 Mar 27 '21 at 18:23
  • yes, TON is a Function Block that is built into the Standard library that comes with CODESYS. The Standard library should be included into every project by default, but just incase, you can check if it is there (someone can remove it for example) – Guiorgy Mar 27 '21 at 19:29
  • I have tried this code to reduce the sample rate but when I run this code, the variable ''hmiValue'' doesnot change and remain zero, because timer.Q always remain zero. VAR plcValue: INT; // this value changes a lot hmiValue: INT := plcValue; // this value is sent to the HMI to be displayed sampleRate: TIME := T#2S; // hmiValue will change every 2 seconds timer: TON; // the timer END_VAR timer(IN := TRUE, PT := sampleRate); IF (timer.Q) THEN hmiValue := plcValue; timer(IN := FALSE, PT := sampleRate); // reset END_IF – Mar_60 Apr 05 '21 at 06:45
  • Huh. Can you check `timer.ET` (ET short for *Elapsed Time*)? If that doesn't change, it means that the timer isn't counting, and that would probably mean that the code is just not being executed – Guiorgy Apr 05 '21 at 08:41
  • Thanks Guiorg for your help. I tried your moving average code and it helped me a little bit in smoothing the needle of my dial but when i give continuous serial data packets after every 1 second then.it again start jittering and could not reach to the desired value. ? . . Moreover, I have one more question, will i have to include all codes together in my project which you have provided to overcome the problem or can only one code solve my problem. Waiting for your kind reply. TIA – Mar_60 Apr 06 '21 at 14:21
  • I don't fully understand your question. [Here](https://youtu.be/kbeDGx3DcJ0)'s a video demo I made of the code above. In it, I take a `50*Sin(x) + noise` where noise is a random number between -5 and 5, thus this value jumps +-5, but the average changes smoothly – Guiorgy Apr 07 '21 at 10:07
  • In this code, value update stepwise but not smoothly. Will it work smoothly if i decrease the increment of 1? What is maIndex in the code? – Mar_60 Apr 07 '21 at 11:13
  • `maIndex` just as the name suggests is the index of the Moving Average buffer array. No need to touch that. "In this code, value update stepwise but not smoothly" Can you clarify what you mean? You should only ever change `plcValue`, the 'hmiValue` will be updated by the average of the buffer array. You can increase the `SIZE` of the buffer array, but I wouldn't recomend setting it too big – Guiorgy Apr 07 '21 at 11:55
  • "In this code, value update stepwise but not smoothly". By this I mean that when value changes from 10 to 45 then the needle of dial in my HMI moves step by step ( i.e: start from 10 then 15 then 20 till 45). I want to make my needle moving smoothly in speed like a speed meter of a car. – Mar_60 Apr 07 '21 at 14:42
  • Increase the `SIZE` of the array. How big is yours? – Guiorgy Apr 07 '21 at 15:44
  • I tried with different values. I even tried with 500, 1000 and 2000 as well but it the results are same. – Mar_60 Apr 07 '21 at 16:56
  • With a moving average it shuldn't be jumping too much: [video](https://youtu.be/oXz_qsdguc0). Can you record your code and execution? – Guiorgy Apr 07 '21 at 17:17
  • Yes, but i am running the exactly same moving average code. If I decrease the +1 increment to +0.1 then should it move smoothly ? – Mar_60 Apr 07 '21 at 17:50
  • As I told you, `maIndex` is an INDEX of the array. An index can't be a fractional, it must be an integer, and there is no reason to try to change that! – Guiorgy Apr 07 '21 at 18:45
1

You can use some different blocks on OSCAT library (It's a 3rd party free library. You need to downloade it if you want to use it). I know you work in CFC and perhaps you are not familiar with ST, but this is best way to represent how to solve your task.

FADE

This block allows slowly change value from one value to another.

PROGRAM PLC_PRG
    VAR
        iValue: INT(-100..100); (* Value input *)
        iGauge: INT(-100..100); (* Smoothed Value for HMI *)
        fbFade: FADE; (* fade block *)
    END_VAR

    (* Play with TF parameter to achieve desired smoothness *)
    fbFade(IN1 := INT_TO_REAL(iValue), IN2 := INT_TO_REAL(iGauge), F := FALSE, TF := T#500MS);
    iGauge := REAL_TO_INT(fbFade.Y);
END_PROGRAM

FILTER_I

This block averages value for a given time interval. FILTER_I is a filter of the first degree for 16-bit INT data.

PROGRAM PLC_PRG
    VAR
        iValue: INT(-100..100); (* Value input *)
        iGauge: INT(-100..100); (* Smoothed Value for HMI *)
        fbFilter: FILETR_I; (* filter block *)
    END_VAR

    (* Play with T parameter to achieve desired smoothness *)
    fbFilter(X := iValue, T := T#500MS, Y => iGauge);
END_PROGRAM

FILTER_MAV_W

And another filter is like @Guiorgy made en example based not on time but on number of values stored which is called MA (Moving Average).

PROGRAM PLC_PRG
    VAR
        iValue: INT(-100..100); (* Value input *)
        iGauge: INT(-100..100); (* Smoothed Value for HMI *)
        fbFilter: FILTER_MAV_W; (* filter block *)
    END_VAR

    (* Play with N parameter to achieve desired smoothness *)
    fbFilter(X := INT_TO_WORD(iValue), N := INT#32);
    iGauge := WORD_TO_INT(fbFilter.Y);
END_PROGRAM
Guiorgy
  • 1,405
  • 9
  • 26
Sergey Romanov
  • 2,949
  • 4
  • 23
  • 38