waveview/lib/ss_nsout.c

359 lines
8.5 KiB
C

/*
* ss_nsout.c: routines for SpiceStream that handle the ".out" file format
* from Synopsis' nanosim.
*
* include LICENSE
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
// #include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <float.h>
#include <spicestream.h>
#ifdef TRACE_MEM
#include <tracemem.h>
#endif
struct nsvar {
char *name;
int index;
VarType type;
};
void sf_clean_vlist(GList *list)
{
if ( ! list ){
return;
}
while (list) {
GList *next = list->next;
struct nsvar *nsv = (struct nsvar *) list->data;
g_free ( nsv->name);
g_free ( nsv);
list = next;
}
g_list_free (list);
}
/* convert variable type string from out-file to
* our type numbers
*/
static VarType sf_str2type_nsout(char *s)
{
if (app_strcasecmp(s, "v") == 0) {
return VOLTAGE;
} else if(app_strcasecmp(s, "i") == 0) {
return CURRENT;
} else {
return UNKNOWN;
}
}
/*
* return 1 ok
* 0 EOF
* -1 Error
*/
/* Read spice-type file header - nanosim "out" format */
int sf_rdhdr_nsout(SpiceStream *ss)
{
char *line;
char *key, *val;
int got_ivline = 0;
int ndvars;
GList *vlist = NULL;
int lineno;
int i;
int minindex = 0x7FFFFFFF;
int maxindex = 0;
int ret = -1;
struct nsvar *nsv = NULL;
int got_nsout = 0;
ss->voltage_resolution = 1.0;
ss->current_resolution = 1.0;
ss->time_resolution = 1.0;
while ( (line = fdbuf_get_line(ss->linebuf)) != NULL ) {
lineno = fdbuf_get_lineno(ss->linebuf);
if (lineno == 1 && *line != ';' ) {
/* not an out file; bail out */
msg_dbg("%s:\n line %d: Doesn't look like an ns-out file; \"output_format\" expected\n",
ss->filename, lineno );
goto err;
}
if ( app_strcasestr(line, "output_format") || app_strcasestr(line, "NanoSim") ) {
got_nsout = 1;
}
if (line[0] == ';'){
continue;
}
if ( ! got_nsout ) {
goto err;
}
if (line[0] == '.') {
key = strtok(&line[1], " \t");
if ( ! key) {
msg_error(_("%d: syntax error, expected \"keyword:\""), lineno );
goto err;
}
if (strcmp(key, "time_resolution") == 0) {
val = strtok(NULL, " \t\n");
if ( ! val) {
msg_error(_("%d: syntax error, expected number"), lineno );
goto err;
}
ss->time_resolution = g_ascii_strtod(val, NULL);
}
if (strcmp(key, "current_resolution") == 0) {
val = strtok(NULL, " \t\n");
if ( ! val) {
msg_error(_("%d: syntax error, expected number"), lineno);
goto err;
}
ss->current_resolution = g_ascii_strtod(val, NULL);
}
if (strcmp(key, "voltage_resolution") == 0) {
val = strtok(NULL, " \t\n");
if ( ! val) {
msg_error(_("%d: syntax error, expected number"), lineno);
goto err;
}
ss->voltage_resolution = g_ascii_strtod(val, NULL);
}
if (strcmp(key, "index") == 0) {
/* .index name index type */
nsv = g_new0(struct nsvar, 1);
vlist = g_list_append(vlist, nsv);
val = strtok(NULL, " \t\n");
if ( ! val) {
msg_error(_("%d: syntax error, expected varname"), lineno);
goto err;
}
nsv->name = g_strdup(val);
val = strtok(NULL, " \t\n");
if( ! val) {
msg_error(_("%d: syntax error, expected var-index"), lineno);
goto err;
}
nsv->index = atoi(val);
if (minindex > nsv->index ){
minindex = nsv->index;
}
if (nsv->index > maxindex){
maxindex = nsv->index;
}
val = strtok(NULL, " \t\n");
if ( ! val) {
msg_error(_("%d: syntax error, expected variable type"), lineno);
goto err;
}
nsv->type = sf_str2type_nsout(val);
}
}
if (isdigit(line[0])) {
got_ivline = 1;
break;
}
}
if ( ! line) {
return 0;
}
if ( ! vlist) {
msg_error(_("%d: no variable indices found in header"), lineno);
}
if ( ! got_ivline) {
msg_error(_("%d: EOF without data-line in header"), lineno);
goto err;
}
ndvars = g_list_length(vlist);
ss->minindex = minindex;
ss->maxindex = maxindex;
ss->datrow = g_new0(double, maxindex + 1 - minindex);
ss->nsindexes = g_new0(int, ndvars);
ss->ncols = 1;
ss->ntables = 1;
ss->ndv = ndvars;
dataset_var_add( ss->wds, "TIME", TIME, 1 );
for (i = 0; i < ndvars; i++) {
nsv = g_list_nth_data(vlist, i);
dataset_var_add( ss->wds, nsv->name, nsv->type, 1 );
ss->nsindexes[i] = nsv->index;
ss->ncols++;
msg_dbg("dv[%d] \"%s\" nsindex = %d",
i, nsv->name, ss->nsindexes[i]);
}
msg_dbg("Done with header at offset 0x%lx", (long) fdbuf_tello(ss->linebuf) );
ss->flags = SSF_NORDHDR | SSF_CPVARS | SSF_PUSHBACK;
ret = 1;
err:
sf_clean_vlist(vlist);
return ret;
}
/*
* Read row of values from an out-format file
* upon call, line buffer should always contain the
* independent-variable line that starts this set of values.
*/
int sf_readrow_nsout(SpiceStream *ss )
{
int i;
int lineno;
int idx;
char *sidx;
char *sval;
double val;
double scale;
char *line = ((DBuf *) ss->linebuf)->s;
// process iv line
// val = g_ascii_strtod(line, NULL) * ss->time_resolution * 1e-9; /* ns */
val = g_ascii_strtod(line, NULL) ; /* conversion should be done at display ? */
spicestream_val_add( ss, val);
// read and process dv lines until we see another iv line
while ( (line = fdbuf_get_line(ss->linebuf)) != NULL) {
if (line[0] == ';') {
continue;
}
lineno = fdbuf_get_lineno(ss->linebuf);
sidx = strtok(line, " \t");
if ( ! sidx) {
msg_error(_("%s:%d: expected value"), ss->filename, lineno);
return -1;
}
sval = strtok(NULL, " \t");
if ( ! sval)
/* no value token: this is the ivar line for the next row */
break;
idx = atoi(sidx);
if (idx <= ss->maxindex) {
ss->datrow[idx - ss->minindex ] = g_ascii_strtod(sval, NULL);
}
}
if ( line == NULL ) {
return 0;
}
for (i = 0; i < ss->ndv; i++) {
scale = 1.0;
int type = dataset_get_wavevar_type( ss->wds, i + 1 );
switch(type) {
case VOLTAGE:
scale = ss->voltage_resolution;
break;
case CURRENT:
scale = ss->current_resolution;
break;
default:
break;
}
val = ss->datrow[ss->nsindexes[i] - ss->minindex] * scale;
spicestream_val_add( ss, val );
}
return 1;
}
static char *sf_type2str_nsout(int type)
{
switch (type) {
case UNKNOWN:
return "U";
case TIME:
return "T";
case VOLTAGE:
return "V";
case CURRENT:
return "I";
case FREQUENCY:
return "F";
}
return "U";
}
void sf_write_file_nsout( FILE *fd, WaveTable *wt, char *fmt)
{
int i;
int j;
int k = 0;
char format1[32];
char format2[32];
time_t now;
double voltage_resolution = 1.0;
double current_resolution = 1.0;
double time_resolution = 1.0;
int index;
fprintf( fd, "; ------------------------------------------------------- \n");
fprintf( fd, ";| NanoSim Output Format |\n");
fprintf( fd, ";| |\n");
fprintf( fd, ";| Generated by Gaw |\n");
fprintf( fd, ";| |\n");
fprintf( fd, "; ------------------------------------------------------- \n");
fprintf( fd, ";\n");
time(&now) ;
fprintf( fd, "; %s", ctime(&now) );
fprintf( fd, ";\n");
fprintf( fd, ".voltage_resolution %g\n", voltage_resolution );
fprintf( fd, ".current_resolution %g\n", current_resolution );
fprintf( fd, ".time_resolution %g\n", time_resolution );
fprintf( fd, ";\n");
WDataSet *wds = wavetable_get_dataset( wt, k);
/* do not output ivar as index */
for ( i = 1 ; i < wds->numVars ; i++ ){
WaveVar *var = g_ptr_array_index( wds->vars, i);
index = 130 + i * 2;
fprintf( fd, ".index %s %d %s\n", var->varName, index,
sf_type2str_nsout(var->type) );
}
if ( ! fmt ) {
fmt = "%0.8f";
}
sprintf( format1, "%s\n", fmt );
sprintf( format2, "%%d %s\n", fmt );
while ( (wds = wavetable_get_dataset( wt, k++)) ){
for ( i = 0 ; i < wds->nrows ; i++ ){
for ( j = 0 ; j < wds->ncols ; j++ ){
index = 130 + j * 2;
double val = dataset_val_get( wds, i, j );
if ( j == 0 ){
fprintf( fd, format1, val);
} else {
fprintf( fd, format2, index, val);
}
}
}
}
}