This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

C2000-DIGITAL-CONTROL-LIBRARY: Updating DCL PID parameters in a routine

Part Number: C2000-DIGITAL-CONTROL-LIBRARY

Hi,

In my digital power converter, I'm using DCL libraries. I use DCL_runPID_C4 and DCL_runClamp_C1 for anti-windup reset. I'm calling PID update function at every 100msec in order to tune it.

If I don't call update function at every 100msec task, my power converter works stable.

If I call update function at every 100msec task, my power converter gets unstable in time. It seems that something change behind.

I'm using fupdate function in order not to break any ISR.

During Init I use below function:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// initialise controller variables
gi_pid.sps = &gi_pid_sps;
gi_pid.css = &gi_pid_css;
gi_pid.css->T = (float32_t)1.0f / DRV_EPWM_SWITCHING_FREQUENCY;
gi_pid.Kp = 0.05f;
gi_pid.Ki = 0.001f;
gi_pid.Kd = 0.0f;
gi_pid.Kr = 1.0f;
gi_pid.c1 = 188.0f;
gi_pid.c2 = 0.88f;
gi_pid.d2 = 0.0f;
gi_pid.d3 = 0.0f;
gi_pid.i10 = 0.0f;
gi_pid.i14 = 1.0f;
gi_pid.Umax = 0.8f;
gi_pid.Umin = 0.0f;
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

I call below function at every 100msec task;

Fullscreen
1
2
3
4
5
6
7
8
9
gi_pid.sps->Kp = gi_Kp_temp/100000.0f;
gi_pid.sps->Ki = gi_Ki_temp/100000.0f;
gi_pid.sps->Kd = gi_Kd_temp/100.0f;
gi_pid.sps->Umax = gi_Umax_temp / 100.0f;
gi_pid.sps->c1 = gi_c1_temp;
gi_pid.sps->c2 = gi_c2_temp / 100.0f;
// Values taken from UART
DCL_REQUEST_UPDATE(&gi_pid);
DCL_fupdatePID(&gi_pid);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Even if I don't change any PID parameters, update function at above is called.

1) Could you please review my code and if any fix required comment please?

2) I actually don't know why setting DRV_EPWM_SWITCHING_FREQUENCY for css->T. Do I need to call it again at 100msec task? Please, comment on purpose.

3) I use ADC prescaler and get into ISR routine at 50kHz. However, Fpwm =100kHz. Which value should I use for DRV_EPWM_SWITCHING_FREQUENCY for css->T?

