MATLAB Answers

reading ASCII data from a file from s function

6 views (last 30 days)
Tushar
Tushar on 29 Mar 2011
I would like to read an ASCII data from a file in an s-function. For example, the data in the file is a column array of real numbers like A(100,1) =[1;2;3;..]. I tried to read this data from a file (.dat file) in a s-function using the following code (given in an example by Jarrod Rivituso in Matlab Central file exchange http://www.mathworks.com/matlabcentral/fileexchange/13438:
static void mdlStart(SimStruct *S)
{
void** pwork = ssGetPWork(S);
FILE *datafile;
datafile = fopen("datafile.dat","r");
pwork[0] = datafile;
}
static void mdlOutputs(SimStruct *S, int_T tid)
{
//get pointer to the block's output signal
real_T *y = ssGetOutputPortSignal(S,0);
/*get pointer to array of pointers, where the first element is the address
*of the open file */
void** pwork = ssGetPWork(S);
/*read a floating point number and then the comma delimiter
*store the result in y*/
fscanf(pwork[0],"%f%*c",y);
}
This works fine. But if I try to use the values of in the array y (for example, read the data and assign it to y and then store it in z for o/p):
static void mdlOutputs(SimStruct *S, int_T tid)
{
//get pointer to the block's output signal
int ii;
real_T *z = ssGetOutputPortSignal(S,0);
real_T y[100];
/*get pointer to array of pointers, where the first element is the address
*of the open file */
void** pwork = ssGetPWork(S);
/*read a floating point number and then the comma delimiter
*store the result in y*/
fscanf(pwork[0],"%f%*c",&y);
for (ii=0;ii<100;ii++)
{z[ii]=y[ii];
}
}
Matlab crashes when I execute the corresponding file using mex (mex cfileiosfun.c)
It will be nice if someone can comment on this.

  0 Comments

Sign in to comment.

Answers (4)

MarkB
MarkB on 29 Mar 2011
I suspect that this is only a subset of the code in the S-function, so it is a little difficult to tell if things are truly missing, or if you just didn't paste them. However, it looks like you are using the "pwork" vector without actually allocating it in the first place.
You can confirm this by either attaching a debugger to the ".mex" file while it's running to see exactly which line is causing the break, or by the low-tech, old-fashioned way of commenting-out almost everything until it works, and then uncommenting things until it breaks again.
You can allocate one with the command "ssSetNumPWork", which can be called in "mdlInitializeSizes" or in "mdlSetWorkWidths". In this case, "mdlInitializeSizes" is probably the "right" place to do it. "mdlSetWorkWidths" is an optional function, which lets you set the size of your work vectors a little later, in case they depend on information that might not be available at "mdlInitializeSizes", such as a port dimensions. In this case, you know how much "pwork" you need, so you might as well do it in "mdlInitializeSizes" and not bother to write another function.
Also, make sure to close the file in "mdlTerminate".

  0 Comments

Sign in to comment.


Kaustubha Govind
Kaustubha Govind on 29 Mar 2011
Assuming that you are using Jarrod's code almost exactly (only with the stated modification to mdlOutputs), I see two issues with your code:
  1. The following line in the S-function: ssSetOutputPortWidth(S, 0, 1); states that the outport port width is only 1. However, you are trying to access 100 elements, which is causing a segmentation violation since you do not own those adjacent 99 values. If you really want to the output width to be 100, you should use: ssSetOutputPortWidth(S, 0, 100);
  2. The other issue does not cause the crash, but is something you should consider. The statement: fscanf(pwork[0],"%f%*c",&y); states that only one floating point number is read into the variable 'y' - therefore, the remaining 99 elements in 'y' are never assigned and will hold some arbitrary values.

  2 Comments

Kaustubha Govind
Kaustubha Govind on 31 Mar 2011
Tushar wrote:
-----------------------
1. In the Jarrod's code, he is also using the output port width of 1 (ssSetOutputPortWidth(S, 0, 1))while the data in the file datafile.dat is (1,1000).
2. In the code by Jarrod, he read the data file datafile.dat with (1,1000) size using the fscanf(pwork[0],"%f%*c",&y);
But I cannot use the values in the y array further as done in the modified code. The c file is executed correctly without errors using mex cfileiosfun.c. But when I run the simulink model filetest.mdl, Matlab crashes.
Please comment on this.
Also it will be nice if you tell me how to read a column matrix for example (100 2). How the fscanf statement looks like for data file with column matrix (100 2)?
Kaustubha Govind
Kaustubha Govind on 31 Mar 2011
What Jarrod does is read data incrementally from datafile.dat - since the file pointer is opened in mdlStart, each call to fscanf moves the pointer one floating point number down the stream. So, one number is read at _every_ time step. Therefore, the model would have to run through 1000 time-steps to read all the values in the file. (You must be careful about reading past EOF though).
To answer your question about reading a 100x2 matrix - you must first determine, whether you want to read a 1x2 matrix per time-step for 100 time-steps, or 100x2 at each time-step.
To read 1x2 per time-step, you can use:
real_T temp[2];
fscanf(pwork[0], "%f%*c%f%*c", temp, temp+1);
To read 100x2, I would recommend putting a for-loop with 100 iterations around the above statement.

Sign in to comment.


Tushar
Tushar on 1 Apr 2011
Thanks for your reply. But still my problem is not solved. Let me define my problem again.
I am using a Simulink model in which a block is controlled by an s-function (for the code see below). The values in the array xc and yc of size (1,716) each (only few values shown below) are hard coded in the s-function. These values are used further to calculate yout.
#define S_FUNCTION_NAME mysfunction
#define S_FUNCTION_LEVEL 2
#include "simstruc.h"
/* Define error messages */
#define ERR_INVALID_SET_INPUT_DTYPE_CALL \
"Invalid call to mdlSetInputPortDataType"
#define ERR_INVALID_SET_OUTPUT_DTYPE_CALL \
"Invalid call to mdlSetOutputPortDataType"
#define ERR_INVALID_DTYPE "Invalid input or output port data type"
static void mdlInitializeSizes(SimStruct *S){
/* Register parameters */
ssSetNumSFcnParams(S, 0);
if(ssGetNumSFcnParams(S)!=ssGetSFcnParamsCount(S))
return;
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
/* Register number and kind of ports */
if(!ssSetNumInputPorts(S, 1)) return;
if(!ssSetNumOutputPorts(S, 1)) return;
ssSetInputPortDataType(S, 0, SS_DOUBLE);
ssSetOutputPortDataType(S, 0, SS_DOUBLE);
ssSetInputPortDimensionInfo(S, 0, DYNAMIC_DIMENSION);
ssSetOutputPortDimensionInfo(S, 0, DYNAMIC_DIMENSION);
ssSetInputPortRequiredContiguous(S, 0, true);
ssSetInputPortDirectFeedThrough(S, 0, 1);
/* Inherited sample time */
ssSetNumSampleTimes(S, 1);
/* Number of steady states */
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
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){
/*lookup-table*/
real_T xc[]={ 0.000000000000e+00,
5.615535850000e-18,
1.212592399000e-17,...}
real_T yc[]={ 0.000000000000e+00,
6.000000000000e-05,
1.500000000000e-04,
3.100000000000e-04,...}
int_T x_len=716; /* Lenght of array */
int_T InDataWidth=ssGetInputPortWidth(S,0);/*Lenght of input */
const real_T *xin=(const real_T*)ssGetInputPortSignal(S,0); /* Input values*/
real_T *yout=(real_T*)ssGetOutputPortSignal(S,0);/*Output values */
int l; /* Auxiliary variable */
real_T abs_xin; /* Current input value */
for(l=0; l<InDataWidth; l++){
/* Find nearest x for xin by a binary search */
int n_up=x_len-1;
int n_low=0;
int k=x_len-1;
real_T m;
real_T b;
if(xin[l]<0)
abs_xin = -xin[l];
else
abs_xin = xin[l];
if(abs_xin < xc[k]){
while(n_up > n_low+1){
k=(n_up+n_low)/2;
if(abs_xin < xc[k])
n_up=k;
else
n_low=k;
}
}
/* Calculate m and b */
m=(yc[n_up]-yc[n_low])/(xc[n_up]-xc[n_low]);
b=yc[n_low]-m*xc[n_low];
/* Calculate yout */
yout[l]=m*abs_xin+b;
/* Adapt sign of xin to yout */
if(xin[l]<0)
yout[l]=-yout[l];
}
}
static void mdlTerminate(SimStruct *S){}
#ifdef MATLAB_MEX_FILE
#include "simulink.c" /* MEX-file interface mechanism */
#else
#include "cg_sfun.h" /* Code generation registration function */
#endif
I would like to read the values of these arrays from outside, from a file. I started to do it by following the code by Jarrod. But it is not working properly. I made following changes (I wrote only the changes, rest part of the code is as above). Here I started to read the values of xc, only, from a file Input_xc_row.dat:
#include <stdio.h>
ssSetOutputPortWidth(S, 0, 716);
ssSetNumPWork(S, 1);
static void mdlStart(SimStruct *S)
{
void** pwork = ssGetPWork(S);
FILE *datafile_xc;
datafile_xc = fopen("Input_xc_row.dat","r");
pwork[0] = datafile_xc;
}
static void mdlOutputs(SimStruct *S, int_T tid){
real_T xc[716];
int n;
void** pwork=ssGetPWork(S);
for (n=0;n<x_len;n++){
real_T temp;
fscanf(pwork[0],"%f",&temp);
xc[n]=temp;
}
static void mdlTerminate(SimStruct *S){
void** pwork = ssGetPWork(S);
FILE *datafile_xc;
datafile_xc=pwork[0];
fclose(datafile_xc);
}
The corresponding mex file excutes without any error but Matlab crashes when I run the corresponding Simulink model. Please comment.

  1 Comment

Kaustubha Govind
Kaustubha Govind on 1 Apr 2011
Could you try debugging your MEX file as described in the documentation: http://www.mathworks.com/help/techdoc/matlab_external/f32489.html. It might be useful to determine the exact line that causes the crash.

Sign in to comment.


Tushar
Tushar on 7 Apr 2011
I get the following error when I try to debug the MEX file:
MEX level2 S-function "DepFET" must be called with at least 4 right hand arguments

  1 Comment

Kaustubha Govind
Kaustubha Govind on 7 Apr 2011
Apologies. I gave you the wrong link for debugging. Here is how you debug S-functions: http://www.mathworks.com/support/tech-notes/1800/1819.html
You need to run the Simulink model which in turn runs the S-function (you cannot call the S-function directly from the MATLAB prompt as you can with MEX-functions).

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!