Motherboard Forums


Reply
Thread Tools Display Modes

PID... maybe I need a PhD...?

 
 
cerr
Guest
Posts: n/a
 
      01-06-2012, 06:13 PM
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!

Thank you!
roN
 
Reply With Quote
 
 
 
 
cerr
Guest
Posts: n/a
 
      01-06-2012, 10:40 PM
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?

Thanks,
Ron

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!
>
> Thank you!
> roN


 
Reply With Quote
 
 
 
 
Bruce Varley
Guest
Posts: n/a
 
      01-07-2012, 05:49 AM

"cerr" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> 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!
>
> Thank you!
> roN


From your followup posting, this may not be a simple loop oscillation. A bit
of info on your timing would help, maybe it's inferrable from your code but
I don't have the energy to troll through it. Can you let us know the
frequency of the PID function and of the PWM?


 
Reply With Quote
 
Tim Wescott
Guest
Posts: n/a
 
      01-07-2012, 07:48 AM
On Fri, 06 Jan 2012 10:13:26 -0800, cerr 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!
>
> Thank you!
> roN


I'm not sure what else is going on, but your error term should be
command - feedback; you've got the value backwards.

--
Tim Wescott
Control system and signal processing consulting
www.wescottdesign.com
 
Reply With Quote
 
Tim Wescott
Guest
Posts: n/a
 
      01-07-2012, 07:56 AM
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
 
Reply With Quote
 
 
 
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: OT (maybe, maybe not): freeware utility software Phred Dell 3 08-09-2008 06:35 PM
Re: OT (maybe, maybe not): freeware utility software Bob Johnson Dell 0 08-06-2008 01:42 PM
maybe its a scan, but maybe its for real free stuff guy Hardware 1 09-16-2004 06:04 AM
Re: Maybe I do need a PDA?! Dell Axim? Howard Dell 0 10-21-2003 09:06 PM
Re: Maybe I do need a PDA?! Dell Axim? Prilosec Dell 1 10-17-2003 05:41 AM


All times are GMT. The time now is 04:33 AM.


Welcome!
Welcome to Motherboard Point
 

Advertisment