PID control discussion

Official FreeEMS vanilla firmware development, the heart and soul of the system!
Post Reply
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 »

Apparently Smith is used in the PID O2 correction in ms2 base code.
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
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 »

Yes, I wonder if the smith predictor stuff is on a 'good' PID loop, or added into their not-so-good PID loop.

Ken said he has the same form of the other loops, and while they all += the output, if they are doing a full z-transform, it's not an issue.

---------
Oh, and even hyandia uses some active control of the AC to improve idle and pulling away from a start, it shuts it off under conditions where it would make it harder to leave a stop sign. Nice cars, those.


thebigmacd wrote:It would work but I don't think it should be implemented. I was just trying to show how a PID is just one of many types of controller that will do the same thing.
That I'm curious about. I like how it sounds, I'm tempted to try it, but you think it's a poor choice for idle control? I bet it's awesome for boost control, which has big issues with overshoot.

Tell me about that, I guess I will throw together code for idle control, either PID or this two-loop guy. Also, were it you, would you do the z-transform or the regular PID?

As to the programing, could I define alpha, beta, gamma on start up, or do I need to (costily) recalc them every time through the loop? If so, it seems you don't make the gains with the z-transform that you would otherwise have - the expensive opperations involved in rederiving them each time you might as well just use on doing true untransformed PID.
-Abe.
thebigmacd
LQFP112 - Up with the play
Posts: 205
Joined: Thu Apr 10, 2008 5:51 pm

Re: PID control discussion

Post by thebigmacd »

8InchesFlacid wrote:That I'm curious about. I like how it sounds, I'm tempted to try it, but you think it's a poor choice for idle control? I bet it's awesome for boost control, which has big issues with overshoot.

Tell me about that, I guess I will throw together code for idle control, either PID or this two-loop guy. Also, were it you, would you do the z-transform or the regular PID?

As to the programing, could I define alpha, beta, gamma on start up, or do I need to (costily) recalc them every time through the loop? If so, it seems you don't make the gains with the z-transform that you would otherwise have - the expensive opperations involved in rederiving them each time you might as well just use on doing true untransformed PID.
-Abe.
The reason I say not use it is you pretty much have to tune the inner loop independently which is isn't practical in an idle control situation. I figured out how to tune it with both loops active at once, but it's not quite as intuitive as tuning a PID.

If you maintain a fixed cycle period, Alpha, Beta, Gamma can be calculated at runtime, even compile-time if need be. Kd and Ki change in discrete space when you change the cycle period. If the cycle period changes (ie not on a strict schedule) ABG have to be calculated every time the cycle period changes.

Keep in mind that if you do a purely time-based PID, you still have to recalculate the constants every time the period changes. Otherwise, as you slow it down Ki will have less of an effect, and if you speed it up Ki will have more of an effect, as it affects how fast the accumulator is added to.

In code space, the z-transform form is most compact because the calculation is performed in one line with one equation, with a bunch of data shifts to accommodate it.
Keith MacDonald
Control Engineering (Systems) Technologist
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 »

Hmmm, ok, yeah. Unless you want to write an auto-tuner. Or assume one or the other can be held fixed at a reasonable value, but it doesn't sound too good.

PID:
Uh huh, I was dividing by time explicitly, and yes, that's much more work! I guess part of the choice on how to do it is how regularly you can update things. If it's irregular, I like the non-transform version.

What I'd really like is some sleep. :-) But I might try to throw together something.....
SSDwellah
TO92 - Vaguely active
Posts: 1
Joined: Sat May 03, 2008 6:42 pm

Re: PID control discussion

Post by SSDwellah »

Hello everyone,

This is my first time on this forum and between this thread and the Nissan CAS one, I think I am in the right place. I have a background in systems programming (especially on Linux in c and C++) and also electrical engineering so I hope I can be of some assistance.

Anyway, regarding the topic at hand, there are a couple of things I wanted to throw out there because I don't think they got too much coverage yet.

1. You're best bet is to stick with a PI controller, the D is too problematic and when it's wrong can make your control loop very unstable. I think some people already covered just making a PI controller, so I am in agreement with those people. This relates to the sensitivity of your sensors too, since a small amount of output change results in a wild output change.

2. I haven't seen much worry about integral runoff. If you don't know what that is, basically all of your sensor error (not just the actual error between your setpoint and current output, but the perceived output error due to noise, senor imprecision, etc...) gets accumulated into the integral portion of your PI or PID system. This can be dealt with by occasionally cross-referencing the output with an external trusted sensor input (not always possible), or by resetting/decrementing/halving or otherwise diminishing the integral part periodically.

