1
\$\begingroup\$

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

enter image description here

The internal details of the PID Controller super block:

enter image description here

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

enter image description here

and I have received following outcomes

enter image description here

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

enter image description here

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? Thanks for any ideas.

UPDATE:

Scilab/Xcos simulation outcomes in case one clock source is used for whole simulation

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Without details about the PID blocks, themselves, noone can tell (both Xcos and C). It looks like the period for the Xcos is ~3.x times greater, maybe pi? Maybe the sampling? Maybe the PID in Xcos has different settings? \$\endgroup\$ – a concerned citizen Sep 16 at 9:59
  • \$\begingroup\$ @aconcernedcitizen thank you for your reaction. I have just attempted to append the missing details into the question. \$\endgroup\$ – Steve Sep 16 at 10:36
  • \$\begingroup\$ The values for Kp, Ti, etc, are defined in the C code, but in the Xcos code all I can see is that they are read from block->rpar[n]. Can you verify that the values correspond? In rest, the code looks equivalent (I hope I didn't miss out on anything). \$\endgroup\$ – a concerned citizen Sep 16 at 13:50
  • 1
    \$\begingroup\$ @Steve Well, about the only thing left that I can see is that you are using two clocks in Xcos. Have you tried using the same clock for the scope, too? \$\endgroup\$ – a concerned citizen Sep 17 at 11:11
  • 1
    \$\begingroup\$ @aconcernedcitizen I have just replaced the clock for the scope by the clock signal used for timing of the rest of the simulation and the simulation outcomes are in accordance with the outcomes comming from the C language simulation! Do you have explanation for this behavior? \$\endgroup\$ – Steve Sep 17 at 11:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.