Simulink to DLL compatiable with TRNSYS

26 views (last 30 days)
saleh
saleh on 17 Feb 2013
Answered: Mark McBroom on 29 Mar 2022
Hello all,
I have been able to generate a DLL from Simulink model. The DLL is generated using a special system target file (TLC file) based on grt.tlc file as well as grt_main.c as template files (the generated files are called trnsys.tlc and trnsys_main.c) . In addition, a wrapper is added at the end of the c source code, trnsys_main.c to acknowledge the trnsys coding structure (the wrapper is attached). The DLL works fine for one instance but once I used it for more than one instance in one model at the same time, the inputs from one DLL is overwriting the other DLL's inputs.
Is there a way to generate a DLL that can be used for multiple calls in the same model (called at the same time)? Any help is really appreciated.
This piece of code is written at the end of trnsys_main.c (all above code structure is similar to grt_main.c with little difference) :
//*********************************************************************************************************************** //*** Simplified MATLAB initialization for TRNSYS //***********************************************************************************************************************
char* initMatlab() {
const char *status; // RT_MODEL *S;
/******************************
* MathError Handling for BC++ *
******************************/
#ifdef BORLAND
signal(SIGFPE, (fptr)divideByZero);
#endif
{
/****************************
* Initialize global memory *
****************************/
// rtExtModeParseArgs(argc, argv, NULL);
(void)memset(&GBLbuf, 0, sizeof(GBLbuf));
/************************
* Initialize the model *
************************/
rt_InitInfAndNaN(sizeof(real_T));
S = MODEL();
starttime = getSimulationStartTime(); // &&& convert [s]/[h] ?
stoptime = getSimulationStopTime();
steptime = getSimulationTimeStep();
S->solverInfo.stepSizePtr = &steptime;
S->solverInfo.solverStopTime= stoptime;
if (rtmGetErrorStatus(S) != NULL) {
(void)fprintf(stderr,"Error during model registration: %s\n",
rtmGetErrorStatus(S));
exit(EXIT_FAILURE);
sprintf(errorMsg, "Error during model registration: %s", rtmGetErrorStatus(S));
return(errorMsg);
}
//rtmSetTFinal(S,RUN_FOREVER);
rtmSetTFinal(S,stoptime);
MdlInitializeSizes();
MdlInitializeSampleTimes();
status = rt_SimInitTimingEngine(rtmGetNumSampleTimes(S),
rtmGetStepSize(S),
rtmGetSampleTimePtr(S),
rtmGetOffsetTimePtr(S),
rtmGetSampleHitPtr(S),
rtmGetSampleTimeTaskIDPtr(S),
rtmGetTStart(S),
&rtmGetSimTimeStep(S),
&rtmGetTimingData(S));
if (status != NULL) {
(void)fprintf(stderr,
"Failed to initialize sample time engine: %s\n", status);
exit(EXIT_FAILURE);
sprintf(errorMsg, "Failed to initialize sample time engine: %s", status);
return errorMsg;
}
rt_CreateIntegrationData(S);
GBLbuf.errmsg = rt_StartDataLogging(rtmGetRTWLogInfo(S),
rtmGetTFinal(S),
rtmGetStepSize(S),
&rtmGetErrorStatus(S));
rtExtModeWaitForStartPkt(rtmGetRTWExtModeInfo(S),
rtmGetNumSampleTimes(S),
(boolean_T *)&rtmGetStopRequested(S));
MdlStart();
if (rtmGetErrorStatus(S) != NULL) {
GBLbuf.stopExecutionFlag = 1;
}
errorMsg[0] = 0;
return errorMsg;
}
}
//*********************************************************************************************************************** //*** perform one MATLAB step //*********************************************************************************************************************** char* OneStep( int nbrInputArgs, double* inputArgs, int nbrOutputArgs, double* outputArgs) { real_T tnext;
int i;
real_T *pVariableValue;
//S=MODEL();
//MdlInitializeSizes();
//Subsystem_U.OutputVar1 = inputArgs[0];
pVariableValue = S->ModelData.inputs;
for (i=0; i<S->Sizes.numU; i++)
{
*pVariableValue = inputArgs[i];
//pVariableValue = pVariableValue + sizeof(real_T);
pVariableValue++;
}
/***********************************************
* Check and see if base step time is too fast *
***********************************************/
if (GBLbuf.isrOverrun++)
{
GBLbuf.stopExecutionFlag = 1;
sprintf(errorMsg, "GBLbuf.isrOverrun");
return errorMsg;
}
/***********************************************
* Check and see if error status has been set *
***********************************************/
if (rtmGetErrorStatus(S) != NULL)
{
GBLbuf.stopExecutionFlag = 1;
sprintf(errorMsg, "rtmGetErrorStatus(S) != null");
return errorMsg;
}
/* enable interrupts here */
/*
* In a multi-tasking environment, this would be removed from the base rate
* and called as a "background" task.
*/
rtExtModeOneStep(rtmGetRTWExtModeInfo(S),
rtmGetNumSampleTimes(S),
(boolean_T *)&rtmGetStopRequested(S));
tnext = rt_SimGetNextSampleHit();
rtsiSetSolverStopTime(rtmGetRTWSolverInfo(S),tnext);
MdlOutputs(0);
rtExtModeSingleTaskUpload(S);
GBLbuf.errmsg = rt_UpdateTXYLogVars(rtmGetRTWLogInfo(S),
rtmGetTPtr(S));
if (GBLbuf.errmsg != NULL)
{
GBLbuf.stopExecutionFlag = 1;
sprintf(errorMsg, "GBLbuf.errmsg != null");
return errorMsg;
}
rt_UpdateSigLogVars(rtmGetRTWLogInfo(S), rtmGetTPtr(S));
MdlUpdate(0);
rt_SimUpdateDiscreteTaskSampleHits(rtmGetNumSampleTimes(S),
rtmGetTimingData(S),
rtmGetSampleHitPtr(S),
rtmGetTPtr(S));
if (rtmGetSampleTime(S,0) == CONTINUOUS_SAMPLE_TIME)
{
rt_UpdateContinuousStates(S);
}
GBLbuf.isrOverrun--;
rtExtModeCheckEndTrigger();
//outputArgs[0] = Subsystem_Y.InputVariable1; etc. pVariableValue = S->ModelData.outputs; for (i=0; i<S->Sizes.numY; i++) { outputArgs[i]=*pVariableValue; //pVariableValue = pVariableValue + sizeof(real_T); pVariableValue++; }
return errorMsg;
}
//************************************************************************ // * start TRNSYS //************************************************************************ double inArray; double *outArray; //*********************************************************************** // Object: Matlab model wrapper // IISiBat Model: Component1 // // Author: Werner Keilholz // Editor: Werner Keilholz // Date: octobre 03, 2007 last modified: octobre 03, 2007 // // // * // * Model Parameters : none (transform MATLAB parameters to inputs if required) // *
// * // * Model Inputs : depends on the MATLAB model // *
// * // * Model Outputs : depends on the MATLAB model // *
// * // * Model Derivatives : none // *
// (Based on routine interface generated by TRNSYS Studio) //************************************************************************
static int nin= 0; // number of inputs static int nout=0; // number of outputs // extern __declspec(dllexport) int TRNSYS_SUBROUTINE_NAME ( double ptime, // the simulation time - & operator in C++ double xin[], // the array containing the component InpUTS double xout[], // the array which the component fills with its appropriate OUTPUTS double *pt, // the array containing the dependent variables for which the derivatives are evaluated - & operator in C++ double *pdtdt, // the array containing the derivatives of T which are evaluated - & operator in C++ double par[], // the array containing the PARAMETERS of the component int info[], // the information array described in Section 3.3.3 of the manual int icntrl // the control array described in Section 3.3.4 of the manual ) { //************************************************************************ //*** TYPE implementation //*** This function will be called by TRNSYS //*** - once at the beginning of the simulation for initialization //*** - once at the beginning of every timestep for initialization //*** - once for each iteration of the TRNSYS solver //*** - once at the end of each timestep for cleanup //*** - once at the end of the simulation for cleanup //************************************************************************* // //*** //*** WARNING: explanations in the TRNSYS manual use FORTRAN conventions for //*** array indices. Subtract 1 to obtain 0-based C or C++ conventions. //*** Example: //*** TRNSYS manual: info(6) = number of OUTPUTS //*** -> write no = info[5] to obtain number of outputs in C or C++ //*** //*** We also spell variables in lower case according to C tradition, while they //*** are spelled in uppercase in the TRNSYS manual (according to FORTRAN tradition) //***
//----------------------------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------------------------- double time; double t; double dtdt;
// *** STANDARD TRNSYS DECLARATIONS
int npar= 0; // number of parameters we expect
int nder=0; // number of derivatives
int iunit; // UNIT number ('serial number' of the component, from the input file (the 'deck')
int itype; // TYPE number (component number)
int dummy=1;
int i;
int nMatlabOutputs; /* Number of model outputs */
int nMatlabInputs; /* Number of model inputs */
time = *ptime; t=*pt; dtdt=*pdtdt;
// read context information from TRNSYS
// (uncomment lines as required)
//info[2] = nin; // number of outputs
//info[5] = nout; // number of outputs
iunit = info[0]; // UNIT number itype = info[1]; // TYPE number
//info[2] ; // number of INPUTS specified by the user of the component //info[3] ; // number of PARAMETERS specified by the user of the component //info[4] ; // number of DERIVATIVES specified by the user of the component //info[5] ; // number of OUTPUTS specified by the user of the component
//info[6] ; // number of iterative calls to the UNIT in the current timestep
// -2 = initialization
// -1 = initial call in simulation for this UNIT
// 0 = first call in timestep for this UNIT.
// 1 = second call in timestep for this UNIT, etc.
//info(7) ; // total number of calls to the UNIT in the simulation // * inform TRNSYS about properties of this type info[8] = 0; // indicates whether TYPE depends on the passage of time: 0=no info[9] = 0; // use to allocate storage (see Section 3.5 of the TRNSYS manual): 0 = none // info[10]; // indicates number of discrete control variables (see Section 3.3.4 of the TRNSYS manual) //-----------------------------------------------------------------------------------------------------------------------
iunit=info[0]; itype=info[1];
//----------------------------------------------------------------------------------------------------------------------- // SET THE VERSION INFORMATION FOR TRNSYS if (info[6]== -2) { info[11]=16; // add additional initialisation code here, if any return 1; } //-----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------- // DO ALL THE VERY LAST CALL OF THE SIMULATION MANIPULATIONS HERE if (info[7]== -1) { #ifdef UseMMIDataLogging rt_CleanUpForStateLogWithMMI(rtmGetRTWLogInfo(S)); rt_CleanUpForSigLogWithMMI(rtmGetRTWLogInfo(S)); #endif rt_StopDataLogging(MATFILE,rtmGetRTWLogInfo(S));
rtExtModeShutdown(rtmGetNumSampleTimes(S));
if (GBLbuf.errmsg)
{
(void)fprintf(stderr,"%s\n",GBLbuf.errmsg);
exit(EXIT_FAILURE);
}
if (rtmGetErrorStatus(S) != NULL) {
(void)fprintf(stderr,"ErrorStatus set: \"%s\"\n", rtmGetErrorStatus(S));
exit(EXIT_FAILURE);
}
if (GBLbuf.isrOverrun) {
(void)fprintf(stderr,
"%s: ISR overrun - base sampling rate is too fast\n",
QUOTE(MODEL));
exit(EXIT_FAILURE);
}
#ifdef MULTITASKING else { int_T i; for (i=1; i<NUMST; i++) { if (GBLbuf.overrunFlags[i]) { (void)fprintf(stderr, "%s ISR overrun - sampling rate is too fast for " "sample time index %d\n", QUOTE(MODEL), i); exit(EXIT_FAILURE); } } } #endif
MdlTerminate();
return 1; }
//-----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------- // PERFORM ANY 'AFTER-ITERATION' MANIPULATIONS THAT ARE REQUIRED HERE // e.g. save variables to storage array for the next timestep if (info[12]>0) { return 1; } //-----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------- // DO ALL THE VERY FIRST CALL OF THE SIMULATION MANIPULATIONS HERE if (info[6]== -1) // first call of this component in the simulation { //S=MODEL(); initMatlab(); // MATLAB
MdlInitializeSizes();
nMatlabOutputs = S->Sizes.numY; // Number of MATLAB model outputs
nMatlabInputs = S->Sizes.numU; // Number of MATLAB model inputs
nin = nMatlabInputs;
nout = nMatlabOutputs;
// SET SOME INFO ARRAY VARIABLES TO TELL THE TRNSYS ENGINE HOW THIS TYPE IS TO WORK
info[2]=nin;
info[5]=nout;
info[8]=1;
info[9]=0; // STORAGE FOR VERSION 16 HAS BEEN CHANGED
// SET THE REQUIRED NUMBER OF INPUTS, PARAMETERS AND DERIVATIVES THAT THE USER SHOULD SUPPLY IN THE INPUT FILE // IN SOME CASES, THE NUMBER OF VARIABLES MAY DEPEND ON THE VALUE OF PARAMETERS TO THIS MODEL.... npar=0; nder=0; // CALL THE TYPE CHECK SUBROUTINE TO COMPARE WHAT THIS COMPONENT REQUIRES TO WHAT IS SUPPLIED IN // THE TRNSYS INPUT FILE
TYPECK(&dummy,info,&nin,&npar,&nder);
inArray = (double*) malloc(nin*sizeof(double)); outArray= (double*) malloc(nout*sizeof(double));
// init outputs for (i=0; i<nout;i++) xout[i]=0;
for (i=0; i<nout;i++) xout[i]=0;
return 1;
}
//----------------------------------------------------------------------------------------------------------------------- // DO ALL OF THE INITIAL TIMESTEP MANIPULATIONS HERE - THERE ARE NO ITERATIONS AT THE INTIAL TIME if (time < (getSimulationStartTime() + getSimulationTimeStep()/2.0)) { // SET THE UNIT NUMBER FOR FUTURE CALLS iunit=info[0]; itype=info[1];
// PERFORM ANY REQUIRED CALCULATIONS TO SET THE INITIAL VALUES OF THE OUTPUTS HERE // out1
// init matlab
return 1;
}
//-----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------- // * ITS AN ITERATIVE CALL TO THIS COMPONENT * //-----------------------------------------------------------------------------------------------------------------------
// prepare inputs for MATLAB
for (i=0; i<nin;i++)
inArray[i]=xin[i];
OneStep(nin,inArray,nout,outArray); // run, Forest!
// get outputs from MATLAB, give them back to TRNSYS
for (i=0; i<nout;i++)
xout[i]=outArray[i];
return 1;
}
/* EOF: trnsys_main.c */
  1 Comment
sahar tajik
sahar tajik on 25 Nov 2017
how can i write type 840 in trnsys?

Sign in to comment.

Answers (1)

Mark McBroom
Mark McBroom on 29 Mar 2022
By default grt.tlc generates non-resuable code. In <model>.c you will note global variables for holding state information. To avoid this, on the Configuration Paramters -> Code Generation -> Interface tab, change "Code Interface packaging" to "Reusable Function". This will now generate a reusable function that has data structures for inputs, outputs, states and parameters all passed to the generated code. This will allow you to reuse the DLL multiple times in the same Simulink model.

Tags

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!