PID control discussion

Official FreeEMS vanilla firmware development, the heart and soul of the system!
User avatar
AbeFM
Post Whore!
Posts: 629
Joined: Sat Feb 16, 2008 12:11 am
Location: Sunny San Diego
Contact:

Re: PID control discussion

Post by AbeFM »

The two places they use it, which are reasonable places if not great, are boost solenoid control and idle control.

It might not be up to the task of boost control, I'm not sure. The best I got it working was maringally on boost.

For idle it is just plain wacky, and next to impossible to tune.

Sure, if you really wanted to get these values right, you would have an integrated answer for RPM, something that would run on the side to give you that number.

But, if your time period makes sense (on the MS they use ~200 +/-50 ms), you can do it how I said. RPM at idle isn't going to do anything so weird in 200 ms that you can't just assume it was a linear change during that time. You figure you have 10-25 revolutions per second (30-100 ms/revolution) so you're RPM aren't going to wander off and come back without you noticing, likewise you're not going to try to control it multiple times per tooth.

It's something I could do no trouble with my foot on the gas. :-)


I guess this is twofold, then. 1) I'd like to come up with a decent argument to tell the MS people they need to work on their code, and 2) It would be nice to have a decent understainding of what we need to do here when we start trying to control those simpler things.

There are lots of interesting fudges people do on boost control, and that I would love to learn more about. It seems to be a hard thing to get right....

--------------
As to t space, etc, if you use the simplified version I was posting, you shouldn't run into those issues as long as you're controlling in a reasonable range of times. What's the reason NOT to do it that way?
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: PID control discussion

Post by Fred »

the wiki page talks about limitations and using the PID only to correct from a base curve that is an approximation to the real shape you want. this sounds very very good to me. it means you will always be close (duty vs rpm plot) and it will just add some to that if required...
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
User avatar
muythaibxr
TO220 - Visibile
Posts: 4
Joined: Sat Apr 05, 2008 12:39 am

Re: PID control discussion

Post by muythaibxr »

8InchesFlacid wrote:You must be good, you used italics AND bold (not just holding down shift).

Seriously, thanks for the nice write up. Here's what I noticed, aside from the obvious that Engineers start with 'the z transform blah blah' instead of what a z transform is or why you'd do it... :-) But it's ok, I think I managed to make some sense of it anyway. And again, thanks for putting it out explicitly!

