Error occurred while executing External Mode MEX-file 'rtwinext': Error loading real-time image: undefined symbol "FAST_Sizes"
    5 Ansichten (letzte 30 Tage)
  
       Ältere Kommentare anzeigen
    
Dear all,
I want to simulate a S-Function Modell in Simulink External Mode. The s-function is working well in Normal mode but when i switch to external mode using SImulink Deslktop Real-Time it show the following error:
Error occurred while executing External Mode MEX-file 'rtwinext':
Error loading real-time image: undefined symbol "FAST_Sizes"
This is my C-Function
      /*
   *  TEMPLATE File: sfuntmpl_gate_fortran.c
   *  TEMPLATE Copyright 1990-2013 The MathWorks, Inc.
   *
   * Modified by B. Jonkman, National Renewable Energy Laboratory
   *   for use with FAST v8
   *   20-Jan-2015
   */
/*
 * You must specify the S_FUNCTION_NAME as the name of your S-function
 * (i.e. replace sfungate with the name of your S-function, which has
 * to match the name of the final mex file, e.g., if the S_FUNCTION_NAME
 * is my_sfuntmpl_gate_fortran, the mex filename will have to be 
 * my_sfuntmpl_gate_fortran.mexXXX where XXX is the 3 letter 
 * mex extension code for your platform).
 */
#define S_FUNCTION_LEVEL 2
#define S_FUNCTION_NAME  FAST_SFunc
/*
 * Need to include simstruc.h for the definition of the SimStruct and
 * its associated macro definitions.
 */
#include "simstruc.h"
// #include "mex.h"     // for mexPutVariable
// #include "matrix.h"  // for mxCreateDoubleScalar
#include "FAST_Library.h"
#define PARAM_FILENAME 0
#define PARAM_TMAX 1
#define PARAM_ADDINPUTS 2
#define NUM_PARAM 3
// two DWork arrays:
#define WORKARY_OUTPUT 0
#define WORKARY_INPUT 1
static double dt = 0;
static double TMax = 0;
static int NumInputs = NumFixedInputs;
static int NumAddInputs = 0;  // number of additional inputs
static int NumOutputs = 1;
static int ErrStat = 0;
static char ErrMsg[INTERFACE_STRING_LENGTH];        // make sure this is the same size as IntfStrLen in FAST_Library.f90
static char InputFileName[INTERFACE_STRING_LENGTH]; // make sure this is the same size as IntfStrLen in FAST_Library.f90
static int n_t_global = -2;  // counter to determine which fixed-step simulation time we are at currently (start at -2 for initialization)
// function definitions
static int checkError(SimStruct *S);
static void mdlTerminate(SimStruct *S); // defined here so I can call it from checkError
static void getInputs(SimStruct *S, double *InputAry);
static void setOutputs(SimStruct *S, double *OutputAry);
/* Error handling
* --------------
*
* You should use the following technique to report errors encountered within
* an S-function:
*
*       ssSetErrorStatus(S,"Error encountered due to ...");
*       return;
*
* Note that the 2nd argument to ssSetErrorStatus must be persistent memory.
* It cannot be a local variable. 
*/
static int
checkError(SimStruct *S){
     if (ErrStat >= AbortErrLev){
        ssPrintf("\n");
        ssSetErrorStatus(S, ErrMsg);
        mdlTerminate(S);  // terminate on error (in case Simulink doesn't do so itself)
        return 1;
     }
     else if (ErrStat >= ErrID_Warn){
        ssPrintf("\n");
        ssWarning(S, ErrMsg);
     }
     else if (ErrStat != ErrID_None){
        ssPrintf("\n%s\n", ErrMsg);
     }
     return 0;
}
static void
getInputs(SimStruct *S, double *InputAry){
     int     k;
     InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0);
     for (k = 0; k < ssGetDWorkWidth(S, WORKARY_INPUT); k++) {
        InputAry[k] = (double)(*uPtrs[k]);
     }
}
static void
setOutputs(SimStruct *S, double *OutputAry){
     int     k;
     double *y = ssGetOutputPortRealSignal(S, 0);
     for (k = 0; k < ssGetOutputPortWidth(S, WORKARY_OUTPUT); k++) {
        y[k] = OutputAry[k];
     }
}
/*====================*
 * S-function methods *
 *====================*/
