
Comments and Discussions




Thanks for the code example, which I found via the wikipedia page for "PID Controller", reference #19 at this time.
I'm using this to control a temperature setpoint for an oven. When the oven is close to the setpoint, the logic works great. However, when I change the setpoint to a different value, the integral variable gets out of hand.
Specifically, note that "integral = integral + (error * Dt)". My Dt=0.25 seconds, and it takes maybe 10 seconds to slew the oven 1 degree C. So it takes about 40 update periods (Dt's) to slew the oven. During this time, error starts at 1 and gradually decreases toward zero. Well, integral is accumulating this error*Dt 40 times. For discussion purposes, assume that this decrease occurs linearly (1/40=0.025 per update), which means integral will accumulate (40*.25 + 39.975*.25 + 39.95*.25 + ... + 0.05*.25 + 0.025*.25), which adds up to 40*((40+1)/2)*.25 = 205.
As a result, by the time the oven reaches temperature, had integral started at 0, it would now be a whopping 205. This large number times any reasonable Ki overwhelms all other factors and causes horrible overshoot of the temperature. During the initial stages of this overshoot, error is small and of the other sign, so it begins reducing the integral variable. However, the small error takes far too long to put a dent in the 205.
I've tried to fix this by making note of a stable "margin". When the temp first gets within the margin, I zap the integral value back to 0. This helps, but not perfectly well.
Otherwise, if I start near the setpoint, the code works great. So what am I missing here?





Hi ,
I have seen this article when i am trying to implement this algorithm in my application(heat controller).
I have used this algorithm to switch ON and OFF the heater. Heater is controlled with 420ma current source. I am using only proportional and integral values, not derivative.
For example i have calculated like this.
PV= 20 °C; SP= 80°C; Kp= 2; Ki= 0.02;
dt= 1000ms (every sec); integral= 0;
Error=> SPPV=>8020=60°C;
integral = integral+(error*dt) ==> 0+60*1000 =60000;
output = (Kp*error)+(Kd*integral)==> 2*60+(0,02*60000)=1320;
I am confusing here how to use this output value to switch ON and OFF the heater.
Please can you explain me.
Thank you very much.
modified 31Jul13 15:18pm.






There is something that I don't get  why in method tmrPV_Tick it is Pv that is changed (the speed of the car)? As far I understand, it should not be the speed that has to be changed, but the amount of pressure to the gas pedal, in this case the output variable, that has to be changed and that way indirectly change the Pv (the speed).
In my project I use a physics framework that takes into account lots of variables, but the most important thing is, I use the following snippet of code:
_Pv = _body.velocity.length;
tmrPVTick();
if (stepNumber % 5 == 0)
tmrPIDCtrlTick();
I wonder how could I fit the example into the context of my application...
Thank you,
Martin
modified 18Mar13 12:00pm.





Great. Simple and complete.





How would you use the PID controller with negative SetPoint values. For example imagine a servo that could be set at a positive or negative value.
In your example of a cruise control the values are only from say 0>100, you never go negative. In fact it looks like you trim values that are less than zero.
To make this work with negative number would I just remove the "clamp" code that sets any negative number to 0?





I think I answered my own question. I did the following:
1) Change the min value for the set point slider to 1000
2) Changed the "clamps" from 0 to 1000, for example:
if (pPV < 1000)
pPV = 1000;
3) Subtracted 500 from the current y value in buildChart to recenter the chart at 0 thereby showing negative values:
for (x = 0; x < qSP.Count; x++)
{
y = 1000  (int)Math.Round(qSP.ElementAt(x));
pointSP[x] = new Point(x, y  500);
y = 1000  (int)Math.Round(qPV.ElementAt(x));
pointPV[x] = new Point(x, y  500);
y = 1000  (int)Math.Round(qMV.ElementAt(x));
pointMV[x] = new Point(x, y  500);
}





The sample code is well written and easy to understand. This is a wonderful example of a PID control loop with great graphical feedback.





I'm trying to find the formula for PV, in order to simulate a PID regulation on a HVAC system? is anyone have an idea of how I could determine this?
In Fact, I am trying to make a simulation of a HVAC at Heat Mode. The measures of the température is after a fan who's drowing mixed air through a hotbattery. Ideally I need the PV to equal the SP around 1 minute after SP change.