3. PID control is linear, so it will not be able to control all types of systems optimally. That being said, temperature is a non-linear variable and we control it with thermostats so there is hope (thankfully, the temperature doesn't oscillate wildly between the outside ambient temperature and the set point of typically 70* F, it is a very slow responding system). Pressure is another nonlinear quantity, but we have boost controllers now don't we so it is a tractable problem. Maybe that's why nobody mentioned this aspect, because you are all "can do" positive type who like to DIY ;)

4. I'm curious which applications are we thinking of using PID control for? I can think of the obvious idle control, boost control, and perhaps some kind of adaptive knock timing retardation/fuel enrichment. For other types of outputs, such as frequency sensing binary outputs (think EGR operating at a certain band, or Honda VTEC/Nissan VTC or VVL/Toyota VVTI etc.. activating after a certain band) then we have to consider the idea of deadbands to avoid burning out switched output, but this is not a PID control so I won't derail this thread any further :P
User avatar
ababkin
LQFP112 - Up with the play
Posts: 215
Joined: Tue Jan 15, 2008 5:14 pm

Re: PID control discussion

Post by ababkin »

welcome
SSDwellah wrote: I'm curious which applications are we thinking of using PID control for? I
how about anything that has a feedback? ;)
Legal disclaimer for all my posts: I'm not responsible for anything, you are responsible for everything. This is an open and free world with no strings attached.
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 »

Welcome along :-)
SSDwellah wrote:This is my first time on this forum and between this thread and the Nissan CAS one, I think I am in the right place.
Awesome, just what I want to hear!
SSDwellah wrote:I have a background in systems programming (especially on Linux in c and C++) and also electrical engineering so I hope I can be of some assistance.
Even more awesome as I'm a Java guy and a noob to C :-)
Maybe that's why nobody mentioned this aspect, because you are all "can do" positive type who like to DIY ;)
More of exactly what I want to hear, I'm glad we come across that way to you :-)
SSDwellah wrote:4. I'm curious which applications are we thinking of using PID control for? I can think of the obvious idle control, boost control, and perhaps some kind of adaptive knock timing retardation/fuel enrichment. For other types of outputs, such as frequency sensing binary outputs (think EGR operating at a certain band, or Honda VTEC/Nissan VTC or VVL/Toyota VVTI etc.. activating after a certain band) then we have to consider the idea of deadbands to avoid burning out switched output, but this is not a PID control so I won't derail this thread any further :P
Just the obvious really. I knew there were questions raised about the MS2 implementation and wanted to get some discussion going on so that we get it right. So far 3 of you have real world experience with these things and another one (yes you Abe) has some strong opinions.

I'm a fairly practical pragmatic perfectionist, so I'm up for whatever makes the engine run the best while trying to strive for technical superiority and scientific accuracy.

In other words, we will do whatever works best for things such as that :-)

Thanks for signing up!

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!
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 »

thebigmacd wrote:

Code: Select all

OUTPUT[0] = (Kp + Ki + Kd) * Error[0] - (Kp + 2 * Kd) * Error[1] + Kd * Error[2] + OUTPUT[1]
We add lines before and after to shift the data to the proper array location and we are done. As stated in the info above, Kd, Ki, and Kp change depending on the sample period. We can add the last output value by using += rather than using an array index.

Code: Select all

Error[2] = Error[1]              //Shift data by one time constant
Error[1] = Error[0]              //Shift data by one time constant
Error[0] = Actual - Requested    //Calculate error NOW
Alpha = Kp + Ki + Kd             //Calculate Alpha constant
Beta = Kp + 2 * Kd               //Calculate Beta constant
Gamma = Kd                       //Calculate Gamma constant
OUTPUT += Alpha * Error[0] - Beta * Error[1] + Gamma * Error[2]
Instant PID control.

Ok, for kicks, I tried to write this up. Only, with everything being an int, can I really do this? Isn't kP, kI, and kD often less than one?

I have a feeling I'll need to multiply everything by 1000, and divide the output by 1000, but I'm just not sure.

Anyway, here's what I got. Haven't even tried to compile it yet.
Declarations:

Code: Select all

char valve_closed;
int boost_ctl_error_sum, boost_ctl_last_error;
int pwmidle_error_sum, pwmidle_last_error;
int pwmidle_stepsize, pwmidle_numsteps;
int pwmidle_error_array[3];		//Holds the current error (element 0) through the error two loops ago (element 2)
int z_alpha, z_beta, z_gamma;		//holders for the z-transform proportional, integral and derivative k constants, respectively
Initialization:

Code: Select all

