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

Steve stepan.podhorsky at gmail.com
Wed Sep 16 12:43:04 CEST 2020


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



More information about the users mailing list