Often is it impossible to obtain a system or a process transfer function (= relation between the Process Value and the SetPoint) analytically due the components parts cant easily be identified etc.
I quess the easiest way to determine the relation between the Process Value and the SetPoint is measure the Output of the Process by a given setpoint( a Stepinput) FRom the response you can determine the time constant and the steady state value. From here you can calculate the transfer function. ( Assuming it is a firstorder process)
TF = K/(s+a)
1/a = time constant and K/a = steady state value. Time constant is the time when the amplitude reaches 63% of the steady state value. The value of K can be calculated by substituting the value of a





Very nice article, how can I determine the transfer function of the process??






this article is very help full and very good
mn78





Just stumbled across this today. Really good job!
Question though... can this be implemented without the use of floats do you think? Just fixed point math? If "no", then "no" is good enough... but if "yes", I'd appreciate some tips because I've been struggling with this for days.
Thanks.





Short answer, yes, Programmable Logic Controllers (PLC's) do it that way. However...
1) They use a different algorithm.
2) There are variants depending on the PLC manufacturer.
3) The P, I, & D terms have different meanings and different multipliers.
try this link to see a different PID algorithm:
http://www.jashaw.com/pid/code.htm
www.ControlSoftInc.com has a good PID loop tuning guide that indicates what P, I, and D mean for each PLC manufacturer.
For this algorithm, you have to have 32 bit resolution. Then it's just a matter of multiplying. You can multiply Setpoint, PV, Kp, Ki, and Kd by 1000 in order for the output to keep its resolution. [Another way of looking at this is to say Kp, Ki and Kd need to be entered as values that are 1000x what you really want, then you don't need to multiply the constants by 1000. (Only the SP and PV would need x1000)]
Modify in tmrPID_Ctrl_Tick() in the following way to test the integers:
private void tmrPID_Ctrl_Tick(object sender, EventArgs e)
{
int spInt, PVInt, IntegralInt, ErrorInt, derivInt, OutputInt;
spInt = (int)(setpoint * 1000);
PVInt = (int)(PV * 1000);
ErrorInt = spInt  PVInt;
IntegralInt = (int)(integral + (ErrorInt * Dt));
derivInt = (int)((ErrorInt  preError) / Dt);
OutputInt = (int)( ( ( 1000 * Kp * ErrorInt / 1000)
+ (1000* Ki*IntegralInt/1000)
+ (1000 * Kd * derivInt / 1000) ) /1000);
error = ErrorInt;
integral = IntegralInt;
derivative = derivInt;
output = OutputInt;
preError = error;
}
Of course, if your processor has only 8 bit resolution, look into the alternative algorithms in the link above.
Hope this helps,
Lowell Cady





upscale, math, downscale... got it, thanks.
32 bit INT not a problem here so that seems the way to go. I can use floats too, its just bogging down things. Because of our functional range, a 32 bit in allows for an upscale of approx 65000X if necessary. 16 bit only gives me 128X  probably not enough. Too bad, I'd like to save the space.
Thank you.
modified on Wednesday, September 9, 2009 1:26 AM





Question... is your Dt there in ms because we're scaling by 1000? Ie. if unscaled, is Dt in seconds?





Time is independent, and not scaled. If your smallest unit is seconds it's seconds everywhere. In the case of Dt, the timer's resolution is ms, so Dt is in ms.
Something else to think about...
... Some processes take seconds, to minutes before the PV changes. For example, if you are melting 18 lbs of metal (like lead) in a 500W(VA) 120VAC pot it will take 20 minutes to go from 75F to 675F. In this case 10 second is a good resolution. Why? There are 1200 seconds in 20 minutes, or 120 "10 second samples" from 75F to 675F (change of 600F). On average that's 5F per 10 seconds (600F / 120samples = 5F/sample). You should be able to control the temperature to +5F of the setpoint. IF you need to keep the temperature to +0.5F the sample time would need to be 1s. An AC solid state relay, or SCR, is used to convert the output into power for the melting pot. [Electrically the output would be scaled to a 0  10V signal that is sent to the SCR.]





