On Fri, 06 Jan 2012 14:40:16 -0800, cerr wrote:

(top posting fixed)

> On Jan 6, 10:13Â*am, cerr <(E-Mail Removed)> wrote:

>> Hi Guys,

>>

>> I used Tim Wescott's PID without a PhD document to come up with my

>> controller loop.

>> Now, my application is a light source that is being controlled with the

>> duty cycle of a pwm - I have a current feedback loop that is telling me

>> how much current is going through the LEDs. Now to get these values on

>> the same scale, I just read what my ADC reads at maximum allowed

>> current and that is 100%. And then my input (IRDrive) is controlling

>> how intens the LEDs should be (again in %). My control loop looks like

>> this:

>> double UpdatePID(SPid * pid, double error, double position) {

>> double pTerm,

>> dTerm, iTerm;

>> pTerm = pid->pGain * error;

>> // calculate the proportional term

>> // calculate the integral state with appropriate limiting pid->iState

>> += error;

>> if (pid->iState > pid->iMax) pid->iState = pid->iMax; else if

>> (pid->iState

>> <

>> pid->iMin) pid->iState = pid->iMin;

>> iTerm = pid->iGain * pid->iState; // calculate the integral term dTerm

>> = pid->dGain * (position - pid->dState); pid->dState = position;

>> return pTerm + iTerm - dTerm;}

>>

>> And I played around with various P,I and D gains but seem not to be

>> able to get it ionto a steady state, it keeps flocking all over. The

>> struct looks like this:

>> typedef struct

>> {

>> double dState; // Last position input double iState; // Integrator

>> state

>> double iMax, iMin;

>> // Maximum and minimum allowable integrator state double iGain, //

>> integral gain

>> pGain, // proportional gain

>> dGain; // derivative gain} SPid;

>>

>> Before I implemented the PID controller, I simply had this:

>> AVGfdbckprcnt = ((float)100/(float)MAX_CURRENT) * AVGfeedback; /* Â* Â* Â*

>> Â* Â* Â* Â*if (AVGfdbckprcnt < IRDrive){

>> Â* Â* Â* Â* Â* Â* Â* Â* Â* if (CurrPWM < 255)

>> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* CurrPWM++;

>> Â* Â* Â* Â* Â* Â* Â* Â* Â* PWM_WriteCompare(CurrPWM);

>> Â* Â* Â* Â* Â* Â* Â* Â* }

>> Â* Â* Â* Â* Â* Â* Â* Â* else if (AVGfdbckprcnt > IRDrive){

>> Â* Â* Â* Â* Â* Â* Â* Â* Â* if (CurrPWM > 0)

>> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* CurrPWM--;

>> Â* Â* Â* Â* Â* Â* Â* Â* Â* PWM_WriteCompare(CurrPWM);

>> Â* Â* Â* Â* Â* Â* Â* Â* }

>> Â* Â* Â* Â* Â* Â* Â* Â* else

>> Â* Â* Â* Â* Â* Â* Â* Â* Â* continue;

>> Â* Â* Â* Â* Â* Â* Â* Â* PWM_WriteCompare(CurrPWM);

>> Which worked fine and now i replaced this with: AVGfdbckprcnt =

>> ((float)100/(float)MAX_CURRENT) * AVGfeedback; CurrPWM =

>> UpdatePID(&Cntrl, AVGfdbckprcnt-IRDrive, AVGfdbckprcnt);

>> PWM_WriteCompare(CurrPWM);

>> which doesn't quite work yet... Any clues, hints or suggestions would

>> be appreciated!

>>

> Ok,

>

> I got a few more details. In order to tuine the controller, in the doc

> it says

> "If it isn't set already, set the proportional gain to a starting value

> between 1 and 100. Your system will probably either show terribly slow

> performance or it will oscillate. If you see oscillation, drop the

> proportional gain by factors of eight or 10 until the oscillation

> stops."

>

> Now at 1 my circuit oscillates thus I go down and down and down and am

> now at a pGain or 0.020405 and it's still oscillating - it just seems

> like the smaller the number gets, the lower the oscillation frequency

> gets. I'm now in the milliHertz area already, it seems like it trys to

> reach the target ever 3 (or so) seconds and the rest of the time it's

> just at 0. It also seems to change as I modify the target to reach but

> there's no talk of that in the doc from T. Wescott. Not sure if my code

> is off somewhere...?

>

> Any hints or suggestions anyone?
What is the basic behavior of your LED circuit? It seems that this

should be a fairly instantaneous (if not always nicely linear) response:

i.e., the response to a step change in the drive is a step change in the

feedback, without any "tail" -- is this so?

If so, then I'm surprised. That sort of behavior is best handled with a

pure integrator (proportional and differential action are only of help

when the plant shows lag that extends past the next sampling instant). A

purely proportional gain will either be stable or will go into an

oscillation with a period of half the sampling rate; it certainly won't

do what you're seeing. Given that your original code is a very crude

approximation of a pure integrator, I'm even more puzzled why pure

proportional gain causes problems.

Try fixing your sign inversion problem, then (if I'm correct about your

plant behavior) try setting the proportional and derivative gains to

zero, and experiment with integral gain only. You should be able to

deduce proper operation -- if the current is too high then the drive

should go down, and visa-versa. What integral action will give you that

your current algorithm doesn't (aside from not giving control guys who

look at it headaches) is a much faster response when the actual feedback

is a good deal different than the target value.

--

Tim Wescott

Control system and signal processing consulting

www.wescottdesign.com