Change a value from A to B in a certain time

213 views Asked by At

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) 
1

There are 1 answers

6
Guiorgy On

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.