/* Function: mdlInitializeSizes ===============================================
 * Abstract:
 *    The sizes information is used by Simulink to determine the S-function
 *    block's characteristics (number of inputs, outputs, states, etc.).
 */
static void mdlInitializeSizes(SimStruct *S)
{
     int i = 0;
     int j = 0;
     int k = 0;
     static char ChannelNames[CHANNEL_LENGTH * MAXIMUM_OUTPUTS + 1];
     static double InitInputAry[MAXInitINPUTS];
     //static char OutList[MAXIMUM_OUTPUTS][CHANNEL_LENGTH + 1];
     static char OutList[CHANNEL_LENGTH + 1];
     double *AdditionalInitInputs;
     mxArray *pm, *chrAry;
     mwSize m, n;
     mwIndex indx;
     if (n_t_global == -2) {
              /* Expected S-Function Input Parameter(s) */
        ssSetNumSFcnParams(S, NUM_PARAM);  /* Number of expected parameters */
        if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) {
             /* Return if number of expected != number of actual parameters */
             return;
         }
           // The parameters should not be changed during the course of a simulation
         ssSetSFcnParamTunable(S, PARAM_FILENAME, SS_PRM_NOT_TUNABLE); 
         mxGetString(ssGetSFcnParam(S, PARAM_FILENAME), InputFileName, INTERFACE_STRING_LENGTH);
         ssSetSFcnParamTunable(S, PARAM_TMAX, SS_PRM_NOT_TUNABLE); 
         TMax = mxGetScalar(ssGetSFcnParam(S, PARAM_TMAX));
         ssSetSFcnParamTunable(S, PARAM_ADDINPUTS, SS_PRM_NOT_TUNABLE);
         NumAddInputs = (int)(mxGetScalar(ssGetSFcnParam(S, PARAM_ADDINPUTS)) + 0.5); // add 0.5 for rounding from double
         if (NumAddInputs < 0){
            ErrStat = ErrID_Fatal;
            strcpy(ErrMsg, "Parameter specifying number of additional inputs to the FAST SFunc must not be negative.\n");
            checkError(S);
            return;
         }
         NumInputs = NumFixedInputs + NumAddInputs;
         // now see if there are other inputs that need to be processed...
         if (NumAddInputs > 0){
            k = (int)mxGetNumberOfElements(ssGetSFcnParam(S, PARAM_ADDINPUTS));
           // k = min( k , MAXInitINPUTS );
            AdditionalInitInputs = (double *)mxGetData(ssGetSFcnParam(S, PARAM_ADDINPUTS));
            for (i = 0; i < k; i++){
               InitInputAry[i] = AdditionalInitInputs[i + 1];
            }
         }
         else{
            InitInputAry[0] = SensorType_None; // tell it not to use lidar (shouldn't be necessary, but we'll cover our bases)
         }
         // set this before possibility of error in Fortran library:
         ssSetOptions(S,
            SS_OPTION_CALL_TERMINATE_ON_EXIT);
      /*  ---------------------------------------------  */
      //   strcpy(InputFileName, "../../CertTest/Test01.fst");
         FAST_Sizes(&TMax, InitInputAry, InputFileName, &AbortErrLev, &NumOutputs, &dt, &ErrStat, ErrMsg, ChannelNames);
         n_t_global = -1;
         if (checkError(S)) return;
         // set DT in the Matlab workspace (necessary for Simulink block solver options)
         pm = mxCreateDoubleScalar(dt);
         ErrStat = mexPutVariable("base", "DT", pm);
         mxDestroyArray(pm);
         if (ErrStat != 0){
            ErrStat = ErrID_Fatal;
            strcpy(ErrMsg, "Error copying string array to 'DT' variable in the base Matlab workspace.");
            checkError(S);
            return;
         }
         // put the names of the output channels in a cell-array variable called "OutList" in the base matlab workspace
        /* m = NumOutputs;
         n = 1;
       //pm = mxCreateCellMatrix(m, n);
       pm = mxCreateDoubleMatrix(m, n, mxREAL);
         for (i = 0; i < NumOutputs; i++){
            j = CHANNEL_LENGTH - 1;
            while (ChannelNames[i*CHANNEL_LENGTH + j] == ' '){
               j--;
            }
            strncpy(&OutList[0], &ChannelNames[i*CHANNEL_LENGTH], j+1);
            OutList[j + 1] = '\0';
            chrAry = mxCreateString(OutList);
            indx = i;
         mxGetPr(pm, indx, chrAry);
            //mxSetCell(pm, indx, chrAry);
            //mxDestroyArray(chrAry);
         }
         ErrStat = mexPutVariable("base", "OutList", pm);
         mxDestroyArray(pm);
            */
         if (ErrStat != 0){
            ErrStat = ErrID_Fatal;
            strcpy(ErrMsg, "Error copying string array to 'OutList' variable in the base Matlab workspace.");
            checkError(S);
            return;
         }
         //  ---------------------------------------------  
         ssSetNumContStates(S, 0);  /* how many continuous states? */
         ssSetNumDiscStates(S, 0);  /* how many discrete states?*/
           /* sets input port characteristics */
         if (!ssSetNumInputPorts(S, 1)) return; 
         ssSetInputPortWidth(S, 0, NumInputs); // width of first input port
         /*
          * Set direct feedthrough flag (1=yes, 0=no).
          * A port has direct feedthrough if the input is used in either
          * the mdlOutputs or mdlGetTimeOfNextVarHit functions.
          */
         ssSetInputPortDirectFeedThrough(S, 0, 0); // no direct feedthrough because we're just putting everything in one update routine (acting like a discrete system)
         if (!ssSetNumOutputPorts(S, 1)) return;
         ssSetOutputPortWidth(S, 0, NumOutputs);
         ssSetNumSampleTimes(S, 1); // -> setting this > 0 calls mdlInitializeSampleTimes()
         /* 
          * If your Fortran code uses REAL for the state, input, and/or output 
          * datatypes, use these DWorks as work areas to downcast continuous 
          * states from double to REAL before calling your code.  You could
          * also put the work vectors in hard-coded local (stack) variables.
          *
          * For fixed step code, keep a copy of the variables  to be output 
          * in a DWork vector so the mdlOutputs() function can provide output 
          * data when needed. You can use as many DWork vectors as you like 
          * for both input and output (or hard-code local variables).
          */
         if(!ssSetNumDWork(   S, 2)) return;
         ssSetDWorkWidth(   S, WORKARY_OUTPUT, ssGetOutputPortWidth(S, 0));
         ssSetDWorkDataType(S, WORKARY_OUTPUT, SS_DOUBLE); /* use SS_DOUBLE if needed */
         ssSetDWorkWidth(   S, WORKARY_INPUT, ssGetInputPortWidth(S, 0));
         ssSetDWorkDataType(S, WORKARY_INPUT, SS_DOUBLE);
         ssSetNumNonsampledZCs(S, 0);
         /* Specify the sim state compliance to be same as a built-in block */
         /* see sfun_simstate.c for example of other possible settings */
         ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE);
         // ssSetOptions(S, 0); // bjj: what does this do? (not sure what 0 means: no options?) set option to call Terminate earlier...
      }
  }
