This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Issue in PID for temperature controller : May be integral Windup or Derivative issue

Genius 3300 points

Hi,

1. We are trying to implement PID controller

2. We need to maintain temperature of a Oven & we are trying to write C code for that, which can control pulse of 2.5 seconds to SSR which in turn control Oven On/off

3. We studied many PID controllers available in market like Delta Electonics, UTAdvanced, Cautoni-Swastik and some other also.
They all use Proportional band(Pb), Ti & Td instead of Kp,Ki & Kd .
Ultimately we finalized on Delta Electronics PID and saw how it works. It uses Pb, Ti & Td


4. We had a word with Delta Electonics In Taiwan, they said they are using this formula in PI Controllers. Reply from Delta Electronics:
They apply integral once PV start falling  :  drive.google.com/.../view


5. Since we are doing PID control so we are using this formula:
Output :
drive.google.com/.../view

Output Range: 0 to 100%
Pb is in degree C (Not sure it should be in Celsius or percentage, but with celsius we are getting nearby results.)
Ti is in seconds
Td is in seconds
Ioffset we are not using at the moment, since we don't know how to calculate it.


6. Derivative term is subtracted to avoid derivative kick. So derivative term is subtracted. No filter here is applied yet though. many papers I found apply derivative filter also.

7. We had done autotuning by Astrom-Hagglund(Relay) method, same is done in Delta Electronics PID controller DTC1000, whose manual is attached.
a) Ti, Td calculated by us is same as values calculated by Delta PID

b) Pb we have just copied from what Delta Electronics PID gives, we noticed from multiple test on Delta Autotune PID, that Pb=3.69*(Amplitude)
where Amplitude is difference between max and min temperature goes during Autotune cycle as in image


8. Now we put the formula, as in code attached. Issue is first peak during maintain temperature goes very high upto 10C it goes, and we still tried only setpoints upto 100C only.

9. One issue is Integral WIndup just keeps on growing. SO we implemented this:
e2e.ti.com/.../teaching-your-pi-controller-to-behave-part-vii


10. issue with this also, that integral windup keeps on growing and dont get clamped at some point.
As proportional term falls with decrease in temp, Max_limit_integral also keeps on growing

11. Can you please help in this. Our basic c code is attached. Our observation is once setpoint is crossed, the integral don't fall immediately (fast enough) or it gets accumulated so much that it takes time to fall off, which leads to spike in PV(process variable)

12. Here is code, what could be we are doing wrong?

void compute_pid_duty_cycle(void)
{          
/* get error */    
    error = setpoint_temperature - input_temperature;
    
    if(first_time)
    {
        first_time = 0U;
        previous_temperature = input_temperature;
    }    

/* calculate duty cycle */
    if(error > pb)
    {
        output_duty_cycle = 100.0f;
    }    
    else if(error < -pb)
    {
        output_duty_cycle = 0.0f;        
    }    
    else
    {   
    /* calcukate p term */
        p_term = (100.0f * error) / pb;

    /* differential error */  
        d_term = (input_temperature - previous_temperature)/dt;     //dt = 1seconds
        d_term = d_term * td * 100.0f / pb;
        
        
    /* calculate i term */
        if((p_term + i_term - d_term) < 80.0f)
        {
            i_term = i_term + (100.0f / (pb * ti))*error*dt;
        }    
        

    /* Compute PID Output */
        output_duty_cycle = p_term + i_term - d_term;
        unclamped_output = output_duty_cycle;
        if(output_duty_cycle > c_output_max)
        {
            output_duty_cycle = c_output_max;
        }    
        else if(output_duty_cycle < c_output_min)
        {
            output_duty_cycle = c_output_min;
        }    
        else
        {
        }  
    }


/* Remember some variables for next time */
    previous_temperature = input_temperature;
}

  • Sorry, I will not be able to debug your system and code, and this is something we do not support. If you have a specific device related question we could assits.

    We have a DCL library, that you may want to look at for further understanding on what we offer. 

    https://www.ti.com/tool/C2000-DIGITAL-CONTROL-LIBRARY

    There is some training material associated with that as well. 

  • Hi,
       /* calculate i term */
            if((p_term + i_term - d_term) < 80.0f)
            {
                i_term = i_term + (100.0f / (pb * ti))*error*dt;
            }   
     
    ^^ this doesn't look good. For positive error yes, it will stop i_term growing, but it will as well stop i_term decreasing on negative error while at PID ouput >= 80. Try calculating PID output first, and then if it's breaks the limits, recalculate i_term from PID output = limit formula. This should stop saturating.
    Edward
  • Hi @Ek,

    Thanks for reply. is this what you are suggesting?

    Also we are checking temp_total to 80.0f, since we dont integral to give any effect after 80% of out. Is it right way? Or should we take it as 100.

    /* calcukate p term */
            p_term = (100.0f * error) / pb;
    
    /* differential error */  
        d_term = (input_temperature - previous_temperature)/dt;     //dt = 1seconds
        d_term = d_term * td * 100.0f / pb;
        
        
    /* calculate i term */
        temp_i_term = i_term + (100.0f / (pb * ti))*error*dt;
        temp_total = p_term + temp_i_term - d_term;
        
    /* output isout of range for max or min value */
        if( (temp_total > 80.0f)  || (temp_total < 0.0f) )
        {
            //do nothing, donot add i_term, as already saturating either in max side or in min side
        }
        else
        {
            i_term = temp_i_term;
        }
        
    /* calcukate output */   
        output = p_term + temp_i_term - d_term;
        if(output > 100.0f)
        {
            output = 100.0f;
        }
        else if(output <0.0f)
        {
            output = 0.0f;
        }
        else
        {
        }

  • Hi,

    no. While you output violates limits, integral shouldn't grow towards worse output limits violation, but you should let it grow/reduce in good direction, away limits violation. You should take into account the sign of error while deciding to update or not update integral.

    Assuming pb, ti and dt are positive, and thus not changing sign of iterm addend, it could be something like this

    /* output isout of range for max or min value */
        if(    ((temp_total <= 80.0f) || (error < 0.0)) 
            || ((temp_total >= 0.0f) || (error >= 0.0))    )
        {
            i_term = temp_i_term;
        }
    ((temp_total <= 80.0f) || (error < 0.0)) // if output is below hi limit or (output is above hi limit but) error is negative
     
     ((temp_total >= 0.0f) || (error >= 0.0)) ) // if output is above lo limit or (output is below lo limit but) error is positive
     

    Say you are above high limit. Since it takes time to reach set point, iterm integral most likely already grew to quite big number. With your code you are stuck at big ouput as iterm is frozen. The same was the case with your previous version. You should either recalculate iterm so that it won't saturate (keep outputs within limits), or let iterm unsaturate on right sign of error. Both ways are good.
     
    Edward