You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

411 lines
12 KiB

/*.......1.........2.........3.........4.........5.........6.........7.........8
================================================================================
FILE filesource/cfunc.mod
Copyright 2011
Thomas Sailer
AUTHORS
20 May 2011 Thomas Sailer
03 Sep 2012 Holger Vogt
27 Feb 2017 Marcel Hendrix
23 JUL 2018 Holger Vogt
MODIFICATIONS
SUMMARY
This file contains the model-specific routines used to
functionally describe the file source code model used
to read an array from a file containing lines with
time and analog values, and returning them per time step.
INTERFACES
FILE ROUTINE CALLED
N/A N/A
REFERENCED FILES
Inputs from and outputs to ARGS structure.
NON-STANDARD FEATURES
NONE
===============================================================================*/
/*=== INCLUDE FILES ====================*/
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
/*=== CONSTANTS ========================*/
/*=== MACROS ===========================*/
#if defined(__MINGW32__) || defined(_MSC_VER)
#define DIR_PATHSEP "\\"
#else
#define DIR_PATHSEP "/"
#endif
/* For WIN32, make strdup become _strdup unless it is defined already,
* as it would be if CRT debugging is being used */
#if defined(_WIN32) && !defined(strdup)
#define strdup _strdup
#endif
/*=== LOCAL VARIABLES & TYPEDEFS =======*/
struct filesource_state {
FILE *fp;
unsigned char atend;
};
struct infiledata {
double *datavec;
size_t vecallocated;
int maxoccupied;
int actpointer;
int size;
};
typedef struct {
double *amplinterval; /* the storage array for the
amplitude offsets */
double *timeinterval; /* the storage array for the
time offset */
struct filesource_state *state; /* the storage array for the
filesource status. */
struct infiledata *indata; /* the storage vector for the input data
sourced from file. */
} Local_Data_t;
/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/
/*==============================================================================
FUNCTION void cm_filesource()
AUTHORS
20 May 2011 Thomas Sailer
MODIFICATIONS
07 Sept 2012 Holger Vogt
27 Feb 2017 Marcel Hendrix
23 JUL 2018 Holger Vogt
SUMMARY
This function implements the filesource code model.
INTERFACES
FILE ROUTINE CALLED
N/A N/A
RETURNED VALUE
Returns inputs and outputs via ARGS structure.
GLOBAL VARIABLES
NONE
NON-STANDARD FEATURES
NONE
==============================================================================*/
/*=== CM_FILESOURCE ROUTINE ===*/
static void cm_filesource_callback(ARGS, Mif_Callback_Reason_t reason);
void cm_filesource(ARGS) /* structure holding parms, inputs, outputs, etc. */
{
int size = PORT_SIZE(out);
int stepsize = size + 1;
int amplscalesize;
int amploffssize;
int j;
Local_Data_t *loc; /* Pointer to local static data, not to be included
in the state vector */
if(ANALYSIS == MIF_AC) {
return;
}
if (INIT == 1) {
int count;
/*** allocate static storage for *loc ***/
if ((loc = (Local_Data_t *) (STATIC_VAR(locdata) = calloc(1,
sizeof(Local_Data_t)))) == (Local_Data_t *) NULL) {
cm_message_send("Unable to allocate Local_Data_t "
"in cm_filesource()");
return;
}
/* Allocate storage for internal state */
loc->timeinterval = (double *) calloc(2, sizeof(double));
loc->amplinterval = (double *) calloc(2 * (size_t) size,
sizeof(double));
loc->state = (struct filesource_state *) calloc(1,
sizeof(struct filesource_state)); /* calloc to null fp */
loc->indata = (struct infiledata *) malloc(
sizeof(struct infiledata));
loc->indata->datavec = (double *) malloc(sizeof(double) *
(size_t) (stepsize * 1000));
/* Check allocations */
if (loc->timeinterval == (double *) NULL ||
loc->amplinterval == (double *) NULL ||
loc->state == (struct filesource_state *) NULL ||
loc->indata == (struct infiledata *) NULL ||
loc->indata->datavec == (double *) NULL) {
cm_message_send("Unable to allocate Local_Data_t fields "
"in cm_filesource()");
cm_filesource_callback(mif_private, MIF_CB_DESTROY);
return;
}
CALLBACK = cm_filesource_callback;
loc->indata->vecallocated = (size_t) (stepsize * 1000);
loc->indata->maxoccupied = 0;
loc->indata->actpointer = 0;
loc->indata->size = stepsize;
/* open the file */
loc->state->fp = fopen_with_path(PARAM(file), "r");
loc->state->atend = 0;
if (!loc->state->fp) {
char *lbuffer;
lbuffer = getenv("NGSPICE_INPUT_DIR");
if (lbuffer && *lbuffer) {
char *p;
if ((p = (char *) malloc(strlen(lbuffer) +
strlen(DIR_PATHSEP) + strlen(PARAM(file)) + 1)) ==
(char *) NULL) {
cm_message_send("Unable to allocate buffer "
"for building file name in cm_filesource()");
}
else {
sprintf(p, "%s%s%s", lbuffer, DIR_PATHSEP, PARAM(file));
loc->state->fp = fopen(p, "r");
free(p);
}
}
if (!loc->state->fp) {
cm_message_printf("cannot open file %s", PARAM(file));
loc->state->atend = 1;
}
}
/* read, preprocess and store the data */
amplscalesize = PARAM_NULL(amplscale) ? 0 : PARAM_SIZE(amplscale);
amploffssize = PARAM_NULL(amploffset) ? 0 : PARAM_SIZE(amploffset);
count = 0;
while (!loc->state->atend) {
char line[512];
char *cp, *cpdel;
char *cp2;
double t, tprev = 0;
int i;
if (!fgets(line, sizeof(line), loc->state->fp)) {
loc->state->atend = 1;
break;
}
if ((cpdel = cp = strdup(line)) == (char *) NULL) {
cm_message_send("Unable to duplicate string "
"cm_filesource()");
loc->state->atend = 1;
break;
}
/* read the time channel; update the time difference */
while (*cp && isspace_c(*cp))
++cp;
if (*cp == '*' || *cp == '#' || *cp == ';') {
free(cpdel);
continue;
}
t = strtod(cp, &cp2);
if (cp2 == cp) {
free(cpdel);
continue;
}
cp = cp2;
if (!PARAM_NULL(timescale))
t *= PARAM(timescale);
if (!PARAM_NULL(timerelative) && PARAM(timerelative) == MIF_TRUE)
t += tprev;
else if (!PARAM_NULL(timeoffset))
t += PARAM(timeoffset);
tprev = t;
/* before storing, check if vector size is large enough.
If not, add another 1000*size doubles */
if (count > (int) loc->indata->vecallocated - size) {
loc->indata->vecallocated += (size_t) (size * 1000);
void * const p = realloc(loc->indata->datavec,
sizeof(double) * loc->indata->vecallocated);
if (p == NULL) {
cm_message_printf("cannot allocate enough memory");
break; // loc->state->atend = 1;
}
loc->indata->datavec = (double *) p;
}
loc->indata->datavec[count++] = t;
/* read the data channels; update the amplitude difference of each channel */
for (i = 0; i < size; ++i) {
while (*cp && (isspace_c(*cp) || *cp == ','))
++cp;
t = strtod(cp, &cp2);
if (cp2 == cp)
break;
cp = cp2;
if (i < amplscalesize)
t *= PARAM(amplscale[i]);
if (i < amploffssize)
t += PARAM(amploffset[i]);
loc->indata->datavec[count++] = t;
}
free(cpdel);
}
loc->indata->maxoccupied = count;
if(loc->state->fp) {
fclose(loc->state->fp);
loc->state->fp = NULL;
}
/* set the start time data */
loc->timeinterval[0] = loc->indata->datavec[loc->indata->actpointer];
loc->timeinterval[1] = loc->indata->datavec[loc->indata->actpointer + stepsize];
}
loc = STATIC_VAR (locdata);
/* The file pointer is at the same position it was for the last simulator TIME ...
* If TIME steps backward, for example due to a second invocation of a 'tran' analysis
* step back in datavec[loc->indata->actpointer] .
*/
if (TIME < loc->timeinterval[0]) {
while (TIME < loc->indata->datavec[loc->indata->actpointer] && loc->indata->actpointer >= 0)
loc->indata->actpointer -= stepsize;
loc->timeinterval[0] = loc->indata->datavec[loc->indata->actpointer];
loc->timeinterval[1] = loc->indata->datavec[loc->indata->actpointer + stepsize];
}
while (TIME > loc->timeinterval[1]) {
loc->indata->actpointer += stepsize;
if (loc->indata->actpointer > loc->indata->maxoccupied) {
/* we are done */
return;
}
loc->timeinterval[1] = loc->indata->datavec[loc->indata->actpointer + stepsize];
loc->timeinterval[0] = loc->indata->datavec[loc->indata->actpointer];
}
for (j = 0; j < size; j++) {
loc->amplinterval[2 * j] = loc->indata->datavec[loc->indata->actpointer + j + 1];
loc->amplinterval[2 * j + 1] = loc->indata->datavec[loc->indata->actpointer + stepsize + j + 1];
}
if (loc->timeinterval[0] <= TIME && TIME <= loc->timeinterval[1]) {
if (!PARAM_NULL(amplstep) && PARAM(amplstep) == MIF_TRUE) {
int i;
for (i = 0; i < size; ++i)
OUTPUT(out[i]) = loc->amplinterval[2 * i];
} else {
double mul0 = (loc->timeinterval[1] - TIME) / (loc->timeinterval[1] - loc->timeinterval[0]);
double mul1 = 1.0 - mul0;
int i;
for (i = 0; i < size; ++i)
OUTPUT(out[i]) = mul0 * loc->amplinterval[2 * i] + mul1 * loc->amplinterval[2 * i + 1];
}
} else {
int i;
for (i = 0; i < size; ++i)
OUTPUT(out[i]) = loc->amplinterval[2 * i + 1];
}
} /* end of function cm_filesource */
static void cm_filesource_callback(ARGS, Mif_Callback_Reason_t reason)
{
switch (reason) {
case MIF_CB_DESTROY: {
Local_Data_t *loc = (Local_Data_t *) STATIC_VAR(locdata);
if (loc == (Local_Data_t *) NULL) {
break;
}
if (loc->state != (struct filesource_state *) NULL) {
if (loc->state->fp != (FILE *) NULL) {
fclose(loc->state->fp);
}
free(loc->state);
}
if (loc->amplinterval != (double *) NULL) {
free(loc->amplinterval);
}
if (loc->timeinterval != (double *) NULL) {
free(loc->timeinterval);
}
if (loc->indata) {
if (loc->indata->datavec) {
free(loc->indata->datavec);
}
free(loc->indata);
}
free(loc);
STATIC_VAR(locdata) = NULL;
break;
}
}
} /* end of function cm_filesource_callback */