I am trying to implement PI control algorithm in c#. I found some help in internet and i understand the formula how to use. I have measured value(PV)= 20 °C and set point (SP)= 80°C; I would like to update every 2 sec in time. once the measured value reach to setpoint the controller has to switch off like that.
I found this code link to pid algorithm
but what i need is how to calculate gain factors Kp and Ki gains as well as what about dt. I am neglecting Derivative. So please can anyone explain me how to calculate those gain factors. I am using shimaden SR90 digital controller(i bought this). I found some factors in the manual but i am not sure can i use those gain factors.
Edited for doubts.
I have tried your code like this, i am not sure this is the correct way or not.
int temperature;
//int setpoint; // i have commented these because we never used.
//int status = 0;
int pulses = 0;
//int integral = 4;
//int derivative = 5;
int upperTemp = 1000; //100.0C
int upperLimit = 100; //pulses per time frame // i can take 100 pulses per sec.
runtime //make a timer that runs and updates temperature value...lets say every second
{
read temperature; //every second
temperature *= 10; //multiply by 10 for decimal place, but still keeping in integer
pulses = map(temperature, upperTemp, 0, 0, upperLimit);
//take this value of pulses to update the timer interval
I didn't understand the above line if i am right then here i need to call the
timer like
if(pulses> somevalue)
call timer
else
no call
}
//borrowed from arduino
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
I have some question here 1) This method seems to be different than previous because we never used gains or error in this method? 2) I understand that "upperTemp" is the setpoint value.
I have tried with simple example like this
int temperature = 20;
int pulses = 0;
int upperTemp = 800; //80.0C
int upperLimit = 100; //pulses per time frame // i can take 100 pulses per sec.
read temperature; //every second which is 20 in this case
temperature *= 10; //multiply by 10 for decimal place, 20*10 =200;
pulses = map(temperature, upperTemp, 0, 0, upperLimit);// map(200,800,0,0,100)
//then map function will return pulses = 75;
//then here i don't understand that much but i am thinking like that
if(pulses> 75)
switch on;
else
switch off;
I am not sure that i am doing right! can you suggest me some more here.
-
\$\begingroup\$ Using pulses = map(etc), the further the current temperature value is away from the set point, the more pulses you will get (i.e: 20C is 60C from reaching 80C). The closer you are to the setpoint, the less pulses you will get (i.e: 78C is only 2C from 80C). The timer acts as a switch to turn on and off your relay with a 50% duty cycle. From your example, let's say you get 75 pulses. For example, in C# I could say timer.interval = 1000/pulses. Initially, it's 1000mS...once it gets the update, it becomes 1000/75 = 13.3 or it turns On/Off relay every 13mS to achieve 75pulses/second. \$\endgroup\$NothinRandom– NothinRandom2013年07月30日 17:46:08 +00:00Commented Jul 30, 2013 at 17:46
-
\$\begingroup\$ @NothinRandom Thank you very much for your clear explanation. thanks alot. \$\endgroup\$reddy– reddy2013年07月30日 18:52:48 +00:00Commented Jul 30, 2013 at 18:52
-
\$\begingroup\$ Glad to help out. PM me for other questions if you need help. \$\endgroup\$NothinRandom– NothinRandom2013年07月31日 01:20:56 +00:00Commented Jul 31, 2013 at 1:20
1 Answer 1
The key to good engineering is to keep it simple. In your case, you can use something very simple to turn on/off a relay to control a heater. A psuedo code:
int temperature;
int setpoint;
int status = 0;
int pulses = 0;
int integral = 4;
int derivative = 5;
int upperTemp = 1000; //100.0C
int upperLimit = 100; //pulses per time frame
int counter = 0;
//NO PULSING
runtime //make a timer that runs and updates temperature value
{
read temperature;
temperature *= 10; //still keeping in int for faster processing
status = ((setpoint - temperature)*integral)/derivative; //EX: (800-400)*4/5 = 320
//EX: (800-780)*4/5 = 16
status = abs(status); //get absolute value, this for for within range
//(800-850)*4/5 = -40 -> ABS(-40) = 40
if(status < 16) //from example, 16 means that value is within 2*C, you can always
Relay Off; //change this value to something else (e.g: (800-795)*4/5 = 4
else //4 gives 0.5*C tolerance range...which is a bit tight for temp.
Relay On; //anyway, play around with this value;
//you can also change integral and derivative if you wish.
}
//WITH PULSING
runtime //make a timer that runs and updates temperature value...lets say every second
{
read temperature; //every second
temperature *= 10; //multiply by 10 for decimal place, but still keeping in integer
pulses = map(temperature, upperTemp, 0, 0, upperLimit); //when temperature increases,
//pulses decreases...vice versa
//take this value of pulses to update the timer interval
//timer's interval = pulses per second or minute
}
timer
{
if(Relay On)
Relay Off;
else
Relay On;
}
//borrowed from arduino
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
//PWM method: still need the runtime with pulsing from above. Let's say you get 75 pulses, this means that the relay will be on for 75% of the duration of each pulse and off for the other 25%. Let's say that you want to have a frequency of 1s (1000mS). Relay will be on for 750mS and off for 250mS. If the temperature is very far away from setpoint, then it might even be on for 100% of the time.
//choose entire duration by tick_interval*percentage: 100mS*100 = 10000mS or 10seconds. Back to example. If you have 75 pulses, then relay will be on for 7.5 seconds and off for 2.5 seconds.
timer //example 100mS per tick
{
if(counter > 100) //has reached the end of time period
counter = 0;
if(counter > pulses) //pulses from above is now the duty cycle
{
if(Relay is On)
Relay off;
}
else
{
if(Relay is Off)
Relay on;
}
counter++; //increment by 1
}
//this method is more flexible than using a fixed number (30 minutes) because different heater controllers respond differently
-
\$\begingroup\$ Thanks for you reply, I have small question how did you come by these values integral= 4, derivative=5. Those are just random values picked by yourself or fallowed any procedure? one more may i know the reason why you haven't used proportional gain? \$\endgroup\$reddy– reddy2013年07月29日 17:50:11 +00:00Commented Jul 29, 2013 at 17:50
-
\$\begingroup\$ In feedback, the value is required to be below 1 for stable output. If the value is above one, then over shoot will occur. The value is 4 or 5 because we're performing int calculation here, no floating point, so 4/5 is essential 0.8 or 80%. The lower you go (1/10 or 0.1), the slower the pid loop will process, but more stable...aka less chance of overshoot. You shouldn't need proportional gain because you're not controlling a motor or anything that pulses rapidly. This is for a simple relay, either on or off. \$\endgroup\$NothinRandom– NothinRandom2013年07月29日 18:18:31 +00:00Commented Jul 29, 2013 at 18:18
-
\$\begingroup\$ Thanks for your reply, the concept is OK but in my case may be i need proportional gain because I am trying to like this. for example i have measured value as 20 °C and i set-point is 80 °C what i am trying to implement is up to certain point it has to increase and then i need to do pulses rapidly because my application is like that. So please can you suggest me how to add that also. \$\endgroup\$reddy– reddy2013年07月29日 20:16:20 +00:00Commented Jul 29, 2013 at 20:16
-
\$\begingroup\$ @reddy how many pulses can your application handle per second? In other words, how many pulses per second (frequency) can your relay handle? Let me edit the code with the pulsing. \$\endgroup\$NothinRandom– NothinRandom2013年07月29日 20:40:59 +00:00Commented Jul 29, 2013 at 20:40
-
\$\begingroup\$ I have understand your code. This method is new to me. I have some questions. can you have a look at my edited post. \$\endgroup\$reddy– reddy2013年07月30日 08:33:00 +00:00Commented Jul 30, 2013 at 8:33