Thanks. I'm not sure why I can't wrap my head around this
Time is relative. I mean that in terms of my code has no idea if its running once a second or a thousand times a second or 40 million times a second. Externally, I (the human) know that it is running, in fact, 20 times per second in this case.
Let's give this some context. I came to this article, entitled "PID process control, a "Cruise Control" example" and in my case I am in fact coding a cruise control for an automotive application. Unfortunately, despite that being the title a lot of this article is more generic or even specific to temperature control (see comments in code surrounding, "Most PLC's have relatively slow data buses, and would sample temperatures on the order of 100's of milliseconds.") and the example application really has nothing to do specifically with automotive cruise control. But I am attempting to code for a cruise control.
The processor has the capability to sample the speed at 40Mhz but the car is producing a speed signal at only approximately 50hz. I can set my code arbitrarily to perform reliably from 20hz to about 1Mhz.
Just a note: the speed data is coming into the CPU already upscaled by 32X.
I *can* use floats, but I'm very much trying to use only integers. The processor can have variables declared at 8 bit, 16 bit or 32 bit.
Coding in c. This is what I have so far?
int8 basicPID( bool reset = false, signed int32 error ) {
CONST int8 Dt = XX; static signed int32 integral, previous_error; signed int32 derivative, proportional, output, imax, imin;
if ( reset ) { integral = 0;
previous_error = 0;
return 0;
}
else
{
error <<= 7; proportional = PGAIN * error;
derivative = DGAIN * ( ( error  previous_error ) / Dt );
imax = ( PEDAL_MAX << 12 )  proportional  derivative; imin = ( PEDAL_MIN << 12 ) + proportional + derivative;
integral = IGAIN * ( integral + ( error * Dt ) );
if ( integral > imax )
{
integral = imax;
}
else if ( integral < imin )
{
integral = imin;
}
output = proportional + integral + derivative;
previous_error = error;
return output >> 12; }
}





I see that I have made a mistake in modeling the PV. In cruise control output is a measure of acceleration, and PV is velocity. So the velocity added due to output is dependent on the time interval.
This is a closer model to your actual process.
(Dt is in ms, output is m/s^2, PV is m/s)
PV = PV + (output * Dt/1000)  (PV * 0.10) + noise;
There are two problems however. It ignores deceleration since output can't be negative, and Dt needs to be large enough that the change in PV is not truncated. So Dt needs to be at least 100ms, which will cause the gains to be retuned.
Let me get back to you with a solution.
Can you tell me the acceleration if output is equal to 52, 104, 156, and 208?





I'd say that "output" is the degree to which the pedal is being pushed because that is something you can control directly, not acceleration which you can only control indirectly (via output). There are problems with answering your question, "what is the acceleration if output = X?". It depends greatly on external factors, such as as terrain (how steep is the grade we're on) but it also depends on the PV and even that relationship isn't linear or even a curve because it also depends on what gear the car is in.
I'd say there is no possible way to predict an acceleration given a specific output. Think of a car that's already at its maximum PV for example. Or one going up a steep hill where it needs the full output puower to just maintain speed  or possibly not even be able to maintain speed. A car in 4th gear going 30 is going to accelerate a whole lot differently than one in 2nd gear at the same speed.
At low speeds all of your samples will accelerate violently. But at higher speeds, the first couple may be required just to maintain speed and as you approach the car's speed limits none of them will really do much of anything.
I think a lot of the factors that effect the PV can't be accounted for in an alogorithm but with program logic. For the most part, we can say that the higher the output that PV will attempt to grow (how responsive is difficult to predict) and for cases where it can't we'll handle with logic.
So I don't mind your original algorithm... I'm still confused on the concept of "time". The vehicle reports its speed in kph does that mean my unit of time measurements need to be in hours? Or because it is natively upscaled by 32X is my time in 1/32nd of an hour? And then why if I'm upscaling it to 4096X is my time not in 1/4096 of an hour? You said before not to scale the time but if you look at your equation, the factor of scaling is going to make Dt more or less significant which suggests an arbitrary effect and then why have time at all?





downloaded the source code, but there seems to be something missing (Microsoft.csharp.targets)





I ran into the same thing. I think it's because I'm using VS2005, not VS2008.





Very helpful for me to control speed of a car by steering wheels torque.





I have done PID control logic in the past and never quite understood how to "tune" the constants to produce a stable control (usually had to rely on someone else to do this).
I wish I would have had this article back then. It would have been a lot of help.





I have not been able to get the source code project to load.
I keep getting the following message:
"Unable to read the project file PID_EXAMPLE.CSPROJ
.
.
.
Microsoft.CSharp.targets was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.
Do you know the solution for this?
Thank You,
j.bc.3@hotmail.com





Thanks mate. I have been trying to get my head around PID controllers when used with robots and gyroscopes. You've helped clear this up for me.





This is the kind of article that interests many of us
in the control and measurement industry.
Regards,
Steve.







General News Suggestion Question Bug Answer Joke Rant Admin Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Type  Article 
Licence  CPOL 
First Posted  14 May 2009 
Views  97,162 
Downloads  9,443 
Bookmarked  64 times 

