InicioCiencia EducacionMatlab, simulink y s-function en lenguaje c en tiempo real.

Matlab, simulink y s-function en lenguaje c en tiempo real.

Ciencia Educacion6/25/2011
Como armar un bloque programado en lenguaje C para que funcione en tiempo real:

Voy a hacer solamente un controlador PI para no complicarme la vida. Va a tener una entrada de ancho dos, como si tuviera dos entradas pero es un vector. Va a integrar la diferencia entre las señales de entrada y las multiplica por la ganacia posteriormente las suma. Sigue ma siguiente ecuación;

Salida = Kp.(entrada1 - entrada2) + Ki. ( integral(entrada1 - entrada2) )

Una vez que abren Matlab, el mio es el 2010 en windows 7, tiene que crear un modelo en simulink para colocar los bloques que necesitan.



Los bloques que coloco son; Una s-function, Una fuente constante y un osciloscopio. En la imagen sólo aparece la s-function.



Para escribir lo que tiene que hacer la s-function uso el programa DEV C++.



Cuando programen el bloque s-function en lenguaje C deben escribir lo siguiente:

# define S_FUNCTION_NAME taringa
# define S_FUNCTION_LEVEL 2
# include "simstruc.h"
# include "conio.h"
# define MDL_INITIALIZE_CONDITIONS
# define MDL_UPDATE


# define U(element) (*uPtrs[element])

/* Aquí va el programa. */

#ifdef MATLAB_MEX_FILE
#include "simulink.c"
#else
#include "cg_sfun.h"
#endif


Ahora hago algunos comentarios al respecto.
---El primer renglón dice # define S_FUNCTION_NAME taringa y "taringa" es el nombre del archivo que guardan, también es el nombre del bloque s-function, pero no es el nombre del archivo del modelo en simulink, si lo hacen les tira error.
---El quinto renglón dice # define MDL_INITIALIZE_CONDITIONS "MDL_INITIALIZE_CONDITIONS" declara que van a darle condiciones iniciales a la simulación que realizarán.
---El sexto renglón dice # define MDL_UPDATE "MDL_UPDATE" es para usar veriables de estado.
---El renglón que dice # define U(element) (*uPtrs[element]) es muy importante les vá a servir para cuando hagan cuentas con vectores. Cada componente de la matriz "U" tiene almacenada el valor cada una de las entradas. Mucho más importante es para que no se les cuelgue la compu cuando ejecuten el programa.
Los últimos renglones son para usar uno de los archivos que están entre comillas. Dentro del espacio libre, en el medio, se escribe el programa.

Ahora hay que declarar todo lo necesario para que funcione el programa en simulink.

static void mdlInitializeSizes(SimStruct *S)
{
}
static void mdlInitializeSampleTimes(SimStruct *S)
{
}
static void mdlInitializeConditions(SimStruct *S)
{
}
static void mdlUpdate(SimStruct *S, int_T tid)
{
}

static void mdlOutputs(SimStruct *S, int_T tid)
{
}
static void mdlTerminate(SimStruct *S)
{
}


Quedando en el programa DEV C++.



Comentarios;
---mdlInitializeSizes ---------- Es para especificar las entradas, salidas, declarar veriables de estado y cuantas, etc.
---mdlInitializeSampleTimes ---------- Es para el tiempo de muestreo si lo usan o indicarle que lo herede del programa en simulink.
---mdlInitializeConditions ------------ Es para las condiciones iniciales.
---mdlUpdate ------------- Es para escribir la matriz de las variables de estado. Xdev = A.x + B.u
---mdlOutputs ------------- Es para escribir la fórmula que calcula la salida. Y = C.x + D.u
---mdlTerminate -------------- Es para cuando cierran el programa como quieren que termine el sistema, ejemplo que la salida sea nula.

Ahora hay que llenar cada uno, empiezo con la especificación de entradas, salidas, etc del bloque. Entre /*--- */ escribo algunos comentarios para darle las dimensiones al bloque que usaremos en la s-function.

static void mdlInitializeSizes(SimStruct *S)
{
ssSetNumSFcnParams(S, 0); /* Sin parámetros. */

ssSetNumContStates (S, 0); /* Sin estados contínuos. */
ssSetNumDiscStates (S, 1); /* Un estado discreto. */

ssSetNumInputPorts(S, 1); /* Con un puerto de entrada.*/
ssSetInputPortWidth(S, 0, 2); /* Ancho del puerto 2.*/
ssSetInputPortDirectFeedThrough(S, 0, 1);
ssSetInputPortDirectFeedThrough(S, 0, 2);

ssSetNumOutputPorts(S, 1); /* Un puerto de salida.*/
ssSetOutputPortWidth(S, 0, 1); /* Ancho del puerto 1.*/

ssSetNumSampleTimes(S, 1);

ssSetNumRWork (S, 0);
ssSetNumIWork (S, 0);
ssSetNumPWork (S, 0);
ssSetNumModes (S, 0);
ssSetNumNonsampledZCs (S, 0);

ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}


