0

I want it to take a certain time for a value to change between value A to value B. It works this way, but I am limited by a BYTE (255) which makes the scale bad if I want to use larger numbers. And I cant figure out how.

I therefore want help to solve this problem.

Thanks in advance!

TX = Internal timer in MS

// fbScale scales a value from one to another.
fbScale[1](nIn := nIn, nInLow := nLow, nInHi := nHi, nOutLow := 0, nOutHi := 255, nOut =>);

IF fbScale[1].nOut > Out_INT AND InitU AND bEn THEN
    TR := T#60S;
    IF (Out_INT <> 255) THEN
        IF tx - tl < TR THEN
            Out_INT := MIN(TO_BYTE(SHL(TO_DWORD(tx - tl), 8) / TO_DWORD(TR)), (BYTE#255 - Start));
            Out_INT := Start + Out_INT;
        ELSE
            Out_INT := 255;
        END_IF  
    END_IF
    
    bBusy := TRUE;
    InitD := FALSE;

ELSIF fbScale[1].nOut < Out_INT AND InitD AND bEn THEN
    TR := SEL(ChangeLowHi, DWtoSec(nRTD),  T#0S);
        IF (Out_INT <> 0) THEN
            IF tx - tl < TR THEN
                Out_INT := MIN(TO_BYTE(SHL(TIME_TO_DWORD(tx - tl), 8) / TO_DWORD(TR)), Start);
                Out_INT := Start - Out_INT;
            ELSE
                Out_INT := 0;
            END_IF;
        END_IF
        
        bBusy := TRUE;
        InitU := FALSE;     
    
ELSE
    tl := tx;
    InitU := TRUE;
    InitD := TRUE;
    Start := Out_INT;
    
END_IF

fbScale[2](nIn := Out_INT, nInLow := 0, nInHi := 255, nOutLow := nLow, nOutHi := nHi, nOut => nOut) 
cha28
  • 41
  • 6
  • What do you mean you are limited by byte? Use word. And I should say if you want better help, please edit our question and describe your task better. It is very blurry what you actually need. And code example does not help. There are a lot of questions like where ` TR` is used.? – Sergey Romanov Dec 04 '20 at 07:19

1 Answers1

1

If what you want is to gradually transition a value over some duration of time, then you could do something like so:

    low_int: INT := 500;
    high_int: INT := 15000;
    duration: TIME := T#5S; // 5 seconds
    timer: TON;
    value: INT;
    scale: REAL;
    timer(IN := TRUE, PT := duration);

    IF (timer.Q) THEN
        value := high_int;
    ELSE
        scale := TIME_TO_REAL(timer.ET) / TIME_TO_REAL(duration);
        value := REAL_TO_INT(low_int + (high_int - low_int) * scale);
    END_IF

Furthermore, you could add a transition ease (for example ease in and out in this example) like so:

    METHOD EaseInOutQuad : REAL
    VAR_INPUT
        scale: REAL;
    END_VAR
    IF (scale < 0.5) THEN
        EaseInOutQuad := 2 * scale * scale;
    ELSE
        EaseInOutQuad := -1 + (4 - 2 * scale) * scale;
    END_IF
    scale := TIME_TO_REAL(timer.ET) / TIME_TO_REAL(duration);
    scale := EaseInOutQuad(scale);
    value := REAL_TO_INT(low_int + (high_int - low_int) * scale);

If you want further control over how the value changes over time, then you would have to define a custom function. here is a codesys project with an example where I use Linear interpolation, though you may use polynomial interpolation if you want it to be smoother.

Guiorgy
  • 1,405
  • 9
  • 26
  • I would use BLINK from Util. – Sergey Romanov Dec 06 '20 at 05:28
  • @SergeyRomanov, if the goal is for the transition to be a step function, then yes, but if it is to have a gradual change over time, then as far as I know BLINK won't work – Guiorgy Dec 06 '20 at 13:52
  • I read it as "to change between value A to value B" not as "to change from value A to value B". As I understand question, he change it instantly. – Sergey Romanov Dec 08 '20 at 04:50
  • Thank you @Guiorgy ! Sorry for a bad explanatin, but you´re on the right track. You´re right about I want a gradual change. But I lets say that low_int is 0 and high_int is 100 and that the duration is 10s. So 0-100 takes 10s. But I also want the value to take 5s from 0-5, and from 5-7 2,5s and so on – cha28 Dec 08 '20 at 18:46
  • @cha28, what you are asking, for is for a way to control how the value changes over time, and that's what I did in the second example (EaseInOutQuad), but I only used a simple easing bazier curve for that (see examples [here](https://cubic-bezier.com/)). The one I used simply makes the value start slow, then speed up and then slow down again. If you want to have more control over it, you would need to define a custom function that takes and outputs a number between [0, 1]. Using linear or polynomial interpolation would be the easiest in my opinion – Guiorgy Dec 09 '20 at 12:41
  • @cha28, I've added a link to my Google Drive with a codesys project with an example of using linear interpolation to transition an INT value (you can replace all INTs with other types like DINT or REAL if you need). If you want to change the behavior, change the `times` and `scales` arrays. – Guiorgy Dec 09 '20 at 13:26