Guida alla scrittura delle S-Function

Precedente Home Su Successiva

Introduzione

Scrittura delle C-MEX S-Function

 

Introduzione

La realizzazione di una S-Function mediante linguaggio C, come abbiamo già avuto modo di dire, deve sottostare ad una serie di regole che hanno come scopo la realizzazione di un C MEX-file (C Matlab Executable file) che interagisca con Simulink e con l’ODE solver per l’esecuzione dei singoli passi di calcolo che portano all’esecuzione del modello (definizione delle condizioni e delle caratteristiche iniziali del blocco, calcolo delle derivate, stati discreti e uscite del blocco).

Un utile strumento per la compilazione del codice è fornito da sfuntmpl.c, un file di codice C, e dal relativo file sfuntmpl.doc  entrambi presenti nella directory simulink/src.

Un semplice esempio di C-MEX S-Function è il seguente:

  #define S_FUNCTION_NAME  your_sfunction_name_here

  #define S_FUNCTION_LEVEL 2

  #include “simstruct.h”

 

  static void mdlInitializeSizes(SimStrusct *S)

  {

  }

 

  <aggiunta routine/codice di S-Function >

 

  static void mdlTerminate(SimStruct *S)

  {

  }

  #ifdef MATLAB­MEX_FILE   /* Il file è stato compilato come MEX-file? */

  #include “simulink.c”    /* Interfaccia tra Simulink e MEX-file */

  #else

  #include “cg_sfun.h”     /* Funzione per la registrazione della*/

                           /* generazione del codice */

  #endif

La routine mdlInitializeSizes è solo una, la prima in genere ad essere chiamata quando Simulink interagisce con la S-Function, delle tante routine del tipo mdl* che devono essere utilizzate nella compilazione del codice. Il contenuto delle suddette routine è stabilito dal programmatore e varia con il tipo di S_Function che viene implementata. L’ultima routine ad essere chiamata da Simulink è mdlTerminate che termina l’esecuzione del blocco.

Le informazioni relative alla S_Function sono contenute in una struttura dati chiamata SimStruct. L’inclusione nel codice, mediante l’istruzione #include, del file simstruc.h fornisce, oltre alla dichiarazione della struttura, anche un insieme di macro mediante le quali è possibile accedere, copiare e leggere dati dalla struttura.

Scrittura delle C-MEX S-Function

Lo scopo di questo paragrafo è quello di fornire dei semplici esempi di S-Function, dove semplici significa contenenti quelle routine che devono essere sempre presenti anche se vuote, cioè prive di codice. Uno di questi esempi è quello della S_Function  timestwo  che prende un ingresso e lo moltiplica per due (vedi matlabroot/simulink/src/timestwo.c).

Il modello simulink che la rappresenta è il seguente:

 Il blocco S_Function è stato prelevato dalla libreria Simulink ed è stato modificato il nome del blocco in timestwo accedendo alla finestra delle proprietà, non sono stati specificati altri parametri. Il codice che è stato scritto per la S_Function rispetta il seguente schema:

 

E’ necessario quindi che le suddette routine siano inserite nel codice della S_Function, in quest’esempio sono state digitate all’interno di un file di nome timestwo.c, la successiva esecuzione del comando:

    mex   timestwo.c 

dal prompt di Matlab permette a quest’ultimo di eseguire la compilazione e il link di questo programma, creando un file caricabile ed eseguibile da Simulink. 

Ciò che ne risulta è un file di tipo MEX la cui estensione, se si lavora in ambiente Windows, è .dll. Il codice di quest’esempio è dato dal seguente listato:

#define S_FUNCTION_NAME  timestwo

#define S_FUNCTION_LEVEL 2

 

#include "simstruc.h"

 

static void mdlInitializeSizes(SimStruct *S)