Hay que usar tiempo discreto, elijo un periodo de muestreo de 4ms. El valor mínimo que pueden poner depende de la capacidad de su compu.

static void mdlInitializeSampleTimes(SimStruct *S)
{
ssSetSampleTime(S, 0, 0.004); //INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
}


Lo que dice "INHERITED_SAMPLE_TIME" es si quieren que el bloque s-function use el tiempo de muestreo de simulink.

Lo que sigue son las condiciones iniciales, por lo general son nulas. Es una condición inicial por cada variable de estado.

static void mdlInitializeConditions(SimStruct *S)
{
real_T *x0 = ssGetRealDiscStates(S);
*x0 = 0.0;
}


Comentarios;
--- ssGetRealDiscStates --------- tiene acceso a las variables de estado discretas. Se trabaja con punteros por eso el asterisco.

Sigo con el cálculo de la variable de estado.

static void mdlUpdate(SimStruct *S, int_T tid)
{
real_T w=0;
real_T *x = ssGetRealDiscStates(S);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0);

int_T g = 1;

w = x[0] + 0.01 * g*(U(0) - U(1));
x[0] = w;
}


En primer lugar el cálculo se hace en una variable auxiliar, llamada "w", y después se pasa a la variable de estado. Todo es para que no se les cuelgue la compu. En realidad les saldría la famosa pantalla azul.

En segundo la variable "U()" es la que declaramos en un principio tiene acceso a cada entrada para hacer las cuentas. Por ejemplo si queremos que la variable de estado sea tres veces la primer entrada escribimos "w = 3* U(0)" luego copiamos a "w" en "x".
Después " U(0)-U(1) " es simplemente la resta de la primer entrada con la segunda. "g" es sólo un número. "x[0]" es el valor anterior de la variable de estado la cual vamos a actualizar con la fórmula.

Lo que sigue es calcular la salida;

static void mdlOutputs(SimStruct *S, int_T tid)
{
real_T *y0 = ssGetOutputPortRealSignal(S, 0);
/* Puntero para la salida.*/
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0);
/* Puntero para la entrada.*/
real_T *x = ssGetRealDiscStates(S);
/* Acceso a la variable de estado. */
int_T kp = 1;
y0[0] = x[0]+ kp*(U(0)-U(1));
}


---ssGetOutputPortRealSignal ----- tiene acceso a la salida, escribe en ella a través del puntero " *y0 ".
---InputRealPtrsType uPtrs ----- es la clásica declaración del puntero a la entrada la cual es necesaria porque uso a "U".
--- real_T --- en vez de declarar la variable como entera, int, se la declara como "real_T" es sólo para que el programa declare la variable como más le guste.

Por último es la terminación la pueden dejar vacía o no.

Ahora hay que regresar a Matlab. Como había dicho anteriormente el archivo de simulink no debe tener el mismo nombre que el bloque s-function.



Antes de hacer simulaciones tenemos que indicarle a Matlab donde se encuentra el archivo que describe al bloque s-function. En mi caso puse dicho archivo dentro de una carpeta llamada "post". Para buscarla hay que hacer un click al botón que tiene los tres puntos.



Ahora lo que sigue es la preparación para compilar el archivo en lenguaje C que llamamos "taringa" el cual realiza las operaciones del bloque s-function. Para compilarlo primero tenemos que decirle a Matlab que compilador usar puede ser Watcom, Lcc, etc. En mi caso uso el Lcc y lo hago con la instrucción;

>>mex -setup

Eligen la opción "y" y presionan enter luego escriben un "1" y de nuevo enter. Si eligen "n" les aparece una lista de todos los compiladores compatibles con su matlab, pero no indica cuales están instalados.
Después les pide confirmar donde está instalado el compilador le dicen que si y listo.



Una vez elegido el compilador lo utilizan como lo hago a continuación, si está todo bien no les tira los mensajes en rojo;

>> mex taringa.c
>>


Cuando guardan el archivo en lenguaje C háganlo como ".c" no como ".cpp"

Lo siguiente es activar el sistema para usar a Matlab en tiempo real y es como sigue;

>>rtwintgt -setup

y Matlab hace el resto.

Continuo asignando al bloque s-function el archivo C llamado "taringa.c" para hacerlo hay que darle doble click al bloque y aparece una ventana donde escriben el nombre del archivo C y le dan ok.