/* Function: mdlInitializeSampleTimes =========================================
 * Abstract:
 *    This function is used to specify the sample time(s) for your
 *    S-function. You must register the same number of sample times as
 *    specified in ssSetNumSampleTimes.
 */
static void mdlInitializeSampleTimes(SimStruct *S)
{
      /* 
       * If the Fortran code implicitly steps time
       * at a fixed rate and you don't want to change
       * the code, you need to use a discrete (fixed
       * step) sample time, 1 second is chosen below.
       */
      ssSetSampleTime(S, 0, dt); /* Choose the sample time here if discrete */ 
      ssSetOffsetTime(S, 0, 0.0);
      ssSetModelReferenceSampleTimeDefaultInheritance(S);
  }
#undef MDL_INITIALIZE_CONDITIONS   /* Change to #undef to remove function */
#define MDL_START  /* Change to #undef to remove function */
#if defined(MDL_START) 
  /* Function: mdlStart =======================================================
   * Abstract:
   *    This function is called once at start of model execution. If you
   *    have states that should be initialized once, this is the place
   *    to do it.
   */
  static void mdlStart(SimStruct *S)
  {
       /* bjj: this is really the initial output; I'd really like to have the inputs from Simulink here.... maybe if we put it in mdlOutputs? 
          but then do we need to say we have direct feed-through?
       */
       double *InputAry = (double *)ssGetDWork(S, WORKARY_INPUT); //malloc(NumInputs*sizeof(double));   
       double *OutputAry = (double *)ssGetDWork(S, WORKARY_OUTPUT);
       //n_t_global is -1 here; maybe use this fact in mdlOutputs
       if (n_t_global == -1){ // first time to compute outputs:
//        getInputs(S, InputAry);
          FAST_Start(&NumInputs, &NumOutputs, InputAry, OutputAry, &ErrStat, ErrMsg);
          n_t_global = 0;
          if (checkError(S)) return;
       }
    }
  #endif /*  MDL_START */