Now THAT'S exactly what I've been saying all along, that the P term should be purely proportional to the current error, plus some initial 'best guess' term, chosen to be the steady state position you think it the best guess (I'd probably use the valve opening for idle that I normally set it at).
IT IS purely proportional to current error.

error = curr_rpm - targ_rpm;

Kp = p_gain * error;

That is purely proportional, and what my code does.

I'll have to look, I think what happened is the MS folks are using
Alpha = KP
Beta = KI
Gama = KD

Or something like that, I have to look closer. But they are doing something way wrong.
No, this just shows that you didn't read the code carefully. What we're doing is:

Alpha = Kp + Ki - Kd

And we're not doing Beta or Gamma...

The Beta and Gamma allows for some prediction, which we're not doing.
which in turn boils down to:

Code: Select all

                            error = target - actual;
                            OUTPUT += Kp * error;
That's an integral.
No, it's not... the output of the PID math (Kp * error) is a corrected for min vs max valve position delta. A delta is an amount of change. The fact is that the "delta" at each iteration of the loop will change because as the valve position changes, RPM changes. So, for example, if I've got a current valve position of
60%, and my RPM is at 1600, and my target is 800, and my P term is set to 60, I'll get a delta for this iteration of -6 (assuming a valve closed of 0, and valve open of 100). That gives me a valve position of 54% now.

OK so next iteration of the loop, I now have a valve position of 54%, and lets say RPM dropped to 1200, because the valve closed some on the last iteration.. that gives us a delta of -3. or a new valve position of 51%, next time through, lets say the RPM is 1000, that gives us -1.5, or a new valve position of 49.5%...

You'll notice a trend, in that the correction amount is proportionally growing smaller as I get closer to my target, which is exactly what is supposed to happen. Once I'm close enough, the amount of correction due to P will reach 0, and I think we can all agree on that. That is with my current algorithm. Once the delta reaches 0, the valve position (or OUTPUT as you're calling it) will remain the same, which means RPM will remain the same.
My questions now is how do I convince the MS guys they are wrong?
You don't, because it isn't wrong.
If I felt the guys on that board wanted to make it work right, instead of just BE right, I'd go through the trouble of fixing it.
We do want it to work right, the trouble is that it already does!

Ken
User avatar
muythaibxr
TO220 - Visibile
Posts: 4
Joined: Sat Apr 05, 2008 12:39 am

Re: PID control discussion

Post by muythaibxr »

8InchesFlacid wrote: For idle it is just plain wacky, and next to impossible to tune.
Which is why several people have tuned it and are using it daily on their daily drivers... the problem isn't the algorithm, it's that it needs to be tuned correctly.
I guess this is twofold, then. 1) I'd like to come up with a decent argument to tell the MS people they need to work on their code
There is no argument, I believe I just proved that in my last post. The P term is doing exactly what it should, with actual numbers entered into the equations I used. I'd be open to argument if the argument were logically sound.

Ken
User avatar
muythaibxr
TO220 - Visibile
Posts: 4
Joined: Sat Apr 05, 2008 12:39 am

Re: PID control discussion

Post by muythaibxr »

Also, Abe... I believe I made a good point on msextra the last time you tried to say that there was a built-in integral:
IF the output continues to increase/decrease as you get close to the set point, it is because the integral limit I have in the code is too large for your application, or because you have your I term set too high. If you build up positive error, even as you get close to the set-point, you have to get just as much negative error to offset it, which means you have to overshoot a bit for it to correct. The easiest way to avoid this happening is to reduce your I term.

I *could* zero the error sum when you cross the set-point, and this behavior would go away.
Ken
User avatar
AbeFM
Post Whore!
Posts: 629
Joined: Sat Feb 16, 2008 12:11 am
Location: Sunny San Diego
Contact:

Re: PID control discussion

Post by AbeFM »

muythaibxr wrote:
I'll have to look, I think what happened is the MS folks are using
Alpha = KP
Beta = KI
Gama = KD

Or something like that, I have to look closer. But they are doing something way wrong.
No, this just shows that you didn't read the code carefully.
Great, let's get into symantics on the ONE part where I specifically qualified it with "I have to look closer".

Come ON here. I'm trying to get a handle on this, with a guy who seems to know some of the controller theory pretty well, specifically to avoid cluttering up the MS board with any under thought out conversation.

What we're doing is:

Alpha = Kp + Ki - Kd


And we're not doing Beta or Gamma...
So, you've applied a transform, then dropped a bunch of terms? You'll note the beta term specifically cancels out the additive effects of the Kp in the alpha term. It's a shortcut, and I think it breaks the way it's supposed to work.
which in turn boils down to:

Code: Select all

                            error = target - actual;
                            OUTPUT += Kp * error;
That's an integral.
No, it's not...
It's not an integral? Here's a thought experiment (which works really well in the limit the timing period is very short compared to the response, more on this later).

Let's use your numbers, ok?
So, for example, if I've got a current valve position of
60%, and my RPM is at 1600, and my target is 800, and my P term is set to 60, I'll get a delta for this iteration of -6 (assuming a valve closed of 0, and valve open of 100). That gives me a valve position of 54% now.
Ok, awesome.
OK so next iteration of the loop, I now have a valve position of 54%, and lets say RPM dropped to 1200, because the valve closed some on the last iteration..
Now you have to be kidding me. Your motor was at 1600 rpm. That's 26 revolutions per second, or 37milliseconds per revolution. Now I forget if you run 200 ms loop time or 100, but either way, you expect me to believe in 5 revolutions you dropped 400 RPM, all from cracking a valve a couple percent? I can kill the ignition and my motor won't drop 400 revolutions per second.

I've watched my tach, and I can tell you that in 200 ms you'll be lucky to see the RPM change ... My target was likely 800 or 850 rpm in all this.

Ok, from my logs:
valve at 66%, rpm at 1030, time 2.198 seconds
valve at 57%, rpm at 913, time 2.854 seconds
valve still 57, rpm at 733, time 3.869 seconds.

Another case, RPM had been stable between 940 and 935 rpm for a few seconds.
Valve stable at 58%, RPM 935, time 79.2
valve closes linearly to 41% at time 80.5, RPM 924
valve stays at new position (41%), RPM drops to 788 at 81.2 seconds.

So, more like 194 (call it 200) rpm/second, or 40 rpm per loop.

Now, with a factor of ten removed, it reads
OK so next iteration of the loop, I now have a valve position of 54%, and lets say RPM dropped to 1540, because the valve closed some on the last iteration..
that gives us a delta of -3. or a new valve position of 51%, next time through, lets say the RPM is 1000, that gives us -1.5, or a new valve position of 49.5%...
Ok, this becomes
that gives us a delta of -6. or a new valve position of 48%, next time through, lets say the RPM is 1500, that gives us -5.5, or a new valve position of 42.5%...

The trend I'm seeing here is exactly what I'd expect from an integral only controller. The longer you're on one side of the target, the more the correction piles up, making your set point further and further from the correct value by the time you get to the steady state.

The error in a proportional control should stay at a fixed value, there should be an offset in the steady state.

Now I'm not arguing what you're doing can't work, I'm saying it's not a PID controller, it's just an equation that moves an output based on some input, and you might be able to make it work (and in this case, people have. Kudos).

The P-only controller you have will only work (as a P controller) in the case that your time steps are much much slower than the response of the system. You can compensate somewhat by making the P values very very small, then waiting for their integration to add up to what they should be, then using your integral term as a double integral hoping that function will overpower the P term in some way to integrate faster, a higher order term... But it's sloppy.

The basic point is, in a correct Z-transform (did you read that part, or just skim for something to argue with?), the older P contributions are subtracted back out. In a true PID controller without the transform, you never add them in.

You are not defining how much to move the output, you're defining the output directly with the P-term.

My questions now is how do I convince the MS guys they are wrong?
I am not convinced yet that you are doing it right. I'm not arguing that it isn't a good effort, and not that it doesn't work. I'm just saying I don't think it's a PID controller. I guess do the math, UN z-transform it, and you'll figure out what you're effectively doing.



One more take on this:
A cleaner, more mathematical way to look at it:
OUTPUT[0] = (Kp + Ki + Kd) * Error[0] - (Kp + 2 * Kd) * Error[1] + Kd * Error[2] + OUTPUT[1]

Here, Ki is not an integral *function*, it's a gain. Kd is also a constant, not a function.

In your code (Is it yours? I'm not assigning fault here, I just mean the MS-IIx code), you have the line:
pwmidle_error_sum += rpm_error;

And what you call Ki ends up being a constant times the above. But, if I understand the Z-transform math above, Ki is only the constant, so you're effectively double integrating again, as I've had the feeling all along.


I'm still floundering a bit here mathematically, but I don't yet see that I'm wrong. I do see several places in the MS-IIx version that don't really make sense to me, I think they are doing other things than intended in a true PID controller, z-transform or otherwise.
User avatar
muythaibxr
TO220 - Visibile
Posts: 4
Joined: Sat Apr 05, 2008 12:39 am

Re: PID control discussion

Post by muythaibxr »

OK so next iteration of the loop, I now have a valve position of 54%, and lets say RPM dropped to 1200, because the valve closed some on the last iteration..
Now you have to be kidding me. Your motor was at 1600 rpm. That's 26 revolutions per second, or 37milliseconds per revolution. Now I forget if you run 200 ms loop time or 100, but either way, you expect me to believe in 5 revolutions you dropped 400 RPM, all from cracking a valve a couple percent? I can kill the ignition and my motor won't drop 400 revolutions per second.
That doesn't matter, the point is that no matter how much engine speed changes, eventually with only a P term set, the delta will reach 0. The only reason it wouldn't is if your P term is too high, and it overcorrects, overshooting the target. This is EXACTLY what can happen with a P term that's too high.

The trend I'm seeing here is exactly what I'd expect from an integral only controller. The longer you're on one side of the target, the more the correction piles up, making your set point further and further from the correct value by the time you get to the steady state.
No, what you're seeing here is overshoot due to the P term being way too high. The correction doesn't "pile up," steady state is just never reached, again because your P term is way too high, or your loop speed is way too fast. If it doesn't overshoot due to having a P term that's way too high, you will eventually get a delta of 0 assuming P only, and it'll stop some set amount above the target RPM.
Now I'm not arguing what you're doing can't work, I'm saying it's not a PID controller, it's just an equation that moves an output based on some input, and you might be able to make it work (and in this case, people have. Kudos).
And I disagree... IT does exactly what it's supposed to do to the limits of the precision of the PWM output I have.
The P-only controller you have will only work (as a P controller) in the case that your time steps are much much slower than the response of the system. You can compensate somewhat by making the P values very very small, then waiting for their integration to add up to what they should be, then using your integral term as a double integral hoping that function will overpower the P term in some way to integrate faster, a higher order term... But it's sloppy.
No, it'll work in any case as long as you set the variables correctly. If you set them according to the wiki, adjust P until you get oscillation, then I, etc... it works. IT's not hard to tune. The only people who have had trouble have had trouble because the PWM output is not that precise being that it's actuated from the RTC and not using a real PWM channel.
The basic point is, in a correct Z-transform (did you read that part, or just skim for something to argue with?), the older P contributions are subtracted back out. In a true PID controller without the transform, you never add them in.
Actually, I did read that section, and the code presented in that section almost EXACTLY MATCHES my code. I implemented my code independently of the wiki in any case, so it's pretty nice that my code matches up pretty well with the code that was there.

The Alpha-Beta-Gamma algorithm introduces predictions into a standard PID loop, which can end up subtracting out some P in a slow-to-react system. However, that doesn't mean that my code isn't a PID controller, it means that there are different types of PID controller.
You are not defining how much to move the output, you're defining the output directly with the P-term.
This is where we disagree... pretty much all the PID controllers I've seen take an error and use it to generate a delta, which is added/subtracted from the steady-state value.
I am not convinced yet that you are doing it right. I'm not arguing that it isn't a good effort, and not that it doesn't work. I'm just saying I don't think it's a PID controller. I guess do the math, UN z-transform it, and you'll figure out what you're effectively doing.
I actually went and implemented it the non-z-transform way, and it didn't work at all. I probably could've made it work if I readjusted the other parts of my code to make it work, but then I'd end up with something that wasn't any better than what I started with.

In your code (Is it yours? I'm not assigning fault here, I just mean the MS-IIx code), you have the line:
pwmidle_error_sum += rpm_error;

And what you call Ki ends up being a constant times the above. But, if I understand the Z-transform math above, Ki is only the constant, so you're effectively double integrating again, as I've had the feeling all along.
No, I'm taking the current error sum, and adding to it the current RPM error, and then multiplying that by a gain. I'm not double integrating... because the OUTPUT is not an INPUT to the PID loop. I'm doing a single integration, and then using that and a gain to determine how much effect I want the accumulated error to have on the delta that's generated.
I'm still floundering a bit here mathematically, but I don't yet see that I'm wrong. I do see several places in the MS-IIx version that don't really make sense to me, I think they are doing other things than intended in a true PID controller, z-transform or otherwise.
As I've said countless times, I think your only major problem here is that you're confusing the inputs to the PID loop with the outputs of the loop.

The inputs are error, error_sum, and error_diff, the output is delta, which is applied to a current position... if I take the inputs and do the proper math, generate a delta, and apply it to a current valve position, RPM will change, and the next time through the PID loop, I can re-evaluate all the parameters.

Never at any time does the current valve position or the last delta get re-incorporated as an input to the PID controller, every time through the loop I take error, error_sum, and error_diff, multiply them by their appropriate gains, use them to generate a delta, and apply that delta to the current valve position.

I'm sure there are probably just a couple of settings that are incorrect on your setup that are causing the problems you're seeing. I asked you for an msq so I could help you get more reasonable behavior, and I never got that. I think the root cause of your problem is that I can only control the valve to about .4% units at very low frequencies, or at usable frequencies, 1-2%, which is why Keithg is pulling apart his ms2 to get at those real pwm channels.

In any case, it works as well as it can given the PWM output problem, so I'm done arguing it. The wonderful thing about PID controllers is that they can be done different ways. I chose the way I chose, it works for everyone who's tried it aside from you and the odd few who recently ran into bugs that were unrelated to the PID loop itself, so I'm done discussing it. If you don't like the way it works, go write some code that works the way you want it to. My code is a PID controller, and it does work the way it's supposed to. I'd fix the code if anything you said made me think it was broken, as I don't want bugs in my code.

Ken
thebigmacd
LQFP112 - Up with the play
Posts: 205
Joined: Thu Apr 10, 2008 5:51 pm

Re: PID control discussion

Post by thebigmacd »

Output += Ki*Error is a purely integral controller. The += denotes that it is a first-order controller in that it refers to its previous value. Do not use Kp here.

Output = Kp*Error is a proportional controller. This is a zeroeth-order function and will never stabilize at setpoint. A proportional controller ignores all past states. It operates "in the now".

I disagree with Ken here: If it doesn't have Alpha, Beta, AND Gamma, it is NOT a PID loop, it is a PI loop, PD loop, lead/lag controller, or some other related IIR filter.

PID means Proportional, Integral, Derivative

The derivative term is the prediction part, where you modify the output based on where the error is going. If Kd is included in Alpha, you have to include Beta and Gamma or else it just won't behave like a PID should. The math of a true PID controller in discrete space dictates that you must use "two samples ago" in the equation because it is a second-order transfer function.

If you aren't going to use a proper derivative, Kd should not find its way into your programming. The PID, PI, and P controller formulas I have provided are correct. Leaving out constants in some places and leaving them in in another is a bastardization and would have gotten me a failing grade in Control Engineering (Systems) Technology.
Keith MacDonald
Control Engineering (Systems) Technologist
User avatar
Fred
Moderator
Posts: 15431
Joined: Tue Jan 15, 2008 2:31 pm
Location: Home sweet home!
Contact:

Re: PID control discussion

Post by Fred »

Thanks for having your say Ken! A balanced discussion is important, and I appreciate that you took the time to make it that way.

It seems to me that what we have is some sort of issue with nomenclature mainly.

I won't get involved more than that though, as I don't have the time to think it through for myself, and shallow reading and then commenting is clearly not appropriate in this thread. This will certainly serve as a good reference though for later when we do need such code to perform certain functions.

I think Flacid nailed it when he said this :
It would be nice to have a decent understanding of what we need to do here when we start trying to control those simpler things.
That to me is the key thing as my math is a little rusty :-)

Admin.
DIYEFI.org - where Open Source means Open Source, and Free means Freedom
FreeEMS.org - the open source engine management system
FreeEMS dev diary and its comments thread and my turbo truck!
n00bs, do NOT PM or email tech questions! Use the forum!
The ever growing list of FreeEMS success stories!
gearhead
LQFP112 - Up with the play
Posts: 120
Joined: Sun Feb 03, 2008 9:30 pm
Location: Chicago, USA

Re: PID control discussion

Post by gearhead »

thebigmacd wrote:Output += Ki*Error is a purely integral controller. The += denotes that it is a first-order controller in that it refers to its previous value. Do not use Kp here.

Output = Kp*Error is a proportional controller. This is a zeroeth-order function and will never stabilize at setpoint. A proportional controller ignores all past states. It operates "in the now".

I disagree with Ken here: If it doesn't have Alpha, Beta, AND Gamma, it is NOT a PID loop, it is a PI loop, PD loop, lead/lag controller, or some other related IIR filter.

PID means Proportional, Integral, Derivative

The derivative term is the prediction part, where you modify the output based on where the error is going. If Kd is included in Alpha, you have to include Beta and Gamma or else it just won't behave like a PID should. The math of a true PID controller in discrete space dictates that you must use "two samples ago" in the equation because it is a second-order transfer function.

If you aren't going to use a proper derivative, Kd should not find its way into your programming. The PID, PI, and P controller formulas I have provided are correct. Leaving out constants in some places and leaving them in in another is a bastardization and would have gotten me a failing grade in Control Engineering (Systems) Technology.
This explains why D really does not act in a derivative manner as it is increased in the O2 controller as well as the idle speed. You hit on the one thing that has been a factor that many have not paid enough heed to... This is discrete and not continuous *and* the inputs are way finer than the time variable and a few quanta finer than the output.

Gearhead
Post Reply