# CasADi codegen and S-Functions

Estimated reading time: 3 minutes

While the user guide does explain code-generation in full detail, it is handy to have a demonstration in a real environment like Matlab’s S-functions.

# The problem

We will design a Simulink block that implements a nonlinear mapping from ($\mathbf{R}^2$, $\mathbf{R}$) to ($\mathbf{R}$,$\mathbf{R}^2$):

import casadi.*

x = MX.sym('x',2);
y = MX.sym('y');

w = dot(x,y*x);
z = sin(x)+y+w;

f = Function('f',{x,y},{w,z});


# Code-generating

You may generate code from this with:

f.generate('f.c')


However, we’ll use the more advanced syntax since we have advanced requirements. In particular, we will use Matlab’s data-types for real and integer numbers, requiring us to include a header:

cg_options = struct;
cg = CodeGenerator('f',cg_options);
cg.generate();


This will create f.c, and also f.h (since we set the option with_header).

# S-Function initialize routine

Our S-Function code should include the header f.h. With it, we have access to the problem dimensions:

int_T n_in  = f_n_in();
int_T n_out = f_n_out();


Next, we can set the block’s input/output port dimensions:

int_T i;
if (!ssSetNumInputPorts(S, n_in)) return;
for (i=0;i<n_in;++i) {
const int_T* sp = f_sparsity_in(i);
/* Dense vector inputs assumed here */
ssSetInputPortWidth(S, i, sp[0]);
ssSetInputPortDirectFeedThrough(S, i, 1);
}

if (!ssSetNumOutputPorts(S, n_out)) return;
for (i=0;i<n_out;++i) {
const int_T* sp = f_sparsity_out(i);
/* Dense vector outputs assumed here */
ssSetOutputPortWidth(S, i, sp[0]);
}


CaADi codegenerated functions require working memory to evaluate. We can query the size requirements with:

int_T sz_arg, sz_res, sz_iw, sz_w;
f_work(&sz_arg, &sz_res, &sz_iw, &sz_w);


Our notion of workspaces maps easily to Simulink’s:

ssSetNumRWork(S, sz_w);
ssSetNumIWork(S, sz_iw);
ssSetNumPWork(S, sz_arg+sz_res);


The only issue is that we differentiate between pointers for the arguments and the results, while they are combined into a generic void* buffer in Simulink.

# S-Function output routine

First, we need access to the working memory. Simple enough for the real and integer workspaces:

    real_T* w = ssGetRWork(S);
int_T* iw = ssGetIWork(S);


For arg and res we have to perform arithmatic and casting from void** to the desired types:

    void** p = ssGetPWork(S);
const real_T** arg = (const real_T**) p;
p += sz_arg;
real_T** res = (real_T**) p;


Next, make arg point to the input data:

    for (i=0; i<n_in;++i) {
arg[i] = *ssGetInputPortRealSignalPtrs(S,i);
}


Make res point to the output data:

    for (i=0; i<n_out;++i) {
res[i] = ssGetOutputPortRealSignal(S,i);
}


Finally, run the CasADi function:

    f(arg,res,iw,w,0);


# Running

To actually run the block, we need to compile our S-Function:

mex s_function.c f.c