📄 loadsig.c
字号:
/*
* loadsig.c: retrieval of HSPICE data into MATLAB
* written by Michael Perrott while at Silicon
* Laboratories. This code leveraged the work of
* Stephen G. Tell (i.e., his Gwave viewer) to
* develop the Hspice loading functions. At this
* point, the code here has little similarity to the
* routines he provided, but many thanks to Stephen
* for providing enough info to get started.
* For those wishing to modify this code - good luck!
* Unfortunatley, it is quite "hacked" due
* to the fact that the actual binary format of Hspice output
* was never provided (i.e., I simply updated the
* code each time a new issue was found), and due to the
* fact that I had little time to develop it. However,
* after years of use, it's pretty solid now.
*
* To compile this code into a mex file for Matlab, simply
* run Matlab in the directory that loadsig.c is contained
* and then type:
* mex loadsig.c
* You'll then have a loadsig mex function for whatever
* computer (i.e., Sun, Linux, Windows) that you're running
* on at the time.
*
* I do ask for one thing for those that use this code - please
* keep my name and Silicon Labs attached to it when the user
* first executes it (as currently done). I am not particularly
* interested in getting anything for this package other then
* recognition, but I do want that since this was a nontrivial
* amount of work. Of course, if you want to throw money at me,
* I'm happy to accomodate you. :) - Michael Perrott 6/3/03
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the MxFree
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#define MAX_NAME_LENGTH 1000
#define MAX_HEADER_BLOCKS 100
#define TIME 1
#define FREQUENCY 4
#define VOLTAGE 2
#define CURRENT 3
#define UNKNOWN 0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <float.h>
#include "mat.h"
#include "mex.h"
typedef struct
{
char **signal_name, **sweep_name;
int *signal_type; /* i.e. FREQ, TIME, VOLTAGE ... */
int num_signals, num_data_rows, num_data_cols, nauto;
int current_column, cur_sweep, num_sweeps, num_sweep_vars, num_sweep_names;
int *signal_first_row,*signal_num_rows;
float **signal_data, **sweep_data;
int block_size;
} SpiceData;
int fread_float_values(char *simsource,float *fval, FILE *fp);
size_t fread_int_values(char *simsource, unsigned int *ibuf,
int size_of_block, FILE *fp);
int hs_determine_variables(FILE *fp, SpiceData *sf, char *simsource);
void hs_process_header(char *line, SpiceData *sf);
int hs_read_column(FILE *fp, SpiceData *sf, char *simsource);
SpiceData *init_SpiceData(int num_signals, int nauto, int num_data_rows, int num_data_cols, int num_sweeps, int num_sweep_vars, int num_sweep_names, int block_size);
int hs_determine_num_data_rows(char *line, int num_signals, int nauto,
int *ind_sig_type, int num_sweep_names, int *num_sweep_vars);
SpiceData *hs_allocate_sf(FILE *fp, char *simsource);
int hs_validate_column(FILE *fp, int num_data_rows, int current_column, int num_sweep_vars, int block_size, char *simsource, int col_count);
void free_SpiceData(SpiceData *A);
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
SpiceData *sf;
FILE *fp;
int i,j,k,m,sweep_name_num;
float val;
/* char name[MAX_NAME_LENGTH],filename[MAX_NAME_LENGTH]; */
char filename[MAX_NAME_LENGTH], simsource[MAX_NAME_LENGTH];
mxArray *pa1;
double *matData;
const char *field_name[20] = {"name","data"};
static first_run=0;
/* mexPrintf("field_name = %s, %s\n",field_name[0],field_name[1]); */
if (nrhs != 1)
mexErrMsgTxt("Error: missing filename. Usage: x = loadsig('filename')");
if (!mxIsChar(prhs[0]))
mexErrMsgTxt("Error: filename must be a string");
if (nlhs != 1)
mexErrMsgTxt("Error: missing output variable. Usage: x = loadsig('filename')");
mxGetString(prhs[0],filename,MAX_NAME_LENGTH);
if (first_run == 0)
{
first_run = 1;
mexPrintf("\n*********************************************************\n");
mexPrintf(" Hspice Toolbox for Matlab\n");
mexPrintf(" written by Michael Perrott (http://www-mtl.mit.edu/~perrott)\n");
mexPrintf(" while at Silicon Laboratories (http://www.silabs.com)\n");
mexPrintf(" Copyright (C) 1999 by Silicon Laboratories, Inc.\n");
mexPrintf(" This software is distributed under the terms of\n");
mexPrintf(" the GNU Public License (see the COPYING file\n");
mexPrintf(" for more details), and comes with no warranty or support\n");
mexPrintf("*********************************************************\n\n");
}
if ((fp = fopen(filename,"rb")) == NULL)
mexErrMsgTxt("Error: file can't be opened");
sf = hs_allocate_sf(fp,simsource);
/*
mexPrintf("num_data_cols = %d, num_data_rows = %d, num_signals = %d\n",
sf->num_data_cols, sf->num_data_rows, sf->num_signals);
mexPrintf("current_col = %d\n",sf->current_column);
*/
if (sf == NULL)
return;
if (hs_determine_variables(fp,sf,simsource) == 0)
return;
/*
mexPrintf("num_data_cols = %d, num_data_rows = %d, num_signals = %d\n",
sf->num_data_cols, sf->num_data_rows, sf->num_signals);
mexPrintf("current_col = %d\n",sf->current_column);
*/
for (k = 0; k < sf->num_signals; k++)
{
for (i = 0; sf->signal_name[k][i] != '\0'; i++)
if (sf->signal_name[k][i] == '.' || sf->signal_name[k][i] == '(' ||
sf->signal_name[k][i] == ')' || sf->signal_name[k][i] == '+' ||
sf->signal_name[k][i] == '[' || sf->signal_name[k][i] == ']' ||
sf->signal_name[k][i] == '-' || sf->signal_name[k][i] == '*' ||
sf->signal_name[k][i] == '/' || sf->signal_name[k][i] == ',')
sf->signal_name[k][i] = '_';
/*
if (k == 0)
sprintf(name,"i");
else
sprintf(name,"d");
switch(sf->signal_type[k])
{
case TIME:
strcat(name,"t_");
break;
case FREQUENCY:
strcat(name,"f_");
break;
case VOLTAGE:
strcat(name,"v_");
break;
case CURRENT:
strcat(name,"i_");
break;
default:
strcat(name,"u_");
break;
}
strncat(name,sf->signal_name[k],MAX_NAME_LENGTH-3);
sprintf(sf->signal_name[k],"%s",name);
*/
}
/*
for (i = 0; i < sf->num_signals; i++)
mexPrintf("%s, type = %d, first_row = %d, num_rows = %d\n",
sf->signal_name[i], sf->signal_type[i],
sf->signal_first_row[i], sf->signal_num_rows[i]);
mexPrintf("num_signals = %d, nauto = %d\n",
sf->num_signals, sf->nauto);
mexPrintf("num_data_rows = %d, num_data_cols = %d, current_column = %d\n",
sf->num_data_rows, sf->num_data_cols, sf->current_column);
*/
for (k = 0; k < sf->num_sweeps; k++)
{
sf->cur_sweep = k;
sf->current_column = 0;
if (k > 0)
{
while(1)
{
if (fread_float_values(simsource,&val, fp) != 1)
{
mexPrintf("error: premature file end\n");
return;
}
if (strncmp(simsource,"hspice",6) == 0)
{
if (val >= (1e30 - DBL_EPSILON))
{
fseek(fp,20,SEEK_CUR);
break;
}
}
}
}
for (i = 0; i < sf->num_data_cols; i++)
{
if(hs_read_column(fp,sf,simsource) == 1)
{
mexPrintf("error: premature break\n");
break;
}
}
}
fclose(fp);
/* write into MATLAB structure */
plhs[0] = mxCreateStructMatrix(sf->num_signals+sf->num_sweep_vars,1,2,field_name);
/*
mexPrintf("num fields = %d\n",mxGetNumberOfFields(plhs[0]));
mexPrintf("size = %d\n",mxGetN(plhs[0])*mxGetM(plhs[0]));
for (i = 0; i < 2; i++)
mexPrintf("field name = %s\n",mxGetFieldNameByNumber(plhs[0],i));
*/
for (k = 0; k < sf->num_signals; k++)
{
/* copy over the signal name to the structure */
pa1 = mxCreateString(sf->signal_name[k]);
mxSetField(plhs[0],k,field_name[0],pa1);
if (sf->signal_num_rows[k] == 1)
pa1 = mxCreateDoubleMatrix(sf->num_data_cols,sf->num_sweeps,mxREAL);
else
pa1 = mxCreateDoubleMatrix(sf->num_data_cols,sf->num_sweeps,mxCOMPLEX);
/* copy over the spice data to the matlab matrix */
matData = mxGetPr(pa1);
j = 0; /* first data row */
for (i = 0; i < sf->num_data_cols; i++)
{
for (m = 0; m < sf->num_sweeps; m++)
{
matData[i + m*sf->num_data_cols] =
sf->signal_data[sf->signal_first_row[k]+j+m*sf->num_data_rows][i];
}
}
if (sf->signal_num_rows[k] == 2)
{
/* mexPrintf("complex for k = %d\n",k); */
matData = mxGetPi(pa1);
j = 1; /* second data row */
for (i = 0; i < sf->num_data_cols; i++)
{
for (m = 0; m < sf->num_sweeps; m++)
{
matData[i + m*sf->num_data_cols] =
sf->signal_data[sf->signal_first_row[k]+j+m*sf->num_data_rows][i];
}
}
}
mxSetField(plhs[0],k,field_name[1],pa1);
}
/* copy sweep parameters */
for (sweep_name_num = 0; k < sf->num_signals+sf->num_sweep_vars; k++, sweep_name_num++)
{
/* copy over the sweep parameter name to the structure */
pa1 = mxCreateString(sf->sweep_name[sweep_name_num]);
mxSetField(plhs[0],k,field_name[0],pa1);
pa1 = mxCreateDoubleMatrix(1,sf->num_sweeps,mxREAL);
/* copy over the spice data to the matlab matrix */
matData = mxGetPr(pa1);
for (i = 0; i < sf->num_sweeps; i++)
{
matData[i] = sf->sweep_data[sweep_name_num][i];
}
mxSetField(plhs[0],k,field_name[1],pa1);
}
free_SpiceData(sf);
return;
}
SpiceData *hs_allocate_sf(FILE *fp, char *simsource)
{
char *ahdr;
unsigned int ahdrsize, term_seq;
int nprobe,num_signals,nauto,block_size;
char nbuf[16], version[16], full_version[50];
int data_rows,i,data_cols,nsweep_var,nsweep_names;
int sig_type,val_flag,sweep_count;
int char_position,j;
unsigned int header_seg_length[MAX_HEADER_BLOCKS],k;
unsigned int ibuf[4];
int col_count;
/* probably not necessary to rewind, but just to make sure ... */
rewind(fp);
/* assume hspice is simulation source by default */
sprintf(simsource,"hspice");
if(fread_int_values(simsource,ibuf, 4, fp) != 4)
{
mexPrintf("error in hs_allocate_sf: EOF reading block1 header\n");
return(NULL);
}
if(ibuf[0] != 4 || ibuf[2] != 4)
{
/* check if Windows Hspice */
/*
printf("ibuf[0] = %x, ibuf[1] = %x, ibuf[2] = %x, ibuf[3] = %x\n",
ibuf[0],ibuf[1],ibuf[2],ibuf[3]);
*/
if (ibuf[0] == 0x4000000 && ibuf[2] == 0x4000000)
{
sprintf(simsource,"hspice_win");
/* printf("sim = %s\n",simsource); */
rewind(fp);
if (fread_int_values(simsource,ibuf, 4, fp) != 4)
{
mexPrintf("error in hs_allocate_sf: EOF reading block1 header\n");
return(NULL);
}
/* printf("ibuf[0] = %x, ibuf[1] = %x, ibuf[2] = %x, ibuf[3] = %x\n",
ibuf[0],ibuf[1],ibuf[2],ibuf[3]); */
if (ibuf[0] != 4 || ibuf[2] != 4)
{
mexPrintf("error in hs_allocate_sf: unexpected values in block1 header\n");
return(NULL);
}
}
else
{
mexPrintf("error in hs_allocate_sf: unexpected values in block1 header\n");
return(NULL);
}
}
ahdrsize = 0;
for (i = 0; i < MAX_HEADER_BLOCKS; i++)
{
header_seg_length[i] =ibuf[3];
ahdrsize += header_seg_length[i];
fseek(fp,header_seg_length[i]-8,SEEK_CUR);
if(fread_int_values(simsource,&term_seq,1, fp) != 1)
{
mexPrintf("error in hs_allocate_sf: EOF reading block trailer\n");
return(NULL);
}
/* mexPrintf("term_seq = %x\n",term_seq); */
fseek(fp,4,SEEK_CUR);
if(fread_int_values(simsource,ibuf,1, fp) != 1)
{
mexPrintf("error in hs_allocate_sf: EOF reading block trailer\n");
return(NULL);
}
/*
mexPrintf("ibuf[0] = %x, ibuf[1] = %x, ibuf[2] = %x, ibuf[3] = %x, head_length = %x\n",
ibuf[0],ibuf[1],ibuf[2],ibuf[3],header_seg_length[i]);
*/
if (ibuf[0] != header_seg_length[i])
{
mexPrintf("error in hs_allocate_sf: block trailer mismatch\n");
return(NULL);
}
if(fread_int_values(simsource,ibuf, 4, fp) != 4)
{
mexPrintf("error in hs_allocate_sf: EOF reading block header\n");
return(NULL);
}
if(ibuf[0] != 4 || ibuf[2] != 4)
{
mexPrintf("error in hs_allocate_sf: unexepected values in block header\n");
return(NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -