[Scilab-users] PID controller simulation in Scilab/Xcos

classic Classic list List threaded Threaded
2 messages Options
Steve Steve
Reply | Threaded
Open this post in threaded view
|

[Scilab-users] PID controller simulation in Scilab/Xcos

Hello,

I have been attempting to resolve following issue related to the simulation
in Scilab/Xcos. I have been developing a control software and at the time
being I have been developing a library of the building blocks. One of the
building blocks is a PID controller. I have written the C code of the PID
controller in velocity form and my idea was to verify its behavior via
simulation in Scilab/Xcos with the CBLOCK usage. For that purpose I have
developed following simulation in Scilab/Xcos

<http://mailinglists.scilab.org/file/t497955/PID_simulace_diagram.jpg>

The internal details of the PID Controller super block:

<http://mailinglists.scilab.org/file/t497955/PID_CBLOCK.jpg>

the code inside the CBLOCK:


#include <math.h>
#include <stdlib.h>
#include <scicos_block.h>
#include <stdio.h>

FILE *f;

// U(k-1)
double U1 = 0.0;
// E(k-1)
double E1 = 0.0;
// E(k-2)
double E2 = 0.0;
// Ud(k-1)
double Ud1 = 0.0;
// Ud(k-2)
double Ud2 = 0.0;
// act(k-1)
double A1 = 0.0;
// act(k-2)
double A2 = 0.0;

void PID_controller(scicos_block *block,int flag)
{
  /*
  int block->nevprt;
  int block->nz;
  double* block->z;
  int block->nx;
  double* block->x;
  double* block->xd;
  double* block->res;
  int block->nin;
  int *block->insz;
  double **block->inptr;
  int block->nout;
  int *block->outsz;
  double **block->outptr;
  int block->nevout;
  int block->nrpar;
  double *block->rpar;
  int block->nipar;
  int *block->ipar;
  int block->ng;
  double *block->g;
  int *block->jroot;
  char block->label[41];
  */
  if (flag == 4) { /* initialization */
   PID_controller_bloc_init(block,flag);
 
  } else if(flag == 1) { /* output computation*/
   set_block_error(PID_controller_bloc_outputs(block,flag));
  } else if(flag == 2) { /* computation of next discrte state*/
     set_block_error(PID_controller_bloc_states(block,flag));
  } else  if (flag == 5) { /* ending */
     set_block_error(PID_controller_bloc_ending(block,flag));
  }
}
 
int PID_controller_bloc_init(scicos_block *block,int flag)
{

f = fopen("PID.txt", "w");
fprintf(f, "R A2 A1  A  E2  E1   E   DUp   DUi   DUd  
U1   U      SatU\n");
fprintf(f,
"==============================================================================================================================================================================================================\n");

return 0;
}

int PID_controller_bloc_outputs(scicos_block *block,int flag)
{

// block parameters
double Kp;
double Ti;
double Td;
double N;
double Umin;
double Umax;
double T;

// reference value
double R;
// actual value
double A;
// control error
double E;
// control value
double U;
double SatU;

// increment of proportional part
double DUp;
// increment of integration part
double DUi;
// increment of derivative part
double DUd;
// derivative part
double Ud;
// increment of control value
double DU;


// reading in of the block inputs
R      = block->inptr[0][0];
A      = block->inptr[1][0];

// reading in of the block parameters
Kp   = block->rpar[0];
Ti   = block->rpar[1];
Td   = block->rpar[2];
N    = block->rpar[3];
Umin = block->rpar[4];
Umax = block->rpar[5];
T    = block->rpar[6];

// current control error
E = R - A;                                  

DUp = Kp*(E - E1);                                  // increment of
proportional part
DUi = (Kp*T)/(2*Ti)*(E + E1);                                  //
increment of integration part
DUd = (Td)/(Td + N*T)*(Ud1 - Ud2) - (Kp*Td*N)/(Td + N*T)*(A - 2*A1 + A2); //
increment of derivative part with filtering pole
Ud = Ud1 + DUd;  // derivative part
DU = DUp + DUi + DUd;                                  // increment of
control value
U  = U1 + DU;                                  // control value

// saturation of the control value according to the limits of the actuator
if(U > Umax)
{
        SatU = Umax;
}
else if(U < Umin)
{
        SatU = Umin;
}
else
{
        SatU = U;
}

U1 = SatU;

// writing at the outputs
block->outptr[0][0] = SatU;

fprintf(f, "%f, %f, %f, %f, %f, %f, %f %f %f %f %f %f %f \n", R, A2, A1, A,
E2, E1, E, DUp, DUi, DUd, U1, U, SatU);

// memory refresh
E2 = E1;
E1 = E;
A2 = A1;
A1 = A;
Ud2 = Ud1;
Ud1 = Ud;

return 0;
}

int PID_controller_bloc_states(scicos_block *block,int flag)
{

return 0;
}

int PID_controller_bloc_ending(scicos_block *block,int flag)
{

fclose(f);

return 0;
}



I have run the simulation with below given setup

<http://mailinglists.scilab.org/file/t497955/PID_simulace_nastaveni.jpg>

and I have received following outcomes

<http://mailinglists.scilab.org/file/t497955/PID_simulace_diagram_vystupy_Scilab.gif>

The outcomes seemed strange to me. So I have decided to develop the whole
simulation in C language in parallel. The C code of my simulation:


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// random noise in <-0.01; +0.01>
#define RANDOM_NOISE (0.02*((double)rand()/(double)RAND_MAX) - 0.01)


FILE *f;

typedef struct
{
    float T;
    float tau;
    float out1;
}FilterLP_t;

typedef struct
{
    float T;
    float Kp;
    float Ti;
    float Td;
    float N;
    float OutMin;
    float OutMax;
    float Ud1;
    float Ud2;
    float U1;
    float Err1;
    float Err2;
    float Act1;
    float Act2;
}PID_t;

void filter(float *in, float *out, FilterLP_t *instance);
void pid(float *ref, float *act, float *out, PID_t *instance);

/*
 *
 */
int main(int argc, char** argv) {

    f = fopen("PID_Sim.txt", "w");
   
    FilterLP_t sysModel;
    sysModel.T   = 0.01;
    sysModel.tau = 10.0;
    sysModel.out1= 0.0;
   
    PID_t controller;
    controller.T      = 0.01;
    controller.Kp     = 3.0;
    controller.Ti     = 0.125;
    controller.Td     = 2.0;
    controller.N      = 2.0;
    controller.OutMin = 0.0;
    controller.OutMax = 1.5;
    controller.Ud1    = 0.0;
    controller.Ud2    = 0.0;
    controller.U1     = 0.0;
    controller.Err1   = 0.0;
    controller.Err2   = 0.0;
    controller.Act1   = 0.0;
    controller.Act2   = 0.0;
   
    float ref            = 1.0;
    float sysIn;
    float sysOut         = 0.0;
    float sysOutMeasured = 0.0;
   
    fprintf(f, "r(k),   u(k),   y(k)\n");
    fprintf(f, "====================\n");
       
    uint16_t i;
    for(i = 0; i < 3000; i++)
    {
        pid(&ref, &sysOutMeasured, &sysIn, &controller);
        filter(&sysIn, &sysOut, &sysModel);
        sysOutMeasured = sysOut;
        fprintf(f, "%f, %f, %f \n", ref, sysIn, sysOut);
    }
   
    fclose(f);
   
    return (EXIT_SUCCESS);
}

void filter(float *in, float *out, FilterLP_t *instance)
{
    float tmp;
   
    tmp = instance->out1 + (instance->T/(instance->T + instance->tau))*(*in
- instance->out1);
    instance->out1 = tmp;
    *out = tmp;
}

void pid(float *ref, float *act, float *out, PID_t *instance)
{
    double Ki, Ad, Bd;
    double Err, DUp, DUi, DUd, Ud, DU, U, SatU;
   
   
    Ki = (instance->Kp*instance->T)/(2*instance->Ti);
    Ad = instance->Td/(instance->Td + instance->N*instance->T);
    Bd = (instance->Kp*instance->Td*instance->N)/(instance->Td +
instance->N*instance->T);
       
    Err = *ref - *act;
   
    DUp = instance->Kp*(Err - instance->Err1);
    DUi = Ki*(Err + instance->Err1);
    DUd = Ad*(instance->Ud1 - instance->Ud2) - Bd*(*act - 2*instance->Act1 +
instance->Act2);
    Ud  = instance->Ud1 + DUd;
    DU  = DUp + DUi + DUd;
    U   = instance->U1 + DU;
   
    if(U > instance->OutMax)
    {
        SatU = instance->OutMax;
    }
    else if(U < instance->OutMin)
    {
        SatU = instance->OutMin;
    }
    else
    {
        SatU = U;
    }
   
    instance->U1 = SatU;
   
    *out = SatU;
   
    instance->Err2 = instance->Err1;
    instance->Err1 = Err;
    instance->Act2 = instance->Act1;
    instance->Act1 = *act;
    instance->Ud2  = instance->Ud1;
    instance->Ud1  = Ud;
}



I have run the simulation with exactly the same PID controller settings and
I have received these outcomes

<http://mailinglists.scilab.org/file/t497955/PID_simulace_diagram_vystupy_C.jpg>

There are obvious differences between what the Scilab/Xcos gives and what
gives my simulation in C language. I trust more the C language simulation.
So I would say that there is some problem in my simulation in the
Scilab/Xcos. Unfortunatelly I don't know what is wrong. It seems that the
control loop in the Scilab/Xcos has lower damping than in the C language
simulation. Does anybody have any idea why this behavior occurs?



--
Sent from: http://mailinglists.scilab.org/Scilab-users-Mailing-Lists-Archives-f2602246.html
_______________________________________________
users mailing list
[hidden email]
http://lists.scilab.org/mailman/listinfo/users
Steve Steve
Reply | Threaded
Open this post in threaded view
|

Re: PID controller simulation in Scilab/Xcos

I have just revealed that the results are in accordance with each other in
case I use one common clock source for controlling of the timing of the
whole simulation. Based on that finding a doubt regarding the timing of my
simulation popped up in my mind. Can anybody give me an advice how to
correctly control timing of my simulation i.e simulation containing discrete
system in parallel to continuous system with sample and hold block as an
interface between them.



--
Sent from: http://mailinglists.scilab.org/Scilab-users-Mailing-Lists-Archives-f2602246.html
_______________________________________________
users mailing list
[hidden email]
http://lists.scilab.org/mailman/listinfo/users