{

    ssSetNumSFcnParams(S, 0);

    if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) 

    {

        return; /* Parameter mismatch will be reported by Simulink */

    }

 

    if (!ssSetNumInputPorts(S, 1)) return;

    ssSetInputPortWidth(S, 0, DYNAMICALLY_SIZED);

    ssSetInputPortDirectFeedThrough(S, 0, 1);

 

    if (!ssSetNumOutputPorts(S,1)) return;

    ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED);

 

    ssSetNumSampleTimes(S, 1);

 

    ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);

}

 

static void mdlInitializeSampleTimes(SimStruct *S)

{

    ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);

    ssSetOffsetTime(S, 0, 0.0);

}

 

static void mdlOutputs(SimStruct *S, int_T tid)

{

    int_T             i;

    InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);

    real_T            *y    = ssGetOutputPortRealSignal(S,0);

    int_T             width = ssGetOutputPortWidth(S,0);

 

    for (i=0; i<width; i++) {

        *y++ = 2.0 *(*uPtrs[i]);

    }

}

 

static void mdlTerminate(SimStruct *S)

{

}

 

#ifdef  MATLAB_MEX_FILE    /* Is this file being compiled as a MEX-file? */

#include "simulink.c"      /* MEX-file interface mechanism */

#else

#include "cg_sfun.h"       /* Code generation registration function */

#endif

E’ utile a questo punto fornire ulteriori spiegazioni relative all’esempio fornito.

Istruzioni define ed include – Queste due istruzioni vengono utilizzate per informare Simulink che si intende realizzare una funzione di livello due (specificare sempre quest’opzione) ed il nome di questa, oltre a fornirgli il riferimento (il file header  simstruct.h) in cui trovare la struttura dati SimStruct utilizzata dal modello.

mdlInitialize specifica i  seguenti parametri:

Zero parametri – Significa che il campo S-function parameters nella finestra di dialogo della S_Function è vuota.

Una porta di ingresso e una di uscita – Le ampiezze delle porte di ingresso e uscita sono stabilite dinamicamente, Simulink moltiplicherà ciascuna linea d’ingresso (nel caso in cui tale porta sia un vettore n-dimensionale) per due e renderà tali valori disponibili in uscita.

Singolo istante di campionamento. E’ necessario specificare il tempo di campionamento nella routine mdlInitializeSampleTimes.

Il codice è exception free. Qualora il codice non preveda chiamate a funzioni esterne che interrompono l’esecuzione di Simulink è opportuno specificare questa opzione che contribuisce a rendere il codice più efficiente

mdlInitializeSampleTimes

 Il tempo di campionamento è acquisito dal blocco che precede la S_Function quindi funzionerà bene con qualsiasi blocco connesso in ingresso.

mdlOutput: 

Il calcolo numerico. mdlOutput dice a Simulink di moltiplicare il segnale d’ingresso per 2.0 e mettere il risultato nel segnale d’uscita.

Per accedere al segnale d’ingresso si utilizza:

InputRealPtrsType uptrs = ssGetInputPortRealSignaluPtrs(S,0)

dove uPtrs è un vettore di puntatori e si può accedere ai suoi elementi nel modo seguente:

Elementoi = *uPtrs[i]

Per accedere al segnale d’uscita si utilizza:

real_T *y = ssGetOutputPortRealSignal(S,0)

che fornisce un array contenente i valori in uscita.

mdlTerminate:

In questo caso particolare non c’è bisogno di eseguire nessuna azione conclusiva.

Al termine del codice è necessario inserire il codice che permette di connettere il blocco realizzato a Simulink o al Real-Time Workshop.

#ifdef  MATLAB_MEX_FILE

    #include “simulink.c”

#else

    #include “cg_sfun.h”

#endif

Questa pagina è stata aggiornata il 02/01/04.

Testo originale: Massimo Demofonte

Aggiornamento e adattamento: Leonardo Daga

Leonardo Daga's Warehouseâ, http://leonardodaga.insyde.it
Send any Comments to: leonardo.daga@gmail.com