/* Copyright (c) 2017 Dassault Systemes. All rights reserved. */
#define S_FUNCTION_NAME sfun_ndtable
#define S_FUNCTION_LEVEL 2
#include
#if (_MSC_VER >= 1600)
#define __STDC_UTF_16__
#endif
extern "C" {
#include "simstruc.h"
}
#include "NDTable.h"
enum Parameter {
interpMethodParam,
extrapMethodParam,
dataParam,
numberOfParams
};
inline NDTable_InterpMethod_t interpMethod(SimStruct *S) {
int v = static_cast(mxGetScalar(ssGetSFcnParam(S, interpMethodParam)));
return static_cast(v);
}
inline NDTable_ExtrapMethod_t extrapMethod(SimStruct *S) {
int v = static_cast(mxGetScalar(ssGetSFcnParam(S, extrapMethodParam)));
return static_cast(v);
}
inline void _getDims(SimStruct *S, int *dims) {
real_T *data = static_cast(mxGetData(ssGetSFcnParam(S, dataParam)));
int ndims = data[0];
for (int i = 0; i < ndims; i++) {
dims[i] = data[i + 1];
}
}
#define MDL_CHECK_PARAMETERS
#if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE)
static void mdlCheckParameters(SimStruct *S) {
//ssPrintf("\nmdlCheckParameters()\n");
if (!mxIsNumeric(ssGetSFcnParam(S, interpMethodParam)) || mxGetNumberOfElements(ssGetSFcnParam(S, interpMethodParam)) != 1) {
ssSetErrorStatus(S, "Parameter 1 (interpolation method) must be a scalar");
return;
}
switch (interpMethod(S)) {
case NDTABLE_INTERP_HOLD:
case NDTABLE_INTERP_NEAREST:
case NDTABLE_INTERP_LINEAR:
case NDTABLE_INTERP_AKIMA:
case NDTABLE_INTERP_FRITSCH_BUTLAND:
case NDTABLE_INTERP_STEFFEN:
break;
default:
ssSetErrorStatus(S, "Parameter 1 (interpolation method) must be one of 1 (= hold), 2 (= nearest), 3 (= linear), 4 (= Akima), 5 (= Fritsch-Butland) or 6 (= Steffen)");
return;
}
if (!mxIsNumeric(ssGetSFcnParam(S, extrapMethodParam)) || mxGetNumberOfElements(ssGetSFcnParam(S, extrapMethodParam)) != 1) {
ssSetErrorStatus(S, "Parameter 2 (extrapolation method) must be a scalar");
return;
}
switch (extrapMethod(S)) {
case NDTABLE_EXTRAP_HOLD:
case NDTABLE_EXTRAP_LINEAR:
case NDTABLE_EXTRAP_NONE:
break;
default:
ssSetErrorStatus(S, "Parameter 2 (extrapolation method) must be one of 1 (= hold), 2 (= linear) or 3 (= no extrapolation)");
return;
}
int rank, i, size, dims[32];
const double *scales[32];
NDTable_h table = NULL;
if (!mxIsNumeric(ssGetSFcnParam(S, dataParam))) {
ssSetErrorStatus(S, "Parameter 3 (data) must be numeric");
return;
}
size = mxGetNumberOfElements(ssGetSFcnParam(S, dataParam));
if (size < 2) {
ssSetErrorStatus(S, "The number of elements in parameter 3 (data) must be >= 2");
return;
}
const real_T *data = (real_T *)mxGetData(ssGetSFcnParam(S, dataParam));
rank = *data++;
// check the rank
if (rank < 0 || rank > 32) {
ssSetErrorStatus(S, "The first element in data must be in the range [0;32]");
return;
}
// check the size
if (size < 1 + rank) {
ssSetErrorStatus(S, "Parameter 3 (data) has not enough elements for the given number of dimensions");
return;
}
// check the dimensions
for (i = 0; i < rank; i++) {
dims[i] = *data++;
if (dims[i] < 1) {
ssSetErrorStatus(S, "The size of the dimensions must be >= 1");
return;
}
}
// check the number of elements
int numel = 1;
for (i = 0; i < rank; i++) {
numel *= dims[i]; // data
}
for (i = 0; i < rank; i++) {
numel += dims[i]; // scales
}
numel += rank; // dims
numel++; // ndims
if (size != numel) {
ssSetErrorStatus(S, "Parameter 3 (data) has the wrong number of elements for the given dimensions. Expected %d but was %d.", numel, size);
return;
}
}
#endif /* MDL_CHECK_PARAMETERS */
static void mdlInitializeSizes(SimStruct *S) {
//ssPrintf("\nmdlInitializeSizes()\n");
size_t i = 0;
int ndims = -1;
//
ssSetNumSFcnParams(S, numberOfParams);
#if defined(MATLAB_MEX_FILE)
if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
mdlCheckParameters(S);
if (ssGetErrorStatus(S) != NULL) {
return;
}
} else {
return; // parameter mismatch will be reported by Simulink
}
#endif
ssSetNumPWork(S, 1);
ndims = ((real_T *)(mxGetData(ssGetSFcnParam(S, dataParam))))[0];
if (!ssSetNumInputPorts(S, ndims)) return;
for(i = 0; i < (size_t)ndims; i++) {
ssSetInputPortWidth(S, i, 1);
ssSetInputPortDirectFeedThrough(S, i, 1);
}
if (!ssSetNumOutputPorts(S,1)) return;
ssSetOutputPortWidth(S, 0, 1);
ssSetNumSampleTimes(S, 1);
/* Take care when specifying exception free code - see sfuntmpl.doc */
ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE);
}
static void mdlInitializeSampleTimes(SimStruct *S) {
ssSetSampleTime(S, 0, INHERITED_SAMPLE_TIME);
ssSetOffsetTime(S, 0, 0.0);
}
#define MDL_START
#if defined(MDL_START)
static void mdlStart(SimStruct *S) {
int ndims = 0;
int dims[32] = { 0 };
const double *scales[32] = { 0 };
real_T *data = (real_T *)mxGetData(ssGetSFcnParam(S, dataParam));
int idx = 0;
ndims = data[idx++];
for (int i = 0; i < ndims; i++) {
dims[i] = data[idx++];
}
for (int i = 0; i < ndims; i++) {
scales[i] = &data[idx];
idx += dims[i];
}
NDTable_h table = NDTable_create_table(ndims, dims, &data[idx], scales);
if (!table) {
ssSetErrorStatus(S, NDTable_get_error_message());
return;
}
ssGetPWork(S)[0] = table;
}
#endif /* MDL_START */
static void mdlOutputs(SimStruct *S, int_T tid) {
double params[32] = { 0 };
int i;
InputRealPtrsType u = nullptr;
NDTable_h table = static_cast(ssGetPWork(S)[0]);
for(i = 0; i < table->ndims; i++) {
u = ssGetInputPortRealSignalPtrs(S, i);
params[i] = *u[0];
}
real_T *y = ssGetOutputPortRealSignal(S, 0);
if (NDTable_evaluate(table, table->ndims, params, interpMethod(S), extrapMethod(S), y) != 0) {
ssSetErrorStatus(S, NDTable_get_error_message());
}
}
static void mdlTerminate(SimStruct *S) {
NDTable_free_table((NDTable_h)ssGetPWork(S)[0]);
}
#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