Thanks in advance.

  • Hi Gokhan,

    Thank you for posting questions on this forum, I'll also answer your questions in bullet points:

    1.) Everything looks good to me as far as the routine goes, I don't see any issues here.

    2.) The controller period (css->T) is only used by helper functions that help determine PID's low-pass filter coefficient (c1 & c2), since you already have these coefficients pre-determined and not using the helper function, this variable is irrelevant to you.

    3.) As above, css-> T is irrelevant in PID calculations.

    As to the reason why PID gets unstable, it could due to several causes. But my suspicion would be that the update ISR occasionally interrupts in the middle of PID calculation which causes the sudden spikes in PID outputs. Testing this hypothesis would be pretty straightforward as well, you could try disabling the interrupts during PID calculation and see if the unstable behavior still exists. 

    In DCL we've also provided the macro to disable and re-enable the interrupts ( DCL_DISABLE_INTS(), DCL_RESTORE_INTS() ).

    Best,

    Sen Wang

  • Hi Sen,

    Can you please explain more on usage helper function? If any document available, please provide.

    Do I need to insert above lines at ISR before and after control loop run function or during PID Update task before and after function in 100msec task?

    I observed that if I call below functions, my PID gets unstable.

    " DCL_REQUEST_UPDATE(&gi_pid);
    DCL_fupdatePID(&gi_pid);"

  • Hi Sen,

    I also wanted to use fupdate function in order not to cut my isr routine. However, as I read from users guide, it cuts my other PWM interrupt.

    It is written that interrupts are blocked. Can you comment please?

  • Hi,

    I added DCL_CLEAR_UPDATE_REQUEST(&gi_pid); after "DCL_fupdatePID(&gi_pid); " line. So I firstly request and then update and than clear. It fixed some of my issues but I need to learn more how some oscillations got cleared. Can you also comment on this line and its feature?

  • Hi Gokhan,

    DCL_fupdatePID stands for fast update and it does block interrupts but in a minimalist way and is implemented in assembly. If you don't need a function interrupt protection, you could implement it yourself and it will be pretty straightforward as well. (Copying values from CSS->SPS to CSS)

     As to DCL_CLEAR_UPDATE_REQUEST, it shouldn't do anything to the underlaying code, the flag should be already cleared by DCL_fupdatePID.

     And please disregard my previous comment on the possible cause, I had the wrong assumption due to lack of info. If PWM is driving your output and is ISR frequency is time critical, then the interrupt disruption from DCL_fupdatePID might be the culprit.

    Best,

    Sen Wang

  • Hi Sen,

    DCL_fupdatePID stands for fast update and it does block interrupts but in a minimalist way and is implemented in assembly. If you need a function interrupt protection, you could implement it yourself and it will be pretty straightforward as well. (Copying values from CSS->SPS to CSS)

    Could you please write required lines? I really cannot find enough information about the usage. I refer DCL User's guide, but there is no detailed explanation about the usage.

    Can you please explain more on usage helper function? If any document available, please provide.

    Do I need to insert above lines at ISR before and after control loop run function or during PID Update task before and after function in 100msec task?

    Could you please explain further? 

  • Hi Gokhan,

    I made a typo on my previous response, I meant to say " If you don't need interrupt protection". My apologies.

    The update routine without interrupt protection is as follow:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if (p->css->sts & STS_UPDATE_PENDING)
    {
    p->Kp = p->sps->Kp;
    p->Ki = p->sps->Ki;
    p->Kd = p->sps->Kd;
    p->Kr = p->sps->Kr;
    p->c1 = p->sps->c1;
    p->c2 = p->sps->c2;
    p->Umax = p->sps->Umax;
    p->Umin = p->sps->Umin;
    DCL_CLEAR_UPDATE_REQUEST(p);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Essentially the same as DCL_updatePID implemented in DCLF32.h but without interrupt protection. In your case, you could even get rid of the if statement and DCL_CLEAR_UPDATE_REQUEST. As you want the update routine to update parameter regardless of the semaphore bit.

    See if this helps, if not we can further troubleshoot the problem.

    And Gokhan do you mind pointing out things you found missing from the DCL user's guide. We could incorporate your input into the next revision of the user's guide. 

    Best,

    Sen Wang

     

  • Hi Sen,

    I changed update routine as below. Is it correct? I got " #45 expression must have pointer type " buid errors. Can you help on it?

    I call below lines at ADC ISR.

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    PSFB_gi_pid.sps->Kp = New_PSFB_gi_Kp_temp/100000.0f;
    PSFB_gi_pid.sps->Ki = New_PSFB_gi_Ki_temp/100000.0f;
    PSFB_gi_pid.sps->Kd = New_PSFB_gi_Kd_temp/100.0f;
    PSFB_gi_pid.sps->Umax = New_PSFB_gi_Umax_temp / 100.0f;
    PSFB_gi_pid.sps->c1 = New_PSFB_gi_c1_temp;
    PSFB_gi_pid.sps->c2 = New_PSFB_gi_c2_temp / 100.0f;
    DCL_REQUEST_UPDATE(&PSFB_gi_pid);
    if (PSFB_gi_pid->css->sts & STS_UPDATE_PENDING)
    {
    PSFB_gi_pid->Kp = PSFB_gi_pid->sps->Kp;
    PSFB_gi_pid->Ki = PSFB_gi_pid->sps->Ki;
    PSFB_gi_pid->Kd = PSFB_gi_pid->sps->Kd;
    PSFB_gi_pid->Kr = PSFB_gi_pid->sps->Kr;
    PSFB_gi_pid->c1 = PSFB_gi_pid->sps->c1;
    PSFB_gi_pid->c2 = PSFB_gi_pid->sps->c2;
    PSFB_gi_pid->Umax = PSFB_gi_pid->sps->Umax;
    PSFB_gi_pid->Umin = PSFB_gi_pid->sps->Umin;
    DCL_CLEAR_UPDATE_REQUEST(PSFB_gi_pid);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Hi Gokhan,

    This is a simple C programming question, please refer to online C programming tutorials for more info. From the looks of it your PSFB_gi_pid is a struct but not a pointer to a struct,  therefore your can't deference it with "->" operator, as "->" operator is a dereference attribute operator (i.e. (*PSFB_gi_pid).sps).

    Changing "->" back to "." should suffice. 

    Best,

    Sen Wang