1. This forum section is a read-only archive which contains old newsgroup posts. If you wish to post a query, please do so in one of our main forum sections (here). This way you will get a faster, better response from the members on Motherboard Point.

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

Discussion in 'Embedded' started by cerr, Jan 6, 2012.

  1. cerr

    cerr Guest

    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
     
    cerr, Jan 6, 2012
    #1
    1. Advertising

  2. cerr

    cerr Guest

    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 <> 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
     
    cerr, Jan 6, 2012
    #2
    1. Advertising

  3. cerr

    Bruce Varley Guest

    "cerr" <> wrote in message
    news:...
    > 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?
     
    Bruce Varley, Jan 7, 2012
    #3
  4. cerr

    Tim Wescott Guest

    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
     
    Tim Wescott, Jan 7, 2012
    #4
  5. cerr

    Tim Wescott Guest

    On Fri, 06 Jan 2012 14:40:16 -0800, cerr wrote:
    (top posting fixed)
    > On Jan 6, 10:13 am, 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!
    >>

    > 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
     
    Tim Wescott, Jan 7, 2012
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dr. Albert Koelmans

    CFPart2: UK Embedded PhD Forum (deadline approaching)

    Dr. Albert Koelmans, May 14, 2004, in forum: Embedded
    Replies:
    1
    Views:
    294
    Ian Bell
    May 14, 2004
  2. free stuff guy

    maybe its a scan, but maybe its for real

    free stuff guy, Sep 16, 2004, in forum: Hardware
    Replies:
    1
    Views:
    296
    zixaq
    Sep 16, 2004
  3. Bob Johnson
    Replies:
    0
    Views:
    431
    Bob Johnson
    Aug 6, 2008
  4. Phred
    Replies:
    3
    Views:
    462
    Tony Harding
    Aug 9, 2008
  5. kishor
    Replies:
    9
    Views:
    634
    Jon Kirwan
    Dec 6, 2009
Loading...

Share This Page