[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