Hay que realizan una prueba en tiempo normal para ver si funciona y después lo ejecutan en tiempo real.
En la ventana del modelo en simulink llamado "taringa_no" vamos a;

Simulation -> Configuration Parameters... le damos click y aparece la siguiente ventana.



Donde seleccionan el modo "Fixed-Step" y colocan el tiempo de muetreo de 4ms, está escrito en segundos 0,004. Le dan play y después hacen doble click en el osciloscopio.



Una vez que realiza lo que quieren podemos hacerlo correr en tiempo real.

En la ventana del modelo en simulink vamos a;

tools ->Real-Time WorkShop -> Build Model y hacemos click. Para construir lo que necesita el modelo.





Por último falta la configuración del real time. Vamos a;

Simulation -> Configuration Parameters... y en la ventana que aparece elegimos "Real-Time WorkShop" en la lista que aparece al costado seleccionamos el target, el cual ejecuta el programa en tiempo real. Elijo el famoso "Real Time Windos Target" presionando el botón que dice "Browse.." y en la ventana que aparece lo busco.


Le damos OK y esperamos un poquito.
Cada vez que modifiquen el archivo .c, el llamado "taringa.c", hay que reconstruir todo. Desde el "mex taringa.c" y todo lo que sigue.

Ahora si lo ejecutamos en tiempo real, primero hay que conectarlo, presionando el botón que parece un enchufe y luego le dan play.



Post data:

El principal problema que tiene es que los punteros escriben en una zona ajena a la que tiene el programa habilitada y les aparece la pantalla azul, para solucionarlo tiene que hacer los cálculos en variables auxiliares y luego lo copian a la salida o a la variable de estado.

Les dejo algo nada que ver con esto.............



Chau.

En un archivo ".m" hay que escribir el programa, donde uno lo coloca en casos:

case 1:
case 2:
......

Cada uno de estos casos corresponde a los bloques de programa en lenguaje ".c", que es el post.
Los bloques son:

static void mdlInitializeSizes(SimStruct *S)
{
}
static void mdlInitializeSampleTimes(SimStruct *S)
{
}
static void mdlInitializeConditions(SimStruct *S)
{
}
static void mdlUpdate(SimStruct *S, int_T tid)
{
}

static void mdlOutputs(SimStruct *S, int_T tid)
{
}
static void mdlTerminate(SimStruct *S)
{
}


Comienzo con una breve explicación:

function [sys, x0, str, ts] = taringa (t, x, u, flag)
switch flag,

case 0, // Es para inicializar la s-function, no funciona en tiempo real al ser un ".m"
sizes = simsizes;
sizes.NumContStates = 0; // Sin estados continuos.
sizes.NumDiscStates = 1; // Un estado discreto.
sizes.NumOutputs = 1; // Una salida.
sizes.NumInputs = 1; // Una salida.
sizes.DirFeedthrough = 1; // Es de paso directo.
sizes.NumSampleTimes = 1; // Tiempo de muestreo = 1.
sys = simsizes(sizes); // Se crea una estructura de datos para la s-function.
x0 = [0]; // Condición inicial.
str = [];
ts = [0];

case 1, // Es para calcular las derivadas continuas.
sys = []; // Se pone la fórmula para la derivada.

case 2,
sys = []; // Para calcular derivadas discretas.

case 3, // Calcula la salida.
sys = [];

case 4, // Llamada para calcular la próxima iteración.
sys = [];

case 9, // Es para finalizar, cuando uno cierra el programa se ejecuta este caso.
sys = [];

otherwise, // Cuando hay un error, no se reconoce el flag.
error(['flag no conocido =', num2str(flag)]);

end

Una vez que están todos los casos hay que pasarlos al archivo ".c" de la siguiente manera;

Coloco en columnas al caso que se relaciona con el bloque del archivo ".c"





Y así sigue no??????????.

Con esto podes empezar.
Datos archivados del Taringa! original
36puntos
15,943visitas
0comentarios
Actividad nueva en Posteamelo
0puntos
3visitas
0comentarios
Dar puntos:

Dejá tu comentario

0/2000

Autor del Post

c
cmorris🇦🇷
Usuario
Puntos0
Posts9
Ver perfil →
PosteameloArchivo Histórico de Taringa! (2004-2017). Preservando la inteligencia colectiva de la internet hispanohablante.

CONTACTO

18 de Septiembre 455, Casilla 52

Chillán, Región de Ñuble, Chile

Solo correo postal

© 2026 Posteamelo.com. No afiliado con Taringa! ni sus sucesores.

Contenido preservado con fines históricos y culturales.