/* Function: mdlOutputs =======================================================
 * Abstract:
 *    In this function, you compute the outputs of your S-function
 *    block.  The default datatype for signals in Simulink is double,
 *    but you can use other intrinsic C datatypes or even custom
 *    datatypes if you wish.  See Simulink document "Writing S-functions"
 *    for details on datatype topics.
 */
static void mdlOutputs(SimStruct *S, int_T tid)
{
      /* 
       *    For Fixed Step Code
       *    -------------------
       * If the Fortran code implements discrete states (implicitly or
       * registered with Simulink, it doesn't matter), call the code
       * from mdlUpdates() and save the output values in a DWork vector.  
       * The variable step solver may call mdlOutputs() several
       * times in between calls to mdlUpdate, and you must extract the 
       * values from the DWork vector and copy them to the block output
       * variables.
       *
       * Be sure that the ssSetDWorkDataType(S,0) declaration in 
       * mdlInitializeSizes() uses SS_DOUBLE for the datatype when 
       * this code is active.
       */
      double *InputAry  = (double *)ssGetDWork(S, WORKARY_INPUT);
      double *OutputAry = (double *)ssGetDWork(S, WORKARY_OUTPUT);
      if (n_t_global == -1){ // first time to compute outputs:
         getInputs(S, InputAry);
         FAST_Start(&NumInputs, &NumOutputs, InputAry, OutputAry, &ErrStat, ErrMsg);
         n_t_global = 0;
         if (checkError(S)) return;
      }
      setOutputs(S, OutputAry);
}
#define MDL_UPDATE  /* Change to #undef to remove function */
#if defined(MDL_UPDATE)
/* Function: mdlUpdate ======================================================
 * Abstract:
 *    This function is called once for every major integration time step.
 *    Discrete states are typically updated here, but this function is useful
 *    for performing any tasks that should only take place once per
 *    integration step.
 */
static void mdlUpdate(SimStruct *S, int_T tid)
{
      /* 
       *    For Fixed Step Code Only
       *    ------------------------
       * If your Fortran code runs at a fixed time step that advances
       * each time you call it, it is best to call it here instead of
       * in mdlOutputs().  The states in the Fortran code need not be
       * continuous if you call your code from here.
       */
      double *InputAry  = (double *)ssGetDWork(S, WORKARY_INPUT);
      double *OutputAry = (double *)ssGetDWork(S, WORKARY_OUTPUT);
      //time_T t = ssGetSampleTime(S, 0);
      getInputs(S, InputAry);
      /* ==== Call the Fortran routine (args are pass-by-reference) */
      FAST_Update(&NumInputs, &NumOutputs, InputAry, OutputAry, &ErrStat, ErrMsg);
      n_t_global = n_t_global + 1;
      if (checkError(S)) return;
      setOutputs(S, OutputAry);
}
#endif /* MDL_UPDATE */
#undef MDL_DERIVATIVES  /* Change to #undef to remove function */
/* Function: mdlTerminate =====================================================
 * Abstract:
 *    In this function, you should perform any actions that are necessary
 *    at the termination of a simulation.  For example, if memory was
 *    allocated in mdlStart, this is the place to free it.
 */
static void mdlTerminate(SimStruct *S)
{
   if (n_t_global > -2){ // just in case we've never initialized, check this time step
      FAST_End();
      n_t_global = -2;
   }  
}
/*=============================*
 * Required S-function trailer *
 *=============================*/
#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
Thank you in advance and best regards
David
1 Kommentar
Antworten (0)
Siehe auch
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!

