Bug in Control Loop Library, Setpoint off by 1

janderson
2023-08-03
2023-08-08
  • janderson - 2023-08-03

    I may have discovered a bug in the control loop library.

    I am using a PID Controller and when I use an anti-wind-up strategy the response will settle at exactly the setpoint-1.

    When the anti-windup strategy is removed the controller settles at the setpoint correctly.

    PROGRAM temperature_control
    VAR
        //PID Controllers
    
        PID_1_output: LREAL := 0.0;
        PID_1_error: Ctrl.Controller_Error;
    
        PID_1_integrator : Ctrl.Integrator_ParabolicApproximation;
        PID_1_diff : Ctrl.Differentiator_LinearAverageApproximation;
        b_array : ARRAY [0.. 99] OF LREAL := [100(0.01)];
        filter_1 : Ctrl.Filter_FIR := (palrCoefficientsB := ADR(b_array), udiSizeCoefficientsB := SIZEOF(b_array));
        filter_1_error : Ctrl.Controller_Error;
        PID_1: Ctrl.Controller_PID;
    
        kp: LREAL := 0.3;
        ki: LREAL := 0.03;
        kd: LREAL := 0.00;
        PID_1_limits_active : BOOL;
    
        //PWM Generators
        PWM_1_cool : Ctrl.PWM_Creator_FixedCycle;
        PWM_1_heat : Ctrl.PWM_Creator_FixedCycle;
    
    END_VAR
    
    //config
    PWM_1_cool.udiPWMCycleTime := 100000; //microseconds
    PWM_1_heat.udiPWMCycleTime := 100000; //microseconds
    
    //turn on heatsink fans
    GVL.heatsink_fan := TRUE;
    
    
    // filter temperature signal
    
    filter_1(
        lrValue := GVL.TC1,
        xEnable := GVL.temperature_control_1_enable,
        lrFilteredValue => GVL.TC1_filtered,
        eErrorID => filter_1_error);
    
    //PID Controllers
    PID_1(
        //inputs
        lrActualValue := GVL.TC1_filtered,
        lrSetPoint := GVL.temperature_setpoint_1,
        xEnable := GVL.temperature_control_1_enable, //output will go to zero on disable
    
        //config
        lrOffset := 0,
        lrMinValue := -1,
        lrMaxValue := 1,
        lrKP := kp,
        lrKI := ki,
        lrKD := kd,
        itfIntegrator := PID_1_integrator,
        itfDifferentiator := PID_1_diff,
    
        //outputs
        lrOutput => PID_1_output,
        eErrorID => PID_1_error,
        xLimitsActive => PID_1_limits_active,
    );
    
    IF PID_1_output <= 0 THEN
        PWM_1_cool(
            lrProportionValue := -1*PID_1_output,
            xOutput => GVL.h_bridge_1_cool,
            eErrorID =>,
            xEnable := GVL.temperature_control_1_enable);
        PWM_1_heat(
            lrProportionValue := 0,
            xOutput => GVL.h_bridge_1_heat,
            eErrorID =>,
            xEnable := GVL.temperature_control_1_enable);
    ELSIF PID_1_output > 0 THEN
        PWM_1_cool(
            lrProportionValue := 0,
            xOutput => GVL.h_bridge_1_cool,
            eErrorID =>,
            xEnable := GVL.temperature_control_1_enable);
        PWM_1_heat(
            lrProportionValue := PID_1_output,
            xOutput => GVL.h_bridge_1_heat,
            eErrorID =>,
            xEnable := GVL.temperature_control_1_enable);
    
    END_IF
    

    Does anyone else experience this behavior?

     
  • janderson - 2023-08-08

    Nevermind, i did not recognize that the clamp is placed on the value of the integrator prior to it being scaled by KI. After increasing the max and decreasing the min, it functions normally.

     

Log in to post a comment.