//My version of idle_ctl_init
void idle_ctl_init(void)
{
    pwmidle_error_sum = 0;
    pwmidle_last_error = 0;
    IACmotor_reset = 2;
    pwmidle_timer = 0;
    pwmidle_stepsize = 0;
    pwmidle_numsteps = 0;
		ztrans_idle_error_array = {0,0,0};    	//Be sure there's no weird data in the error array.
   		//Perhaps there are better values to use here for initialization?
		
		//Initialize the Alpha, Beta, Gamma constants of the Z-transform
		z_alpha = flash5.pwmidle_Kp + flash5.pwmidle_Ki + flash5.pwmidle_Kd;		//initiallize the Alpha constant
		z_beta = flash5.pwmidle_Kp + (2 * flash5.pwmidle_Kd);		//initiallize the Beta constant
		z_gamma = flash5.pwmidle_Kd;		//initiallize the Gamma constant
		}

Code: Select all

														//shift over values in error array each loop, a "time step". Z += 1
														ztrans_idle_error_array[2] = ztrans_idle_error_array[1];
														ztrans_idle_error_array[1] = ztrans_idle_error_array[0];
														
                            ztrans_idle_error_array[0] = (int)outpc.rpm - (int)targ_rpm;	// Error is actual - target
                            	//Is the sign correct here?

//Original code repeated here.  Don't know what IdleCtl = 6 is, don't know these constants. Try leaving them out?
//                            if (IdleCtl == 6) {
//				tmp1 = (((long)((Kp + Ki - Kd) / 100 ) << 8) *
//				       (int)(flash5.pwmidle_open_duty - flash5.pwmidle_closed_duty)) /
//                                       ((long)pg5_ptr->pwmidle_target_rpms[PWMIDLE_NUM_BINS - 1] * 2550);
//			    } else {
//				tmp1 = ((long)(Kp + Ki - Kd) * (int)(flash5.pwmidle_open_duty - flash5.pwmidle_closed_duty)) /
//				       ((long)pg5_ptr->pwmidle_target_rpms[PWMIDLE_NUM_BINS - 1] * 1000);
//			    }



//output of the form: OUTPUT += Alpha * Error[0] - Beta * Error[1] + Gamma * Error[2]
//Note subtraction of the beta term prevents kP term from summing to infinity
                            tmp1 = (IACmotor_pos // this is the += part
                            				+ (z_alpha * pwmidle_error_array[0])	//this is the "now" part
                            				- (z_beta * pwmidle_error_array[1])		//this is the "last time" part
                            				+ (z_gamma * pwmidle_error_array[2]));	//this is contribution from 2 loops ago

                            if (IdleCtl == 7 || IdleCtl == 8) {
                                if (tmp1 > (int)flash5.pwmidle_min_duty) {
                                    tmp1 = flash5.pwmidle_min_duty;
                                } else if (tmp1 < (int)flash5.pwmidle_open_duty) {
                                    tmp1 = flash5.pwmidle_open_duty;
                                }
                            } else {
                                if (tmp1 < flash5.pwmidle_min_duty) {
                                    tmp1 = flash5.pwmidle_min_duty;
                                } else if (tmp1 > flash5.pwmidle_open_duty) {
                                    tmp1 = flash5.pwmidle_open_duty;
                                }
                            }
                            DISABLE_INTERRUPTS;
                            IACmotor_pos = tmp1;	//Set output (valve pos) to calculated value
                            ENABLE_INTERRUPTS;
You can tell which lines I wrote because there are comments on them. Everything else is original MS-IIx 2.0.1 code.

Let me know if you think my car will explode running this. :-) Or if I'm doing something way wrong.
thebigmacd
LQFP112 - Up with the play
Posts: 205
Joined: Thu Apr 10, 2008 5:51 pm

Re: PID control discussion

Post by thebigmacd »

It will rev to infinity ;)

Error should be changed to "target - actual". Unless your idle valve is reverse acting, where more PWM = lower idle. In that case your code would work, but you would be better off doing the inversion on the output handling side of things.

Yes you want your initial error to be zeros across the board. Unless you want to give a bit of a "blip" when the control kicks in, then you could initialize them to some negative number. But I can't see you wanting to do that.

Yes you may have to do some constant multiplication to get the resolution you want.
Keith MacDonald
Control Engineering (Systems) Technologist
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 »

Heh... I hate to say this, but I had it the other way around, but got the sign from your code snippet and figured I'd read through it before and it seemed reasonable so didn't bother with the details. I'll put it back.

But thanks for the once over. Now if I can finish my Battle with the Compiler, I'll let you know how it works.
-Abe.
Post Reply